power: reset: at91-reset: add support for sama7g5
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> -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAmKsnYYACgkQ2O7X88g7 +pqRDRAApx77QWoH7xQ709cc4F77Y9dO6vtAhANtwloS1SAE4//bu2rds0bunWVG 096BQMXMo1U0NFUiNlPkCYHVBKPkYJPPXAUuL83nIF1Q+Y+mxpVbqaitQOgUvus4 nrToZvMQdStjSU7XbkXyQ3gtNKqHR5m2pSWmkbd/v7UZY057Djj6g65r5zqc3Weq fdcw6ID9vRTvlt8KOw7G+BKjNTPOY0zSWnIyJTJjRMQUSqAXb5kYS7vkup1q0Z10 GOw1ZdNnhkZvvSguQFDobq6cLq0IEs/pHt+DXoaUCBogJQ/DH8zv4HVoTVyzLbXC Lp9ALk+ApGWHIMIcaDmxuOTdAAiFqsSlYaBotuKC/0Iek6lSXltPvLW3lsgtvZp5 lgbv6SXo7iafKcHybF8607Waw55vHx+TOr9YziAlTwtEf1+dn04/31rkqYzjXp7N CVXzNrIGVW9iRewbwQams758FcXoj5LPd1hG1Dt3GpAv1YHGc8PIkqBYZ2VYrCZ2 D6cas7NJOWpJnkVd4Yezx3jHFMOK9o/AYQDYgcnmBV0tS8M7rkrAPVkqXX+WdpSg hMDq7hqB2crbyVvPbpYEeIKiy7/jr+eALfcO1gpHUhZpu6szf3cK+kN4hNsQw6bh bVJtcuFRe19/kq7SKkMf77RJxEK9mYT7Vq47e6untftaXuzjn6w= =yEq+ -----END PGP SIGNATURE----- Merge tag 'at91-reset-sama7g5-signed' into psy-next 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>
This commit is contained in:
commit
f94ba7039f
|
@ -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",
|
||||
|
|
|
@ -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>;
|
||||
};
|
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
|
|
@ -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 */
|
Loading…
Reference in New Issue