AT91 SoC for 4.19:

- New low power mode for sama5d2: ULP1
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEXx9Viay1+e7J/aM4AyWl4gNJNJIFAltRmW8ACgkQAyWl4gNJ
 NJK4pA//b9N5mRbbp9QQcDE3Yel/uBep+USCT/Xw9yoyPLrtIt0UjR519guUSPOp
 brfvZcL9wFJCnUI17yt6SZzmqUaeN5fHit/G2MGjbgxVjpbD89zH23PPh/TXQulJ
 3LgJpM7hLwKTxd/gxASLyYRU0zrBu6lPwbLmNietbQNt06u9IwRcrlu3O5fkHQun
 bVjSjEfo5oxf/+6mIqlgZ3qQuF6PQu8FVLJwKacQSEeXnJx7SJ2vbbActh8amulP
 +L0M3y08OZbj+f9efCoQ7VPS3/O05NTw5nvcy8N29/9mQgExWBfURAjMl0cdISRT
 /3o+7fGFa0yZZlS5HbM/U+jqn0DngtBqEphWkfXi8ZjyahAJWIL3oeImYXRxKLop
 KnTWELeB/uZOqC7vVf+irR+uuyfVSR50ZLMe3GfU3A08yKSpDzLW+/d7OkcPzH6B
 4yivQ9CHO+fw2lTrf0GKxtOxSYBLIuDQQtC0x8B+35YCj/D+H27bMD4qGu7NO/Io
 yrGjGG3wwrWGmA/izb+jqxtO0C+Zb1I01VojBKKTruOit6WsQi4CO7pT1l1Bwyrk
 NwgO9kzIPjQ+23qiRbjXyo0InJ5o7tG4WmulaFQUNz9L6UfqDDhihHh+CoWFCHVj
 RD624TUc7ZAovH23dbrPQazoLUUlZYLPwajC1D1n6nO9wZVENhs=
 =QPpc
 -----END PGP SIGNATURE-----

Merge tag 'at91-ab-4.19-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux into next/soc

AT91 SoC for 4.19:
 - New low power mode for sama5d2: ULP1

* tag 'at91-ab-4.19-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux:
  ARM: at91: pm: configure wakeup sources for ULP1 mode
  ARM: at91: pm: add PMC fast startup registers defines
  ARM: at91: pm: Add ULP1 mode support
  ARM: at91: pm: Use ULP0 naming instead of slow clock
  MAINTAINERS: Remove the AT91 clk driver entry

Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
Olof Johansson 2018-07-21 14:18:29 -07:00
commit 10567c49b9
5 changed files with 297 additions and 58 deletions

View File

@ -1256,11 +1256,6 @@ F: arch/arm/mach-aspeed/
F: arch/arm/boot/dts/aspeed-*
N: aspeed
ARM/ATMEL AT91 Clock Support
M: Boris Brezillon <boris.brezillon@bootlin.com>
S: Maintained
F: drivers/clk/at91
ARM/CALXEDA HIGHBANK ARCHITECTURE
M: Rob Herring <robh@kernel.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)

View File

@ -40,15 +40,16 @@ extern void at91_pinctrl_gpio_resume(void);
#endif
static const match_table_t pm_modes __initconst = {
{ 0, "standby" },
{ AT91_PM_SLOW_CLOCK, "ulp0" },
{ AT91_PM_STANDBY, "standby" },
{ AT91_PM_ULP0, "ulp0" },
{ AT91_PM_ULP1, "ulp1" },
{ AT91_PM_BACKUP, "backup" },
{ -1, NULL },
};
static struct at91_pm_data pm_data = {
.standby_mode = 0,
.suspend_mode = AT91_PM_SLOW_CLOCK,
.standby_mode = AT91_PM_STANDBY,
.suspend_mode = AT91_PM_ULP0,
};
#define at91_ramc_read(id, field) \
@ -79,6 +80,90 @@ static struct at91_pm_bu {
phys_addr_t resume;
} *pm_bu;
struct wakeup_source_info {
unsigned int pmc_fsmr_bit;
unsigned int shdwc_mr_bit;
bool set_polarity;
};
static const struct wakeup_source_info ws_info[] = {
{ .pmc_fsmr_bit = AT91_PMC_FSTT(10), .set_polarity = true },
{ .pmc_fsmr_bit = AT91_PMC_RTCAL, .shdwc_mr_bit = BIT(17) },
{ .pmc_fsmr_bit = AT91_PMC_USBAL },
{ .pmc_fsmr_bit = AT91_PMC_SDMMC_CD },
};
static const struct of_device_id sama5d2_ws_ids[] = {
{ .compatible = "atmel,sama5d2-gem", .data = &ws_info[0] },
{ .compatible = "atmel,at91rm9200-rtc", .data = &ws_info[1] },
{ .compatible = "atmel,sama5d3-udc", .data = &ws_info[2] },
{ .compatible = "atmel,at91rm9200-ohci", .data = &ws_info[2] },
{ .compatible = "usb-ohci", .data = &ws_info[2] },
{ .compatible = "atmel,at91sam9g45-ehci", .data = &ws_info[2] },
{ .compatible = "usb-ehci", .data = &ws_info[2] },
{ .compatible = "atmel,sama5d2-sdhci", .data = &ws_info[3] },
{ /* sentinel */ }
};
static int at91_pm_config_ws(unsigned int pm_mode, bool set)
{
const struct wakeup_source_info *wsi;
const struct of_device_id *match;
struct platform_device *pdev;
struct device_node *np;
unsigned int mode = 0, polarity = 0, val = 0;
if (pm_mode != AT91_PM_ULP1)
return 0;
if (!pm_data.pmc || !pm_data.shdwc)
return -EPERM;
if (!set) {
writel(mode, pm_data.pmc + AT91_PMC_FSMR);
return 0;
}
/* SHDWC.WUIR */
val = readl(pm_data.shdwc + 0x0c);
mode |= (val & 0x3ff);
polarity |= ((val >> 16) & 0x3ff);
/* SHDWC.MR */
val = readl(pm_data.shdwc + 0x04);
/* Loop through defined wakeup sources. */
for_each_matching_node_and_match(np, sama5d2_ws_ids, &match) {
pdev = of_find_device_by_node(np);
if (!pdev)
continue;
if (device_may_wakeup(&pdev->dev)) {
wsi = match->data;
/* Check if enabled on SHDWC. */
if (wsi->shdwc_mr_bit && !(val & wsi->shdwc_mr_bit))
goto put_node;
mode |= wsi->pmc_fsmr_bit;
if (wsi->set_polarity)
polarity |= wsi->pmc_fsmr_bit;
}
put_node:
of_node_put(np);
}
if (mode) {
writel(mode, pm_data.pmc + AT91_PMC_FSMR);
writel(polarity, pm_data.pmc + AT91_PMC_FSPR);
} else {
pr_err("AT91: PM: no ULP1 wakeup sources found!");
}
return mode ? 0 : -EPERM;
}
/*
* Called after processes are frozen, but before we shutdown devices.
*/
@ -97,7 +182,7 @@ static int at91_pm_begin(suspend_state_t state)
pm_data.mode = -1;
}
return 0;
return at91_pm_config_ws(pm_data.mode, true);
}
/*
@ -145,7 +230,7 @@ static int at91_pm_verify_clocks(void)
*/
int at91_suspend_entering_slow_clock(void)
{
return (pm_data.mode >= AT91_PM_SLOW_CLOCK);
return (pm_data.mode >= AT91_PM_ULP0);
}
EXPORT_SYMBOL(at91_suspend_entering_slow_clock);
@ -186,7 +271,7 @@ static void at91_pm_suspend(suspend_state_t state)
* event sources; and reduces DRAM power. But otherwise it's identical to
* PM_SUSPEND_ON: cpu idle, and nothing fancy done with main or cpu clocks.
*
* AT91_PM_SLOW_CLOCK is like STANDBY plus slow clock mode, so drivers must
* AT91_PM_ULP0 is like STANDBY plus slow clock mode, so drivers must
* suspend more deeply, the master clock switches to the clk32k and turns off
* the main oscillator
*
@ -204,7 +289,7 @@ static int at91_pm_enter(suspend_state_t state)
/*
* Ensure that clocks are in a valid state.
*/
if ((pm_data.mode >= AT91_PM_SLOW_CLOCK) &&
if (pm_data.mode >= AT91_PM_ULP0 &&
!at91_pm_verify_clocks())
goto error;
@ -233,6 +318,7 @@ error:
*/
static void at91_pm_end(void)
{
at91_pm_config_ws(pm_data.mode, false);
}
@ -478,31 +564,28 @@ static void __init at91_pm_sram_init(void)
&at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz);
}
static void __init at91_pm_backup_init(void)
static bool __init at91_is_pm_mode_active(int pm_mode)
{
return (pm_data.standby_mode == pm_mode ||
pm_data.suspend_mode == pm_mode);
}
static int __init at91_pm_backup_init(void)
{
struct gen_pool *sram_pool;
struct device_node *np;
struct platform_device *pdev = NULL;
int ret = -ENODEV;
if ((pm_data.standby_mode != AT91_PM_BACKUP) &&
(pm_data.suspend_mode != AT91_PM_BACKUP))
return;
if (!at91_is_pm_mode_active(AT91_PM_BACKUP))
return 0;
pm_bu = NULL;
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-shdwc");
if (!np) {
pr_warn("%s: failed to find shdwc!\n", __func__);
return;
}
pm_data.shdwc = of_iomap(np, 0);
of_node_put(np);
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-sfrbu");
if (!np) {
pr_warn("%s: failed to find sfrbu!\n", __func__);
goto sfrbu_fail;
return ret;
}
pm_data.sfrbu = of_iomap(np, 0);
@ -529,6 +612,7 @@ static void __init at91_pm_backup_init(void)
pm_bu = (void *)gen_pool_alloc(sram_pool, sizeof(struct at91_pm_bu));
if (!pm_bu) {
pr_warn("%s: unable to alloc securam!\n", __func__);
ret = -ENOMEM;
goto securam_fail;
}
@ -536,19 +620,60 @@ static void __init at91_pm_backup_init(void)
pm_bu->canary = __pa_symbol(&canary);
pm_bu->resume = __pa_symbol(cpu_resume);
return;
return 0;
sfrbu_fail:
iounmap(pm_data.shdwc);
pm_data.shdwc = NULL;
securam_fail:
iounmap(pm_data.sfrbu);
pm_data.sfrbu = NULL;
return ret;
}
if (pm_data.standby_mode == AT91_PM_BACKUP)
pm_data.standby_mode = AT91_PM_SLOW_CLOCK;
if (pm_data.suspend_mode == AT91_PM_BACKUP)
pm_data.suspend_mode = AT91_PM_SLOW_CLOCK;
static void __init at91_pm_use_default_mode(int pm_mode)
{
if (pm_mode != AT91_PM_ULP1 && pm_mode != AT91_PM_BACKUP)
return;
if (pm_data.standby_mode == pm_mode)
pm_data.standby_mode = AT91_PM_ULP0;
if (pm_data.suspend_mode == pm_mode)
pm_data.suspend_mode = AT91_PM_ULP0;
}
static void __init at91_pm_modes_init(void)
{
struct device_node *np;
int ret;
if (!at91_is_pm_mode_active(AT91_PM_BACKUP) &&
!at91_is_pm_mode_active(AT91_PM_ULP1))
return;
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-shdwc");
if (!np) {
pr_warn("%s: failed to find shdwc!\n", __func__);
goto ulp1_default;
}
pm_data.shdwc = of_iomap(np, 0);
of_node_put(np);
ret = at91_pm_backup_init();
if (ret) {
if (!at91_is_pm_mode_active(AT91_PM_ULP1))
goto unmap;
else
goto backup_default;
}
return;
unmap:
iounmap(pm_data.shdwc);
pm_data.shdwc = NULL;
ulp1_default:
at91_pm_use_default_mode(AT91_PM_ULP1);
backup_default:
at91_pm_use_default_mode(AT91_PM_BACKUP);
}
struct pmc_info {
@ -644,7 +769,7 @@ void __init sama5d2_pm_init(void)
if (!IS_ENABLED(CONFIG_SOC_SAMA5D2))
return;
at91_pm_backup_init();
at91_pm_modes_init();
sama5_pm_init();
}

View File

@ -21,8 +21,10 @@
#define AT91_MEMCTRL_SDRAMC 1
#define AT91_MEMCTRL_DDRSDR 2
#define AT91_PM_SLOW_CLOCK 0x01
#define AT91_PM_BACKUP 0x02
#define AT91_PM_STANDBY 0x00
#define AT91_PM_ULP0 0x01
#define AT91_PM_ULP1 0x02
#define AT91_PM_BACKUP 0x03
#ifndef __ASSEMBLY__
struct at91_pm_data {

View File

@ -41,6 +41,15 @@ tmp2 .req r5
beq 1b
.endm
/*
* Wait for main oscillator selection is done
*/
.macro wait_moscsels
1: ldr tmp1, [pmc, #AT91_PMC_SR]
tst tmp1, #AT91_PMC_MOSCSELS
beq 1b
.endm
/*
* Wait until PLLA has locked.
*/
@ -112,19 +121,20 @@ ENTRY(at91_pm_suspend_in_sram)
bl at91_sramc_self_refresh
ldr r0, .pm_mode
cmp r0, #AT91_PM_SLOW_CLOCK
beq slow_clock
cmp r0, #AT91_PM_STANDBY
beq standby
cmp r0, #AT91_PM_BACKUP
beq backup_mode
bl at91_ulp_mode
b exit_suspend
standby:
/* Wait for interrupt */
ldr pmc, .pmc_base
at91_cpu_idle
b exit_suspend
slow_clock:
bl at91_slowck_mode
b exit_suspend
backup_mode:
bl at91_backup_mode
b exit_suspend
@ -151,7 +161,102 @@ ENTRY(at91_backup_mode)
str tmp1, [r0, #0]
ENDPROC(at91_backup_mode)
ENTRY(at91_slowck_mode)
.macro at91_pm_ulp0_mode
ldr pmc, .pmc_base
/* Turn off the crystal oscillator */
ldr tmp1, [pmc, #AT91_CKGR_MOR]
bic tmp1, tmp1, #AT91_PMC_MOSCEN
orr tmp1, tmp1, #AT91_PMC_KEY
str tmp1, [pmc, #AT91_CKGR_MOR]
/* Wait for interrupt */
at91_cpu_idle
/* Turn on the crystal oscillator */
ldr tmp1, [pmc, #AT91_CKGR_MOR]
orr tmp1, tmp1, #AT91_PMC_MOSCEN
orr tmp1, tmp1, #AT91_PMC_KEY
str tmp1, [pmc, #AT91_CKGR_MOR]
wait_moscrdy
.endm
/**
* Note: This procedure only applies on the platform which uses
* the external crystal oscillator as a main clock source.
*/
.macro at91_pm_ulp1_mode
ldr pmc, .pmc_base
/* Switch the main clock source to 12-MHz RC oscillator */
ldr tmp1, [pmc, #AT91_CKGR_MOR]
bic tmp1, tmp1, #AT91_PMC_MOSCSEL
bic tmp1, tmp1, #AT91_PMC_KEY_MASK
orr tmp1, tmp1, #AT91_PMC_KEY
str tmp1, [pmc, #AT91_CKGR_MOR]
wait_moscsels
/* Disable the crystal oscillator */
ldr tmp1, [pmc, #AT91_CKGR_MOR]
bic tmp1, tmp1, #AT91_PMC_MOSCEN
bic tmp1, tmp1, #AT91_PMC_KEY_MASK
orr tmp1, tmp1, #AT91_PMC_KEY
str tmp1, [pmc, #AT91_CKGR_MOR]
/* Switch the master clock source to main clock */
ldr tmp1, [pmc, #AT91_PMC_MCKR]
bic tmp1, tmp1, #AT91_PMC_CSS
orr tmp1, tmp1, #AT91_PMC_CSS_MAIN
str tmp1, [pmc, #AT91_PMC_MCKR]
wait_mckrdy
/* Enter the ULP1 mode by set WAITMODE bit in CKGR_MOR */
ldr tmp1, [pmc, #AT91_CKGR_MOR]
orr tmp1, tmp1, #AT91_PMC_WAITMODE
bic tmp1, tmp1, #AT91_PMC_KEY_MASK
orr tmp1, tmp1, #AT91_PMC_KEY
str tmp1, [pmc, #AT91_CKGR_MOR]
wait_mckrdy
/* Enable the crystal oscillator */
ldr tmp1, [pmc, #AT91_CKGR_MOR]
orr tmp1, tmp1, #AT91_PMC_MOSCEN
bic tmp1, tmp1, #AT91_PMC_KEY_MASK
orr tmp1, tmp1, #AT91_PMC_KEY
str tmp1, [pmc, #AT91_CKGR_MOR]
wait_moscrdy
/* Switch the master clock source to slow clock */
ldr tmp1, [pmc, #AT91_PMC_MCKR]
bic tmp1, tmp1, #AT91_PMC_CSS
str tmp1, [pmc, #AT91_PMC_MCKR]
wait_mckrdy
/* Switch main clock source to crystal oscillator */
ldr tmp1, [pmc, #AT91_CKGR_MOR]
orr tmp1, tmp1, #AT91_PMC_MOSCSEL
bic tmp1, tmp1, #AT91_PMC_KEY_MASK
orr tmp1, tmp1, #AT91_PMC_KEY
str tmp1, [pmc, #AT91_CKGR_MOR]
wait_moscsels
/* Switch the master clock source to main clock */
ldr tmp1, [pmc, #AT91_PMC_MCKR]
bic tmp1, tmp1, #AT91_PMC_CSS
orr tmp1, tmp1, #AT91_PMC_CSS_MAIN
str tmp1, [pmc, #AT91_PMC_MCKR]
wait_mckrdy
.endm
ENTRY(at91_ulp_mode)
ldr pmc, .pmc_base
/* Save Master clock setting */
@ -174,22 +279,19 @@ ENTRY(at91_slowck_mode)
orr tmp1, tmp1, #(1 << 29) /* bit 29 always set */
str tmp1, [pmc, #AT91_CKGR_PLLAR]
/* Turn off the main oscillator */
ldr tmp1, [pmc, #AT91_CKGR_MOR]
bic tmp1, tmp1, #AT91_PMC_MOSCEN
orr tmp1, tmp1, #AT91_PMC_KEY
str tmp1, [pmc, #AT91_CKGR_MOR]
ldr r0, .pm_mode
cmp r0, #AT91_PM_ULP1
beq ulp1_mode
/* Wait for interrupt */
at91_cpu_idle
at91_pm_ulp0_mode
b ulp_exit
/* Turn on the main oscillator */
ldr tmp1, [pmc, #AT91_CKGR_MOR]
orr tmp1, tmp1, #AT91_PMC_MOSCEN
orr tmp1, tmp1, #AT91_PMC_KEY
str tmp1, [pmc, #AT91_CKGR_MOR]
ulp1_mode:
at91_pm_ulp1_mode
b ulp_exit
wait_moscrdy
ulp_exit:
ldr pmc, .pmc_base
/* Restore PLLA setting */
ldr tmp1, .saved_pllar
@ -212,7 +314,7 @@ ENTRY(at91_slowck_mode)
wait_mckrdy
mov pc, lr
ENDPROC(at91_slowck_mode)
ENDPROC(at91_ulp_mode)
/*
* void at91_sramc_self_refresh(unsigned int is_active)

View File

@ -47,8 +47,10 @@
#define AT91_CKGR_MOR 0x20 /* Main Oscillator Register [not on SAM9RL] */
#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */
#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass */
#define AT91_PMC_WAITMODE (1 << 2) /* Wait Mode Command */
#define AT91_PMC_MOSCRCEN (1 << 3) /* Main On-Chip RC Oscillator Enable [some SAM9] */
#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */
#define AT91_PMC_KEY_MASK (0xff << 16)
#define AT91_PMC_KEY (0x37 << 16) /* MOR Writing Key */
#define AT91_PMC_MOSCSEL (1 << 24) /* Main Oscillator Selection [some SAM9] */
#define AT91_PMC_CFDEN (1 << 25) /* Clock Failure Detector Enable [some SAM9] */
@ -155,6 +157,19 @@
#define AT91_PMC_GCKRDY (1 << 24) /* Generated Clocks */
#define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */
#define AT91_PMC_FSMR 0x70 /* Fast Startup Mode Register */
#define AT91_PMC_FSTT(n) BIT(n)
#define AT91_PMC_RTCAL BIT(17) /* RTC Alarm Enable */
#define AT91_PMC_USBAL BIT(18) /* USB Resume Enable */
#define AT91_PMC_SDMMC_CD BIT(19) /* SDMMC Card Detect Enable */
#define AT91_PMC_LPM BIT(20) /* Low-power Mode */
#define AT91_PMC_RXLP_MCE BIT(24) /* Backup UART Receive Enable */
#define AT91_PMC_ACC_CE BIT(25) /* ACC Enable */
#define AT91_PMC_FSPR 0x74 /* Fast Startup Polarity Reg */
#define AT91_PMC_FS_INPUT_MASK 0x7ff
#define AT91_PMC_PLLICPR 0x80 /* PLL Charge Pump Current Register */
#define AT91_PMC_PROT 0xe4 /* Write Protect Mode Register [some SAM9] */