AT91 SoC for 5.10

- ULP0 fast wakeup support
  - PM cleanups
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEycoQi/giopmpPgB12wIijOdRNOUFAl9ifcIACgkQ2wIijOdR
 NOWb9BAAq25Kz3s3e13oUF2txfvELbYSimWKJF2sMKojekj/RLVZKuxbc8CN0bBR
 QHQmHroJFdao15RR/IvyrpXmM19eaXQvj+Y0HlGAd5yeNCku2t2vRIkJ35r/PQL5
 jZYyttz8ln6LyzZ4zCo7YPPISbIiT899SnO1Fghbu1h/3Wz/b9txDvAxpN1irZr2
 oCjcr/Cl1E4DjOrcCEki1ey61XRbHanKYuv0MmG1AcYTCj9/7k8BNDD+UKBjtNUF
 qtxYCFSCzG6DU0uOA+hue5R1ObZNBQm9fESXyAieswLE/FHOwIh9m0RVqjpgMwFf
 1IMZw8YVniPS1PWd0ANPKD4qzVN9GbMn3jjTVqB/K3VqSIq/dVsKA68vZCBopuQe
 OPPXp5iOAsF9TP17iASif+uK2EDPQABYquSVTJisYh/MZ3PtexpiQXUbm7k3M89q
 aR2jg4ClkrGq2TmZRysbD2Hng6pSSaiVXpq5D6mCedm9OhAXkBSS0/nqDU78uHT4
 bk1rYu9vWCNFoVaz72pqt5oB6h5H4B9Uz99cS1g6C4oI0+iuWJz1ujBtIiZrGcjS
 QNv9z23wXJfH4WRyrxDj5qAcKxfVamnD3GWDVj35NAUTcjv2C1sdp+4gaZKEG0cB
 wH+1sz4ueGcx4xqb1WCYnQZI/2nFbAYtBu1v1e55TkLFFEU/xRM=
 =GtAw
 -----END PGP SIGNATURE-----

Merge tag 'at91-soc-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/at91/linux into arm/soc

AT91 SoC for 5.10

 - ULP0 fast wakeup support
 - PM cleanups

* tag 'at91-soc-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/at91/linux:
  ARM: at91: pm: remove unnecessary at91sam9x60_idle
  ARM: at91: pm: of_node_put() after its usage
  ARM: at91: pm: add per soc validation of pm modes
  ARM: at91: pm: add support for ULP0 fast wakeup

Link: https://lore.kernel.org/r/20200916211119.GA275438@piout.net
Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
Olof Johansson 2020-09-26 12:35:34 -07:00
commit 8af11ee90c
3 changed files with 126 additions and 17 deletions

View File

@ -51,10 +51,11 @@ static struct at91_soc_pm soc_pm = {
};
static const match_table_t pm_modes __initconst = {
{ AT91_PM_STANDBY, "standby" },
{ AT91_PM_ULP0, "ulp0" },
{ AT91_PM_ULP1, "ulp1" },
{ AT91_PM_BACKUP, "backup" },
{ AT91_PM_STANDBY, "standby" },
{ AT91_PM_ULP0, "ulp0" },
{ AT91_PM_ULP0_FAST, "ulp0-fast" },
{ AT91_PM_ULP1, "ulp1" },
{ AT91_PM_BACKUP, "backup" },
{ -1, NULL },
};
@ -557,11 +558,6 @@ static void at91rm9200_idle(void)
writel(AT91_PMC_PCK, soc_pm.data.pmc + AT91_PMC_SCDR);
}
static void at91sam9x60_idle(void)
{
cpu_do_idle();
}
static void at91sam9_idle(void)
{
writel(AT91_PMC_PCK, soc_pm.data.pmc + AT91_PMC_SCDR);
@ -789,6 +785,51 @@ static const struct of_device_id atmel_pmc_ids[] __initconst = {
{ /* sentinel */ },
};
static void __init at91_pm_modes_validate(const int *modes, int len)
{
u8 i, standby = 0, suspend = 0;
int mode;
for (i = 0; i < len; i++) {
if (standby && suspend)
break;
if (modes[i] == soc_pm.data.standby_mode && !standby) {
standby = 1;
continue;
}
if (modes[i] == soc_pm.data.suspend_mode && !suspend) {
suspend = 1;
continue;
}
}
if (!standby) {
if (soc_pm.data.suspend_mode == AT91_PM_STANDBY)
mode = AT91_PM_ULP0;
else
mode = AT91_PM_STANDBY;
pr_warn("AT91: PM: %s mode not supported! Using %s.\n",
pm_modes[soc_pm.data.standby_mode].pattern,
pm_modes[mode].pattern);
soc_pm.data.standby_mode = mode;
}
if (!suspend) {
if (soc_pm.data.standby_mode == AT91_PM_ULP0)
mode = AT91_PM_STANDBY;
else
mode = AT91_PM_ULP0;
pr_warn("AT91: PM: %s mode not supported! Using %s.\n",
pm_modes[soc_pm.data.suspend_mode].pattern,
pm_modes[mode].pattern);
soc_pm.data.suspend_mode = mode;
}
}
static void __init at91_pm_init(void (*pm_idle)(void))
{
struct device_node *pmc_np;
@ -800,6 +841,7 @@ static void __init at91_pm_init(void (*pm_idle)(void))
pmc_np = of_find_matching_node_and_match(NULL, atmel_pmc_ids, &of_id);
soc_pm.data.pmc = of_iomap(pmc_np, 0);
of_node_put(pmc_np);
if (!soc_pm.data.pmc) {
pr_err("AT91: PM not supported, PMC not found\n");
return;
@ -830,6 +872,14 @@ void __init at91rm9200_pm_init(void)
if (!IS_ENABLED(CONFIG_SOC_AT91RM9200))
return;
/*
* Force STANDBY and ULP0 mode to avoid calling
* at91_pm_modes_validate() which may increase booting time.
* Platform supports anyway only STANDBY and ULP0 modes.
*/
soc_pm.data.standby_mode = AT91_PM_STANDBY;
soc_pm.data.suspend_mode = AT91_PM_ULP0;
at91_dt_ramc();
/*
@ -842,12 +892,17 @@ void __init at91rm9200_pm_init(void)
void __init sam9x60_pm_init(void)
{
static const int modes[] __initconst = {
AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1,
};
if (!IS_ENABLED(CONFIG_SOC_SAM9X60))
return;
at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
at91_pm_modes_init();
at91_dt_ramc();
at91_pm_init(at91sam9x60_idle);
at91_pm_init(NULL);
soc_pm.ws_ids = sam9x60_ws_ids;
soc_pm.config_pmc_ws = at91_sam9x60_config_pmc_ws;
@ -858,26 +913,46 @@ void __init at91sam9_pm_init(void)
if (!IS_ENABLED(CONFIG_SOC_AT91SAM9))
return;
/*
* Force STANDBY and ULP0 mode to avoid calling
* at91_pm_modes_validate() which may increase booting time.
* Platform supports anyway only STANDBY and ULP0 modes.
*/
soc_pm.data.standby_mode = AT91_PM_STANDBY;
soc_pm.data.suspend_mode = AT91_PM_ULP0;
at91_dt_ramc();
at91_pm_init(at91sam9_idle);
}
void __init sama5_pm_init(void)
{
static const int modes[] __initconst = {
AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST,
};
if (!IS_ENABLED(CONFIG_SOC_SAMA5))
return;
at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
at91_dt_ramc();
at91_pm_init(NULL);
}
void __init sama5d2_pm_init(void)
{
static const int modes[] __initconst = {
AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1,
AT91_PM_BACKUP,
};
if (!IS_ENABLED(CONFIG_SOC_SAMA5D2))
return;
at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
at91_pm_modes_init();
sama5_pm_init();
at91_dt_ramc();
at91_pm_init(NULL);
soc_pm.ws_ids = sama5d2_ws_ids;
soc_pm.config_shdwc_ws = at91_sama5d2_config_shdwc_ws;

View File

@ -19,8 +19,9 @@
#define AT91_PM_STANDBY 0x00
#define AT91_PM_ULP0 0x01
#define AT91_PM_ULP1 0x02
#define AT91_PM_BACKUP 0x03
#define AT91_PM_ULP0_FAST 0x02
#define AT91_PM_ULP1 0x03
#define AT91_PM_BACKUP 0x04
#ifndef __ASSEMBLY__
struct at91_pm_data {

View File

@ -164,7 +164,22 @@ ENDPROC(at91_backup_mode)
.macro at91_pm_ulp0_mode
ldr pmc, .pmc_base
ldr tmp2, .pm_mode
ldr tmp3, .mckr_offset
/* Check if ULP0 fast variant has been requested. */
cmp tmp2, #AT91_PM_ULP0_FAST
bne 0f
/* Set highest prescaler for power saving */
ldr tmp1, [pmc, tmp3]
bic tmp1, tmp1, #AT91_PMC_PRES
orr tmp1, tmp1, #AT91_PMC_PRES_64
str tmp1, [pmc, tmp3]
wait_mckrdy
b 1f
0:
/* Turn off the crystal oscillator */
ldr tmp1, [pmc, #AT91_CKGR_MOR]
bic tmp1, tmp1, #AT91_PMC_MOSCEN
@ -192,7 +207,18 @@ ENDPROC(at91_backup_mode)
/* Wait for interrupt */
1: at91_cpu_idle
/* Restore RC oscillator state */
/* Check if ULP0 fast variant has been requested. */
cmp tmp2, #AT91_PM_ULP0_FAST
bne 5f
/* Set lowest prescaler for fast resume. */
ldr tmp1, [pmc, tmp3]
bic tmp1, tmp1, #AT91_PMC_PRES
str tmp1, [pmc, tmp3]
wait_mckrdy
b 6f
5: /* Restore RC oscillator state */
ldr tmp1, .saved_osc_status
tst tmp1, #AT91_PMC_MOSCRCS
beq 4f
@ -216,6 +242,7 @@ ENDPROC(at91_backup_mode)
str tmp1, [pmc, #AT91_CKGR_MOR]
wait_moscrdy
6:
.endm
/**
@ -473,23 +500,29 @@ ENDPROC(at91_backup_mode)
ENTRY(at91_ulp_mode)
ldr pmc, .pmc_base
ldr tmp2, .mckr_offset
ldr tmp3, .pm_mode
/* Save Master clock setting */
ldr tmp1, [pmc, tmp2]
str tmp1, .saved_mckr
/*
* Set the Master clock source to slow clock
* Set master clock source to:
* - MAINCK if using ULP0 fast variant
* - slow clock, otherwise
*/
bic tmp1, tmp1, #AT91_PMC_CSS
cmp tmp3, #AT91_PM_ULP0_FAST
bne save_mck
orr tmp1, tmp1, #AT91_PMC_CSS_MAIN
save_mck:
str tmp1, [pmc, tmp2]
wait_mckrdy
at91_plla_disable
ldr r0, .pm_mode
cmp r0, #AT91_PM_ULP1
cmp tmp3, #AT91_PM_ULP1
beq ulp1_mode
at91_pm_ulp0_mode