Clock patches for SAMA5D2 backup mode
Subsystems (2)
v6 cover Clock patches for SAMA5D2 backup mode
While the core of the backup mode for SAMA5D2 has been integrated in v4.13, it is far from complete. Individual controllers in the chip have drivers that do not support the reset of the registers during suspend, and they need to be adapted to handle it.
The first patch uses the clock wakeup code from the prototype backup mode instead of the version integrated in the mainline, as the mainline version is not stable. During a test loop with two-second backup suspend, the mainline version will hang in less than one day, whereas the proposed version has been running the same test for more than a month without hanging.
Changes in v2:
* drop the IIO patch duplicating existing code
* determine the number of programmable clocks to save dynamically
* declare a required local variable in the tty/serial patch
Changes in v3:
* drop dev_printk changes for PMECC
* rework the resume code for PMECC
* improve comments on PMC clock handling
Changes in v4:
* fix a bug in the PMECC resume code
Changes in v5:
* drop all patches already taken
* split the patch series by subsystem
Changes in v6:
* rebase on v4.15-rc3
Romain Izard (3):
clk: at91: pmc: Wait for clocks when resuming
clk: at91: pmc: Save SCSR during suspend
clk: at91: pmc: Support backup for programmable clocks
drivers/clk/at91/clk-programmable.c | 2 ++ drivers/clk/at91/pmc.c | 63 +++++++++++++++++++++++++++++++------ drivers/clk/at91/pmc.h | 2 ++ 3 files changed, 57 insertions(+), 10 deletions(-)
Signature · 1 line
2.14.1
PATCH v6 1/3 clk: at91: pmc: Wait for clocks when resuming
Wait for the syncronization of all clocks when resuming, not only the UPLL clock. Do not use regmap_read_poll_timeout, as it will call BUG() when interrupts are masked, which is the case in here.
--- drivers/clk/at91/pmc.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)
drivers/clk/at91/pmc.c +16 -8
@@ -107,10 +107,20 @@ static int pmc_suspend(void)return 0 ; } +static bool pmc_ready (unsigned int mask) +{ +unsigned int status; + +regmap_read (pmcreg,AT91_PMC_SR , &status); + +return ((status & mask) == mask) ?1 :0 ; +} +static void pmc_resume (void ) { -int i, ret =0 ; +int i;u32 tmp; +u32 mask =AT91_PMC_MCKRDY |AT91_PMC_LOCKA ;regmap_read (pmcreg,AT91_PMC_MCKR , &tmp);if (pmc_cache.mckr != tmp)
@@ -134,13 +144,11 @@ static void pmc_resume(void) AT91_PMC_PCR_CMD); } -if (pmc_cache.uckr &AT91_PMC_UPLLEN ) { - ret =regmap_read_poll_timeout (pmcreg,AT91_PMC_SR , tmp, - !(tmp &AT91_PMC_LOCKU ), -10 ,5000 ); -if (ret) -pr_crit ("USB PLL didn't lock when resuming\n" ); - } +if (pmc_cache.uckr &AT91_PMC_UPLLEN ) + mask |=AT91_PMC_LOCKU ; + +while (!pmc_ready (mask)) +cpu_relax (); }static struct syscore_ops pmc_syscore_ops = {
Signature · 1 line
2.14.1
Re: [PATCH v6 1/3] clk: at91: pmc: Wait for clocks when resuming
Quoted 7 lines · Romain Izard
Wait for the syncronization of all clocks when resuming, not only the UPLL clock. Do not use
regmap_read_poll_timeout, as it will callBUG()when interrupts are masked, which is the case in here.Signed-off-by Romain Izard <[email protected]>Acked-by Nicolas Ferre <[email protected]>
Quoted 52 lines
--- drivers/clk/at91/pmc.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)drivers/clk/at91/pmc.c +16
-8@@ -107,10 +107,20 @@ static int pmc_suspend(void)return 0 ; } +static bool pmc_ready (unsigned int mask) +{ +unsigned int status; + +regmap_read (pmcreg,AT91_PMC_SR , &status); + +return ((status & mask) == mask) ?1 :0 ; +} +static void pmc_resume (void ) { -int i, ret =0 ; +int i;u32 tmp; +u32 mask =AT91_PMC_MCKRDY |AT91_PMC_LOCKA ;regmap_read (pmcreg,AT91_PMC_MCKR , &tmp);if (pmc_cache.mckr != tmp)@@ -134,13 +144,11 @@ static void pmc_resume(void) AT91_PMC_PCR_CMD); } -if (pmc_cache.uckr &AT91_PMC_UPLLEN ) { - ret =regmap_read_poll_timeout (pmcreg,AT91_PMC_SR , tmp, - !(tmp &AT91_PMC_LOCKU ), -10 ,5000 ); -if (ret) -pr_crit ("USB PLL didn't lock when resuming\n" ); - } +if (pmc_cache.uckr &AT91_PMC_UPLLEN ) + mask |=AT91_PMC_LOCKU ; + +while (!pmc_ready (mask)) +cpu_relax (); }static struct syscore_ops pmc_syscore_ops = {Signature · 1 line
2.14.1
Signature · 3 lines
Alexandre Belloni, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
Stephen Boyd
AppliedRe: [PATCH v6 1/3] clk: at91: pmc: Wait for clocks when resuming
In reply to Romain IzardQuoted 8 lines · Romain Izard
Wait for the syncronization of all clocks when resuming, not only the UPLL clock. Do not use
regmap_read_poll_timeout, as it will callBUG()when interrupts are masked, which is the case in here.Signed-off-by Romain Izard <[email protected]>Acked-by Nicolas Ferre <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v6 2/3 clk: at91: pmc: Save SCSR during suspend
In reply to Romain IzardThe contents of the System Clock Status Register (SCSR) needs to be restored into the System Clock Enable Register (SCER).
As the bootloader will restore some clocks by itself, the issue can be missed as only the USB controller, the LCD controller, the Image Sensor controller and the programmable clocks will be impacted.
Fix the obvious typo in the suspend/resume code, as the IMR register does not need to be saved twice.
--- drivers/clk/at91/pmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clk/at91/pmc.c +2 -2
@@ -86,7 +86,7 @@ static int pmc_suspend(void) {int i; -regmap_read (pmcreg,AT91_PMC_IMR , &pmc_cache.scsr); +regmap_read (pmcreg,AT91_PMC_SCSR , &pmc_cache.scsr);regmap_read (pmcreg,AT91_PMC_PCSR , &pmc_cache.pcsr0);regmap_read (pmcreg,AT91_CKGR_UCKR , &pmc_cache.uckr);regmap_read (pmcreg,AT91_CKGR_MOR , &pmc_cache.mor);
@@ -129,7 +129,7 @@ static void pmc_resume(void)if (pmc_cache.pllar != tmp)pr_warn ("PLLAR was not configured properly by the firmware\n" ); -regmap_write (pmcreg,AT91_PMC_IMR , pmc_cache.scsr); +regmap_write (pmcreg,AT91_PMC_SCER , pmc_cache.scsr);regmap_write (pmcreg,AT91_PMC_PCER , pmc_cache.pcsr0);regmap_write (pmcreg,AT91_CKGR_UCKR , pmc_cache.uckr);regmap_write (pmcreg,AT91_CKGR_MOR , pmc_cache.mor);
Signature · 1 line
2.14.1
Re: [PATCH v6 2/3] clk: at91: pmc: Save SCSR during suspend
Quoted 7 lines · Romain Izard
The contents of the System Clock Status Register (SCSR) needs to be restored into the System Clock Enable Register (SCER).
As the bootloader will restore some clocks by itself, the issue can be missed as only the USB controller, the LCD controller, the Image Sensor controller and the programmable clocks will be impacted.
Quoted 5 lines
Fix the obvious typo in the suspend/resume code, as the IMR register does not need to be saved twice.
Signed-off-by Romain Izard <[email protected]>Acked-by Nicolas Ferre <[email protected]>
Quoted 29 lines
--- drivers/clk/at91/pmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)drivers/clk/at91/pmc.c +2
-2@@ -86,7 +86,7 @@ static int pmc_suspend(void) {int i; -regmap_read (pmcreg,AT91_PMC_IMR , &pmc_cache.scsr); +regmap_read (pmcreg,AT91_PMC_SCSR , &pmc_cache.scsr);regmap_read (pmcreg,AT91_PMC_PCSR , &pmc_cache.pcsr0);regmap_read (pmcreg,AT91_CKGR_UCKR , &pmc_cache.uckr);regmap_read (pmcreg,AT91_CKGR_MOR , &pmc_cache.mor);@@ -129,7 +129,7 @@ static void pmc_resume(void)if (pmc_cache.pllar != tmp)pr_warn ("PLLAR was not configured properly by the firmware\n" ); -regmap_write (pmcreg,AT91_PMC_IMR , pmc_cache.scsr); +regmap_write (pmcreg,AT91_PMC_SCER , pmc_cache.scsr);regmap_write (pmcreg,AT91_PMC_PCER , pmc_cache.pcsr0);regmap_write (pmcreg,AT91_CKGR_UCKR , pmc_cache.uckr);regmap_write (pmcreg,AT91_CKGR_MOR , pmc_cache.mor);Signature · 1 line
2.14.1
Signature · 3 lines
Alexandre Belloni, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
Stephen Boyd
AppliedRe: [PATCH v6 2/3] clk: at91: pmc: Save SCSR during suspend
In reply to Romain IzardQuoted 7 lines · Romain Izard
The contents of the System Clock Status Register (SCSR) needs to be restored into the System Clock Enable Register (SCER).
As the bootloader will restore some clocks by itself, the issue can be missed as only the USB controller, the LCD controller, the Image Sensor controller and the programmable clocks will be impacted.
Quoted 6 lines
Fix the obvious typo in the suspend/resume code, as the IMR register does not need to be saved twice.
Signed-off-by Romain Izard <[email protected]>Acked-by Nicolas Ferre <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v6 3/3 clk: at91: pmc: Support backup for programmable clocks
In reply to Romain IzardWhen an AT91 programmable clock is declared in the device tree, register it into the Power Management Controller driver. On entering suspend mode, the driver saves and restores the Programmable Clock registers to support the backup mode for these clocks.
---
Changes in v2:
* register PCKs on clock startup
Changes in v3:
* improve comments on hanling 0 in pmc_register_id and pmc_register_pck
* declare local variables earlier for checkpatch
Changes in v6:
* Use the correct author email address
drivers/clk/at91/clk-programmable.c | 2 ++ drivers/clk/at91/pmc.c | 35 +++++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 2 ++ 3 files changed, 39 insertions(+)
drivers/clk/at91/clk-programmable.c +2 -0
@@ -204,6 +204,8 @@ at91_clk_register_programmable(struct regmap *regmap,if (ret) {kfree (prog); hw =ERR_PTR (ret); + }else { +pmc_register_pck (id); }return hw;
drivers/clk/at91/pmc.c +35 -0
@@ -22,6 +22,7 @@#include "pmc.h" #define PMC_MAX_IDS 128 +#define PMC_MAX_PCKS 8int of_at91_get_clk_range (struct device_node *np,const char *propname,struct clk_range *range)
@@ -50,6 +51,7 @@ EXPORT_SYMBOL_GPL(of_at91_get_clk_range);static struct regmap *pmcreg;static u8 registered_ids[PMC_MAX_IDS ]; +static u8 registered_pcks[PMC_MAX_PCKS ]; static struct {
@@ -66,8 +68,13 @@ static structu32 pcr[PMC_MAX_IDS ];u32 audio_pll0;u32 audio_pll1; +u32 pckr[PMC_MAX_PCKS ]; } pmc_cache; +/* +* As Peripheral ID 0 is invalid on AT91 chips, the identifier is stored +* without alteration in the table, and 0 is for unused clocks. +*/ void pmc_register_id (u8 id) {int i;
@@ -82,9 +89,28 @@ void pmc_register_id(u8 id) } } +/* +* As Programmable Clock 0 is valid on AT91 chips, there is an offset +* of 1 between the stored value and the real clock ID. +*/ +void pmc_register_pck (u8 pck) +{ +int i; + +for (i =0 ; i <PMC_MAX_PCKS ; i++) { +if (registered_pcks[i] ==0 ) { + registered_pcks[i] = pck +1 ; +break ; + } +if (registered_pcks[i] == (pck +1 )) +break ; + } +} +static int pmc_suspend (void ) {int i; +u8 num;regmap_read (pmcreg,AT91_PMC_SCSR , &pmc_cache.scsr);regmap_read (pmcreg,AT91_PMC_PCSR , &pmc_cache.pcsr0);
@@ -103,6 +129,10 @@ static int pmc_suspend(void)regmap_read (pmcreg,AT91_PMC_PCR , &pmc_cache.pcr[registered_ids[i]]); } +for (i =0 ; registered_pcks[i]; i++) { + num = registered_pcks[i] -1 ; +regmap_read (pmcreg,AT91_PMC_PCKR (num), &pmc_cache.pckr[num]); + }return 0 ; }
@@ -119,6 +149,7 @@ static bool pmc_ready(unsigned int mask)static void pmc_resume (void ) {int i; +u8 num;u32 tmp;u32 mask =AT91_PMC_MCKRDY |AT91_PMC_LOCKA ;
@@ -143,6 +174,10 @@ static void pmc_resume(void) pmc_cache.pcr[registered_ids[i]] | AT91_PMC_PCR_CMD); } +for (i =0 ; registered_pcks[i]; i++) { + num = registered_pcks[i] -1 ; +regmap_write (pmcreg,AT91_PMC_PCKR (num), pmc_cache.pckr[num]); + }if (pmc_cache.uckr &AT91_PMC_UPLLEN ) mask |=AT91_PMC_LOCKU ;
drivers/clk/at91/pmc.h +2 -0
@@ -31,8 +31,10 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname,#ifdef CONFIG_PM void pmc_register_id (u8 id); +void pmc_register_pck (u8 pck);#else static inline void pmc_register_id (u8 id) {} +static inline void pmc_register_pck (u8 pck) {}#endif #endif /* __PMC_H_ */
Signature · 1 line
2.14.1
Re: [PATCH v6 3/3] clk: at91: pmc: Support backup for programmable clocks
Quoted 7 lines · Romain Izard
When an AT91 programmable clock is declared in the device tree, register it into the Power Management Controller driver. On entering suspend mode, the driver saves and restores the Programmable Clock registers to support the backup mode for these clocks.
Signed-off-by Romain Izard <[email protected]>Acked-by Nicolas Ferre <[email protected]>
Quoted 140 lines
---
Changes in v2:
* register PCKs on clock startupChanges in v3:
* improve comments on hanling 0 inpmc_register_idandpmc_register_pck
* declare local variables earlier for checkpatchChanges in v6:
* Use the correct author email addressdrivers/clk/at91/clk-programmable.c | 2 ++ drivers/clk/at91/pmc.c | 35 +++++++++++++++++++++++++++++++++++ drivers/clk/at91/pmc.h | 2 ++ 3 files changed, 39 insertions(+)drivers/clk/at91/clk-programmable.c +2
-0@@ -204,6 +204,8 @@ at91_clk_register_programmable(struct regmap *regmap,if (ret) {kfree (prog); hw =ERR_PTR (ret); + }else { +pmc_register_pck (id); }return hw;drivers/clk/at91/pmc.c +35
-0@@ -22,6 +22,7 @@#include "pmc.h" #define PMC_MAX_IDS 128 +#define PMC_MAX_PCKS 8int of_at91_get_clk_range (struct device_node *np,const char *propname,struct clk_range *range)@@ -50,6 +51,7 @@ EXPORT_SYMBOL_GPL(of_at91_get_clk_range);static struct regmap *pmcreg;static u8 registered_ids[PMC_MAX_IDS ]; +static u8 registered_pcks[PMC_MAX_PCKS ]; static struct {@@ -66,8 +68,13 @@ static structu32 pcr[PMC_MAX_IDS ];u32 audio_pll0;u32 audio_pll1; +u32 pckr[PMC_MAX_PCKS ]; } pmc_cache; +/* +* As Peripheral ID 0 is invalid on AT91 chips, the identifier is stored +* without alteration in the table, and 0 is for unused clocks. +*/ void pmc_register_id (u8 id) {int i;@@ -82,9 +89,28 @@ void pmc_register_id(u8 id) } } +/* +* As Programmable Clock 0 is valid on AT91 chips, there is an offset +* of 1 between the stored value and the real clock ID. +*/ +void pmc_register_pck (u8 pck) +{ +int i; + +for (i =0 ; i <PMC_MAX_PCKS ; i++) { +if (registered_pcks[i] ==0 ) { + registered_pcks[i] = pck +1 ; +break ; + } +if (registered_pcks[i] == (pck +1 )) +break ; + } +} +static int pmc_suspend (void ) {int i; +u8 num;regmap_read (pmcreg,AT91_PMC_SCSR , &pmc_cache.scsr);regmap_read (pmcreg,AT91_PMC_PCSR , &pmc_cache.pcsr0);@@ -103,6 +129,10 @@ static int pmc_suspend(void)regmap_read (pmcreg,AT91_PMC_PCR , &pmc_cache.pcr[registered_ids[i]]); } +for (i =0 ; registered_pcks[i]; i++) { + num = registered_pcks[i] -1 ; +regmap_read (pmcreg,AT91_PMC_PCKR (num), &pmc_cache.pckr[num]); + }return 0 ; }@@ -119,6 +149,7 @@ static bool pmc_ready(unsigned int mask)static void pmc_resume (void ) {int i; +u8 num;u32 tmp;u32 mask =AT91_PMC_MCKRDY |AT91_PMC_LOCKA ;@@ -143,6 +174,10 @@ static void pmc_resume(void) pmc_cache.pcr[registered_ids[i]] | AT91_PMC_PCR_CMD); } +for (i =0 ; registered_pcks[i]; i++) { + num = registered_pcks[i] -1 ; +regmap_write (pmcreg,AT91_PMC_PCKR (num), pmc_cache.pckr[num]); + }if (pmc_cache.uckr &AT91_PMC_UPLLEN ) mask |=AT91_PMC_LOCKU ;drivers/clk/at91/pmc.h +2
-0@@ -31,8 +31,10 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname,#ifdef CONFIG_PM void pmc_register_id (u8 id); +void pmc_register_pck (u8 pck);#else static inline void pmc_register_id (u8 id) {} +static inline void pmc_register_pck (u8 pck) {}#endif #endif /* __PMC_H_ */ Signature · 1 line
2.14.1
Signature · 3 lines
Alexandre Belloni, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
Stephen Boyd
AppliedRe: [PATCH v6 3/3] clk: at91: pmc: Support backup for programmable clocks
In reply to Romain IzardQuoted 8 lines · Romain Izard
When an AT91 programmable clock is declared in the device tree, register it into the Power Management Controller driver. On entering suspend mode, the driver saves and restores the Programmable Clock registers to support the backup mode for these clocks.
Signed-off-by Romain Izard <[email protected]>Acked-by Nicolas Ferre <[email protected]>---
Applied to clk-next
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project