Re: [PATCH 4/4] powerpc: pm: support deep sleep feature on T104x
On Fri, 2015-07-31 at 20:53 +0800, Chenhui Zhao wrote: > diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S > b/arch/powerpc/kernel/fsl_booke_entry_mapping.S > index f22e7e4..32ec426f 100644 > --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S > +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S > @@ -170,6 +170,10 @@ skpinv: addir6,r6,1 /* > Increment */ > lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h > ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l > mtspr SPRN_MAS2,r6 > +#ifdef ENTRY_DEEPSLEEP_SETUP > + LOAD_REG_IMMEDIATE(r8, MEMORY_START) > + ori r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR) > +#endif > mtspr SPRN_MAS3,r8 > tlbwe > > @@ -212,12 +216,18 @@ next_tlb_setup: > #error You need to specify the mapping or not use this at all. > #endif > > +#ifdef ENTRY_DEEPSLEEP_SETUP > + LOAD_REG_ADDR(r6, 2f) > + mfmsr r7 > + rlwinm r7,r7,0,~(MSR_IS|MSR_DS) > +#else > lis r7,MSR_KERNEL@h > ori r7,r7,MSR_KERNEL@l > bl 1f /* Find our address */ > 1: mflrr9 > rlwimi r6,r9,0,20,31 > addir6,r6,(2f - 1b) > +#endif Could you explain what's going on here? What does the TLB look like before and after? > +int fsl_dp_iomap(void) I don't think this needs to be global (see the comment where it gets called), but if it must be, this name is too terse. > +{ > + struct device_node *np; > + int ret = 0; > + phys_addr_t ccsr_phy_addr, dcsr_phy_addr; > + > + saved_law = NULL; > + ccsr_base = NULL; > + dcsr_base = NULL; > + pld_base = NULL; > + > + ccsr_phy_addr = get_immrbase(); > + if (ccsr_phy_addr == -1) { > + pr_err("%s: Can't get the address of CCSR\n", __func__); > + ret = -EINVAL; > + goto ccsr_err; > + } > + ccsr_base = ioremap(ccsr_phy_addr, SIZE_2MB); > + if (!ccsr_base) { > + ret = -ENOMEM; > + goto ccsr_err; > + } > + > + dcsr_phy_addr = get_dcsrbase(); > + if (dcsr_phy_addr == -1) { > + pr_err("%s: Can't get the address of DCSR\n", __func__); > + ret = -EINVAL; > + goto dcsr_err; > + } > + dcsr_base = ioremap(dcsr_phy_addr, SIZE_1MB); > + if (!dcsr_base) { > + ret = -ENOMEM; > + goto dcsr_err; > + } Please just map the device tree nodes you need. > + > + np = of_find_compatible_node(NULL, NULL, "fsl,tetra-fpga"); > + if (np) { > + pld_flag = T1040QDS_TETRA_FLAG; > + } else { > + np = of_find_compatible_node(NULL, NULL, "fsl,deepsleep-cpld"); I've already rejected fsl,deepsleep-cpld multiple times when others tried to add it to a device tree. > +{ > + u32 ddr_buff_addr; > + > + /* > + * DDR training initialization will break 128 bytes at the beginning > + * of DDR, therefore, save them so that the bootloader will restore > + * them. Assume that DDR is mapped to the address space started with > + * CONFIG_PAGE_OFFSET. > + */ > + memcpy(ddr_buff, (void *)CONFIG_PAGE_OFFSET, DDR_BUF_SIZE); That assumption may not be true in all relocatable scenarios. It'd be a lot simpler to just mark that first page as reserved. > + /* assume ddr_buff is in the physical address space of 4GB */ > + ddr_buff_addr = (u32)(__pa(ddr_buff) & 0x); > + > + /* > + * the bootloader will restore the first 128 bytes of DDR from > + * the location indicated by the register SPARECR3 > + */ > + out_be32(ccsr_base + CCSR_SCFG_SPARECR3, ddr_buff_addr); ...yeah, please just mark it reserved. > +} > + > +static void fsl_dp_mp_save(void *ccsr) > +{ > + struct fsl_bstr *dst = _bstr; > + > + dst->bstrh = in_be32(ccsr + LCC_BSTRH); > + dst->bstrl = in_be32(ccsr + LCC_BSTRL); > + dst->bstar = in_be32(ccsr + LCC_BSTAR); > + dst->cpu_mask = in_be32(ccsr + DCFG_BASE + DCFG_BRR); > +} What is "mp"? > +static void fsl_dp_law_save(void *ccsr) > +{ > + int i; > + struct fsl_law *dst = saved_law; > + struct fsl_law *src = (void *)(ccsr + CCSR_LAW_BASE); > + > + for (i = 0; i < num_laws; i++) { > + dst->lawbarh = in_be32(>lawbarh); > + dst->lawbarl = in_be32(>lawbarl); > + dst->lawar = in_be32(>lawar); > + dst++; > + src++; > + } > +} Why wouldn't U-Boot restore these the same way on resume as they are now? > +int fsl_enter_epu_deepsleep(void) > +{ > + fsl_dp_ddr_save(ccsr_base); > + > + fsl_dp_set_resume_pointer(ccsr_base); > + > + fsl_dp_mp_save(ccsr_base); > + fsl_dp_law_save(ccsr_base); > + /* enable Warm Device Reset request. */ > + setbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN); > + > + /* set GPIO1_29 as an output pin (not open-drain), and output 0 */ > +
[PATCH 4/4] powerpc: pm: support deep sleep feature on T104x
T104x has deep sleep feature, which can switch off most parts of the SoC when it is in deep sleep mode. This way, it becomes more energy-efficient. The DDR controller will also be powered off in deep sleep. Therefore, the last stage (the latter part of fsl_dp_enter_low) will run without DDR access. This piece of code and related TLBs are prefetched in advance. Due to the different initialization code between 32-bit and 64-bit, they have separate resume entry and precedure. The feature supports 32-bit and 64-bit kernel mode. Signed-off-by: Chenhui Zhao --- arch/powerpc/include/asm/fsl_pm.h | 14 + arch/powerpc/kernel/fsl_booke_entry_mapping.S | 10 + arch/powerpc/kernel/head_64.S | 2 +- arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/deepsleep.c | 322 +++ arch/powerpc/platforms/85xx/qoriq_pm.c| 81 +++- arch/powerpc/platforms/85xx/t104x_deepsleep.S | 570 ++ 7 files changed, 997 insertions(+), 3 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c create mode 100644 arch/powerpc/platforms/85xx/t104x_deepsleep.S diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h index 4b09f09..b44f484 100644 --- a/arch/powerpc/include/asm/fsl_pm.h +++ b/arch/powerpc/include/asm/fsl_pm.h @@ -12,6 +12,7 @@ #define __PPC_FSL_PM_H #ifdef __KERNEL__ +#ifndef __ASSEMBLY__ #define E500_PM_PH10 1 #define E500_PM_PH15 2 #define E500_PM_PH20 3 @@ -44,5 +45,18 @@ struct fsl_pm_ops { }; extern const struct fsl_pm_ops *qoriq_pm_ops; + +extern int fsl_dp_iomap(void); +extern void fsl_dp_iounmap(void); + +extern int fsl_enter_epu_deepsleep(void); +extern void fsl_dp_enter_low(void __iomem *ccsr_base, void __iomem *dcsr_base, +void __iomem *pld_base, int pld_flag); +extern void fsl_booke_deep_sleep_resume(void); +#endif /* __ASSEMBLY__ */ + +#define T1040QDS_TETRA_FLAG1 +#define T104xRDB_CPLD_FLAG 2 + #endif /* __KERNEL__ */ #endif /* __PPC_FSL_PM_H */ diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S index f22e7e4..32ec426f 100644 --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S @@ -170,6 +170,10 @@ skpinv:addir6,r6,1 /* Increment */ lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l mtspr SPRN_MAS2,r6 +#ifdef ENTRY_DEEPSLEEP_SETUP + LOAD_REG_IMMEDIATE(r8, MEMORY_START) + ori r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR) +#endif mtspr SPRN_MAS3,r8 tlbwe @@ -212,12 +216,18 @@ next_tlb_setup: #error You need to specify the mapping or not use this at all. #endif +#ifdef ENTRY_DEEPSLEEP_SETUP + LOAD_REG_ADDR(r6, 2f) + mfmsr r7 + rlwinm r7,r7,0,~(MSR_IS|MSR_DS) +#else lis r7,MSR_KERNEL@h ori r7,r7,MSR_KERNEL@l bl 1f /* Find our address */ 1: mflrr9 rlwimi r6,r9,0,20,31 addir6,r6,(2f - 1b) +#endif mtspr SPRN_SRR0,r6 mtspr SPRN_SRR1,r7 rfi /* start execution out of TLB1[0] entry */ diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index d48125d..b9eb02a 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -696,7 +696,7 @@ _GLOBAL(start_secondary_resume) /* * This subroutine clobbers r11 and r12 */ -enable_64b_mode: +_GLOBAL(enable_64b_mode) mfmsr r11 /* grab the current MSR */ #ifdef CONFIG_PPC_BOOK3E orisr11,r11,0x8000 /* CM bit set, we'll set ICM later */ diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 87fb847..a73d563 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o sleep_fsm.o +obj-$(CONFIG_FSL_QORIQ_PM) += deepsleep.o t104x_deepsleep.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/deepsleep.c b/arch/powerpc/platforms/85xx/deepsleep.c new file mode 100644 index 000..5de904d --- /dev/null +++ b/arch/powerpc/platforms/85xx/deepsleep.c @@ -0,0 +1,322 @@ +/* + * Support deep sleep feature for T104x + * + * Copyright 2015 Freescale Semiconductor Inc. + * + * Author: Chenhui Zhao + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include
[PATCH 4/4] powerpc: pm: support deep sleep feature on T104x
T104x has deep sleep feature, which can switch off most parts of the SoC when it is in deep sleep mode. This way, it becomes more energy-efficient. The DDR controller will also be powered off in deep sleep. Therefore, the last stage (the latter part of fsl_dp_enter_low) will run without DDR access. This piece of code and related TLBs are prefetched in advance. Due to the different initialization code between 32-bit and 64-bit, they have separate resume entry and precedure. The feature supports 32-bit and 64-bit kernel mode. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/powerpc/include/asm/fsl_pm.h | 14 + arch/powerpc/kernel/fsl_booke_entry_mapping.S | 10 + arch/powerpc/kernel/head_64.S | 2 +- arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/deepsleep.c | 322 +++ arch/powerpc/platforms/85xx/qoriq_pm.c| 81 +++- arch/powerpc/platforms/85xx/t104x_deepsleep.S | 570 ++ 7 files changed, 997 insertions(+), 3 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c create mode 100644 arch/powerpc/platforms/85xx/t104x_deepsleep.S diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h index 4b09f09..b44f484 100644 --- a/arch/powerpc/include/asm/fsl_pm.h +++ b/arch/powerpc/include/asm/fsl_pm.h @@ -12,6 +12,7 @@ #define __PPC_FSL_PM_H #ifdef __KERNEL__ +#ifndef __ASSEMBLY__ #define E500_PM_PH10 1 #define E500_PM_PH15 2 #define E500_PM_PH20 3 @@ -44,5 +45,18 @@ struct fsl_pm_ops { }; extern const struct fsl_pm_ops *qoriq_pm_ops; + +extern int fsl_dp_iomap(void); +extern void fsl_dp_iounmap(void); + +extern int fsl_enter_epu_deepsleep(void); +extern void fsl_dp_enter_low(void __iomem *ccsr_base, void __iomem *dcsr_base, +void __iomem *pld_base, int pld_flag); +extern void fsl_booke_deep_sleep_resume(void); +#endif /* __ASSEMBLY__ */ + +#define T1040QDS_TETRA_FLAG1 +#define T104xRDB_CPLD_FLAG 2 + #endif /* __KERNEL__ */ #endif /* __PPC_FSL_PM_H */ diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S index f22e7e4..32ec426f 100644 --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S @@ -170,6 +170,10 @@ skpinv:addir6,r6,1 /* Increment */ lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l mtspr SPRN_MAS2,r6 +#ifdef ENTRY_DEEPSLEEP_SETUP + LOAD_REG_IMMEDIATE(r8, MEMORY_START) + ori r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR) +#endif mtspr SPRN_MAS3,r8 tlbwe @@ -212,12 +216,18 @@ next_tlb_setup: #error You need to specify the mapping or not use this at all. #endif +#ifdef ENTRY_DEEPSLEEP_SETUP + LOAD_REG_ADDR(r6, 2f) + mfmsr r7 + rlwinm r7,r7,0,~(MSR_IS|MSR_DS) +#else lis r7,MSR_KERNEL@h ori r7,r7,MSR_KERNEL@l bl 1f /* Find our address */ 1: mflrr9 rlwimi r6,r9,0,20,31 addir6,r6,(2f - 1b) +#endif mtspr SPRN_SRR0,r6 mtspr SPRN_SRR1,r7 rfi /* start execution out of TLB1[0] entry */ diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index d48125d..b9eb02a 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -696,7 +696,7 @@ _GLOBAL(start_secondary_resume) /* * This subroutine clobbers r11 and r12 */ -enable_64b_mode: +_GLOBAL(enable_64b_mode) mfmsr r11 /* grab the current MSR */ #ifdef CONFIG_PPC_BOOK3E orisr11,r11,0x8000 /* CM bit set, we'll set ICM later */ diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 87fb847..a73d563 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o sleep_fsm.o +obj-$(CONFIG_FSL_QORIQ_PM) += deepsleep.o t104x_deepsleep.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/deepsleep.c b/arch/powerpc/platforms/85xx/deepsleep.c new file mode 100644 index 000..5de904d --- /dev/null +++ b/arch/powerpc/platforms/85xx/deepsleep.c @@ -0,0 +1,322 @@ +/* + * Support deep sleep feature for T104x + * + * Copyright 2015 Freescale Semiconductor Inc. + * + * Author: Chenhui Zhao chenhui.z...@freescale.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +
Re: [PATCH 4/4] powerpc: pm: support deep sleep feature on T104x
On Fri, 2015-07-31 at 20:53 +0800, Chenhui Zhao wrote: diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S index f22e7e4..32ec426f 100644 --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S @@ -170,6 +170,10 @@ skpinv: addir6,r6,1 /* Increment */ lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l mtspr SPRN_MAS2,r6 +#ifdef ENTRY_DEEPSLEEP_SETUP + LOAD_REG_IMMEDIATE(r8, MEMORY_START) + ori r8,r8,(MAS3_SX|MAS3_SW|MAS3_SR) +#endif mtspr SPRN_MAS3,r8 tlbwe @@ -212,12 +216,18 @@ next_tlb_setup: #error You need to specify the mapping or not use this at all. #endif +#ifdef ENTRY_DEEPSLEEP_SETUP + LOAD_REG_ADDR(r6, 2f) + mfmsr r7 + rlwinm r7,r7,0,~(MSR_IS|MSR_DS) +#else lis r7,MSR_KERNEL@h ori r7,r7,MSR_KERNEL@l bl 1f /* Find our address */ 1: mflrr9 rlwimi r6,r9,0,20,31 addir6,r6,(2f - 1b) +#endif Could you explain what's going on here? What does the TLB look like before and after? +int fsl_dp_iomap(void) I don't think this needs to be global (see the comment where it gets called), but if it must be, this name is too terse. +{ + struct device_node *np; + int ret = 0; + phys_addr_t ccsr_phy_addr, dcsr_phy_addr; + + saved_law = NULL; + ccsr_base = NULL; + dcsr_base = NULL; + pld_base = NULL; + + ccsr_phy_addr = get_immrbase(); + if (ccsr_phy_addr == -1) { + pr_err(%s: Can't get the address of CCSR\n, __func__); + ret = -EINVAL; + goto ccsr_err; + } + ccsr_base = ioremap(ccsr_phy_addr, SIZE_2MB); + if (!ccsr_base) { + ret = -ENOMEM; + goto ccsr_err; + } + + dcsr_phy_addr = get_dcsrbase(); + if (dcsr_phy_addr == -1) { + pr_err(%s: Can't get the address of DCSR\n, __func__); + ret = -EINVAL; + goto dcsr_err; + } + dcsr_base = ioremap(dcsr_phy_addr, SIZE_1MB); + if (!dcsr_base) { + ret = -ENOMEM; + goto dcsr_err; + } Please just map the device tree nodes you need. + + np = of_find_compatible_node(NULL, NULL, fsl,tetra-fpga); + if (np) { + pld_flag = T1040QDS_TETRA_FLAG; + } else { + np = of_find_compatible_node(NULL, NULL, fsl,deepsleep-cpld); I've already rejected fsl,deepsleep-cpld multiple times when others tried to add it to a device tree. +{ + u32 ddr_buff_addr; + + /* + * DDR training initialization will break 128 bytes at the beginning + * of DDR, therefore, save them so that the bootloader will restore + * them. Assume that DDR is mapped to the address space started with + * CONFIG_PAGE_OFFSET. + */ + memcpy(ddr_buff, (void *)CONFIG_PAGE_OFFSET, DDR_BUF_SIZE); That assumption may not be true in all relocatable scenarios. It'd be a lot simpler to just mark that first page as reserved. + /* assume ddr_buff is in the physical address space of 4GB */ + ddr_buff_addr = (u32)(__pa(ddr_buff) 0x); + + /* + * the bootloader will restore the first 128 bytes of DDR from + * the location indicated by the register SPARECR3 + */ + out_be32(ccsr_base + CCSR_SCFG_SPARECR3, ddr_buff_addr); ...yeah, please just mark it reserved. +} + +static void fsl_dp_mp_save(void *ccsr) +{ + struct fsl_bstr *dst = saved_bstr; + + dst-bstrh = in_be32(ccsr + LCC_BSTRH); + dst-bstrl = in_be32(ccsr + LCC_BSTRL); + dst-bstar = in_be32(ccsr + LCC_BSTAR); + dst-cpu_mask = in_be32(ccsr + DCFG_BASE + DCFG_BRR); +} What is mp? +static void fsl_dp_law_save(void *ccsr) +{ + int i; + struct fsl_law *dst = saved_law; + struct fsl_law *src = (void *)(ccsr + CCSR_LAW_BASE); + + for (i = 0; i num_laws; i++) { + dst-lawbarh = in_be32(src-lawbarh); + dst-lawbarl = in_be32(src-lawbarl); + dst-lawar = in_be32(src-lawar); + dst++; + src++; + } +} Why wouldn't U-Boot restore these the same way on resume as they are now? +int fsl_enter_epu_deepsleep(void) +{ + fsl_dp_ddr_save(ccsr_base); + + fsl_dp_set_resume_pointer(ccsr_base); + + fsl_dp_mp_save(ccsr_base); + fsl_dp_law_save(ccsr_base); + /* enable Warm Device Reset request. */ + setbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN); + + /* set GPIO1_29 as an output pin (not open-drain), and output 0 */ + clrbits32(ccsr_base + CCSR_GPIO1_GPDAT, CCSR_GPIO1_GPDIR_29); + clrbits32(ccsr_base + CCSR_GPIO1_GPODR, CCSR_GPIO1_GPDIR_29); +