Commit 8af11ee9 authored by Olof Johansson's avatar Olof Johansson

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.netSigned-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 632db906 faf6dc64
......@@ -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;
......
......@@ -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 {
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment