Hi,
The following patches rework the at91-reset driver and solves
the SAM9X60 VDDCORE fast drop in the first 100us after power down.
Thank you,
Claudiu Beznea
Claudiu Beznea (15):
power: reset: at91-reset: introduce struct at91_reset
power: reset: at91-reset: add ramc_base[] to struct at91_reset
power: reset: at91-reset: add sclk to struct at91_reset
power: reset: at91-reset: add notifier block to struct at91_reset
power: reset: at91-reset: convert reset in pointer to struct
at91_reset
power: reset: at91-reset: pass rstc base address to
at91_reset_status()
power: reset: at91-reset: devm_kzalloc() for at91_reset data structure
power: reset: at91-reset: introduce struct at91_reset_data
power: reset: at91-reset: introduce args member in at91_reset_data
power: reset: at91-reset: use r4 as tmp argument
power: reset: at91-reset: introduce ramc_lpr to struct at91_reset
power: reset: at91-reset: make at91sam9g45_restart() generic
power: reset: at91-reset: keep only one reset function
power: reset: at91-reset: get rid of at91_reset_data
power: reset: at91-reset: handle nrst async for sam9x60
drivers/power/reset/at91-reset.c | 190 +++++++++++++++++++--------------------
1 file changed, 94 insertions(+), 96 deletions(-)
--
2.7.4
Add ramc_base[] to struct at91_reset.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 2df0610e5527..999d3a1653d2 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -51,11 +51,11 @@ enum reset_type {
struct at91_reset {
void __iomem *rstc_base;
+ void __iomem *ramc_base[2];
};
static struct at91_reset reset;
-static void __iomem *at91_ramc_base[2];
static struct clk *sclk;
/*
@@ -81,7 +81,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
"b .\n\t"
:
- : "r" (at91_ramc_base[0]),
+ : "r" (reset.ramc_base[0]),
"r" (reset.rstc_base),
"r" (1),
"r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN),
@@ -123,8 +123,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
" b .\n\t"
:
- : "r" (at91_ramc_base[0]),
- "r" (at91_ramc_base[1]),
+ : "r" (reset.ramc_base[0]),
+ "r" (reset.ramc_base[1]),
"r" (reset.rstc_base),
"r" (1),
"r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN),
@@ -225,8 +225,8 @@ static int __init at91_reset_probe(struct platform_device *pdev)
if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) {
/* we need to shutdown the ddr controller, so get ramc base */
for_each_matching_node(np, at91_ramc_of_match) {
- at91_ramc_base[idx] = of_iomap(np, 0);
- if (!at91_ramc_base[idx]) {
+ reset.ramc_base[idx] = of_iomap(np, 0);
+ if (!reset.ramc_base[idx]) {
dev_err(&pdev->dev, "Could not map ram controller address\n");
of_node_put(np);
return -ENODEV;
--
2.7.4
Add struct notifier_block to struct at91_reset.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 1bc39bfda0aa..e8840193620d 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -53,6 +53,7 @@ struct at91_reset {
void __iomem *rstc_base;
void __iomem *ramc_base[2];
struct clk *sclk;
+ struct notifier_block nb;
};
static struct at91_reset reset;
@@ -205,10 +206,6 @@ static const struct of_device_id at91_reset_of_match[] = {
};
MODULE_DEVICE_TABLE(of, at91_reset_of_match);
-static struct notifier_block at91_restart_nb = {
- .priority = 192,
-};
-
static int __init at91_reset_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
@@ -235,7 +232,8 @@ static int __init at91_reset_probe(struct platform_device *pdev)
}
match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
- at91_restart_nb.notifier_call = match->data;
+ reset.nb.notifier_call = match->data;
+ reset.nb.priority = 192;
reset.sclk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(reset.sclk))
@@ -247,7 +245,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
return ret;
}
- ret = register_restart_handler(&at91_restart_nb);
+ ret = register_restart_handler(&reset.nb);
if (ret) {
clk_disable_unprepare(reset.sclk);
return ret;
@@ -260,7 +258,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
static int __exit at91_reset_remove(struct platform_device *pdev)
{
- unregister_restart_handler(&at91_restart_nb);
+ unregister_restart_handler(&reset.nb);
clk_disable_unprepare(reset.sclk);
return 0;
--
2.7.4
Introduce ramc_lpr to struct at91_reset. This will lead to the
unification of at91sam9260_restart() and at91sam9g45_restart().
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 3b1d566350f4..4e1961334e4d 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -61,6 +61,7 @@ struct at91_reset {
struct clk *sclk;
struct notifier_block nb;
u32 args;
+ u32 ramc_lpr;
};
/*
@@ -81,7 +82,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
"str %2, [%0, #" __stringify(AT91_SDRAMC_TR) "]\n\t"
/* Power down SDRAM */
- "str %3, [%0, #" __stringify(AT91_SDRAMC_LPR) "]\n\t"
+ "str %3, [%0, %5]\n\t"
/* Reset CPU */
"str %4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t"
@@ -92,7 +93,8 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
"r" (reset->rstc_base),
"r" (1),
"r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN),
- "r" (reset->args));
+ "r" (reset->args),
+ "r" (reset->ramc_lpr));
return NOTIFY_DONE;
}
@@ -122,11 +124,11 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
/* Disable SDRAM0 accesses */
"1: str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
/* Power down SDRAM0 */
- " str %4, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
+ " str %4, [%0, %6]\n\t"
/* Disable SDRAM1 accesses */
" strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
/* Power down SDRAM1 */
- " strne %4, [%1, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
+ " strne %4, [%1, %6]\n\t"
/* Reset CPU */
" str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t"
@@ -137,7 +139,8 @@ static int at91sam9g45_restart(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->args),
+ "r" (reset->ramc_lpr)
: "r4");
return NOTIFY_DONE;
@@ -193,8 +196,14 @@ static void __init at91_reset_status(struct platform_device *pdev,
}
static const struct of_device_id at91_ramc_of_match[] = {
- { .compatible = "atmel,at91sam9260-sdramc", },
- { .compatible = "atmel,at91sam9g45-ddramc", },
+ {
+ .compatible = "atmel,at91sam9260-sdramc",
+ .data = (void *)AT91_SDRAMC_LPR,
+ },
+ {
+ .compatible = "atmel,at91sam9g45-ddramc",
+ .data = (void *)AT91_DDRSDRC_LPR,
+ },
{ /* sentinel */ }
};
@@ -263,7 +272,8 @@ static int __init at91_reset_probe(struct platform_device *pdev)
if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) {
/* we need to shutdown the ddr controller, so get ramc base */
- for_each_matching_node(np, at91_ramc_of_match) {
+ for_each_matching_node_and_match(np, at91_ramc_of_match, &match) {
+ reset->ramc_lpr = (u32)match->data;
reset->ramc_base[idx] = of_iomap(np, 0);
if (!reset->ramc_base[idx]) {
dev_err(&pdev->dev, "Could not map ram controller address\n");
--
2.7.4
Handle NRST asynchronously for SAM9X60 to avoid problem with fast drop of
VDDCORE on shutdown operations in the first 100 us after CPU is shutdown.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 537ccb180568..3ff9d93a5226 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -35,6 +35,7 @@
#define AT91_RSTC_MR 0x08 /* Reset Controller Mode Register */
#define AT91_RSTC_URSTEN BIT(0) /* User Reset Enable */
+#define AT91_RSTC_URSTASYNC BIT(2) /* User Reset Asynchronous Control */
#define AT91_RSTC_URSTIEN BIT(4) /* User Reset Interrupt Enable */
#define AT91_RSTC_ERSTL GENMASK(11, 8) /* External Reset Length */
@@ -228,6 +229,13 @@ static int __init at91_reset_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, reset);
+ if (of_device_is_compatible(pdev->dev.of_node, "microchip,sam9x60-rstc")) {
+ u32 val = readl(reset->rstc_base + AT91_RSTC_MR);
+
+ writel(AT91_RSTC_KEY | AT91_RSTC_URSTASYNC | val,
+ reset->rstc_base + AT91_RSTC_MR);
+ }
+
ret = register_restart_handler(&reset->nb);
if (ret) {
clk_disable_unprepare(reset->sclk);
--
2.7.4
After refactoring struct at91_reset_data and
struct at91_reset_data at91sam9260_reset_data are not needed anymore.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 37 +++++++++----------------------------
1 file changed, 9 insertions(+), 28 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 9c1b69f76a01..537ccb180568 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -49,10 +49,6 @@ enum reset_type {
RESET_TYPE_ULP2 = 8,
};
-struct at91_reset_data {
- u32 args;
-};
-
struct at91_reset {
void __iomem *rstc_base;
void __iomem *ramc_base[2];
@@ -156,42 +152,29 @@ static const struct of_device_id at91_ramc_of_match[] = {
{ /* sentinel */ }
};
-static const struct at91_reset_data at91sam9260_reset_data = {
- .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
-};
-
-static const struct at91_reset_data at91sam9g45_reset_data = {
- .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
-};
-
-static const struct at91_reset_data sama5d3_reset_data = {
- .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
-};
-
-static const struct at91_reset_data samx7_reset_data = {
- .args = AT91_RSTC_KEY | AT91_RSTC_PROCRST,
-};
-
static const struct of_device_id at91_reset_of_match[] = {
{
.compatible = "atmel,at91sam9260-rstc",
- .data = &at91sam9260_reset_data
+ .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
+ AT91_RSTC_PROCRST),
},
{
.compatible = "atmel,at91sam9g45-rstc",
- .data = &at91sam9g45_reset_data
+ .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
+ AT91_RSTC_PROCRST)
},
{
.compatible = "atmel,sama5d3-rstc",
- .data = &sama5d3_reset_data
+ .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
+ AT91_RSTC_PROCRST)
},
{
.compatible = "atmel,samx7-rstc",
- .data = &samx7_reset_data
+ .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST)
},
{
.compatible = "microchip,sam9x60-rstc",
- .data = &samx7_reset_data
+ .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST)
},
{ /* sentinel */ }
};
@@ -199,7 +182,6 @@ MODULE_DEVICE_TABLE(of, at91_reset_of_match);
static int __init at91_reset_probe(struct platform_device *pdev)
{
- const struct at91_reset_data *reset_data;
const struct of_device_id *match;
struct at91_reset *reset;
struct device_node *np;
@@ -230,10 +212,9 @@ static int __init at91_reset_probe(struct platform_device *pdev)
}
match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
- reset_data = match->data;
reset->nb.notifier_call = at91_reset;
reset->nb.priority = 192;
- reset->args = reset_data->args;
+ reset->args = (u32)match->data;
reset->sclk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(reset->sclk))
--
2.7.4
Make at91sam9g45_restart() generic.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 21 ++++++---------------
1 file changed, 6 insertions(+), 15 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 4e1961334e4d..61433060d784 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -105,32 +105,23 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
struct at91_reset *reset = container_of(this, struct at91_reset, nb);
asm volatile(
- /*
- * Test wether we have a second RAM controller to care
- * about.
- *
- * First, test that we can dereference the virtual address.
- */
- "cmp %1, #0\n\t"
- "beq 1f\n\t"
-
- /* Then, test that the RAM controller is enabled */
- "ldr r4, [%1]\n\t"
- "cmp r4, #0\n\t"
-
/* Align to cache lines */
".balign 32\n\t"
/* Disable SDRAM0 accesses */
- "1: str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
+ " tst %0, #0\n\t"
+ " beq 1f\n\t"
+ " str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
/* Power down SDRAM0 */
" str %4, [%0, %6]\n\t"
/* Disable SDRAM1 accesses */
+ "1: tst %1, #0\n\t"
+ " beq 2f\n\t"
" strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
/* Power down SDRAM1 */
" strne %4, [%1, %6]\n\t"
/* Reset CPU */
- " str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t"
+ "2: str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t"
" b .\n\t"
:
--
2.7.4
Introduce struct at91_reset_data to be able to provide per SoC
data. At the moment this being only notifier callback.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 50 +++++++++++++++++++++++++++++++++++-----
1 file changed, 44 insertions(+), 6 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 7ba77555e9e1..c653bd7ac29a 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -49,6 +49,11 @@ enum reset_type {
RESET_TYPE_ULP2 = 8,
};
+struct at91_reset_data {
+ int (*notifier_call)(struct notifier_block *this, unsigned long mode,
+ void *cmd);
+};
+
struct at91_reset {
void __iomem *rstc_base;
void __iomem *ramc_base[2];
@@ -203,18 +208,50 @@ static const struct of_device_id at91_ramc_of_match[] = {
{ /* sentinel */ }
};
+static const struct at91_reset_data at91sam9260_reset_data = {
+ .notifier_call = at91sam9260_restart,
+};
+
+static const struct at91_reset_data at91sam9g45_reset_data = {
+ .notifier_call = at91sam9g45_restart,
+};
+
+static const struct at91_reset_data sama5d3_reset_data = {
+ .notifier_call = sama5d3_restart,
+};
+
+static const struct at91_reset_data samx7_reset_data = {
+ .notifier_call = samx7_restart,
+};
+
static const struct of_device_id at91_reset_of_match[] = {
- { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart },
- { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart },
- { .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart },
- { .compatible = "atmel,samx7-rstc", .data = samx7_restart },
- { .compatible = "microchip,sam9x60-rstc", .data = samx7_restart },
+ {
+ .compatible = "atmel,at91sam9260-rstc",
+ .data = &at91sam9260_reset_data
+ },
+ {
+ .compatible = "atmel,at91sam9g45-rstc",
+ .data = &at91sam9g45_reset_data
+ },
+ {
+ .compatible = "atmel,sama5d3-rstc",
+ .data = &sama5d3_reset_data
+ },
+ {
+ .compatible = "atmel,samx7-rstc",
+ .data = &samx7_reset_data
+ },
+ {
+ .compatible = "microchip,sam9x60-rstc",
+ .data = &samx7_reset_data
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, at91_reset_of_match);
static int __init at91_reset_probe(struct platform_device *pdev)
{
+ const struct at91_reset_data *reset_data;
const struct of_device_id *match;
struct at91_reset *reset;
struct device_node *np;
@@ -244,7 +281,8 @@ static int __init at91_reset_probe(struct platform_device *pdev)
}
match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
- reset->nb.notifier_call = match->data;
+ reset_data = match->data;
+ reset->nb.notifier_call = reset_data->notifier_call;
reset->nb.priority = 192;
reset->sclk = devm_clk_get(&pdev->dev, NULL);
--
2.7.4
Convert reset in pointer to struct at91_reset.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 50 ++++++++++++++++++++++------------------
1 file changed, 27 insertions(+), 23 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index e8840193620d..4bb5eef4b258 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -56,7 +56,7 @@ struct at91_reset {
struct notifier_block nb;
};
-static struct at91_reset reset;
+static struct at91_reset *reset;
/*
* unless the SDRAM is cleanly shutdown before we hit the
@@ -81,8 +81,8 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
"b .\n\t"
:
- : "r" (reset.ramc_base[0]),
- "r" (reset.rstc_base),
+ : "r" (reset->ramc_base[0]),
+ "r" (reset->rstc_base),
"r" (1),
"r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN),
"r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST));
@@ -123,9 +123,9 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
" b .\n\t"
:
- : "r" (reset.ramc_base[0]),
- "r" (reset.ramc_base[1]),
- "r" (reset.rstc_base),
+ : "r" (reset->ramc_base[0]),
+ "r" (reset->ramc_base[1]),
+ "r" (reset->rstc_base),
"r" (1),
"r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN),
"r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)
@@ -138,7 +138,7 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST),
- reset.rstc_base);
+ reset->rstc_base);
return NOTIFY_DONE;
}
@@ -147,7 +147,7 @@ static int samx7_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST),
- reset.rstc_base);
+ reset->rstc_base);
return NOTIFY_DONE;
}
@@ -155,7 +155,7 @@ static int samx7_restart(struct notifier_block *this, unsigned long mode,
static void __init at91_reset_status(struct platform_device *pdev)
{
const char *reason;
- u32 reg = readl(reset.rstc_base + AT91_RSTC_SR);
+ u32 reg = readl(reset->rstc_base + AT91_RSTC_SR);
switch ((reg & AT91_RSTC_RSTTYP) >> 8) {
case RESET_TYPE_GENERAL:
@@ -212,8 +212,12 @@ static int __init at91_reset_probe(struct platform_device *pdev)
struct device_node *np;
int ret, idx = 0;
- reset.rstc_base = of_iomap(pdev->dev.of_node, 0);
- if (!reset.rstc_base) {
+ reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
+ if (!reset)
+ return -ENOMEM;
+
+ reset->rstc_base = of_iomap(pdev->dev.of_node, 0);
+ if (!reset->rstc_base) {
dev_err(&pdev->dev, "Could not map reset controller address\n");
return -ENODEV;
}
@@ -221,8 +225,8 @@ static int __init at91_reset_probe(struct platform_device *pdev)
if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) {
/* we need to shutdown the ddr controller, so get ramc base */
for_each_matching_node(np, at91_ramc_of_match) {
- reset.ramc_base[idx] = of_iomap(np, 0);
- if (!reset.ramc_base[idx]) {
+ reset->ramc_base[idx] = of_iomap(np, 0);
+ if (!reset->ramc_base[idx]) {
dev_err(&pdev->dev, "Could not map ram controller address\n");
of_node_put(np);
return -ENODEV;
@@ -232,22 +236,22 @@ static int __init at91_reset_probe(struct platform_device *pdev)
}
match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
- reset.nb.notifier_call = match->data;
- reset.nb.priority = 192;
+ reset->nb.notifier_call = match->data;
+ reset->nb.priority = 192;
- reset.sclk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(reset.sclk))
- return PTR_ERR(reset.sclk);
+ reset->sclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(reset->sclk))
+ return PTR_ERR(reset->sclk);
- ret = clk_prepare_enable(reset.sclk);
+ ret = clk_prepare_enable(reset->sclk);
if (ret) {
dev_err(&pdev->dev, "Could not enable slow clock\n");
return ret;
}
- ret = register_restart_handler(&reset.nb);
+ ret = register_restart_handler(&reset->nb);
if (ret) {
- clk_disable_unprepare(reset.sclk);
+ clk_disable_unprepare(reset->sclk);
return ret;
}
@@ -258,8 +262,8 @@ static int __init at91_reset_probe(struct platform_device *pdev)
static int __exit at91_reset_remove(struct platform_device *pdev)
{
- unregister_restart_handler(&reset.nb);
- clk_disable_unprepare(reset.sclk);
+ unregister_restart_handler(&reset->nb);
+ clk_disable_unprepare(reset->sclk);
return 0;
}
--
2.7.4
Allocate at91_reset data on probe and set it as platform data.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index bd05496c5ac7..7ba77555e9e1 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -56,8 +56,6 @@ struct at91_reset {
struct notifier_block nb;
};
-static struct at91_reset *reset;
-
/*
* unless the SDRAM is cleanly shutdown before we hit the
* reset register it can be left driving the data bus and
@@ -66,6 +64,8 @@ static struct at91_reset *reset;
static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
+ struct at91_reset *reset = container_of(this, struct at91_reset, nb);
+
asm volatile(
/* Align to cache lines */
".balign 32\n\t"
@@ -93,6 +93,8 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
+ struct at91_reset *reset = container_of(this, struct at91_reset, nb);
+
asm volatile(
/*
* Test wether we have a second RAM controller to care
@@ -137,6 +139,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
+ struct at91_reset *reset = container_of(this, struct at91_reset, nb);
+
writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST),
reset->rstc_base);
@@ -146,6 +150,8 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
static int samx7_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
+ struct at91_reset *reset = container_of(this, struct at91_reset, nb);
+
writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST),
reset->rstc_base);
@@ -210,6 +216,7 @@ MODULE_DEVICE_TABLE(of, at91_reset_of_match);
static int __init at91_reset_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
+ struct at91_reset *reset;
struct device_node *np;
int ret, idx = 0;
@@ -250,6 +257,8 @@ static int __init at91_reset_probe(struct platform_device *pdev)
return ret;
}
+ platform_set_drvdata(pdev, reset);
+
ret = register_restart_handler(&reset->nb);
if (ret) {
clk_disable_unprepare(reset->sclk);
@@ -263,6 +272,8 @@ static int __init at91_reset_probe(struct platform_device *pdev)
static int __exit at91_reset_remove(struct platform_device *pdev)
{
+ struct at91_reset *reset = platform_get_drvdata(pdev);
+
unregister_restart_handler(&reset->nb);
clk_disable_unprepare(reset->sclk);
--
2.7.4
Add new argument to at91_reset_status() that is the pointer to reset
controller base address.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 4bb5eef4b258..bd05496c5ac7 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -152,10 +152,11 @@ static int samx7_restart(struct notifier_block *this, unsigned long mode,
return NOTIFY_DONE;
}
-static void __init at91_reset_status(struct platform_device *pdev)
+static void __init at91_reset_status(struct platform_device *pdev,
+ void __iomem *base)
{
const char *reason;
- u32 reg = readl(reset->rstc_base + AT91_RSTC_SR);
+ u32 reg = readl(base + AT91_RSTC_SR);
switch ((reg & AT91_RSTC_RSTTYP) >> 8) {
case RESET_TYPE_GENERAL:
@@ -255,7 +256,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
return ret;
}
- at91_reset_status(pdev);
+ at91_reset_status(pdev, reset->rstc_base);
return 0;
}
--
2.7.4
Introduce struct at91_reset intended to keep all the at91 reset controller
data.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index d94e3267c3b6..2df0610e5527 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -49,7 +49,13 @@ enum reset_type {
RESET_TYPE_ULP2 = 8,
};
-static void __iomem *at91_ramc_base[2], *at91_rstc_base;
+struct at91_reset {
+ void __iomem *rstc_base;
+};
+
+static struct at91_reset reset;
+
+static void __iomem *at91_ramc_base[2];
static struct clk *sclk;
/*
@@ -76,7 +82,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
"b .\n\t"
:
: "r" (at91_ramc_base[0]),
- "r" (at91_rstc_base),
+ "r" (reset.rstc_base),
"r" (1),
"r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN),
"r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST));
@@ -119,7 +125,7 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
:
: "r" (at91_ramc_base[0]),
"r" (at91_ramc_base[1]),
- "r" (at91_rstc_base),
+ "r" (reset.rstc_base),
"r" (1),
"r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN),
"r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)
@@ -131,8 +137,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
- writel(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
- at91_rstc_base);
+ writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST),
+ reset.rstc_base);
return NOTIFY_DONE;
}
@@ -140,14 +146,16 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
static int samx7_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
- writel(AT91_RSTC_KEY | AT91_RSTC_PROCRST, at91_rstc_base);
+ writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST),
+ reset.rstc_base);
+
return NOTIFY_DONE;
}
static void __init at91_reset_status(struct platform_device *pdev)
{
const char *reason;
- u32 reg = readl(at91_rstc_base + AT91_RSTC_SR);
+ u32 reg = readl(reset.rstc_base + AT91_RSTC_SR);
switch ((reg & AT91_RSTC_RSTTYP) >> 8) {
case RESET_TYPE_GENERAL:
@@ -208,8 +216,8 @@ static int __init at91_reset_probe(struct platform_device *pdev)
struct device_node *np;
int ret, idx = 0;
- at91_rstc_base = of_iomap(pdev->dev.of_node, 0);
- if (!at91_rstc_base) {
+ reset.rstc_base = of_iomap(pdev->dev.of_node, 0);
+ if (!reset.rstc_base) {
dev_err(&pdev->dev, "Could not map reset controller address\n");
return -ENODEV;
}
--
2.7.4
Introduce args member in struct at91_reset_data. It stores the value
that needs to be written in mode register so that the reboot actions
to happen. With these changes samx7_restart() could be removed.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 27 +++++++++++----------------
1 file changed, 11 insertions(+), 16 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index c653bd7ac29a..dc48f6850796 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -52,6 +52,7 @@ enum reset_type {
struct at91_reset_data {
int (*notifier_call)(struct notifier_block *this, unsigned long mode,
void *cmd);
+ u32 args;
};
struct at91_reset {
@@ -59,6 +60,7 @@ struct at91_reset {
void __iomem *ramc_base[2];
struct clk *sclk;
struct notifier_block nb;
+ u32 args;
};
/*
@@ -90,7 +92,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
"r" (reset->rstc_base),
"r" (1),
"r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN),
- "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST));
+ "r" (reset->args));
return NOTIFY_DONE;
}
@@ -135,7 +137,7 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
"r" (reset->rstc_base),
"r" (1),
"r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN),
- "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)
+ "r" (reset->args)
: "r0");
return NOTIFY_DONE;
@@ -146,19 +148,7 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
{
struct at91_reset *reset = container_of(this, struct at91_reset, nb);
- writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST),
- reset->rstc_base);
-
- return NOTIFY_DONE;
-}
-
-static int samx7_restart(struct notifier_block *this, unsigned long mode,
- void *cmd)
-{
- struct at91_reset *reset = container_of(this, struct at91_reset, nb);
-
- writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST),
- reset->rstc_base);
+ writel(reset->args, reset->rstc_base);
return NOTIFY_DONE;
}
@@ -210,18 +200,22 @@ static const struct of_device_id at91_ramc_of_match[] = {
static const struct at91_reset_data at91sam9260_reset_data = {
.notifier_call = at91sam9260_restart,
+ .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
};
static const struct at91_reset_data at91sam9g45_reset_data = {
.notifier_call = at91sam9g45_restart,
+ .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
};
static const struct at91_reset_data sama5d3_reset_data = {
.notifier_call = sama5d3_restart,
+ .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
};
static const struct at91_reset_data samx7_reset_data = {
- .notifier_call = samx7_restart,
+ .notifier_call = sama5d3_restart,
+ .args = AT91_RSTC_KEY | AT91_RSTC_PROCRST,
};
static const struct of_device_id at91_reset_of_match[] = {
@@ -284,6 +278,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
reset_data = match->data;
reset->nb.notifier_call = reset_data->notifier_call;
reset->nb.priority = 192;
+ reset->args = reset_data->args;
reset->sclk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(reset->sclk))
--
2.7.4
Add sclk to struct at91_reset.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 999d3a1653d2..1bc39bfda0aa 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -52,12 +52,11 @@ enum reset_type {
struct at91_reset {
void __iomem *rstc_base;
void __iomem *ramc_base[2];
+ struct clk *sclk;
};
static struct at91_reset reset;
-static struct clk *sclk;
-
/*
* unless the SDRAM is cleanly shutdown before we hit the
* reset register it can be left driving the data bus and
@@ -238,11 +237,11 @@ static int __init at91_reset_probe(struct platform_device *pdev)
match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
at91_restart_nb.notifier_call = match->data;
- sclk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(sclk))
- return PTR_ERR(sclk);
+ reset.sclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(reset.sclk))
+ return PTR_ERR(reset.sclk);
- ret = clk_prepare_enable(sclk);
+ ret = clk_prepare_enable(reset.sclk);
if (ret) {
dev_err(&pdev->dev, "Could not enable slow clock\n");
return ret;
@@ -250,7 +249,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
ret = register_restart_handler(&at91_restart_nb);
if (ret) {
- clk_disable_unprepare(sclk);
+ clk_disable_unprepare(reset.sclk);
return ret;
}
@@ -262,7 +261,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
static int __exit at91_reset_remove(struct platform_device *pdev)
{
unregister_restart_handler(&at91_restart_nb);
- clk_disable_unprepare(sclk);
+ clk_disable_unprepare(reset.sclk);
return 0;
}
--
2.7.4
Use r4 as temporary register. On ARM r0-r3 should be used to hold
function arguments.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index dc48f6850796..3b1d566350f4 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -113,8 +113,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
"beq 1f\n\t"
/* Then, test that the RAM controller is enabled */
- "ldr r0, [%1]\n\t"
- "cmp r0, #0\n\t"
+ "ldr r4, [%1]\n\t"
+ "cmp r4, #0\n\t"
/* Align to cache lines */
".balign 32\n\t"
@@ -138,7 +138,7 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
"r" (1),
"r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN),
"r" (reset->args)
- : "r0");
+ : "r4");
return NOTIFY_DONE;
}
--
2.7.4
Keep only one reset function. With this, notifier_call member of
struct at91_reset_data could be removed.
Signed-off-by: Claudiu Beznea <[email protected]>
---
drivers/power/reset/at91-reset.c | 52 +++-------------------------------------
1 file changed, 3 insertions(+), 49 deletions(-)
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 61433060d784..9c1b69f76a01 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -50,8 +50,6 @@ enum reset_type {
};
struct at91_reset_data {
- int (*notifier_call)(struct notifier_block *this, unsigned long mode,
- void *cmd);
u32 args;
};
@@ -69,38 +67,8 @@ struct at91_reset {
* reset register it can be left driving the data bus and
* killing the chance of a subsequent boot from NAND
*/
-static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
- void *cmd)
-{
- struct at91_reset *reset = container_of(this, struct at91_reset, nb);
-
- asm volatile(
- /* Align to cache lines */
- ".balign 32\n\t"
-
- /* Disable SDRAM accesses */
- "str %2, [%0, #" __stringify(AT91_SDRAMC_TR) "]\n\t"
-
- /* Power down SDRAM */
- "str %3, [%0, %5]\n\t"
-
- /* Reset CPU */
- "str %4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t"
-
- "b .\n\t"
- :
- : "r" (reset->ramc_base[0]),
- "r" (reset->rstc_base),
- "r" (1),
- "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN),
- "r" (reset->args),
- "r" (reset->ramc_lpr));
-
- return NOTIFY_DONE;
-}
-
-static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
- void *cmd)
+static int at91_reset(struct notifier_block *this, unsigned long mode,
+ void *cmd)
{
struct at91_reset *reset = container_of(this, struct at91_reset, nb);
@@ -137,16 +105,6 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
return NOTIFY_DONE;
}
-static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
- void *cmd)
-{
- struct at91_reset *reset = container_of(this, struct at91_reset, nb);
-
- writel(reset->args, reset->rstc_base);
-
- return NOTIFY_DONE;
-}
-
static void __init at91_reset_status(struct platform_device *pdev,
void __iomem *base)
{
@@ -199,22 +157,18 @@ static const struct of_device_id at91_ramc_of_match[] = {
};
static const struct at91_reset_data at91sam9260_reset_data = {
- .notifier_call = at91sam9260_restart,
.args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
};
static const struct at91_reset_data at91sam9g45_reset_data = {
- .notifier_call = at91sam9g45_restart,
.args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
};
static const struct at91_reset_data sama5d3_reset_data = {
- .notifier_call = sama5d3_restart,
.args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
};
static const struct at91_reset_data samx7_reset_data = {
- .notifier_call = sama5d3_restart,
.args = AT91_RSTC_KEY | AT91_RSTC_PROCRST,
};
@@ -277,7 +231,7 @@ static int __init at91_reset_probe(struct platform_device *pdev)
match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
reset_data = match->data;
- reset->nb.notifier_call = reset_data->notifier_call;
+ reset->nb.notifier_call = at91_reset;
reset->nb.priority = 192;
reset->args = reset_data->args;
--
2.7.4
Hi,
On Tue, Jan 21, 2020 at 10:03:29AM +0000, [email protected] wrote:
> The following patches rework the at91-reset driver and solves
> the SAM9X60 VDDCORE fast drop in the first 100us after power down.
Thanks, queued to power-supply's for-next branch.
-- Sebastian
> Claudiu Beznea (15):
> power: reset: at91-reset: introduce struct at91_reset
> power: reset: at91-reset: add ramc_base[] to struct at91_reset
> power: reset: at91-reset: add sclk to struct at91_reset
> power: reset: at91-reset: add notifier block to struct at91_reset
> power: reset: at91-reset: convert reset in pointer to struct
> at91_reset
> power: reset: at91-reset: pass rstc base address to
> at91_reset_status()
> power: reset: at91-reset: devm_kzalloc() for at91_reset data structure
> power: reset: at91-reset: introduce struct at91_reset_data
> power: reset: at91-reset: introduce args member in at91_reset_data
> power: reset: at91-reset: use r4 as tmp argument
> power: reset: at91-reset: introduce ramc_lpr to struct at91_reset
> power: reset: at91-reset: make at91sam9g45_restart() generic
> power: reset: at91-reset: keep only one reset function
> power: reset: at91-reset: get rid of at91_reset_data
> power: reset: at91-reset: handle nrst async for sam9x60
>
> drivers/power/reset/at91-reset.c | 190 +++++++++++++++++++--------------------
> 1 file changed, 94 insertions(+), 96 deletions(-)
>
> --
> 2.7.4