Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 10567c49 authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'at91-ab-4.19-soc' of...

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: default avatarOlof Johansson <olof@lixom.net>
parents 484a033b d7484f5c
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -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)
+156 −31
Original line number Diff line number Diff line
@@ -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 @@ static int at91_pm_enter(suspend_state_t state)
 */
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;
}

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;
}

	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_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();
}

+4 −2
Original line number Diff line number Diff line
@@ -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 {
+122 −20
Original line number Diff line number Diff line
@@ -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)
+15 −0
Original line number Diff line number Diff line
@@ -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] */