Skip to content

Commit

Permalink
Merge tag 'at91-reset-sama7g5-signed' into psy-next
Browse files Browse the repository at this point in the history
This adds reset controller support for SAMA7G5 SoCs. Compared with
previous version the reset controller embedded on SAMA7G5 is able to
reset individual on SoC devices (e.g. USB PHY controllers).

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
  • Loading branch information
Sebastian Reichel committed Jun 17, 2022
2 parents a4c0094 + a22c8e8 commit f94ba70
Show file tree
Hide file tree
Showing 4 changed files with 247 additions and 30 deletions.
15 changes: 0 additions & 15 deletions Documentation/devicetree/bindings/arm/atmel-sysregs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,6 @@ System Timer (ST) required properties:
Its subnodes can be:
- watchdog: compatible should be "atmel,at91rm9200-wdt"

RSTC Reset Controller required properties:
- compatible: Should be "atmel,<chip>-rstc".
<chip> can be "at91sam9260", "at91sam9g45", "sama5d3" or "samx7"
it also can be "microchip,sam9x60-rstc"
- reg: Should contain registers location and length
- clocks: phandle to input clock.

Example:

rstc@fffffd00 {
compatible = "atmel,at91sam9260-rstc";
reg = <0xfffffd00 0x10>;
clocks = <&clk32k>;
};

RAMC SDRAM/DDR Controller required properties:
- compatible: Should be "atmel,at91rm9200-sdramc", "syscon"
"atmel,at91sam9260-sdramc",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/reset/atmel,at91sam9260-reset.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Atmel/Microchip System Reset Controller

maintainers:
- Claudiu Beznea <claudiu.beznea@microchip.com>

description: |
The system reset controller can be used to reset the CPU. In case of
SAMA7G5 it can also reset some devices (e.g. USB PHYs).
properties:
compatible:
oneOf:
- items:
- enum:
- atmel,at91sam9260-rstc
- atmel,at91sam9g45-rstc
- atmel,sama5d3-rstc
- microchip,sam9x60-rstc
- microchip,sama7g5-rstc
- items:
- const: atmel,sama5d3-rstc
- const: atmel,at91sam9g45-rstc

reg:
minItems: 1
items:
- description: base registers for system reset control
- description: registers for device specific reset control

clocks:
maxItems: 1

"#reset-cells":
const: 1

required:
- compatible
- reg
- clocks

allOf:
- if:
properties:
compatible:
contains:
enum:
- microchip,sama7g5-rstc
then:
required:
- "#reset-cells"

additionalProperties: false

examples:
- |
#include <dt-bindings/clock/at91.h>
reset-controller@fffffd00 {
compatible = "atmel,at91sam9260-rstc";
reg = <0xfffffd00 0x10>;
clocks = <&pmc PMC_TYPE_CORE PMC_SLOW>;
};
184 changes: 169 additions & 15 deletions drivers/power/reset/at91-reset.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/reset-controller.h>

#include <soc/at91/at91sam9_ddrsdr.h>
#include <soc/at91/at91sam9_sdramc.h>

#include <dt-bindings/reset/sama7g5-reset.h>

#define AT91_RSTC_CR 0x00 /* Reset Controller Control Register */
#define AT91_RSTC_PROCRST BIT(0) /* Processor Reset */
#define AT91_RSTC_PERRST BIT(2) /* Peripheral Reset */
Expand All @@ -39,6 +42,17 @@
#define AT91_RSTC_URSTIEN BIT(4) /* User Reset Interrupt Enable */
#define AT91_RSTC_ERSTL GENMASK(11, 8) /* External Reset Length */

/**
* enum reset_type - reset types
* @RESET_TYPE_GENERAL: first power-up reset
* @RESET_TYPE_WAKEUP: return from backup mode
* @RESET_TYPE_WATCHDOG: watchdog fault
* @RESET_TYPE_SOFTWARE: processor reset required by software
* @RESET_TYPE_USER: NRST pin detected low
* @RESET_TYPE_CPU_FAIL: CPU clock failure detection
* @RESET_TYPE_XTAL_FAIL: 32KHz crystal failure dectection fault
* @RESET_TYPE_ULP2: ULP2 reset
*/
enum reset_type {
RESET_TYPE_GENERAL = 0,
RESET_TYPE_WAKEUP = 1,
Expand All @@ -50,15 +64,48 @@ enum reset_type {
RESET_TYPE_ULP2 = 8,
};

/**
* struct at91_reset - AT91 reset specific data structure
* @rstc_base: base address for system reset
* @ramc_base: array with base addresses of RAM controllers
* @dev_base: base address for devices reset
* @sclk: slow clock
* @data: platform specific reset data
* @rcdev: reset controller device
* @lock: lock for devices reset register access
* @nb: reset notifier block
* @args: SoC specific system reset arguments
* @ramc_lpr: SDRAM Controller Low Power Register
*/
struct at91_reset {
void __iomem *rstc_base;
void __iomem *ramc_base[2];
void __iomem *dev_base;
struct clk *sclk;
const struct at91_reset_data *data;
struct reset_controller_dev rcdev;
spinlock_t lock;
struct notifier_block nb;
u32 args;
u32 ramc_lpr;
};

#define to_at91_reset(r) container_of(r, struct at91_reset, rcdev)

/**
* struct at91_reset_data - AT91 reset data
* @reset_args: SoC specific system reset arguments
* @n_device_reset: number of device resets
* @device_reset_min_id: min id for device reset
* @device_reset_max_id: max id for device reset
*/
struct at91_reset_data {
u32 reset_args;
u32 n_device_reset;
u8 device_reset_min_id;
u8 device_reset_max_id;
};

/*
* unless the SDRAM is cleanly shutdown before we hit the
* reset register it can be left driving the data bus and
Expand Down Expand Up @@ -95,7 +142,7 @@ static int at91_reset(struct notifier_block *this, unsigned long mode,
"r" (reset->rstc_base),
"r" (1),
"r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN),
"r" (reset->args),
"r" (reset->data->reset_args),
"r" (reset->ramc_lpr)
: "r4");

Expand Down Expand Up @@ -153,34 +200,133 @@ static const struct of_device_id at91_ramc_of_match[] = {
{ /* sentinel */ }
};

static const struct at91_reset_data sam9260 = {
.reset_args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
};

static const struct at91_reset_data samx7 = {
.reset_args = AT91_RSTC_KEY | AT91_RSTC_PROCRST,
};

static const struct at91_reset_data sama7g5 = {
.reset_args = AT91_RSTC_KEY | AT91_RSTC_PROCRST,
.n_device_reset = 3,
.device_reset_min_id = SAMA7G5_RESET_USB_PHY1,
.device_reset_max_id = SAMA7G5_RESET_USB_PHY3,
};

static const struct of_device_id at91_reset_of_match[] = {
{
.compatible = "atmel,at91sam9260-rstc",
.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
AT91_RSTC_PROCRST),
.data = &sam9260,
},
{
.compatible = "atmel,at91sam9g45-rstc",
.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
AT91_RSTC_PROCRST)
.data = &sam9260,
},
{
.compatible = "atmel,sama5d3-rstc",
.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
AT91_RSTC_PROCRST)
.data = &sam9260,
},
{
.compatible = "atmel,samx7-rstc",
.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST)
.data = &samx7,
},
{
.compatible = "microchip,sam9x60-rstc",
.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST)
.data = &samx7,
},
{
.compatible = "microchip,sama7g5-rstc",
.data = &sama7g5,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, at91_reset_of_match);

static int at91_reset_update(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
struct at91_reset *reset = to_at91_reset(rcdev);
unsigned long flags;
u32 val;

spin_lock_irqsave(&reset->lock, flags);
val = readl_relaxed(reset->dev_base);
if (assert)
val |= BIT(id);
else
val &= ~BIT(id);
writel_relaxed(val, reset->dev_base);
spin_unlock_irqrestore(&reset->lock, flags);

return 0;
}

static int at91_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return at91_reset_update(rcdev, id, true);
}

static int at91_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
return at91_reset_update(rcdev, id, false);
}

static int at91_reset_dev_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct at91_reset *reset = to_at91_reset(rcdev);
u32 val;

val = readl_relaxed(reset->dev_base);

return !!(val & BIT(id));
}

static const struct reset_control_ops at91_reset_ops = {
.assert = at91_reset_assert,
.deassert = at91_reset_deassert,
.status = at91_reset_dev_status,
};

static int at91_reset_of_xlate(struct reset_controller_dev *rcdev,
const struct of_phandle_args *reset_spec)
{
struct at91_reset *reset = to_at91_reset(rcdev);

if (!reset->data->n_device_reset ||
(reset_spec->args[0] < reset->data->device_reset_min_id ||
reset_spec->args[0] > reset->data->device_reset_max_id))
return -EINVAL;

return reset_spec->args[0];
}

static int at91_rcdev_init(struct at91_reset *reset,
struct platform_device *pdev)
{
if (!reset->data->n_device_reset)
return 0;

reset->dev_base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 1,
NULL);
if (IS_ERR(reset->dev_base))
return -ENODEV;

spin_lock_init(&reset->lock);
reset->rcdev.ops = &at91_reset_ops;
reset->rcdev.owner = THIS_MODULE;
reset->rcdev.of_node = pdev->dev.of_node;
reset->rcdev.nr_resets = reset->data->n_device_reset;
reset->rcdev.of_reset_n_cells = 1;
reset->rcdev.of_xlate = at91_reset_of_xlate;

return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
}

static int __init at91_reset_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
Expand Down Expand Up @@ -212,10 +358,12 @@ static int __init at91_reset_probe(struct platform_device *pdev)
}
}

match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
reset->data = device_get_match_data(&pdev->dev);
if (!reset->data)
return -ENODEV;

reset->nb.notifier_call = at91_reset;
reset->nb.priority = 192;
reset->args = (u32)match->data;

reset->sclk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(reset->sclk))
Expand All @@ -229,6 +377,10 @@ static int __init at91_reset_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, reset);

ret = at91_rcdev_init(reset, pdev);
if (ret)
goto disable_clk;

if (of_device_is_compatible(pdev->dev.of_node, "microchip,sam9x60-rstc")) {
u32 val = readl(reset->rstc_base + AT91_RSTC_MR);

Expand All @@ -237,14 +389,16 @@ static int __init at91_reset_probe(struct platform_device *pdev)
}

ret = register_restart_handler(&reset->nb);
if (ret) {
clk_disable_unprepare(reset->sclk);
return ret;
}
if (ret)
goto disable_clk;

at91_reset_status(pdev, reset->rstc_base);

return 0;

disable_clk:
clk_disable_unprepare(reset->sclk);
return ret;
}

static int __exit at91_reset_remove(struct platform_device *pdev)
Expand Down
10 changes: 10 additions & 0 deletions include/dt-bindings/reset/sama7g5-reset.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */

#ifndef __DT_BINDINGS_RESET_SAMA7G5_H
#define __DT_BINDINGS_RESET_SAMA7G5_H

#define SAMA7G5_RESET_USB_PHY1 4
#define SAMA7G5_RESET_USB_PHY2 5
#define SAMA7G5_RESET_USB_PHY3 6

#endif /* __DT_BINDINGS_RESET_SAMA7G5_H */

0 comments on commit f94ba70

Please sign in to comment.