2017-03-28 11:19:53

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 00/11] ARM: at91: pm: cleanup

Hi,

This is v2 of the at91 PM cleanup.

The main goal is to use a struct to pass arguments between the C and the
assembly part. This is required to add further functionalities (coming in a
later series).

A bit of refactorization also allows to remove a some initialization in
at91sam9.c

Changes in v2:
- rebased on top of v4.11-rc4 because of a dependency on a fix
- added a patch to correct a typo
- due to an errata on sama5d4, I've left out the following patches for now:
ARM: at91: pm: use struct members directly
ARM: at91: pm: use C functions for standby
ARM: at91: pm: Allow PM even if SRAM allocation failed
I'll get back to those later.
- in preparation of the sama5d4 workaround, renamed standby to idle as the
standby functions are actually used for cpuidle but not standby


Alexandre Belloni (11):
ARM: at91: pm: Cleanup headers
ARM: at91: pm: Move at91_ramc_read/write to pm.c
ARM: at91: pm: Move global variables into at91_pm_data
ARM: at91: pm: Use struct at91_pm_data in pm_suspend.S
ARM: at91: pm: Simplify at91rm9200_standby
ARM: at91: pm: Workaround DDRSDRC self-refresh bug with LPDDR1
memories.
ARM: at91: pm: Tie the memory controller type to the ramc id
ARM: at91: pm: Tie the USB clock mask to the pmc
ARM: at91: pm: Merge all at91sam9*_pm_init
ARM: at91: pm: Remove at91_pm_set_standby
ARM: at91: pm: correct typo

arch/arm/mach-at91/Makefile | 33 ++++++
arch/arm/mach-at91/at91sam9.c | 45 +-------
arch/arm/mach-at91/generic.h | 8 +-
arch/arm/mach-at91/pm.c | 199 +++++++++++++++++------------------
arch/arm/mach-at91/pm.h | 24 ++---
arch/arm/mach-at91/pm_data-offsets.c | 13 +++
arch/arm/mach-at91/pm_suspend.S | 31 +++---
7 files changed, 172 insertions(+), 181 deletions(-)
create mode 100644 arch/arm/mach-at91/pm_data-offsets.c

--
2.11.0


2017-03-28 11:19:52

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 02/11] ARM: at91: pm: Move at91_ramc_read/write to pm.c

Those macros are only used in pm.c, move them there so we can remove the
test on __ASSEMBLY__.

Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/arm/mach-at91/pm.c | 6 ++++++
arch/arm/mach-at91/pm.h | 8 --------
2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 9e2b5c1e503e..41789aa4df86 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -45,6 +45,12 @@ static struct {
} at91_pm_data;

static void __iomem *at91_ramc_base[2];
+#define at91_ramc_read(id, field) \
+ __raw_readl(at91_ramc_base[id] + field)
+
+#define at91_ramc_write(id, field, value) \
+ __raw_writel(value, at91_ramc_base[id] + field)
+

static int at91_pm_valid_state(suspend_state_t state)
{
diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
index bf980c6ef294..8eed156ef19a 100644
--- a/arch/arm/mach-at91/pm.h
+++ b/arch/arm/mach-at91/pm.h
@@ -17,14 +17,6 @@
#include <soc/at91/at91sam9_ddrsdr.h>
#include <soc/at91/at91sam9_sdramc.h>

-#ifndef __ASSEMBLY__
-#define at91_ramc_read(id, field) \
- __raw_readl(at91_ramc_base[id] + field)
-
-#define at91_ramc_write(id, field, value) \
- __raw_writel(value, at91_ramc_base[id] + field)
-#endif
-
#define AT91_MEMCTRL_MC 0
#define AT91_MEMCTRL_SDRAMC 1
#define AT91_MEMCTRL_DDRSDR 2
--
2.11.0

2017-03-28 11:19:54

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 03/11] ARM: at91: pm: Move global variables into at91_pm_data

Instead of having separate global variables to hold IP addresses, move them
to struct at91_pm_data.

Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/arm/mach-at91/pm.c | 44 +++++++++++++++++++++-----------------------
1 file changed, 21 insertions(+), 23 deletions(-)

diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 41789aa4df86..c780dda3b604 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -26,8 +26,6 @@
#include "generic.h"
#include "pm.h"

-static void __iomem *pmc;
-
/*
* FIXME: this is needed to communicate between the pinctrl driver and
* the PM implementation in the machine. Possibly part of the PM
@@ -40,17 +38,17 @@ extern void at91_pinctrl_gpio_resume(void);
#endif

static struct {
+ void __iomem *pmc;
+ void __iomem *ramc[2];
unsigned long uhp_udp_mask;
int memctrl;
} at91_pm_data;

-static void __iomem *at91_ramc_base[2];
#define at91_ramc_read(id, field) \
- __raw_readl(at91_ramc_base[id] + field)
+ __raw_readl(at91_pm_data.ramc[id] + field)

#define at91_ramc_write(id, field, value) \
- __raw_writel(value, at91_ramc_base[id] + field)
-
+ __raw_writel(value, at91_pm_data.ramc[id] + field)

static int at91_pm_valid_state(suspend_state_t state)
{
@@ -86,7 +84,7 @@ static int at91_pm_verify_clocks(void)
unsigned long scsr;
int i;

- scsr = readl(pmc + AT91_PMC_SCSR);
+ scsr = readl(at91_pm_data.pmc + AT91_PMC_SCSR);

/* USB must not be using PLLB */
if ((scsr & at91_pm_data.uhp_udp_mask) != 0) {
@@ -100,7 +98,7 @@ static int at91_pm_verify_clocks(void)

if ((scsr & (AT91_PMC_PCK0 << i)) == 0)
continue;
- css = readl(pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
+ css = readl(at91_pm_data.pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
if (css != AT91_PMC_CSS_SLOW) {
pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css);
return 0;
@@ -143,8 +141,8 @@ static void at91_pm_suspend(suspend_state_t state)
flush_cache_all();
outer_disable();

- at91_suspend_sram_fn(pmc, at91_ramc_base[0],
- at91_ramc_base[1], pm_data);
+ at91_suspend_sram_fn(at91_pm_data.pmc, at91_pm_data.ramc[0],
+ at91_pm_data.ramc[1], pm_data);

outer_resume();
}
@@ -247,7 +245,7 @@ static void at91rm9200_standby(void)
" mcr p15, 0, %0, c7, c0, 4\n\t"
" str %5, [%1, %2]"
:
- : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91_MC_SDRAMC_LPR),
+ : "r" (0), "r" (at91_pm_data.ramc[0]), "r" (AT91_MC_SDRAMC_LPR),
"r" (1), "r" (AT91_MC_SDRAMC_SRR),
"r" (lpr));
}
@@ -262,7 +260,7 @@ static void at91_ddr_standby(void)
u32 lpr0, lpr1 = 0;
u32 saved_lpr0, saved_lpr1 = 0;

- if (at91_ramc_base[1]) {
+ if (at91_pm_data.ramc[1]) {
saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR);
lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB;
lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH;
@@ -274,13 +272,13 @@ static void at91_ddr_standby(void)

/* self-refresh mode now */
at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
- if (at91_ramc_base[1])
+ if (at91_pm_data.ramc[1])
at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1);

cpu_do_idle();

at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
- if (at91_ramc_base[1])
+ if (at91_pm_data.ramc[1])
at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
}

@@ -308,7 +306,7 @@ static void at91sam9_sdram_standby(void)
u32 lpr0, lpr1 = 0;
u32 saved_lpr0, saved_lpr1 = 0;

- if (at91_ramc_base[1]) {
+ if (at91_pm_data.ramc[1]) {
saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR);
lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB;
lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH;
@@ -320,13 +318,13 @@ static void at91sam9_sdram_standby(void)

/* self-refresh mode now */
at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0);
- if (at91_ramc_base[1])
+ if (at91_pm_data.ramc[1])
at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1);

cpu_do_idle();

at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0);
- if (at91_ramc_base[1])
+ if (at91_pm_data.ramc[1])
at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1);
}

@@ -346,8 +344,8 @@ static __init void at91_dt_ramc(void)
const void *standby = NULL;

for_each_matching_node_and_match(np, ramc_ids, &of_id) {
- at91_ramc_base[idx] = of_iomap(np, 0);
- if (!at91_ramc_base[idx])
+ at91_pm_data.ramc[idx] = of_iomap(np, 0);
+ if (!at91_pm_data.ramc[idx])
panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx);

if (!standby)
@@ -373,12 +371,12 @@ static void at91rm9200_idle(void)
* Disable the processor clock. The processor will be automatically
* re-enabled by an interrupt or by a reset.
*/
- writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR);
+ writel(AT91_PMC_PCK, at91_pm_data.pmc + AT91_PMC_SCDR);
}

static void at91sam9_idle(void)
{
- writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR);
+ writel(AT91_PMC_PCK, at91_pm_data.pmc + AT91_PMC_SCDR);
cpu_do_idle();
}

@@ -447,8 +445,8 @@ static void __init at91_pm_init(void (*pm_idle)(void))
platform_device_register(&at91_cpuidle_device);

pmc_np = of_find_matching_node(NULL, atmel_pmc_ids);
- pmc = of_iomap(pmc_np, 0);
- if (!pmc) {
+ at91_pm_data.pmc = of_iomap(pmc_np, 0);
+ if (!at91_pm_data.pmc) {
pr_err("AT91: PM not supported, PMC not found\n");
return;
}
--
2.11.0

2017-03-28 11:19:55

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 11/11] ARM: at91: pm: correct typo

Add a missing bracket at the end of Anti's email

Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/arm/mach-at91/pm_suspend.S | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S
index ed317657e760..96781daa671a 100644
--- a/arch/arm/mach-at91/pm_suspend.S
+++ b/arch/arm/mach-at91/pm_suspend.S
@@ -4,7 +4,7 @@
* Copyright (C) 2006 Savin Zlobec
*
* AT91SAM9 support:
- * Copyright (C) 2007 Anti Sullin <[email protected]
+ * Copyright (C) 2007 Anti Sullin <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--
2.11.0

2017-03-28 11:20:36

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 09/11] ARM: at91: pm: Merge all at91sam9*_pm_init

The PM initialization is now identical for all at91sam9. Merge the
functions.

Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/arm/mach-at91/at91sam9.c | 45 +++----------------------------------------
arch/arm/mach-at91/generic.h | 8 ++------
arch/arm/mach-at91/pm.c | 14 +-------------
3 files changed, 6 insertions(+), 61 deletions(-)

diff --git a/arch/arm/mach-at91/at91sam9.c b/arch/arm/mach-at91/at91sam9.c
index ba28e9cc584d..c089bfd0dc2f 100644
--- a/arch/arm/mach-at91/at91sam9.c
+++ b/arch/arm/mach-at91/at91sam9.c
@@ -52,7 +52,7 @@ static const struct at91_soc at91sam9_socs[] = {
{ /* sentinel */ },
};

-static void __init at91sam9_common_init(void)
+static void __init at91sam9_init(void)
{
struct soc_device *soc;
struct device *soc_dev = NULL;
@@ -62,12 +62,8 @@ static void __init at91sam9_common_init(void)
soc_dev = soc_device_to_device(soc);

of_platform_default_populate(NULL, NULL, soc_dev);
-}

-static void __init at91sam9_dt_device_init(void)
-{
- at91sam9_common_init();
- at91sam9260_pm_init();
+ at91sam9_pm_init();
}

static const char *const at91_dt_board_compat[] __initconst = {
@@ -77,41 +73,6 @@ static const char *const at91_dt_board_compat[] __initconst = {

DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM9")
/* Maintainer: Atmel */
- .init_machine = at91sam9_dt_device_init,
+ .init_machine = at91sam9_init,
.dt_compat = at91_dt_board_compat,
MACHINE_END
-
-static void __init at91sam9g45_dt_device_init(void)
-{
- at91sam9_common_init();
- at91sam9g45_pm_init();
-}
-
-static const char *const at91sam9g45_board_compat[] __initconst = {
- "atmel,at91sam9g45",
- NULL
-};
-
-DT_MACHINE_START(at91sam9g45_dt, "Atmel AT91SAM9G45")
- /* Maintainer: Atmel */
- .init_machine = at91sam9g45_dt_device_init,
- .dt_compat = at91sam9g45_board_compat,
-MACHINE_END
-
-static void __init at91sam9x5_dt_device_init(void)
-{
- at91sam9_common_init();
- at91sam9x5_pm_init();
-}
-
-static const char *const at91sam9x5_board_compat[] __initconst = {
- "atmel,at91sam9x5",
- "atmel,at91sam9n12",
- NULL
-};
-
-DT_MACHINE_START(at91sam9x5_dt, "Atmel AT91SAM9")
- /* Maintainer: Atmel */
- .init_machine = at91sam9x5_dt_device_init,
- .dt_compat = at91sam9x5_board_compat,
-MACHINE_END
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index 28ca57a2060f..f1ead0f13c19 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -13,15 +13,11 @@

#ifdef CONFIG_PM
extern void __init at91rm9200_pm_init(void);
-extern void __init at91sam9260_pm_init(void);
-extern void __init at91sam9g45_pm_init(void);
-extern void __init at91sam9x5_pm_init(void);
+extern void __init at91sam9_pm_init(void);
extern void __init sama5_pm_init(void);
#else
static inline void __init at91rm9200_pm_init(void) { }
-static inline void __init at91sam9260_pm_init(void) { }
-static inline void __init at91sam9g45_pm_init(void) { }
-static inline void __init at91sam9x5_pm_init(void) { }
+static inline void __init at91sam9_pm_init(void) { }
static inline void __init sama5_pm_init(void) { }
#endif

diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index a7c047f0d21f..dedfe9038336 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -505,19 +505,7 @@ void __init at91rm9200_pm_init(void)
at91_pm_init(at91rm9200_idle);
}

-void __init at91sam9260_pm_init(void)
-{
- at91_dt_ramc();
- at91_pm_init(at91sam9_idle);
-}
-
-void __init at91sam9g45_pm_init(void)
-{
- at91_dt_ramc();
- at91_pm_init(at91sam9_idle);
-}
-
-void __init at91sam9x5_pm_init(void)
+void __init at91sam9_pm_init(void)
{
at91_dt_ramc();
at91_pm_init(at91sam9_idle);
--
2.11.0

2017-03-28 11:21:02

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 08/11] ARM: at91: pm: Tie the USB clock mask to the pmc

The USB clocks mask (uhp_udp_mask) depends on the pmc. Tie it to the pmc id
instead of the SoC.

Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/arm/mach-at91/pm.c | 37 +++++++++++++++++++++++--------------
1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index ddf62a006635..a7c047f0d21f 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -442,31 +442,46 @@ static void __init at91_pm_sram_init(void)
&at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz);
}

+struct pmc_info {
+ unsigned long uhp_udp_mask;
+};
+
+static const struct pmc_info pmc_infos[] __initconst = {
+ { .uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP },
+ { .uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP },
+ { .uhp_udp_mask = AT91SAM926x_PMC_UHP },
+};
+
static const struct of_device_id atmel_pmc_ids[] __initconst = {
- { .compatible = "atmel,at91rm9200-pmc" },
- { .compatible = "atmel,at91sam9260-pmc" },
- { .compatible = "atmel,at91sam9g45-pmc" },
- { .compatible = "atmel,at91sam9n12-pmc" },
- { .compatible = "atmel,at91sam9x5-pmc" },
- { .compatible = "atmel,sama5d3-pmc" },
- { .compatible = "atmel,sama5d2-pmc" },
+ { .compatible = "atmel,at91rm9200-pmc", .data = &pmc_infos[0] },
+ { .compatible = "atmel,at91sam9260-pmc", .data = &pmc_infos[1] },
+ { .compatible = "atmel,at91sam9g45-pmc", .data = &pmc_infos[2] },
+ { .compatible = "atmel,at91sam9n12-pmc", .data = &pmc_infos[1] },
+ { .compatible = "atmel,at91sam9x5-pmc", .data = &pmc_infos[1] },
+ { .compatible = "atmel,sama5d3-pmc", .data = &pmc_infos[1] },
+ { .compatible = "atmel,sama5d2-pmc", .data = &pmc_infos[1] },
{ /* sentinel */ },
};

static void __init at91_pm_init(void (*pm_idle)(void))
{
struct device_node *pmc_np;
+ const struct of_device_id *of_id;
+ const struct pmc_info *pmc;

if (at91_cpuidle_device.dev.platform_data)
platform_device_register(&at91_cpuidle_device);

- pmc_np = of_find_matching_node(NULL, atmel_pmc_ids);
+ pmc_np = of_find_matching_node_and_match(NULL, atmel_pmc_ids, &of_id);
pm_data.pmc = of_iomap(pmc_np, 0);
if (!pm_data.pmc) {
pr_err("AT91: PM not supported, PMC not found\n");
return;
}

+ pmc = of_id->data;
+ pm_data.uhp_udp_mask = pmc->uhp_udp_mask;
+
if (pm_idle)
arm_pm_idle = pm_idle;

@@ -487,35 +502,29 @@ void __init at91rm9200_pm_init(void)
*/
at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0);

- pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP;
-
at91_pm_init(at91rm9200_idle);
}

void __init at91sam9260_pm_init(void)
{
at91_dt_ramc();
- pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
at91_pm_init(at91sam9_idle);
}

void __init at91sam9g45_pm_init(void)
{
at91_dt_ramc();
- pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
at91_pm_init(at91sam9_idle);
}

void __init at91sam9x5_pm_init(void)
{
at91_dt_ramc();
- pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
at91_pm_init(at91sam9_idle);
}

void __init sama5_pm_init(void)
{
at91_dt_ramc();
- pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
at91_pm_init(NULL);
}
--
2.11.0

2017-03-28 11:21:26

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 05/11] ARM: at91: pm: Simplify at91rm9200_standby

Since 2008, AT91_MC_SDRAMC_LPR is set to 0 at kernel initialization. There
is no use saving, changing and restoring it.

Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/arm/mach-at91/pm.c | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index a35b1541b328..3d68d93c11c7 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -222,20 +222,15 @@ static void at91_pm_set_standby(void (*at91_standby)(void))
*/
static void at91rm9200_standby(void)
{
- u32 lpr = at91_ramc_read(0, AT91_MC_SDRAMC_LPR);
-
asm volatile(
"b 1f\n\t"
".align 5\n\t"
"1: mcr p15, 0, %0, c7, c10, 4\n\t"
- " str %0, [%1, %2]\n\t"
- " str %3, [%1, %4]\n\t"
+ " str %2, [%1, %3]\n\t"
" mcr p15, 0, %0, c7, c0, 4\n\t"
- " str %5, [%1, %2]"
:
- : "r" (0), "r" (pm_data.ramc[0]), "r" (AT91_MC_SDRAMC_LPR),
- "r" (1), "r" (AT91_MC_SDRAMC_SRR),
- "r" (lpr));
+ : "r" (0), "r" (pm_data.ramc[0]),
+ "r" (1), "r" (AT91_MC_SDRAMC_SRR));
}

/* We manage both DDRAM/SDRAM controllers, we need more than one value to
--
2.11.0

2017-03-28 11:21:54

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 04/11] ARM: at91: pm: Use struct at91_pm_data in pm_suspend.S

The number of register we can safely pass to at91_pm_suspend_in_sram is
limited. Instead, pass the address to the at91_pm_data structure.

The offsets are automatically generated to avoid hardcoding them.

Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/arm/mach-at91/Makefile | 33 +++++++++++++++
arch/arm/mach-at91/pm.c | 78 +++++++++++++++---------------------
arch/arm/mach-at91/pm.h | 16 +++++---
arch/arm/mach-at91/pm_data-offsets.c | 13 ++++++
arch/arm/mach-at91/pm_suspend.S | 29 ++++++--------
5 files changed, 102 insertions(+), 67 deletions(-)
create mode 100644 arch/arm/mach-at91/pm_data-offsets.c

diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index c5bbf8bb8c0f..858ef14f961c 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -18,3 +18,36 @@ endif
ifeq ($(CONFIG_PM_DEBUG),y)
CFLAGS_pm.o += -DDEBUG
endif
+
+# Default sed regexp - multiline due to syntax constraints
+define sed-y
+ "/^->/{s:->#\(.*\):/* \1 */:; \
+ s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
+ s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
+ s:->::; p;}"
+endef
+
+# Use filechk to avoid rebuilds when a header changes, but the resulting file
+# does not
+define filechk_offsets
+ (set -e; \
+ echo "#ifndef $2"; \
+ echo "#define $2"; \
+ echo "/*"; \
+ echo " * DO NOT MODIFY."; \
+ echo " *"; \
+ echo " * This file was generated by Kbuild"; \
+ echo " */"; \
+ echo ""; \
+ sed -ne $(sed-y); \
+ echo ""; \
+ echo "#endif" )
+endef
+
+arch/arm/mach-at91/pm_data-offsets.s: arch/arm/mach-at91/pm_data-offsets.c
+ $(call if_changed_dep,cc_s_c)
+
+include/generated/at91_pm_data-offsets.h: arch/arm/mach-at91/pm_data-offsets.s FORCE
+ $(call filechk,offsets,__PM_DATA_OFFSETS_H__)
+
+arch/arm/mach-at91/pm_suspend.o: include/generated/at91_pm_data-offsets.h
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index c780dda3b604..a35b1541b328 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -37,18 +37,13 @@ extern void at91_pinctrl_gpio_suspend(void);
extern void at91_pinctrl_gpio_resume(void);
#endif

-static struct {
- void __iomem *pmc;
- void __iomem *ramc[2];
- unsigned long uhp_udp_mask;
- int memctrl;
-} at91_pm_data;
+static struct at91_pm_data pm_data;

#define at91_ramc_read(id, field) \
- __raw_readl(at91_pm_data.ramc[id] + field)
+ __raw_readl(pm_data.ramc[id] + field)

#define at91_ramc_write(id, field, value) \
- __raw_writel(value, at91_pm_data.ramc[id] + field)
+ __raw_writel(value, pm_data.ramc[id] + field)

static int at91_pm_valid_state(suspend_state_t state)
{
@@ -84,10 +79,10 @@ static int at91_pm_verify_clocks(void)
unsigned long scsr;
int i;

- scsr = readl(at91_pm_data.pmc + AT91_PMC_SCSR);
+ scsr = readl(pm_data.pmc + AT91_PMC_SCSR);

/* USB must not be using PLLB */
- if ((scsr & at91_pm_data.uhp_udp_mask) != 0) {
+ if ((scsr & pm_data.uhp_udp_mask) != 0) {
pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
return 0;
}
@@ -98,7 +93,7 @@ static int at91_pm_verify_clocks(void)

if ((scsr & (AT91_PMC_PCK0 << i)) == 0)
continue;
- css = readl(at91_pm_data.pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
+ css = readl(pm_data.pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
if (css != AT91_PMC_CSS_SLOW) {
pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css);
return 0;
@@ -124,25 +119,18 @@ int at91_suspend_entering_slow_clock(void)
}
EXPORT_SYMBOL(at91_suspend_entering_slow_clock);

-static void (*at91_suspend_sram_fn)(void __iomem *pmc, void __iomem *ramc0,
- void __iomem *ramc1, int memctrl);
-
-extern void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *ramc0,
- void __iomem *ramc1, int memctrl);
+static void (*at91_suspend_sram_fn)(struct at91_pm_data *);
+extern void at91_pm_suspend_in_sram(struct at91_pm_data *pm_data);
extern u32 at91_pm_suspend_in_sram_sz;

static void at91_pm_suspend(suspend_state_t state)
{
- unsigned int pm_data = at91_pm_data.memctrl;
-
- pm_data |= (state == PM_SUSPEND_MEM) ?
- AT91_PM_MODE(AT91_PM_SLOW_CLOCK) : 0;
+ pm_data.mode = (state == PM_SUSPEND_MEM) ? AT91_PM_SLOW_CLOCK : 0;

flush_cache_all();
outer_disable();

- at91_suspend_sram_fn(at91_pm_data.pmc, at91_pm_data.ramc[0],
- at91_pm_data.ramc[1], pm_data);
+ at91_suspend_sram_fn(&pm_data);

outer_resume();
}
@@ -245,7 +233,7 @@ static void at91rm9200_standby(void)
" mcr p15, 0, %0, c7, c0, 4\n\t"
" str %5, [%1, %2]"
:
- : "r" (0), "r" (at91_pm_data.ramc[0]), "r" (AT91_MC_SDRAMC_LPR),
+ : "r" (0), "r" (pm_data.ramc[0]), "r" (AT91_MC_SDRAMC_LPR),
"r" (1), "r" (AT91_MC_SDRAMC_SRR),
"r" (lpr));
}
@@ -260,7 +248,7 @@ static void at91_ddr_standby(void)
u32 lpr0, lpr1 = 0;
u32 saved_lpr0, saved_lpr1 = 0;

- if (at91_pm_data.ramc[1]) {
+ if (pm_data.ramc[1]) {
saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR);
lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB;
lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH;
@@ -272,13 +260,13 @@ static void at91_ddr_standby(void)

/* self-refresh mode now */
at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
- if (at91_pm_data.ramc[1])
+ if (pm_data.ramc[1])
at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1);

cpu_do_idle();

at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
- if (at91_pm_data.ramc[1])
+ if (pm_data.ramc[1])
at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
}

@@ -306,7 +294,7 @@ static void at91sam9_sdram_standby(void)
u32 lpr0, lpr1 = 0;
u32 saved_lpr0, saved_lpr1 = 0;

- if (at91_pm_data.ramc[1]) {
+ if (pm_data.ramc[1]) {
saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR);
lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB;
lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH;
@@ -318,13 +306,13 @@ static void at91sam9_sdram_standby(void)

/* self-refresh mode now */
at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0);
- if (at91_pm_data.ramc[1])
+ if (pm_data.ramc[1])
at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1);

cpu_do_idle();

at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0);
- if (at91_pm_data.ramc[1])
+ if (pm_data.ramc[1])
at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1);
}

@@ -344,8 +332,8 @@ static __init void at91_dt_ramc(void)
const void *standby = NULL;

for_each_matching_node_and_match(np, ramc_ids, &of_id) {
- at91_pm_data.ramc[idx] = of_iomap(np, 0);
- if (!at91_pm_data.ramc[idx])
+ pm_data.ramc[idx] = of_iomap(np, 0);
+ if (!pm_data.ramc[idx])
panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx);

if (!standby)
@@ -371,12 +359,12 @@ static void at91rm9200_idle(void)
* Disable the processor clock. The processor will be automatically
* re-enabled by an interrupt or by a reset.
*/
- writel(AT91_PMC_PCK, at91_pm_data.pmc + AT91_PMC_SCDR);
+ writel(AT91_PMC_PCK, pm_data.pmc + AT91_PMC_SCDR);
}

static void at91sam9_idle(void)
{
- writel(AT91_PMC_PCK, at91_pm_data.pmc + AT91_PMC_SCDR);
+ writel(AT91_PMC_PCK, pm_data.pmc + AT91_PMC_SCDR);
cpu_do_idle();
}

@@ -445,8 +433,8 @@ static void __init at91_pm_init(void (*pm_idle)(void))
platform_device_register(&at91_cpuidle_device);

pmc_np = of_find_matching_node(NULL, atmel_pmc_ids);
- at91_pm_data.pmc = of_iomap(pmc_np, 0);
- if (!at91_pm_data.pmc) {
+ pm_data.pmc = of_iomap(pmc_np, 0);
+ if (!pm_data.pmc) {
pr_err("AT91: PM not supported, PMC not found\n");
return;
}
@@ -471,8 +459,8 @@ void __init at91rm9200_pm_init(void)
*/
at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0);

- at91_pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP;
- at91_pm_data.memctrl = AT91_MEMCTRL_MC;
+ pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP;
+ pm_data.memctrl = AT91_MEMCTRL_MC;

at91_pm_init(at91rm9200_idle);
}
@@ -480,31 +468,31 @@ void __init at91rm9200_pm_init(void)
void __init at91sam9260_pm_init(void)
{
at91_dt_ramc();
- at91_pm_data.memctrl = AT91_MEMCTRL_SDRAMC;
- at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
+ pm_data.memctrl = AT91_MEMCTRL_SDRAMC;
+ pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
at91_pm_init(at91sam9_idle);
}

void __init at91sam9g45_pm_init(void)
{
at91_dt_ramc();
- at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
- at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
+ pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
+ pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
at91_pm_init(at91sam9_idle);
}

void __init at91sam9x5_pm_init(void)
{
at91_dt_ramc();
- at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
- at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
+ pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
+ pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
at91_pm_init(at91sam9_idle);
}

void __init sama5_pm_init(void)
{
at91_dt_ramc();
- at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
- at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
+ pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
+ pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
at91_pm_init(NULL);
}
diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
index 8eed156ef19a..fc0f7d048187 100644
--- a/arch/arm/mach-at91/pm.h
+++ b/arch/arm/mach-at91/pm.h
@@ -21,12 +21,16 @@
#define AT91_MEMCTRL_SDRAMC 1
#define AT91_MEMCTRL_DDRSDR 2

-#define AT91_PM_MEMTYPE_MASK 0x0f
-
-#define AT91_PM_MODE_OFFSET 4
-#define AT91_PM_MODE_MASK 0x01
-#define AT91_PM_MODE(x) (((x) & AT91_PM_MODE_MASK) << AT91_PM_MODE_OFFSET)
-
#define AT91_PM_SLOW_CLOCK 0x01

+#ifndef __ASSEMBLY__
+struct at91_pm_data {
+ void __iomem *pmc;
+ void __iomem *ramc[2];
+ unsigned long uhp_udp_mask;
+ unsigned int memctrl;
+ unsigned int mode;
+};
+#endif
+
#endif
diff --git a/arch/arm/mach-at91/pm_data-offsets.c b/arch/arm/mach-at91/pm_data-offsets.c
new file mode 100644
index 000000000000..30302cb16df0
--- /dev/null
+++ b/arch/arm/mach-at91/pm_data-offsets.c
@@ -0,0 +1,13 @@
+#include <linux/stddef.h>
+#include <linux/kbuild.h>
+#include "pm.h"
+
+int main(void)
+{
+ DEFINE(PM_DATA_PMC, offsetof(struct at91_pm_data, pmc));
+ DEFINE(PM_DATA_RAMC0, offsetof(struct at91_pm_data, ramc[0]));
+ DEFINE(PM_DATA_RAMC1, offsetof(struct at91_pm_data, ramc[1]));
+ DEFINE(PM_DATA_MEMCTRL, offsetof(struct at91_pm_data, memctrl));
+ DEFINE(PM_DATA_MODE, offsetof(struct at91_pm_data, mode));
+ return 0;
+}
diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S
index a25defda3d22..ed317657e760 100644
--- a/arch/arm/mach-at91/pm_suspend.S
+++ b/arch/arm/mach-at91/pm_suspend.S
@@ -14,6 +14,7 @@
#include <linux/linkage.h>
#include <linux/clk/at91_pmc.h>
#include "pm.h"
+#include "generated/at91_pm_data-offsets.h"

#define SRAMC_SELF_FRESH_ACTIVE 0x01
#define SRAMC_SELF_FRESH_EXIT 0x00
@@ -72,13 +73,9 @@ tmp2 .req r5
.arm

/*
- * void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *sdramc,
- * void __iomem *ramc1, int memctrl)
+ * void at91_suspend_sram_fn(struct at91_pm_data*)
* @input param:
- * @r0: base address of AT91_PMC
- * @r1: base address of SDRAM Controller (SDRAM, DDRSDR, or AT91_SYS)
- * @r2: base address of second SDRAM Controller or 0 if not present
- * @r3: pm information
+ * @r0: base address of struct at91_pm_data
*/
/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */
.align 3
@@ -90,16 +87,16 @@ ENTRY(at91_pm_suspend_in_sram)
mov tmp1, #0
mcr p15, 0, tmp1, c7, c10, 4

- str r0, .pmc_base
- str r1, .sramc_base
- str r2, .sramc1_base
-
- and r0, r3, #AT91_PM_MEMTYPE_MASK
- str r0, .memtype
-
- lsr r0, r3, #AT91_PM_MODE_OFFSET
- and r0, r0, #AT91_PM_MODE_MASK
- str r0, .pm_mode
+ ldr tmp1, [r0, #PM_DATA_PMC]
+ str tmp1, .pmc_base
+ ldr tmp1, [r0, #PM_DATA_RAMC0]
+ str tmp1, .sramc_base
+ ldr tmp1, [r0, #PM_DATA_RAMC1]
+ str tmp1, .sramc1_base
+ ldr tmp1, [r0, #PM_DATA_MEMCTRL]
+ str tmp1, .memtype
+ ldr tmp1, [r0, #PM_DATA_MODE]
+ str tmp1, .pm_mode

/* Active the self-refresh mode */
mov r0, #SRAMC_SELF_FRESH_ACTIVE
--
2.11.0

2017-03-28 11:19:54

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 01/11] ARM: at91: pm: Cleanup headers

Remove unnecessary header inclusions and reorder the remaining ones.

Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/arm/mach-at91/pm.c | 21 +++++----------------
1 file changed, 5 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index a277981f414d..9e2b5c1e503e 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -10,28 +10,17 @@
* (at your option) any later version.
*/

-#include <linux/gpio.h>
-#include <linux/suspend.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
#include <linux/genalloc.h>
-#include <linux/interrupt.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/platform_data/atmel.h>
-#include <linux/io.h>
+#include <linux/suspend.h>
+
#include <linux/clk/at91_pmc.h>

-#include <asm/irq.h>
-#include <linux/atomic.h>
-#include <asm/mach/time.h>
-#include <asm/mach/irq.h>
-#include <asm/fncpy.h>
#include <asm/cacheflush.h>
+#include <asm/fncpy.h>
#include <asm/system_misc.h>

#include "generic.h"
--
2.11.0

2017-03-28 11:20:37

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 10/11] ARM: at91: pm: Remove at91_pm_set_standby

Merge at91_pm_set_standby() in at91_dt_ramc as this is the only callsite.
That moves it to the init section.

Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/arm/mach-at91/pm.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index dedfe9038336..2cd27c830ab6 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -205,12 +205,6 @@ static struct platform_device at91_cpuidle_device = {
.name = "cpuidle-at91",
};

-static void at91_pm_set_standby(void (*at91_standby)(void))
-{
- if (at91_standby)
- at91_cpuidle_device.dev.platform_data = at91_standby;
-}
-
/*
* The AT91RM9200 goes into self-refresh mode with this command, and will
* terminate self-refresh automatically on the next SDRAM access.
@@ -354,7 +348,7 @@ static __init void at91_dt_ramc(void)
struct device_node *np;
const struct of_device_id *of_id;
int idx = 0;
- const void *standby = NULL;
+ void *standby = NULL;
const struct ramc_info *ramc;

for_each_matching_node_and_match(np, ramc_ids, &of_id) {
@@ -378,7 +372,7 @@ static __init void at91_dt_ramc(void)
return;
}

- at91_pm_set_standby(standby);
+ at91_cpuidle_device.dev.platform_data = standby;
}

static void at91rm9200_idle(void)
--
2.11.0

2017-03-28 11:21:03

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 07/11] ARM: at91: pm: Tie the memory controller type to the ramc id

Instead of relying on the SoC type to select the memory controller type,
use the device tree ids as they are parsed anyway.

Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/arm/mach-at91/pm.c | 30 ++++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 488549bc2bed..ddf62a006635 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -329,11 +329,23 @@ static void at91sam9_sdram_standby(void)
at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1);
}

+struct ramc_info {
+ void (*idle)(void);
+ unsigned int memctrl;
+};
+
+static const struct ramc_info ramc_infos[] __initconst = {
+ { .idle = at91rm9200_standby, .memctrl = AT91_MEMCTRL_MC},
+ { .idle = at91sam9_sdram_standby, .memctrl = AT91_MEMCTRL_SDRAMC},
+ { .idle = at91_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR},
+ { .idle = sama5d3_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR},
+};
+
static const struct of_device_id const ramc_ids[] __initconst = {
- { .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby },
- { .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby },
- { .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby },
- { .compatible = "atmel,sama5d3-ddramc", .data = sama5d3_ddr_standby },
+ { .compatible = "atmel,at91rm9200-sdramc", .data = &ramc_infos[0] },
+ { .compatible = "atmel,at91sam9260-sdramc", .data = &ramc_infos[1] },
+ { .compatible = "atmel,at91sam9g45-ddramc", .data = &ramc_infos[2] },
+ { .compatible = "atmel,sama5d3-ddramc", .data = &ramc_infos[3] },
{ /*sentinel*/ }
};

@@ -343,14 +355,17 @@ static __init void at91_dt_ramc(void)
const struct of_device_id *of_id;
int idx = 0;
const void *standby = NULL;
+ const struct ramc_info *ramc;

for_each_matching_node_and_match(np, ramc_ids, &of_id) {
pm_data.ramc[idx] = of_iomap(np, 0);
if (!pm_data.ramc[idx])
panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx);

+ ramc = of_id->data;
if (!standby)
- standby = of_id->data;
+ standby = ramc->idle;
+ pm_data.memctrl = ramc->memctrl;

idx++;
}
@@ -473,7 +488,6 @@ void __init at91rm9200_pm_init(void)
at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0);

pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP;
- pm_data.memctrl = AT91_MEMCTRL_MC;

at91_pm_init(at91rm9200_idle);
}
@@ -481,7 +495,6 @@ void __init at91rm9200_pm_init(void)
void __init at91sam9260_pm_init(void)
{
at91_dt_ramc();
- pm_data.memctrl = AT91_MEMCTRL_SDRAMC;
pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
at91_pm_init(at91sam9_idle);
}
@@ -490,7 +503,6 @@ void __init at91sam9g45_pm_init(void)
{
at91_dt_ramc();
pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
- pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
at91_pm_init(at91sam9_idle);
}

@@ -498,7 +510,6 @@ void __init at91sam9x5_pm_init(void)
{
at91_dt_ramc();
pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
- pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
at91_pm_init(at91sam9_idle);
}

@@ -506,6 +517,5 @@ void __init sama5_pm_init(void)
{
at91_dt_ramc();
pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
- pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
at91_pm_init(NULL);
}
--
2.11.0

2017-03-28 11:21:27

by Alexandre Belloni

[permalink] [raw]
Subject: [PATCH v2 06/11] ARM: at91: pm: Workaround DDRSDRC self-refresh bug with LPDDR1 memories.

As already explained for pm_suspend.S, the DDRSDR controller fails to put
LPDDR1 memories in self-refresh. Force the controller to think it has DDR2
memories during the self-refresh period, as the DDR2 self-refresh spec is
equivalent to LPDDR1, and is correctly implemented in the controller.

Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/arm/mach-at91/pm.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 3d68d93c11c7..488549bc2bed 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -241,12 +241,27 @@ static void at91_ddr_standby(void)
/* Those two values allow us to delay self-refresh activation
* to the maximum. */
u32 lpr0, lpr1 = 0;
+ u32 mdr, saved_mdr0, saved_mdr1 = 0;
u32 saved_lpr0, saved_lpr1 = 0;

+ /* LPDDR1 --> force DDR2 mode during self-refresh */
+ saved_mdr0 = at91_ramc_read(0, AT91_DDRSDRC_MDR);
+ if ((saved_mdr0 & AT91_DDRSDRC_MD) == AT91_DDRSDRC_MD_LOW_POWER_DDR) {
+ mdr = saved_mdr0 & ~AT91_DDRSDRC_MD;
+ mdr |= AT91_DDRSDRC_MD_DDR2;
+ at91_ramc_write(0, AT91_DDRSDRC_MDR, mdr);
+ }
+
if (pm_data.ramc[1]) {
saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR);
lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB;
lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH;
+ saved_mdr1 = at91_ramc_read(1, AT91_DDRSDRC_MDR);
+ if ((saved_mdr1 & AT91_DDRSDRC_MD) == AT91_DDRSDRC_MD_LOW_POWER_DDR) {
+ mdr = saved_mdr1 & ~AT91_DDRSDRC_MD;
+ mdr |= AT91_DDRSDRC_MD_DDR2;
+ at91_ramc_write(1, AT91_DDRSDRC_MDR, mdr);
+ }
}

saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR);
@@ -260,9 +275,12 @@ static void at91_ddr_standby(void)

cpu_do_idle();

+ at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr0);
at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
- if (pm_data.ramc[1])
+ if (pm_data.ramc[1]) {
+ at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr1);
at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
+ }
}

static void sama5d3_ddr_standby(void)
--
2.11.0

2017-03-29 04:49:40

by Wenyou Yang

[permalink] [raw]
Subject: RE: [PATCH v2 01/11] ARM: at91: pm: Cleanup headers



> -----Original Message-----
> From: Alexandre Belloni [mailto:[email protected]]
> Sent: 2017??3??28?? 19:19
> To: Nicolas Ferre - M43238 <[email protected]>
> Cc: [email protected]; [email protected]; Boris
> Brezillon <[email protected]>; Wenyou Yang - A41535
> <[email protected]>; Alexandre Belloni <alexandre.belloni@free-
> electrons.com>
> Subject: [PATCH v2 01/11] ARM: at91: pm: Cleanup headers
>
> Remove unnecessary header inclusions and reorder the remaining ones.
>
> Signed-off-by: Alexandre Belloni <[email protected]>

Acked-by: Wenyou Yang <[email protected]>

> ---
> arch/arm/mach-at91/pm.c | 21 +++++----------------
> 1 file changed, 5 insertions(+), 16 deletions(-)
>
> diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index
> a277981f414d..9e2b5c1e503e 100644
> --- a/arch/arm/mach-at91/pm.c
> +++ b/arch/arm/mach-at91/pm.c
> @@ -10,28 +10,17 @@
> * (at your option) any later version.
> */
>
> -#include <linux/gpio.h>
> -#include <linux/suspend.h>
> -#include <linux/sched.h>
> -#include <linux/proc_fs.h>
> #include <linux/genalloc.h>
> -#include <linux/interrupt.h>
> -#include <linux/sysfs.h>
> -#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/of_address.h>
> #include <linux/of.h>
> #include <linux/of_platform.h>
> -#include <linux/of_address.h>
> -#include <linux/platform_device.h>
> -#include <linux/platform_data/atmel.h>
> -#include <linux/io.h>
> +#include <linux/suspend.h>
> +
> #include <linux/clk/at91_pmc.h>
>
> -#include <asm/irq.h>
> -#include <linux/atomic.h>
> -#include <asm/mach/time.h>
> -#include <asm/mach/irq.h>
> -#include <asm/fncpy.h>
> #include <asm/cacheflush.h>
> +#include <asm/fncpy.h>
> #include <asm/system_misc.h>
>
> #include "generic.h"
> --
> 2.11.0


2017-03-29 04:50:47

by Wenyou Yang

[permalink] [raw]
Subject: RE: [PATCH v2 02/11] ARM: at91: pm: Move at91_ramc_read/write to pm.c



> -----Original Message-----
> From: Alexandre Belloni [mailto:[email protected]]
> Sent: 2017??3??28?? 19:19
> To: Nicolas Ferre - M43238 <[email protected]>
> Cc: [email protected]; [email protected]; Boris
> Brezillon <[email protected]>; Wenyou Yang - A41535
> <[email protected]>; Alexandre Belloni <alexandre.belloni@free-
> electrons.com>
> Subject: [PATCH v2 02/11] ARM: at91: pm: Move at91_ramc_read/write to pm.c
>
> Those macros are only used in pm.c, move them there so we can remove the test
> on __ASSEMBLY__.
>
> Signed-off-by: Alexandre Belloni <[email protected]>

Acked-by: Wenyou Yang <[email protected]>

> ---
> arch/arm/mach-at91/pm.c | 6 ++++++
> arch/arm/mach-at91/pm.h | 8 --------
> 2 files changed, 6 insertions(+), 8 deletions(-)
>
> diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index
> 9e2b5c1e503e..41789aa4df86 100644
> --- a/arch/arm/mach-at91/pm.c
> +++ b/arch/arm/mach-at91/pm.c
> @@ -45,6 +45,12 @@ static struct {
> } at91_pm_data;
>
> static void __iomem *at91_ramc_base[2];
> +#define at91_ramc_read(id, field) \
> + __raw_readl(at91_ramc_base[id] + field)
> +
> +#define at91_ramc_write(id, field, value) \
> + __raw_writel(value, at91_ramc_base[id] + field)
> +
>
> static int at91_pm_valid_state(suspend_state_t state) { diff --git
> a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h index
> bf980c6ef294..8eed156ef19a 100644
> --- a/arch/arm/mach-at91/pm.h
> +++ b/arch/arm/mach-at91/pm.h
> @@ -17,14 +17,6 @@
> #include <soc/at91/at91sam9_ddrsdr.h>
> #include <soc/at91/at91sam9_sdramc.h>
>
> -#ifndef __ASSEMBLY__
> -#define at91_ramc_read(id, field) \
> - __raw_readl(at91_ramc_base[id] + field)
> -
> -#define at91_ramc_write(id, field, value) \
> - __raw_writel(value, at91_ramc_base[id] + field)
> -#endif
> -
> #define AT91_MEMCTRL_MC 0
> #define AT91_MEMCTRL_SDRAMC 1
> #define AT91_MEMCTRL_DDRSDR 2
> --
> 2.11.0


2017-03-29 04:51:25

by Wenyou Yang

[permalink] [raw]
Subject: RE: [PATCH v2 03/11] ARM: at91: pm: Move global variables into at91_pm_data



> -----Original Message-----
> From: Alexandre Belloni [mailto:[email protected]]
> Sent: 2017??3??28?? 19:20
> To: Nicolas Ferre - M43238 <[email protected]>
> Cc: [email protected]; [email protected]; Boris
> Brezillon <[email protected]>; Wenyou Yang - A41535
> <[email protected]>; Alexandre Belloni <alexandre.belloni@free-
> electrons.com>
> Subject: [PATCH v2 03/11] ARM: at91: pm: Move global variables into
> at91_pm_data
>
> Instead of having separate global variables to hold IP addresses, move them to
> struct at91_pm_data.
>
> Signed-off-by: Alexandre Belloni <[email protected]>

Acked-by: Wenyou Yang <[email protected]>

> ---
> arch/arm/mach-at91/pm.c | 44 +++++++++++++++++++++-----------------------
> 1 file changed, 21 insertions(+), 23 deletions(-)
>
> diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index
> 41789aa4df86..c780dda3b604 100644
> --- a/arch/arm/mach-at91/pm.c
> +++ b/arch/arm/mach-at91/pm.c
> @@ -26,8 +26,6 @@
> #include "generic.h"
> #include "pm.h"
>
> -static void __iomem *pmc;
> -
> /*
> * FIXME: this is needed to communicate between the pinctrl driver and
> * the PM implementation in the machine. Possibly part of the PM @@ -40,17
> +38,17 @@ extern void at91_pinctrl_gpio_resume(void); #endif
>
> static struct {
> + void __iomem *pmc;
> + void __iomem *ramc[2];
> unsigned long uhp_udp_mask;
> int memctrl;
> } at91_pm_data;
>
> -static void __iomem *at91_ramc_base[2]; #define at91_ramc_read(id, field) \
> - __raw_readl(at91_ramc_base[id] + field)
> + __raw_readl(at91_pm_data.ramc[id] + field)
>
> #define at91_ramc_write(id, field, value) \
> - __raw_writel(value, at91_ramc_base[id] + field)
> -
> + __raw_writel(value, at91_pm_data.ramc[id] + field)
>
> static int at91_pm_valid_state(suspend_state_t state) { @@ -86,7 +84,7 @@
> static int at91_pm_verify_clocks(void)
> unsigned long scsr;
> int i;
>
> - scsr = readl(pmc + AT91_PMC_SCSR);
> + scsr = readl(at91_pm_data.pmc + AT91_PMC_SCSR);
>
> /* USB must not be using PLLB */
> if ((scsr & at91_pm_data.uhp_udp_mask) != 0) { @@ -100,7 +98,7 @@
> static int at91_pm_verify_clocks(void)
>
> if ((scsr & (AT91_PMC_PCK0 << i)) == 0)
> continue;
> - css = readl(pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
> + css = readl(at91_pm_data.pmc + AT91_PMC_PCKR(i)) &
> AT91_PMC_CSS;
> if (css != AT91_PMC_CSS_SLOW) {
> pr_err("AT91: PM - Suspend-to-RAM with PCK%d
> src %d\n", i, css);
> return 0;
> @@ -143,8 +141,8 @@ static void at91_pm_suspend(suspend_state_t state)
> flush_cache_all();
> outer_disable();
>
> - at91_suspend_sram_fn(pmc, at91_ramc_base[0],
> - at91_ramc_base[1], pm_data);
> + at91_suspend_sram_fn(at91_pm_data.pmc, at91_pm_data.ramc[0],
> + at91_pm_data.ramc[1], pm_data);
>
> outer_resume();
> }
> @@ -247,7 +245,7 @@ static void at91rm9200_standby(void)
> " mcr p15, 0, %0, c7, c0, 4\n\t"
> " str %5, [%1, %2]"
> :
> - : "r" (0), "r" (at91_ramc_base[0]), "r" (AT91_MC_SDRAMC_LPR),
> + : "r" (0), "r" (at91_pm_data.ramc[0]), "r"
> (AT91_MC_SDRAMC_LPR),
> "r" (1), "r" (AT91_MC_SDRAMC_SRR),
> "r" (lpr));
> }
> @@ -262,7 +260,7 @@ static void at91_ddr_standby(void)
> u32 lpr0, lpr1 = 0;
> u32 saved_lpr0, saved_lpr1 = 0;
>
> - if (at91_ramc_base[1]) {
> + if (at91_pm_data.ramc[1]) {
> saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR);
> lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB;
> lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH; @@ -274,13
> +272,13 @@ static void at91_ddr_standby(void)
>
> /* self-refresh mode now */
> at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
> - if (at91_ramc_base[1])
> + if (at91_pm_data.ramc[1])
> at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1);
>
> cpu_do_idle();
>
> at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
> - if (at91_ramc_base[1])
> + if (at91_pm_data.ramc[1])
> at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); }
>
> @@ -308,7 +306,7 @@ static void at91sam9_sdram_standby(void)
> u32 lpr0, lpr1 = 0;
> u32 saved_lpr0, saved_lpr1 = 0;
>
> - if (at91_ramc_base[1]) {
> + if (at91_pm_data.ramc[1]) {
> saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR);
> lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB;
> lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH; @@ -320,13
> +318,13 @@ static void at91sam9_sdram_standby(void)
>
> /* self-refresh mode now */
> at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0);
> - if (at91_ramc_base[1])
> + if (at91_pm_data.ramc[1])
> at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1);
>
> cpu_do_idle();
>
> at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0);
> - if (at91_ramc_base[1])
> + if (at91_pm_data.ramc[1])
> at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1); }
>
> @@ -346,8 +344,8 @@ static __init void at91_dt_ramc(void)
> const void *standby = NULL;
>
> for_each_matching_node_and_match(np, ramc_ids, &of_id) {
> - at91_ramc_base[idx] = of_iomap(np, 0);
> - if (!at91_ramc_base[idx])
> + at91_pm_data.ramc[idx] = of_iomap(np, 0);
> + if (!at91_pm_data.ramc[idx])
> panic(pr_fmt("unable to map ramc[%d] cpu registers\n"),
> idx);
>
> if (!standby)
> @@ -373,12 +371,12 @@ static void at91rm9200_idle(void)
> * Disable the processor clock. The processor will be automatically
> * re-enabled by an interrupt or by a reset.
> */
> - writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR);
> + writel(AT91_PMC_PCK, at91_pm_data.pmc + AT91_PMC_SCDR);
> }
>
> static void at91sam9_idle(void)
> {
> - writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR);
> + writel(AT91_PMC_PCK, at91_pm_data.pmc + AT91_PMC_SCDR);
> cpu_do_idle();
> }
>
> @@ -447,8 +445,8 @@ static void __init at91_pm_init(void (*pm_idle)(void))
> platform_device_register(&at91_cpuidle_device);
>
> pmc_np = of_find_matching_node(NULL, atmel_pmc_ids);
> - pmc = of_iomap(pmc_np, 0);
> - if (!pmc) {
> + at91_pm_data.pmc = of_iomap(pmc_np, 0);
> + if (!at91_pm_data.pmc) {
> pr_err("AT91: PM not supported, PMC not found\n");
> return;
> }
> --
> 2.11.0


2017-03-29 04:55:40

by Wenyou Yang

[permalink] [raw]
Subject: RE: [PATCH v2 10/11] ARM: at91: pm: Remove at91_pm_set_standby



> -----Original Message-----
> From: Alexandre Belloni [mailto:[email protected]]
> Sent: 2017??3??28?? 19:20
> To: Nicolas Ferre - M43238 <[email protected]>
> Cc: [email protected]; [email protected]; Boris
> Brezillon <[email protected]>; Wenyou Yang - A41535
> <[email protected]>; Alexandre Belloni <alexandre.belloni@free-
> electrons.com>
> Subject: [PATCH v2 10/11] ARM: at91: pm: Remove at91_pm_set_standby
>
> Merge at91_pm_set_standby() in at91_dt_ramc as this is the only callsite.
> That moves it to the init section.
>
> Signed-off-by: Alexandre Belloni <[email protected]>

Acked-by: Wenyou Yang <[email protected]>

> ---
> arch/arm/mach-at91/pm.c | 10 ++--------
> 1 file changed, 2 insertions(+), 8 deletions(-)
>
> diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index
> dedfe9038336..2cd27c830ab6 100644
> --- a/arch/arm/mach-at91/pm.c
> +++ b/arch/arm/mach-at91/pm.c
> @@ -205,12 +205,6 @@ static struct platform_device at91_cpuidle_device = {
> .name = "cpuidle-at91",
> };
>
> -static void at91_pm_set_standby(void (*at91_standby)(void)) -{
> - if (at91_standby)
> - at91_cpuidle_device.dev.platform_data = at91_standby;
> -}
> -
> /*
> * The AT91RM9200 goes into self-refresh mode with this command, and will
> * terminate self-refresh automatically on the next SDRAM access.
> @@ -354,7 +348,7 @@ static __init void at91_dt_ramc(void)
> struct device_node *np;
> const struct of_device_id *of_id;
> int idx = 0;
> - const void *standby = NULL;
> + void *standby = NULL;
> const struct ramc_info *ramc;
>
> for_each_matching_node_and_match(np, ramc_ids, &of_id) { @@ -378,7
> +372,7 @@ static __init void at91_dt_ramc(void)
> return;
> }
>
> - at91_pm_set_standby(standby);
> + at91_cpuidle_device.dev.platform_data = standby;
> }
>
> static void at91rm9200_idle(void)
> --
> 2.11.0

Best Regards,
Wenyou Yang


2017-03-29 04:58:30

by Wenyou Yang

[permalink] [raw]
Subject: RE: [PATCH v2 08/11] ARM: at91: pm: Tie the USB clock mask to the pmc



> -----Original Message-----
> From: Alexandre Belloni [mailto:[email protected]]
> Sent: 2017??3??28?? 19:20
> To: Nicolas Ferre - M43238 <[email protected]>
> Cc: [email protected]; [email protected]; Boris
> Brezillon <[email protected]>; Wenyou Yang - A41535
> <[email protected]>; Alexandre Belloni <alexandre.belloni@free-
> electrons.com>
> Subject: [PATCH v2 08/11] ARM: at91: pm: Tie the USB clock mask to the pmc
>
> The USB clocks mask (uhp_udp_mask) depends on the pmc. Tie it to the pmc id
> instead of the SoC.
>
> Signed-off-by: Alexandre Belloni <[email protected]>

Acked-by: Wenyou Yang <[email protected]>

> ---
> arch/arm/mach-at91/pm.c | 37 +++++++++++++++++++++++--------------
> 1 file changed, 23 insertions(+), 14 deletions(-)
>
> diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index
> ddf62a006635..a7c047f0d21f 100644
> --- a/arch/arm/mach-at91/pm.c
> +++ b/arch/arm/mach-at91/pm.c
> @@ -442,31 +442,46 @@ static void __init at91_pm_sram_init(void)
> &at91_pm_suspend_in_sram,
> at91_pm_suspend_in_sram_sz); }
>
> +struct pmc_info {
> + unsigned long uhp_udp_mask;
> +};
> +
> +static const struct pmc_info pmc_infos[] __initconst = {
> + { .uhp_udp_mask = AT91RM9200_PMC_UHP |
> AT91RM9200_PMC_UDP },
> + { .uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP },
> + { .uhp_udp_mask = AT91SAM926x_PMC_UHP }, };
> +
> static const struct of_device_id atmel_pmc_ids[] __initconst = {
> - { .compatible = "atmel,at91rm9200-pmc" },
> - { .compatible = "atmel,at91sam9260-pmc" },
> - { .compatible = "atmel,at91sam9g45-pmc" },
> - { .compatible = "atmel,at91sam9n12-pmc" },
> - { .compatible = "atmel,at91sam9x5-pmc" },
> - { .compatible = "atmel,sama5d3-pmc" },
> - { .compatible = "atmel,sama5d2-pmc" },
> + { .compatible = "atmel,at91rm9200-pmc", .data = &pmc_infos[0] },
> + { .compatible = "atmel,at91sam9260-pmc", .data = &pmc_infos[1] },
> + { .compatible = "atmel,at91sam9g45-pmc", .data = &pmc_infos[2] },
> + { .compatible = "atmel,at91sam9n12-pmc", .data = &pmc_infos[1] },
> + { .compatible = "atmel,at91sam9x5-pmc", .data = &pmc_infos[1] },
> + { .compatible = "atmel,sama5d3-pmc", .data = &pmc_infos[1] },
> + { .compatible = "atmel,sama5d2-pmc", .data = &pmc_infos[1] },
> { /* sentinel */ },
> };
>
> static void __init at91_pm_init(void (*pm_idle)(void)) {
> struct device_node *pmc_np;
> + const struct of_device_id *of_id;
> + const struct pmc_info *pmc;
>
> if (at91_cpuidle_device.dev.platform_data)
> platform_device_register(&at91_cpuidle_device);
>
> - pmc_np = of_find_matching_node(NULL, atmel_pmc_ids);
> + pmc_np = of_find_matching_node_and_match(NULL, atmel_pmc_ids,
> &of_id);
> pm_data.pmc = of_iomap(pmc_np, 0);
> if (!pm_data.pmc) {
> pr_err("AT91: PM not supported, PMC not found\n");
> return;
> }
>
> + pmc = of_id->data;
> + pm_data.uhp_udp_mask = pmc->uhp_udp_mask;
> +
> if (pm_idle)
> arm_pm_idle = pm_idle;
>
> @@ -487,35 +502,29 @@ void __init at91rm9200_pm_init(void)
> */
> at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0);
>
> - pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP |
> AT91RM9200_PMC_UDP;
> -
> at91_pm_init(at91rm9200_idle);
> }
>
> void __init at91sam9260_pm_init(void)
> {
> at91_dt_ramc();
> - pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> at91_pm_init(at91sam9_idle);
> }
>
> void __init at91sam9g45_pm_init(void)
> {
> at91_dt_ramc();
> - pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
> at91_pm_init(at91sam9_idle);
> }
>
> void __init at91sam9x5_pm_init(void)
> {
> at91_dt_ramc();
> - pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> at91_pm_init(at91sam9_idle);
> }
>
> void __init sama5_pm_init(void)
> {
> at91_dt_ramc();
> - pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> at91_pm_init(NULL);
> }
> --
> 2.11.0


Best Regards,
Wenyou Yang


2017-03-29 04:59:08

by Wenyou Yang

[permalink] [raw]
Subject: RE: [PATCH v2 09/11] ARM: at91: pm: Merge all at91sam9*_pm_init



> -----Original Message-----
> From: Alexandre Belloni [mailto:[email protected]]
> Sent: 2017??3??28?? 19:20
> To: Nicolas Ferre - M43238 <[email protected]>
> Cc: [email protected]; [email protected]; Boris
> Brezillon <[email protected]>; Wenyou Yang - A41535
> <[email protected]>; Alexandre Belloni <alexandre.belloni@free-
> electrons.com>
> Subject: [PATCH v2 09/11] ARM: at91: pm: Merge all at91sam9*_pm_init
>
> The PM initialization is now identical for all at91sam9. Merge the functions.
>
> Signed-off-by: Alexandre Belloni <[email protected]>

Acked-by: Wenyou Yang <[email protected]>

> ---
> arch/arm/mach-at91/at91sam9.c | 45 +++----------------------------------------
> arch/arm/mach-at91/generic.h | 8 ++------
> arch/arm/mach-at91/pm.c | 14 +-------------
> 3 files changed, 6 insertions(+), 61 deletions(-)
>
> diff --git a/arch/arm/mach-at91/at91sam9.c b/arch/arm/mach-at91/at91sam9.c
> index ba28e9cc584d..c089bfd0dc2f 100644
> --- a/arch/arm/mach-at91/at91sam9.c
> +++ b/arch/arm/mach-at91/at91sam9.c
> @@ -52,7 +52,7 @@ static const struct at91_soc at91sam9_socs[] = {
> { /* sentinel */ },
> };
>
> -static void __init at91sam9_common_init(void)
> +static void __init at91sam9_init(void)
> {
> struct soc_device *soc;
> struct device *soc_dev = NULL;
> @@ -62,12 +62,8 @@ static void __init at91sam9_common_init(void)
> soc_dev = soc_device_to_device(soc);
>
> of_platform_default_populate(NULL, NULL, soc_dev); -}
>
> -static void __init at91sam9_dt_device_init(void) -{
> - at91sam9_common_init();
> - at91sam9260_pm_init();
> + at91sam9_pm_init();
> }
>
> static const char *const at91_dt_board_compat[] __initconst = { @@ -77,41
> +73,6 @@ static const char *const at91_dt_board_compat[] __initconst = {
>
> DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM9")
> /* Maintainer: Atmel */
> - .init_machine = at91sam9_dt_device_init,
> + .init_machine = at91sam9_init,
> .dt_compat = at91_dt_board_compat,
> MACHINE_END
> -
> -static void __init at91sam9g45_dt_device_init(void) -{
> - at91sam9_common_init();
> - at91sam9g45_pm_init();
> -}
> -
> -static const char *const at91sam9g45_board_compat[] __initconst = {
> - "atmel,at91sam9g45",
> - NULL
> -};
> -
> -DT_MACHINE_START(at91sam9g45_dt, "Atmel AT91SAM9G45")
> - /* Maintainer: Atmel */
> - .init_machine = at91sam9g45_dt_device_init,
> - .dt_compat = at91sam9g45_board_compat,
> -MACHINE_END
> -
> -static void __init at91sam9x5_dt_device_init(void) -{
> - at91sam9_common_init();
> - at91sam9x5_pm_init();
> -}
> -
> -static const char *const at91sam9x5_board_compat[] __initconst = {
> - "atmel,at91sam9x5",
> - "atmel,at91sam9n12",
> - NULL
> -};
> -
> -DT_MACHINE_START(at91sam9x5_dt, "Atmel AT91SAM9")
> - /* Maintainer: Atmel */
> - .init_machine = at91sam9x5_dt_device_init,
> - .dt_compat = at91sam9x5_board_compat,
> -MACHINE_END
> diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index
> 28ca57a2060f..f1ead0f13c19 100644
> --- a/arch/arm/mach-at91/generic.h
> +++ b/arch/arm/mach-at91/generic.h
> @@ -13,15 +13,11 @@
>
> #ifdef CONFIG_PM
> extern void __init at91rm9200_pm_init(void); -extern void __init
> at91sam9260_pm_init(void); -extern void __init at91sam9g45_pm_init(void); -
> extern void __init at91sam9x5_pm_init(void);
> +extern void __init at91sam9_pm_init(void);
> extern void __init sama5_pm_init(void); #else static inline void __init
> at91rm9200_pm_init(void) { } -static inline void __init at91sam9260_pm_init(void)
> { } -static inline void __init at91sam9g45_pm_init(void) { } -static inline void __init
> at91sam9x5_pm_init(void) { }
> +static inline void __init at91sam9_pm_init(void) { }
> static inline void __init sama5_pm_init(void) { } #endif
>
> diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index
> a7c047f0d21f..dedfe9038336 100644
> --- a/arch/arm/mach-at91/pm.c
> +++ b/arch/arm/mach-at91/pm.c
> @@ -505,19 +505,7 @@ void __init at91rm9200_pm_init(void)
> at91_pm_init(at91rm9200_idle);
> }
>
> -void __init at91sam9260_pm_init(void)
> -{
> - at91_dt_ramc();
> - at91_pm_init(at91sam9_idle);
> -}
> -
> -void __init at91sam9g45_pm_init(void)
> -{
> - at91_dt_ramc();
> - at91_pm_init(at91sam9_idle);
> -}
> -
> -void __init at91sam9x5_pm_init(void)
> +void __init at91sam9_pm_init(void)
> {
> at91_dt_ramc();
> at91_pm_init(at91sam9_idle);
> --
> 2.11.0


Best Regards,
Wenyou Yang


2017-03-29 05:02:33

by Wenyou Yang

[permalink] [raw]
Subject: RE: [PATCH v2 04/11] ARM: at91: pm: Use struct at91_pm_data in pm_suspend.S



> -----Original Message-----
> From: Alexandre Belloni [mailto:[email protected]]
> Sent: 2017??3??28?? 19:20
> To: Nicolas Ferre - M43238 <[email protected]>
> Cc: [email protected]; [email protected]; Boris
> Brezillon <[email protected]>; Wenyou Yang - A41535
> <[email protected]>; Alexandre Belloni <alexandre.belloni@free-
> electrons.com>
> Subject: [PATCH v2 04/11] ARM: at91: pm: Use struct at91_pm_data in
> pm_suspend.S
>
> The number of register we can safely pass to at91_pm_suspend_in_sram is
> limited. Instead, pass the address to the at91_pm_data structure.
>
> The offsets are automatically generated to avoid hardcoding them.
>
> Signed-off-by: Alexandre Belloni <[email protected]>

Acked-by: Wenyou Yang <[email protected]>

> ---
> arch/arm/mach-at91/Makefile | 33 +++++++++++++++
> arch/arm/mach-at91/pm.c | 78 +++++++++++++++---------------------
> arch/arm/mach-at91/pm.h | 16 +++++---
> arch/arm/mach-at91/pm_data-offsets.c | 13 ++++++
> arch/arm/mach-at91/pm_suspend.S | 29 ++++++--------
> 5 files changed, 102 insertions(+), 67 deletions(-) create mode 100644
> arch/arm/mach-at91/pm_data-offsets.c
>
> diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index
> c5bbf8bb8c0f..858ef14f961c 100644
> --- a/arch/arm/mach-at91/Makefile
> +++ b/arch/arm/mach-at91/Makefile
> @@ -18,3 +18,36 @@ endif
> ifeq ($(CONFIG_PM_DEBUG),y)
> CFLAGS_pm.o += -DDEBUG
> endif
> +
> +# Default sed regexp - multiline due to syntax constraints define sed-y
> + "/^->/{s:->#\(.*\):/* \1 */:; \
> + s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
> + s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
> + s:->::; p;}"
> +endef
> +
> +# Use filechk to avoid rebuilds when a header changes, but the
> +resulting file # does not define filechk_offsets
> + (set -e; \
> + echo "#ifndef $2"; \
> + echo "#define $2"; \
> + echo "/*"; \
> + echo " * DO NOT MODIFY."; \
> + echo " *"; \
> + echo " * This file was generated by Kbuild"; \
> + echo " */"; \
> + echo ""; \
> + sed -ne $(sed-y); \
> + echo ""; \
> + echo "#endif" )
> +endef
> +
> +arch/arm/mach-at91/pm_data-offsets.s: arch/arm/mach-at91/pm_data-offsets.c
> + $(call if_changed_dep,cc_s_c)
> +
> +include/generated/at91_pm_data-offsets.h: arch/arm/mach-at91/pm_data-
> offsets.s FORCE
> + $(call filechk,offsets,__PM_DATA_OFFSETS_H__)
> +
> +arch/arm/mach-at91/pm_suspend.o:
> +include/generated/at91_pm_data-offsets.h
> diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index
> c780dda3b604..a35b1541b328 100644
> --- a/arch/arm/mach-at91/pm.c
> +++ b/arch/arm/mach-at91/pm.c
> @@ -37,18 +37,13 @@ extern void at91_pinctrl_gpio_suspend(void); extern void
> at91_pinctrl_gpio_resume(void); #endif
>
> -static struct {
> - void __iomem *pmc;
> - void __iomem *ramc[2];
> - unsigned long uhp_udp_mask;
> - int memctrl;
> -} at91_pm_data;
> +static struct at91_pm_data pm_data;
>
> #define at91_ramc_read(id, field) \
> - __raw_readl(at91_pm_data.ramc[id] + field)
> + __raw_readl(pm_data.ramc[id] + field)
>
> #define at91_ramc_write(id, field, value) \
> - __raw_writel(value, at91_pm_data.ramc[id] + field)
> + __raw_writel(value, pm_data.ramc[id] + field)
>
> static int at91_pm_valid_state(suspend_state_t state) { @@ -84,10 +79,10 @@
> static int at91_pm_verify_clocks(void)
> unsigned long scsr;
> int i;
>
> - scsr = readl(at91_pm_data.pmc + AT91_PMC_SCSR);
> + scsr = readl(pm_data.pmc + AT91_PMC_SCSR);
>
> /* USB must not be using PLLB */
> - if ((scsr & at91_pm_data.uhp_udp_mask) != 0) {
> + if ((scsr & pm_data.uhp_udp_mask) != 0) {
> pr_err("AT91: PM - Suspend-to-RAM with USB still active\n");
> return 0;
> }
> @@ -98,7 +93,7 @@ static int at91_pm_verify_clocks(void)
>
> if ((scsr & (AT91_PMC_PCK0 << i)) == 0)
> continue;
> - css = readl(at91_pm_data.pmc + AT91_PMC_PCKR(i)) &
> AT91_PMC_CSS;
> + css = readl(pm_data.pmc + AT91_PMC_PCKR(i)) &
> AT91_PMC_CSS;
> if (css != AT91_PMC_CSS_SLOW) {
> pr_err("AT91: PM - Suspend-to-RAM with PCK%d
> src %d\n", i, css);
> return 0;
> @@ -124,25 +119,18 @@ int at91_suspend_entering_slow_clock(void)
> }
> EXPORT_SYMBOL(at91_suspend_entering_slow_clock);
>
> -static void (*at91_suspend_sram_fn)(void __iomem *pmc, void __iomem *ramc0,
> - void __iomem *ramc1, int memctrl);
> -
> -extern void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem
> *ramc0,
> - void __iomem *ramc1, int memctrl);
> +static void (*at91_suspend_sram_fn)(struct at91_pm_data *); extern void
> +at91_pm_suspend_in_sram(struct at91_pm_data *pm_data);
> extern u32 at91_pm_suspend_in_sram_sz;
>
> static void at91_pm_suspend(suspend_state_t state) {
> - unsigned int pm_data = at91_pm_data.memctrl;
> -
> - pm_data |= (state == PM_SUSPEND_MEM) ?
> - AT91_PM_MODE(AT91_PM_SLOW_CLOCK) : 0;
> + pm_data.mode = (state == PM_SUSPEND_MEM) ?
> AT91_PM_SLOW_CLOCK : 0;
>
> flush_cache_all();
> outer_disable();
>
> - at91_suspend_sram_fn(at91_pm_data.pmc, at91_pm_data.ramc[0],
> - at91_pm_data.ramc[1], pm_data);
> + at91_suspend_sram_fn(&pm_data);
>
> outer_resume();
> }
> @@ -245,7 +233,7 @@ static void at91rm9200_standby(void)
> " mcr p15, 0, %0, c7, c0, 4\n\t"
> " str %5, [%1, %2]"
> :
> - : "r" (0), "r" (at91_pm_data.ramc[0]), "r"
> (AT91_MC_SDRAMC_LPR),
> + : "r" (0), "r" (pm_data.ramc[0]), "r" (AT91_MC_SDRAMC_LPR),
> "r" (1), "r" (AT91_MC_SDRAMC_SRR),
> "r" (lpr));
> }
> @@ -260,7 +248,7 @@ static void at91_ddr_standby(void)
> u32 lpr0, lpr1 = 0;
> u32 saved_lpr0, saved_lpr1 = 0;
>
> - if (at91_pm_data.ramc[1]) {
> + if (pm_data.ramc[1]) {
> saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR);
> lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB;
> lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH; @@ -272,13
> +260,13 @@ static void at91_ddr_standby(void)
>
> /* self-refresh mode now */
> at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0);
> - if (at91_pm_data.ramc[1])
> + if (pm_data.ramc[1])
> at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1);
>
> cpu_do_idle();
>
> at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
> - if (at91_pm_data.ramc[1])
> + if (pm_data.ramc[1])
> at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); }
>
> @@ -306,7 +294,7 @@ static void at91sam9_sdram_standby(void)
> u32 lpr0, lpr1 = 0;
> u32 saved_lpr0, saved_lpr1 = 0;
>
> - if (at91_pm_data.ramc[1]) {
> + if (pm_data.ramc[1]) {
> saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR);
> lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB;
> lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH; @@ -318,13
> +306,13 @@ static void at91sam9_sdram_standby(void)
>
> /* self-refresh mode now */
> at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0);
> - if (at91_pm_data.ramc[1])
> + if (pm_data.ramc[1])
> at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1);
>
> cpu_do_idle();
>
> at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0);
> - if (at91_pm_data.ramc[1])
> + if (pm_data.ramc[1])
> at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1); }
>
> @@ -344,8 +332,8 @@ static __init void at91_dt_ramc(void)
> const void *standby = NULL;
>
> for_each_matching_node_and_match(np, ramc_ids, &of_id) {
> - at91_pm_data.ramc[idx] = of_iomap(np, 0);
> - if (!at91_pm_data.ramc[idx])
> + pm_data.ramc[idx] = of_iomap(np, 0);
> + if (!pm_data.ramc[idx])
> panic(pr_fmt("unable to map ramc[%d] cpu registers\n"),
> idx);
>
> if (!standby)
> @@ -371,12 +359,12 @@ static void at91rm9200_idle(void)
> * Disable the processor clock. The processor will be automatically
> * re-enabled by an interrupt or by a reset.
> */
> - writel(AT91_PMC_PCK, at91_pm_data.pmc + AT91_PMC_SCDR);
> + writel(AT91_PMC_PCK, pm_data.pmc + AT91_PMC_SCDR);
> }
>
> static void at91sam9_idle(void)
> {
> - writel(AT91_PMC_PCK, at91_pm_data.pmc + AT91_PMC_SCDR);
> + writel(AT91_PMC_PCK, pm_data.pmc + AT91_PMC_SCDR);
> cpu_do_idle();
> }
>
> @@ -445,8 +433,8 @@ static void __init at91_pm_init(void (*pm_idle)(void))
> platform_device_register(&at91_cpuidle_device);
>
> pmc_np = of_find_matching_node(NULL, atmel_pmc_ids);
> - at91_pm_data.pmc = of_iomap(pmc_np, 0);
> - if (!at91_pm_data.pmc) {
> + pm_data.pmc = of_iomap(pmc_np, 0);
> + if (!pm_data.pmc) {
> pr_err("AT91: PM not supported, PMC not found\n");
> return;
> }
> @@ -471,8 +459,8 @@ void __init at91rm9200_pm_init(void)
> */
> at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0);
>
> - at91_pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP |
> AT91RM9200_PMC_UDP;
> - at91_pm_data.memctrl = AT91_MEMCTRL_MC;
> + pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP |
> AT91RM9200_PMC_UDP;
> + pm_data.memctrl = AT91_MEMCTRL_MC;
>
> at91_pm_init(at91rm9200_idle);
> }
> @@ -480,31 +468,31 @@ void __init at91rm9200_pm_init(void) void __init
> at91sam9260_pm_init(void) {
> at91_dt_ramc();
> - at91_pm_data.memctrl = AT91_MEMCTRL_SDRAMC;
> - at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> + pm_data.memctrl = AT91_MEMCTRL_SDRAMC;
> + pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> at91_pm_init(at91sam9_idle);
> }
>
> void __init at91sam9g45_pm_init(void)
> {
> at91_dt_ramc();
> - at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
> - at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
> + pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
> + pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
> at91_pm_init(at91sam9_idle);
> }
>
> void __init at91sam9x5_pm_init(void)
> {
> at91_dt_ramc();
> - at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> - at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
> + pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> + pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
> at91_pm_init(at91sam9_idle);
> }
>
> void __init sama5_pm_init(void)
> {
> at91_dt_ramc();
> - at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> - at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
> + pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> + pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
> at91_pm_init(NULL);
> }
> diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h index
> 8eed156ef19a..fc0f7d048187 100644
> --- a/arch/arm/mach-at91/pm.h
> +++ b/arch/arm/mach-at91/pm.h
> @@ -21,12 +21,16 @@
> #define AT91_MEMCTRL_SDRAMC 1
> #define AT91_MEMCTRL_DDRSDR 2
>
> -#define AT91_PM_MEMTYPE_MASK 0x0f
> -
> -#define AT91_PM_MODE_OFFSET 4
> -#define AT91_PM_MODE_MASK 0x01
> -#define AT91_PM_MODE(x) (((x) & AT91_PM_MODE_MASK)
> << AT91_PM_MODE_OFFSET)
> -
> #define AT91_PM_SLOW_CLOCK 0x01
>
> +#ifndef __ASSEMBLY__
> +struct at91_pm_data {
> + void __iomem *pmc;
> + void __iomem *ramc[2];
> + unsigned long uhp_udp_mask;
> + unsigned int memctrl;
> + unsigned int mode;
> +};
> +#endif
> +
> #endif
> diff --git a/arch/arm/mach-at91/pm_data-offsets.c b/arch/arm/mach-at91/pm_data-
> offsets.c
> new file mode 100644
> index 000000000000..30302cb16df0
> --- /dev/null
> +++ b/arch/arm/mach-at91/pm_data-offsets.c
> @@ -0,0 +1,13 @@
> +#include <linux/stddef.h>
> +#include <linux/kbuild.h>
> +#include "pm.h"
> +
> +int main(void)
> +{
> + DEFINE(PM_DATA_PMC, offsetof(struct at91_pm_data,
> pmc));
> + DEFINE(PM_DATA_RAMC0, offsetof(struct at91_pm_data,
> ramc[0]));
> + DEFINE(PM_DATA_RAMC1, offsetof(struct at91_pm_data,
> ramc[1]));
> + DEFINE(PM_DATA_MEMCTRL, offsetof(struct at91_pm_data,
> memctrl));
> + DEFINE(PM_DATA_MODE, offsetof(struct at91_pm_data,
> mode));
> + return 0;
> +}
> diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-
> at91/pm_suspend.S index a25defda3d22..ed317657e760 100644
> --- a/arch/arm/mach-at91/pm_suspend.S
> +++ b/arch/arm/mach-at91/pm_suspend.S
> @@ -14,6 +14,7 @@
> #include <linux/linkage.h>
> #include <linux/clk/at91_pmc.h>
> #include "pm.h"
> +#include "generated/at91_pm_data-offsets.h"
>
> #define SRAMC_SELF_FRESH_ACTIVE 0x01
> #define SRAMC_SELF_FRESH_EXIT 0x00
> @@ -72,13 +73,9 @@ tmp2 .req r5
> .arm
>
> /*
> - * void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *sdramc,
> - * void __iomem *ramc1, int memctrl)
> + * void at91_suspend_sram_fn(struct at91_pm_data*)
> * @input param:
> - * @r0: base address of AT91_PMC
> - * @r1: base address of SDRAM Controller (SDRAM, DDRSDR, or
> AT91_SYS)
> - * @r2: base address of second SDRAM Controller or 0 if not present
> - * @r3: pm information
> + * @r0: base address of struct at91_pm_data
> */
> /* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of
> fncpy() */
> .align 3
> @@ -90,16 +87,16 @@ ENTRY(at91_pm_suspend_in_sram)
> mov tmp1, #0
> mcr p15, 0, tmp1, c7, c10, 4
>
> - str r0, .pmc_base
> - str r1, .sramc_base
> - str r2, .sramc1_base
> -
> - and r0, r3, #AT91_PM_MEMTYPE_MASK
> - str r0, .memtype
> -
> - lsr r0, r3, #AT91_PM_MODE_OFFSET
> - and r0, r0, #AT91_PM_MODE_MASK
> - str r0, .pm_mode
> + ldr tmp1, [r0, #PM_DATA_PMC]
> + str tmp1, .pmc_base
> + ldr tmp1, [r0, #PM_DATA_RAMC0]
> + str tmp1, .sramc_base
> + ldr tmp1, [r0, #PM_DATA_RAMC1]
> + str tmp1, .sramc1_base
> + ldr tmp1, [r0, #PM_DATA_MEMCTRL]
> + str tmp1, .memtype
> + ldr tmp1, [r0, #PM_DATA_MODE]
> + str tmp1, .pm_mode
>
> /* Active the self-refresh mode */
> mov r0, #SRAMC_SELF_FRESH_ACTIVE
> --
> 2.11.0


2017-03-29 05:03:38

by Wenyou Yang

[permalink] [raw]
Subject: RE: [PATCH v2 06/11] ARM: at91: pm: Workaround DDRSDRC self-refresh bug with LPDDR1 memories.



> -----Original Message-----
> From: Alexandre Belloni [mailto:[email protected]]
> Sent: 2017??3??28?? 19:20
> To: Nicolas Ferre - M43238 <[email protected]>
> Cc: [email protected]; [email protected]; Boris
> Brezillon <[email protected]>; Wenyou Yang - A41535
> <[email protected]>; Alexandre Belloni <alexandre.belloni@free-
> electrons.com>
> Subject: [PATCH v2 06/11] ARM: at91: pm: Workaround DDRSDRC self-refresh
> bug with LPDDR1 memories.
>
> As already explained for pm_suspend.S, the DDRSDR controller fails to put
> LPDDR1 memories in self-refresh. Force the controller to think it has DDR2
> memories during the self-refresh period, as the DDR2 self-refresh spec is
> equivalent to LPDDR1, and is correctly implemented in the controller.
>
> Signed-off-by: Alexandre Belloni <[email protected]>

Acked-by: Wenyou Yang <[email protected]>

> ---
> arch/arm/mach-at91/pm.c | 20 +++++++++++++++++++-
> 1 file changed, 19 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index
> 3d68d93c11c7..488549bc2bed 100644
> --- a/arch/arm/mach-at91/pm.c
> +++ b/arch/arm/mach-at91/pm.c
> @@ -241,12 +241,27 @@ static void at91_ddr_standby(void)
> /* Those two values allow us to delay self-refresh activation
> * to the maximum. */
> u32 lpr0, lpr1 = 0;
> + u32 mdr, saved_mdr0, saved_mdr1 = 0;
> u32 saved_lpr0, saved_lpr1 = 0;
>
> + /* LPDDR1 --> force DDR2 mode during self-refresh */
> + saved_mdr0 = at91_ramc_read(0, AT91_DDRSDRC_MDR);
> + if ((saved_mdr0 & AT91_DDRSDRC_MD) ==
> AT91_DDRSDRC_MD_LOW_POWER_DDR) {
> + mdr = saved_mdr0 & ~AT91_DDRSDRC_MD;
> + mdr |= AT91_DDRSDRC_MD_DDR2;
> + at91_ramc_write(0, AT91_DDRSDRC_MDR, mdr);
> + }
> +
> if (pm_data.ramc[1]) {
> saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR);
> lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB;
> lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH;
> + saved_mdr1 = at91_ramc_read(1, AT91_DDRSDRC_MDR);
> + if ((saved_mdr1 & AT91_DDRSDRC_MD) ==
> AT91_DDRSDRC_MD_LOW_POWER_DDR) {
> + mdr = saved_mdr1 & ~AT91_DDRSDRC_MD;
> + mdr |= AT91_DDRSDRC_MD_DDR2;
> + at91_ramc_write(1, AT91_DDRSDRC_MDR, mdr);
> + }
> }
>
> saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR); @@ -260,9
> +275,12 @@ static void at91_ddr_standby(void)
>
> cpu_do_idle();
>
> + at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr0);
> at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0);
> - if (pm_data.ramc[1])
> + if (pm_data.ramc[1]) {
> + at91_ramc_write(0, AT91_DDRSDRC_MDR, saved_mdr1);
> at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
> + }
> }
>
> static void sama5d3_ddr_standby(void)
> --
> 2.11.0


2017-03-29 05:06:59

by Wenyou Yang

[permalink] [raw]
Subject: RE: [PATCH v2 07/11] ARM: at91: pm: Tie the memory controller type to the ramc id



> -----Original Message-----
> From: Alexandre Belloni [mailto:[email protected]]
> Sent: 2017??3??28?? 19:20
> To: Nicolas Ferre - M43238 <[email protected]>
> Cc: [email protected]; [email protected]; Boris
> Brezillon <[email protected]>; Wenyou Yang - A41535
> <[email protected]>; Alexandre Belloni <alexandre.belloni@free-
> electrons.com>
> Subject: [PATCH v2 07/11] ARM: at91: pm: Tie the memory controller type to the
> ramc id
>
> Instead of relying on the SoC type to select the memory controller type, use the
> device tree ids as they are parsed anyway.
>
> Signed-off-by: Alexandre Belloni <[email protected]>

Acked-by: Wenyou Yang <[email protected]>

> ---
> arch/arm/mach-at91/pm.c | 30 ++++++++++++++++++++----------
> 1 file changed, 20 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index
> 488549bc2bed..ddf62a006635 100644
> --- a/arch/arm/mach-at91/pm.c
> +++ b/arch/arm/mach-at91/pm.c
> @@ -329,11 +329,23 @@ static void at91sam9_sdram_standby(void)
> at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1); }
>
> +struct ramc_info {
> + void (*idle)(void);
> + unsigned int memctrl;
> +};
> +
> +static const struct ramc_info ramc_infos[] __initconst = {
> + { .idle = at91rm9200_standby, .memctrl = AT91_MEMCTRL_MC},
> + { .idle = at91sam9_sdram_standby, .memctrl =
> AT91_MEMCTRL_SDRAMC},
> + { .idle = at91_ddr_standby, .memctrl = AT91_MEMCTRL_DDRSDR},
> + { .idle = sama5d3_ddr_standby, .memctrl =
> AT91_MEMCTRL_DDRSDR}, };
> +
> static const struct of_device_id const ramc_ids[] __initconst = {
> - { .compatible = "atmel,at91rm9200-sdramc", .data =
> at91rm9200_standby },
> - { .compatible = "atmel,at91sam9260-sdramc", .data =
> at91sam9_sdram_standby },
> - { .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby },
> - { .compatible = "atmel,sama5d3-ddramc", .data = sama5d3_ddr_standby },
> + { .compatible = "atmel,at91rm9200-sdramc", .data = &ramc_infos[0] },
> + { .compatible = "atmel,at91sam9260-sdramc", .data = &ramc_infos[1] },
> + { .compatible = "atmel,at91sam9g45-ddramc", .data = &ramc_infos[2] },
> + { .compatible = "atmel,sama5d3-ddramc", .data = &ramc_infos[3] },
> { /*sentinel*/ }
> };
>
> @@ -343,14 +355,17 @@ static __init void at91_dt_ramc(void)
> const struct of_device_id *of_id;
> int idx = 0;
> const void *standby = NULL;
> + const struct ramc_info *ramc;
>
> for_each_matching_node_and_match(np, ramc_ids, &of_id) {
> pm_data.ramc[idx] = of_iomap(np, 0);
> if (!pm_data.ramc[idx])
> panic(pr_fmt("unable to map ramc[%d] cpu registers\n"),
> idx);
>
> + ramc = of_id->data;
> if (!standby)
> - standby = of_id->data;
> + standby = ramc->idle;
> + pm_data.memctrl = ramc->memctrl;
>
> idx++;
> }
> @@ -473,7 +488,6 @@ void __init at91rm9200_pm_init(void)
> at91_ramc_write(0, AT91_MC_SDRAMC_LPR, 0);
>
> pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP |
> AT91RM9200_PMC_UDP;
> - pm_data.memctrl = AT91_MEMCTRL_MC;
>
> at91_pm_init(at91rm9200_idle);
> }
> @@ -481,7 +495,6 @@ void __init at91rm9200_pm_init(void) void __init
> at91sam9260_pm_init(void) {
> at91_dt_ramc();
> - pm_data.memctrl = AT91_MEMCTRL_SDRAMC;
> pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> at91_pm_init(at91sam9_idle);
> }
> @@ -490,7 +503,6 @@ void __init at91sam9g45_pm_init(void) {
> at91_dt_ramc();
> pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
> - pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
> at91_pm_init(at91sam9_idle);
> }
>
> @@ -498,7 +510,6 @@ void __init at91sam9x5_pm_init(void) {
> at91_dt_ramc();
> pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> - pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
> at91_pm_init(at91sam9_idle);
> }
>
> @@ -506,6 +517,5 @@ void __init sama5_pm_init(void) {
> at91_dt_ramc();
> pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP |
> AT91SAM926x_PMC_UDP;
> - pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
> at91_pm_init(NULL);
> }
> --
> 2.11.0


Best Regards,
Wenyou Yang