Hi Alexandre, Sorry for late answer.
> -----Original Message----- > From: Alexandre Belloni [mailto:alexandre.bell...@free-electrons.com] > Sent: 2015年10月15日 21:22 > To: Yang, Wenyou > Cc: Ferre, Nicolas; Jean-Christophe Plagniol-Villard; Russell King; Stephen > Boyd; > Michael Turquette; linux-arm-ker...@lists.infradead.org; linux- > ker...@vger.kernel.org; linux-...@vger.kernel.org > Subject: Re: [PATCH 2/2] ARM: at91/pm: add ultra Low-power mode 1(ULP1) > support > > Hello Wenyou, > > On 15/10/2015 at 11:41:07 +0800, Wenyou Yang wrote : > > +#define ULP0_MODE 0x00 > > +#define ULP1_MODE 0x11 > > Those are not used. > > > +static void at91_config_ulp1_wkup_source(void) > > +{ > > + if (at91_pmc_read(AT91_PMC_VERSION) >= SAMA5D2_PMC_VERSION) > { > > + at91_pmc_write(AT91_PMC_FSMR, AT91_PMC_RTCAL | > > + AT91_PMC_FSTT9 | > > + AT91_PMC_FSTT8 | > > + AT91_PMC_FSTT7 | > > + AT91_PMC_FSTT6 | > > + AT91_PMC_FSTT5 | > > + AT91_PMC_FSTT4 | > > + AT91_PMC_FSTT3 | > > + AT91_PMC_FSTT2 | > > + AT91_PMC_FSTT0); > > + > > + at91_pmc_write(AT91_PMC_FSPR, 0); > > Shouldn't those be configured from irq_set_wake() in the aic driver instead of > activating all the wakeup sources? > I think you need to get the PMC syscon from the aic5 driver and implement a > new > irq_set_wake function when you can find the sam5d2 pmc. I understand these code should not be here, but I don't think those should be configured from irq_set_wake(). As said in datasheet, those configuration is to trigger a fast restart signal to the PMC. I think they should not be related to irq. > > The PMC syscon is introduced with that series: > http://lists.infradead.org/pipermail/linux-arm-kernel/2015-October/376493.html > > > @@ -140,6 +165,10 @@ static void at91_pm_suspend(suspend_state_t state) > > pm_data |= (state == PM_SUSPEND_MEM) ? > > AT91_PM_MODE(AT91_PM_SLOW_CLOCK) : 0; > > > > + pm_data |= ((state == PM_SUSPEND_MEM) && > > + (at91_pmc_read(AT91_PMC_VERSION) >= > SAMA5D2_PMC_VERSION)) ? > > + AT91_PM_ULP(AT91_PM_ULP1_MODE) : 0; > > + > > I would prefer not relying on the AT91_PMC_VERSION. Also, you probably > shouldn't read the register each time you go to suspend. > Finally, this could be better written by testing state only once. Yes, it is not good. > > > > flush_cache_all(); > > outer_disable(); > > > > diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h index > > 3fcf881..2e76745 100644 > > --- a/arch/arm/mach-at91/pm.h > > +++ b/arch/arm/mach-at91/pm.h > > @@ -39,4 +39,11 @@ extern void __iomem *at91_ramc_base[]; > > > > #define AT91_PM_SLOW_CLOCK 0x01 > > > > +#define AT91_PM_ULP_OFFSET 5 > > +#define AT91_PM_ULP_MASK 0x03 > > +#define AT91_PM_ULP(x) (((x) & AT91_PM_ULP_MASK) << > AT91_PM_ULP_OFFSET) > > + > > +#define AT91_PM_ULP0_MODE 0x00 > > +#define AT91_PM_ULP1_MODE 0x01 > > + > > #endif > > diff --git a/arch/arm/mach-at91/pm_suspend.S > > b/arch/arm/mach-at91/pm_suspend.S index 825347b..543c430 100644 > > --- a/arch/arm/mach-at91/pm_suspend.S > > +++ b/arch/arm/mach-at91/pm_suspend.S > > @@ -41,6 +41,15 @@ tmp2 .req r5 > > .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. > > */ > > .macro wait_pllalock > > @@ -99,6 +108,10 @@ ENTRY(at91_pm_suspend_in_sram) > > and r0, r0, #AT91_PM_MODE_MASK > > str r0, .pm_mode > > > > + lsr r0, r3, #AT91_PM_ULP_OFFSET > > + and r0, r0, #AT91_PM_ULP_MASK > > + str r0, .ulp_mode > > + > > /* Active the self-refresh mode */ > > mov r0, #SRAMC_SELF_FRESH_ACTIVE > > bl at91_sramc_self_refresh > > @@ -107,6 +120,14 @@ ENTRY(at91_pm_suspend_in_sram) > > tst r0, #AT91_PM_SLOW_CLOCK > > beq standby_mode > > > > + ldr r0, .ulp_mode > > + tst r0, #AT91_PM_ULP1_MODE > > + beq ulp0_mode > > + > > +ulp1_mode: > > + bl at91_pm_ulp1_mode > > + b pm_exit > > + > > ulp0_mode: > > bl at91_pm_ulp0_mode > > b pm_exit > > @@ -313,6 +334,94 @@ ENTRY(at91_pm_ulp0_mode) > > mov pc, lr > > ENDPROC(at91_pm_ulp0_mode) > > > > +/* > > + * void at91_pm_ulp1_mode(void) > > + * > > + */ > > +ENTRY(at91_pm_ulp1_mode) > > + ldr pmc, .pmc_base > > + > > + /* Save PMC_MCKR config */ > > + ldr tmp1, [pmc, #AT91_PMC_MCKR] > > + str tmp1, .saved_mckr > > + > > + /* Switch the master clock source to main clock */ > > + bic tmp1, tmp1, #AT91_PMC_CSS > > + orr tmp1, tmp1, #AT91_PMC_CSS_MAIN > > + str tmp1, [pmc, #AT91_PMC_MCKR] > > + > > + wait_mckrdy > > + > > + /* Save PLLA config, then and disable PLLA */ > > + ldr tmp1, [pmc, #AT91_CKGR_PLLAR] > > + str tmp1, .saved_pllar > > + > > + bic tmp1, tmp1, #AT91_PMC3_MUL > > + str tmp1, [pmc, #AT91_CKGR_PLLAR] > > + > > + /* Switch main clock 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 > > + bic tmp1, tmp1, #(7 << 4) > > + str tmp1, [pmc, #AT91_CKGR_MOR] > > + > > + wait_moscsels > > + > > + /* Disable the main 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 > > + bic tmp1, tmp1, #(7 << 4) > > + str tmp1, [pmc, #AT91_CKGR_MOR] > > + > > + /* Enter the ULP1 mode by setting 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 > > + bic tmp1, tmp1, #(7 << 4) > > + str tmp1, [pmc, #AT91_CKGR_MOR] > > + > > + wait_mckrdy > > + > > + /* Enable the main 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 > > + bic tmp1, tmp1, #(7 << 4) > > + str tmp1, [pmc, #AT91_CKGR_MOR] > > + > > + wait_moscrdy > > + > > + /* Switch main clock to the main 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 > > + bic tmp1, tmp1, #(7 << 4) > > + str tmp1, [pmc, #AT91_CKGR_MOR] > > + > > + wait_moscsels > > + > > + /* Restore PLLA config */ > > + ldr tmp1, .saved_pllar > > + str tmp1, [pmc, #AT91_CKGR_PLLAR] > > + > > + wait_pllalock > > + > > + /* Restore PMC_MCKR config */ > > + ldr tmp1, .saved_mckr > > + str tmp1, [pmc, #AT91_PMC_MCKR] > > + > > + wait_mckrdy > > + > > + mov pc, lr > > +ENDPROC(at91_pm_ulp1_mode) > > + > > This makes a lot of duplication anyway, why not having separate code for > ULP0 and ULP1 that would be copied in SRAM? This would avoid the test > on .ulp_mode Thank you for your suggestion. I agree to have separate code for ULP0 and ULP1 code. But I still think there are a lot a duplication even so. Anyway, I will prepare a patch as your suggestion. > > -- > Alexandre Belloni, Free Electrons > Embedded Linux, Kernel and Android engineering http://free-electrons.com Best Regards, Wenyou Yang N�Р骒r��y����b�X�肚�v�^�)藓{.n�+�伐�{��赙zXФ�≤�}��财�z�&j:+v�����赙zZ+��+zf"�h���~����i���z��wア�?�ㄨ��&�)撷f��^j谦y�m��@A�a囤� 0鹅h���i