[PATCH] cpuidle: remove cpu_pm calls when entering a idle state
The functions, cpu_pm_enter and cpu_pm_exit, assume that CPU would be reset when entering and exiting a idle state. If that is not the case, they would cause issue. Signed-off-by: Chenhui Zhao <chenhui.z...@nxp.com> --- include/linux/cpuidle.h | 7 +-- 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index bb31373..063af89 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -261,12 +261,7 @@ static inline int cpuidle_register_governor(struct cpuidle_governor *gov) return idx; \ } \ \ - __ret = cpu_pm_enter(); \ - if (!__ret) { \ - __ret = low_level_idle_enter(idx); \ - cpu_pm_exit(); \ - } \ - \ + __ret = low_level_idle_enter(idx); \ __ret ? -1 : idx; \ }) -- 1.9.1
[PATCH] cpuidle: remove cpu_pm calls when entering a idle state
The functions, cpu_pm_enter and cpu_pm_exit, assume that CPU would be reset when entering and exiting a idle state. If that is not the case, they would cause issue. Signed-off-by: Chenhui Zhao --- include/linux/cpuidle.h | 7 +-- 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index bb31373..063af89 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -261,12 +261,7 @@ static inline int cpuidle_register_governor(struct cpuidle_governor *gov) return idx; \ } \ \ - __ret = cpu_pm_enter(); \ - if (!__ret) { \ - __ret = low_level_idle_enter(idx); \ - cpu_pm_exit(); \ - } \ - \ + __ret = low_level_idle_enter(idx); \ __ret ? -1 : idx; \ }) -- 1.9.1
Re: [PATCH 2/2] soc: nxp: Add a RCPM driver
On Mon, Aug 1, 2016 at 8:25 PM, Arnd Bergmann <a...@arndb.de> wrote: > On Monday, August 1, 2016 5:49:03 PM CEST Chenhui Zhao wrote: >> The NXP's QorIQ Processors based on ARM Core have a RCPM module >> (Run Control and Power Management), which performs all device-level >> tasks associated with power management. >> >> This patch mainly implements the wakeup sources configuration before >> entering LPM20, a low power state of device-level. The devices can be >> waked up by specified sources, such as Flextimer, GPIO and so on. >> >> Signed-off-by: Chenhui Zhao <chenhui.z...@nxp.com> > > Adding irqchip maintainers to cc, as this wakeup handling is normally > part of the irq controller. > >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +/* So far there are not more than two registers */ >> +#define RCPM_IPPDEXPCR0 0x140 >> +#define RCPM_IPPDEXPCR1 0x144 >> +#define RCPM_IPPDEXPCR(x)(RCPM_IPPDEXPCR0 + 4 * x) >> +#define RCPM_WAKEUP_CELL_MAX_SIZE2 >> + >> +/* it reprents the number of the registers RCPM_IPPDEXPCR */ >> +static unsigned int rcpm_wakeup_cells; >> +static void __iomem *rcpm_reg_base; >> +static u32 ippdexpcr[RCPM_WAKEUP_CELL_MAX_SIZE]; > > Can you make these local to the context of whoever > calls into the driver? > > >> +static void rcpm_wakeup_fixup(struct device *dev, void *data) >> +{ >> + struct device_node *node = dev ? dev->of_node : NULL; >> + u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1]; >> + int ret; >> + int i; >> + >> + if (!dev || !node || !device_may_wakeup(dev)) >> + return; >> + >> + /* >> + * Get the values in the "rcpm-wakeup" property. >> + * Refer to Documentation/devicetree/bindings/soc/fsl/rcpm.txt >> + */ >> + ret = of_property_read_u32_array(node, "rcpm-wakeup",c >> + value, rcpm_wakeup_cells + 1); > > My first impression is that you are trying to do something > in a platform specific way that should be handled by common > code here. > > You are parsing rcpm_wakeup_cells once for the global node, > but you don't check whether the device that has the rcpm-wakeup > node actually refers to this instance, and that would require > an incompatible change if we ever get an implementation that > has multiple such nodes. > > Arnd The code is specific to the QorIQ platform. For a given QorIQ SoC, the value of the "fsl,#rcpm-wakeup-cells" property would not change. Anyway, your suggestion is better getting the rcpm node from the "rcpm-wakeup" property. Thanks, Chenhui
Re: [PATCH 2/2] soc: nxp: Add a RCPM driver
On Mon, Aug 1, 2016 at 8:25 PM, Arnd Bergmann wrote: > On Monday, August 1, 2016 5:49:03 PM CEST Chenhui Zhao wrote: >> The NXP's QorIQ Processors based on ARM Core have a RCPM module >> (Run Control and Power Management), which performs all device-level >> tasks associated with power management. >> >> This patch mainly implements the wakeup sources configuration before >> entering LPM20, a low power state of device-level. The devices can be >> waked up by specified sources, such as Flextimer, GPIO and so on. >> >> Signed-off-by: Chenhui Zhao > > Adding irqchip maintainers to cc, as this wakeup handling is normally > part of the irq controller. > >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +/* So far there are not more than two registers */ >> +#define RCPM_IPPDEXPCR0 0x140 >> +#define RCPM_IPPDEXPCR1 0x144 >> +#define RCPM_IPPDEXPCR(x)(RCPM_IPPDEXPCR0 + 4 * x) >> +#define RCPM_WAKEUP_CELL_MAX_SIZE2 >> + >> +/* it reprents the number of the registers RCPM_IPPDEXPCR */ >> +static unsigned int rcpm_wakeup_cells; >> +static void __iomem *rcpm_reg_base; >> +static u32 ippdexpcr[RCPM_WAKEUP_CELL_MAX_SIZE]; > > Can you make these local to the context of whoever > calls into the driver? > > >> +static void rcpm_wakeup_fixup(struct device *dev, void *data) >> +{ >> + struct device_node *node = dev ? dev->of_node : NULL; >> + u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1]; >> + int ret; >> + int i; >> + >> + if (!dev || !node || !device_may_wakeup(dev)) >> + return; >> + >> + /* >> + * Get the values in the "rcpm-wakeup" property. >> + * Refer to Documentation/devicetree/bindings/soc/fsl/rcpm.txt >> + */ >> + ret = of_property_read_u32_array(node, "rcpm-wakeup",c >> + value, rcpm_wakeup_cells + 1); > > My first impression is that you are trying to do something > in a platform specific way that should be handled by common > code here. > > You are parsing rcpm_wakeup_cells once for the global node, > but you don't check whether the device that has the rcpm-wakeup > node actually refers to this instance, and that would require > an incompatible change if we ever get an implementation that > has multiple such nodes. > > Arnd The code is specific to the QorIQ platform. For a given QorIQ SoC, the value of the "fsl,#rcpm-wakeup-cells" property would not change. Anyway, your suggestion is better getting the rcpm node from the "rcpm-wakeup" property. Thanks, Chenhui
Re: [PATCH 2/2] soc: nxp: Add a RCPM driver
On Mon, Aug 1, 2016 at 9:22 PM, Marc Zyngier <marc.zyng...@arm.com> wrote: > > On 01/08/16 10:49, Chenhui Zhao wrote: > > The NXP's QorIQ Processors based on ARM Core have a RCPM module > > (Run Control and Power Management), which performs all device-level > > tasks associated with power management. > > > > This patch mainly implements the wakeup sources configuration before > > entering LPM20, a low power state of device-level. The devices can be > > waked up by specified sources, such as Flextimer, GPIO and so on. > > > > Signed-off-by: Chenhui Zhao <chenhui.z...@nxp.com> > > --- > > drivers/soc/fsl/Makefile | 1 + > > drivers/soc/fsl/pm/Makefile | 1 + > > drivers/soc/fsl/pm/ls-rcpm.c | 144 > > +++ > > 3 files changed, 146 insertions(+) > > create mode 100644 drivers/soc/fsl/pm/Makefile > > create mode 100644 drivers/soc/fsl/pm/ls-rcpm.c > > > > diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile > > index 203307f..b5adbaf 100644 > > --- a/drivers/soc/fsl/Makefile > > +++ b/drivers/soc/fsl/Makefile > > @@ -4,3 +4,4 @@ > > > > obj-$(CONFIG_QUICC_ENGINE) += qe/ > > obj-$(CONFIG_CPM)+= qe/ > > +obj-$(CONFIG_SUSPEND)+= pm/ > > diff --git a/drivers/soc/fsl/pm/Makefile b/drivers/soc/fsl/pm/Makefile > > new file mode 100644 > > index 000..e275d63 > > --- /dev/null > > +++ b/drivers/soc/fsl/pm/Makefile > > @@ -0,0 +1 @@ > > +obj-$(CONFIG_ARCH_LAYERSCAPE) += ls-rcpm.o > > diff --git a/drivers/soc/fsl/pm/ls-rcpm.c b/drivers/soc/fsl/pm/ls-rcpm.c > > new file mode 100644 > > index 000..c5f2b97 > > --- /dev/null > > +++ b/drivers/soc/fsl/pm/ls-rcpm.c > > @@ -0,0 +1,144 @@ > > +/* > > + * Run Control and Power Management (RCPM) driver > > + * > > + * Copyright 2016 Freescale Semiconductor, Inc. > > + * > > + * 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. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + */ > > +#define pr_fmt(fmt) "RCPM: %s: " fmt, __func__ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +/* So far there are not more than two registers */ > > +#define RCPM_IPPDEXPCR0 0x140 > > +#define RCPM_IPPDEXPCR1 0x144 > > +#define RCPM_IPPDEXPCR(x)(RCPM_IPPDEXPCR0 + 4 * x) > > +#define RCPM_WAKEUP_CELL_MAX_SIZE2 > > + > > +/* it reprents the number of the registers RCPM_IPPDEXPCR */ > > +static unsigned int rcpm_wakeup_cells; > > +static void __iomem *rcpm_reg_base; > > +static u32 ippdexpcr[RCPM_WAKEUP_CELL_MAX_SIZE]; > > + > > +static inline void rcpm_reg_write(u32 offset, u32 value) > > +{ > > + iowrite32be(value, rcpm_reg_base + offset); > > +} > > + > > +static inline u32 rcpm_reg_read(u32 offset) > > +{ > > + return ioread32be(rcpm_reg_base + offset); > > +} > > + > > +static void rcpm_wakeup_fixup(struct device *dev, void *data) > > +{ > > + struct device_node *node = dev ? dev->of_node : NULL; > > + u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1]; > > + int ret; > > + int i; > > + > > + if (!dev || !node || !device_may_wakeup(dev)) > > + return; > > + > > + /* > > + * Get the values in the "rcpm-wakeup" property. > > + * Refer to Documentation/devicetree/bindings/soc/fsl/rcpm.txt > > + */ > > + ret = of_property_read_u32_array(node, "rcpm-wakeup", > > + value, rcpm_wakeup_cells + 1); > > + if (ret) > > + return; > > + > > + pr_debug("wakeup source: the device %s\n", node->full_name); > > This looks absolutely dreadful. You are parsing every node for each > device, and apply a set-in-stone configuration. > > The normal way to handle this is by making this device an interrupt > controller, and honour the irq_set_wake API. This has already been done > on other FSL/NXP hardware (see the iMX GPC stuff). > > Thanks, > > M. The RCPM IP block is really not an interrupt controller, instead it is related to power management. The code in this patch is to set the bits in the IPPDEXPCR register. Setting these bits can make the corresponding IP block alive during the period of sleep, so that the IP blocks working as wakeup sources can wake the device. The "rcpm-wakeup" property records the bit mask which should be set when the IP block is working as wakeup source. The bit definition may be different for each QorIQ SoC. The operation is specific to QorIQ platform, so put the code in drivers/soc/fsl/pm/. Thanks, Chenhui
Re: [PATCH 2/2] soc: nxp: Add a RCPM driver
On Mon, Aug 1, 2016 at 9:22 PM, Marc Zyngier wrote: > > On 01/08/16 10:49, Chenhui Zhao wrote: > > The NXP's QorIQ Processors based on ARM Core have a RCPM module > > (Run Control and Power Management), which performs all device-level > > tasks associated with power management. > > > > This patch mainly implements the wakeup sources configuration before > > entering LPM20, a low power state of device-level. The devices can be > > waked up by specified sources, such as Flextimer, GPIO and so on. > > > > Signed-off-by: Chenhui Zhao > > --- > > drivers/soc/fsl/Makefile | 1 + > > drivers/soc/fsl/pm/Makefile | 1 + > > drivers/soc/fsl/pm/ls-rcpm.c | 144 > > +++ > > 3 files changed, 146 insertions(+) > > create mode 100644 drivers/soc/fsl/pm/Makefile > > create mode 100644 drivers/soc/fsl/pm/ls-rcpm.c > > > > diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile > > index 203307f..b5adbaf 100644 > > --- a/drivers/soc/fsl/Makefile > > +++ b/drivers/soc/fsl/Makefile > > @@ -4,3 +4,4 @@ > > > > obj-$(CONFIG_QUICC_ENGINE) += qe/ > > obj-$(CONFIG_CPM)+= qe/ > > +obj-$(CONFIG_SUSPEND)+= pm/ > > diff --git a/drivers/soc/fsl/pm/Makefile b/drivers/soc/fsl/pm/Makefile > > new file mode 100644 > > index 000..e275d63 > > --- /dev/null > > +++ b/drivers/soc/fsl/pm/Makefile > > @@ -0,0 +1 @@ > > +obj-$(CONFIG_ARCH_LAYERSCAPE) += ls-rcpm.o > > diff --git a/drivers/soc/fsl/pm/ls-rcpm.c b/drivers/soc/fsl/pm/ls-rcpm.c > > new file mode 100644 > > index 000..c5f2b97 > > --- /dev/null > > +++ b/drivers/soc/fsl/pm/ls-rcpm.c > > @@ -0,0 +1,144 @@ > > +/* > > + * Run Control and Power Management (RCPM) driver > > + * > > + * Copyright 2016 Freescale Semiconductor, Inc. > > + * > > + * 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. > > + * > > + * This program is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + */ > > +#define pr_fmt(fmt) "RCPM: %s: " fmt, __func__ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +/* So far there are not more than two registers */ > > +#define RCPM_IPPDEXPCR0 0x140 > > +#define RCPM_IPPDEXPCR1 0x144 > > +#define RCPM_IPPDEXPCR(x)(RCPM_IPPDEXPCR0 + 4 * x) > > +#define RCPM_WAKEUP_CELL_MAX_SIZE2 > > + > > +/* it reprents the number of the registers RCPM_IPPDEXPCR */ > > +static unsigned int rcpm_wakeup_cells; > > +static void __iomem *rcpm_reg_base; > > +static u32 ippdexpcr[RCPM_WAKEUP_CELL_MAX_SIZE]; > > + > > +static inline void rcpm_reg_write(u32 offset, u32 value) > > +{ > > + iowrite32be(value, rcpm_reg_base + offset); > > +} > > + > > +static inline u32 rcpm_reg_read(u32 offset) > > +{ > > + return ioread32be(rcpm_reg_base + offset); > > +} > > + > > +static void rcpm_wakeup_fixup(struct device *dev, void *data) > > +{ > > + struct device_node *node = dev ? dev->of_node : NULL; > > + u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1]; > > + int ret; > > + int i; > > + > > + if (!dev || !node || !device_may_wakeup(dev)) > > + return; > > + > > + /* > > + * Get the values in the "rcpm-wakeup" property. > > + * Refer to Documentation/devicetree/bindings/soc/fsl/rcpm.txt > > + */ > > + ret = of_property_read_u32_array(node, "rcpm-wakeup", > > + value, rcpm_wakeup_cells + 1); > > + if (ret) > > + return; > > + > > + pr_debug("wakeup source: the device %s\n", node->full_name); > > This looks absolutely dreadful. You are parsing every node for each > device, and apply a set-in-stone configuration. > > The normal way to handle this is by making this device an interrupt > controller, and honour the irq_set_wake API. This has already been done > on other FSL/NXP hardware (see the iMX GPC stuff). > > Thanks, > > M. The RCPM IP block is really not an interrupt controller, instead it is related to power management. The code in this patch is to set the bits in the IPPDEXPCR register. Setting these bits can make the corresponding IP block alive during the period of sleep, so that the IP blocks working as wakeup sources can wake the device. The "rcpm-wakeup" property records the bit mask which should be set when the IP block is working as wakeup source. The bit definition may be different for each QorIQ SoC. The operation is specific to QorIQ platform, so put the code in drivers/soc/fsl/pm/. Thanks, Chenhui
[PATCH v3 0/5] powerpc/pm: QorIQ deep sleep
Changes for v3: * add mcke-gpios in dts to specify the GPIO pin which works as MCKE signal Changes for v2: * Ioremap every dts node used in the patches. * Check the board compatible string to see if the board supports deep sleep. * Can not reserve the first page of DDR memory, because PPC64 doesn't support changing the kernel base address. So still save and restore the first 128 bytes of DDR memory. * Still save and restoer CCSR registers in kernel, because bootloader doesn't know what register values to restore * Changed copyright and email address from freescale to NXP Please refer to the version 1: [1/4] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM http://patchwork.ozlabs.org/patch/502549/ [2/4] powerpc: get the physical base address of DCSR http://patchwork.ozlabs.org/patch/502551/ It is removed. [3/4] powerpc: pm: add EPU FSM configuration for deep sleep http://patchwork.ozlabs.org/patch/502548/ [4/4] powerpc: pm: support deep sleep feature on T104x http://patchwork.ozlabs.org/patch/502550/ Chenhui Zhao (5): powerpc/dts: add mcke-gpios for PM feature powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM powerpc: pm: add EPU FSM configuration for deep sleep powerpc/pm: support deep sleep feature on T104x powerpc/pm: save and restore registers during deep sleep Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 13 + arch/powerpc/Kconfig | 3 +- arch/powerpc/boot/dts/fsl/t1040si-post.dtsi| 3 + arch/powerpc/include/asm/fsl_pm.h | 28 +- arch/powerpc/kernel/asm-offsets.c | 12 + arch/powerpc/kernel/fsl_booke_entry_mapping.S | 10 + arch/powerpc/kernel/head_64.S | 2 +- arch/powerpc/platforms/85xx/Kconfig| 5 + arch/powerpc/platforms/85xx/Makefile | 2 + arch/powerpc/platforms/85xx/deepsleep.c| 384 +++ arch/powerpc/platforms/85xx/qoriq_pm.c | 84 arch/powerpc/platforms/85xx/sleep_fsm.c| 267 +++ arch/powerpc/platforms/85xx/sleep_fsm.h| 92 arch/powerpc/platforms/85xx/t104x_deepsleep.S | 531 + arch/powerpc/platforms/86xx/Kconfig| 1 + arch/powerpc/sysdev/fsl_rcpm.c | 28 +- 16 files changed, 1446 insertions(+), 19 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.c create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.h create mode 100644 arch/powerpc/platforms/85xx/t104x_deepsleep.S -- 1.9.1
[PATCH v3 0/5] powerpc/pm: QorIQ deep sleep
Changes for v3: * add mcke-gpios in dts to specify the GPIO pin which works as MCKE signal Changes for v2: * Ioremap every dts node used in the patches. * Check the board compatible string to see if the board supports deep sleep. * Can not reserve the first page of DDR memory, because PPC64 doesn't support changing the kernel base address. So still save and restore the first 128 bytes of DDR memory. * Still save and restoer CCSR registers in kernel, because bootloader doesn't know what register values to restore * Changed copyright and email address from freescale to NXP Please refer to the version 1: [1/4] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM http://patchwork.ozlabs.org/patch/502549/ [2/4] powerpc: get the physical base address of DCSR http://patchwork.ozlabs.org/patch/502551/ It is removed. [3/4] powerpc: pm: add EPU FSM configuration for deep sleep http://patchwork.ozlabs.org/patch/502548/ [4/4] powerpc: pm: support deep sleep feature on T104x http://patchwork.ozlabs.org/patch/502550/ Chenhui Zhao (5): powerpc/dts: add mcke-gpios for PM feature powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM powerpc: pm: add EPU FSM configuration for deep sleep powerpc/pm: support deep sleep feature on T104x powerpc/pm: save and restore registers during deep sleep Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 13 + arch/powerpc/Kconfig | 3 +- arch/powerpc/boot/dts/fsl/t1040si-post.dtsi| 3 + arch/powerpc/include/asm/fsl_pm.h | 28 +- arch/powerpc/kernel/asm-offsets.c | 12 + arch/powerpc/kernel/fsl_booke_entry_mapping.S | 10 + arch/powerpc/kernel/head_64.S | 2 +- arch/powerpc/platforms/85xx/Kconfig| 5 + arch/powerpc/platforms/85xx/Makefile | 2 + arch/powerpc/platforms/85xx/deepsleep.c| 384 +++ arch/powerpc/platforms/85xx/qoriq_pm.c | 84 arch/powerpc/platforms/85xx/sleep_fsm.c| 267 +++ arch/powerpc/platforms/85xx/sleep_fsm.h| 92 arch/powerpc/platforms/85xx/t104x_deepsleep.S | 531 + arch/powerpc/platforms/86xx/Kconfig| 1 + arch/powerpc/sysdev/fsl_rcpm.c | 28 +- 16 files changed, 1446 insertions(+), 19 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/deepsleep.c create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.c create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.h create mode 100644 arch/powerpc/platforms/85xx/t104x_deepsleep.S -- 1.9.1
[PATCH v3 1/5] powerpc/dts: add mcke-gpios for PM feature
Signed-off-by: Chenhui Zhao <chenhui.z...@nxp.com> --- Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 13 + arch/powerpc/boot/dts/fsl/t1040si-post.dtsi| 3 +++ 2 files changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt index e284e4e..1d44a80 100644 --- a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt +++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt @@ -21,6 +21,10 @@ Required properites: * "fsl,qoriq-rcpm-2.0": for chassis 2.0 rcpm * "fsl,qoriq-rcpm-2.1": for chassis 2.1 rcpm +Optional properites: + - mcke-gpios : The GPIO pin is used for keeping the MCKE signal of DDR modules +low in the LPM35 state on some platforms, such as T1040. + All references to "1.0" and "2.0" refer to the QorIQ chassis version to which the chip complies. Chassis VersionExample Chips @@ -37,6 +41,15 @@ The RCPM node for T4240: fsl,#rcpm-wakeup-cells = <2>; }; +The RCPM node for T1040 (which supports LPM35 state): + rcpm: global-utilities@e2000 { + compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1"; + reg = <0xe2000 0x1000>; + fsl,#rcpm-wakeup-cells = <1>; + mcke-gpios = < 29 GPIO_ACTIVE_HIGH> + }; + + * Freescale RCPM Wakeup Source Device Tree Bindings --- Required fsl,rcpm-wakeup property should be added to a device node if the device diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi index 507649e..f66e7dd 100644 --- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi @@ -33,6 +33,7 @@ */ #include +#include _fbpr { compatible = "fsl,bman-fbpr"; @@ -474,6 +475,8 @@ rcpm: global-utilities@e2000 { compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1"; reg = <0xe2000 0x1000>; + fsl,#rcpm-wakeup-cells = <1>; + mcke-gpios = < 29 GPIO_ACTIVE_HIGH>; }; sfp: sfp@e8000 { -- 1.9.1
[PATCH v3 1/5] powerpc/dts: add mcke-gpios for PM feature
Signed-off-by: Chenhui Zhao --- Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 13 + arch/powerpc/boot/dts/fsl/t1040si-post.dtsi| 3 +++ 2 files changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt index e284e4e..1d44a80 100644 --- a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt +++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt @@ -21,6 +21,10 @@ Required properites: * "fsl,qoriq-rcpm-2.0": for chassis 2.0 rcpm * "fsl,qoriq-rcpm-2.1": for chassis 2.1 rcpm +Optional properites: + - mcke-gpios : The GPIO pin is used for keeping the MCKE signal of DDR modules +low in the LPM35 state on some platforms, such as T1040. + All references to "1.0" and "2.0" refer to the QorIQ chassis version to which the chip complies. Chassis VersionExample Chips @@ -37,6 +41,15 @@ The RCPM node for T4240: fsl,#rcpm-wakeup-cells = <2>; }; +The RCPM node for T1040 (which supports LPM35 state): + rcpm: global-utilities@e2000 { + compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1"; + reg = <0xe2000 0x1000>; + fsl,#rcpm-wakeup-cells = <1>; + mcke-gpios = < 29 GPIO_ACTIVE_HIGH> + }; + + * Freescale RCPM Wakeup Source Device Tree Bindings --- Required fsl,rcpm-wakeup property should be added to a device node if the device diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi index 507649e..f66e7dd 100644 --- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi @@ -33,6 +33,7 @@ */ #include +#include _fbpr { compatible = "fsl,bman-fbpr"; @@ -474,6 +475,8 @@ rcpm: global-utilities@e2000 { compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1"; reg = <0xe2000 0x1000>; + fsl,#rcpm-wakeup-cells = <1>; + mcke-gpios = < 29 GPIO_ACTIVE_HIGH>; }; sfp: sfp@e8000 { -- 1.9.1
[PATCH v3 3/5] powerpc: pm: add EPU FSM configuration for deep sleep
In the last stage of deep sleep, software will trigger a Finite State Machine (FSM) to control the hardware precedure, such as board isolation, killing PLLs, removing power, and so on. When the system is waked up by an interrupt, the FSM controls the hardware to complete the early resume precedure. This patch configure the EPU FSM preparing for deep sleep. Signed-off-by: Chenhui Zhao <chenhui.z...@nxp.com> --- arch/powerpc/platforms/85xx/Makefile| 2 +- arch/powerpc/platforms/85xx/sleep_fsm.c | 267 arch/powerpc/platforms/85xx/sleep_fsm.h | 92 +++ 3 files changed, 360 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.c create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.h diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index fdae28b..87fb847 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o -obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o +obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o sleep_fsm.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/sleep_fsm.c b/arch/powerpc/platforms/85xx/sleep_fsm.c new file mode 100644 index 000..2b0c16b --- /dev/null +++ b/arch/powerpc/platforms/85xx/sleep_fsm.c @@ -0,0 +1,267 @@ +/* + * Freescale deep sleep FSM (finite-state machine) configuration + * + * Copyright 2016 Freescale Semiconductor Inc. + * + * Author: Hongbo Zhang <hongbo.zh...@nxp.com> + * Chenhui Zhao <chenhui.z...@nxp.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. + */ + +#include +#include +#include + +#include "sleep_fsm.h" + +struct fsm_reg_vals { + u32 offset; + u32 value; +}; + +/* + * These values are from chip's reference manual. For example, + * the values for T1040 can be found in "8.4.3.8 Programming + * supporting deep sleep mode" of Chapter 8 "Run Control and + * Power Management (RCPM)". + * The default value is applied to T1040, T1042, T1024. + */ +struct fsm_reg_vals epu_default_val[] = { + /* EPGCR (Event Processor Global Control Register) */ + {EPGCR, 0}, + /* EPECR (Event Processor Event Control Registers) */ + {EPECR0 + EPECR_STRIDE * 0, 0}, + {EPECR0 + EPECR_STRIDE * 1, 0}, + {EPECR0 + EPECR_STRIDE * 2, 0xF0004004}, + {EPECR0 + EPECR_STRIDE * 3, 0x8084}, + {EPECR0 + EPECR_STRIDE * 4, 0x2084}, + {EPECR0 + EPECR_STRIDE * 5, 0x0804}, + {EPECR0 + EPECR_STRIDE * 6, 0x8084}, + {EPECR0 + EPECR_STRIDE * 7, 0x8084}, + {EPECR0 + EPECR_STRIDE * 8, 0x6084}, + {EPECR0 + EPECR_STRIDE * 9, 0x0884}, + {EPECR0 + EPECR_STRIDE * 10, 0x4284}, + {EPECR0 + EPECR_STRIDE * 11, 0x9084}, + {EPECR0 + EPECR_STRIDE * 12, 0x8084}, + {EPECR0 + EPECR_STRIDE * 13, 0x0884}, + {EPECR0 + EPECR_STRIDE * 14, 0x0284}, + {EPECR0 + EPECR_STRIDE * 15, 0x0004}, + /* +* EPEVTCR (Event Processor EVT Pin Control Registers) +* SCU8 triger EVT2, and SCU11 triger EVT9 +*/ + {EPEVTCR0 + EPEVTCR_STRIDE * 0, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 1, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x8001}, + {EPEVTCR0 + EPEVTCR_STRIDE * 3, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 4, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 5, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 6, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 7, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 8, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 9, 0xB001}, + /* EPCMPR (Event Processor Counter Compare Registers) */ + {EPCMPR0 + EPCMPR_STRIDE * 0, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 1, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 2, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 3, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 4, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 5, 0x0020}, + {EPCMPR0 + EPCMPR_STRIDE * 6, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 7, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 8, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 9, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 10, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 11, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 12, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 13, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 14, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 15, 0x00FF}, + /* EPCCR (Event Processor Counter Control Registers) */ + {EPCCR0 + EPCCR_STRIDE * 0, 0}, + {EPCCR0 + EPCCR_STRIDE * 1, 0}, + {EPCCR0 + EPCCR_STRIDE * 2, 0x9284}, + {EPCCR0 + EPCCR_ST
[PATCH v3 3/5] powerpc: pm: add EPU FSM configuration for deep sleep
In the last stage of deep sleep, software will trigger a Finite State Machine (FSM) to control the hardware precedure, such as board isolation, killing PLLs, removing power, and so on. When the system is waked up by an interrupt, the FSM controls the hardware to complete the early resume precedure. This patch configure the EPU FSM preparing for deep sleep. Signed-off-by: Chenhui Zhao --- arch/powerpc/platforms/85xx/Makefile| 2 +- arch/powerpc/platforms/85xx/sleep_fsm.c | 267 arch/powerpc/platforms/85xx/sleep_fsm.h | 92 +++ 3 files changed, 360 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.c create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.h diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index fdae28b..87fb847 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o -obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o +obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o sleep_fsm.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/sleep_fsm.c b/arch/powerpc/platforms/85xx/sleep_fsm.c new file mode 100644 index 000..2b0c16b --- /dev/null +++ b/arch/powerpc/platforms/85xx/sleep_fsm.c @@ -0,0 +1,267 @@ +/* + * Freescale deep sleep FSM (finite-state machine) configuration + * + * Copyright 2016 Freescale Semiconductor Inc. + * + * Author: Hongbo Zhang + * 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 "sleep_fsm.h" + +struct fsm_reg_vals { + u32 offset; + u32 value; +}; + +/* + * These values are from chip's reference manual. For example, + * the values for T1040 can be found in "8.4.3.8 Programming + * supporting deep sleep mode" of Chapter 8 "Run Control and + * Power Management (RCPM)". + * The default value is applied to T1040, T1042, T1024. + */ +struct fsm_reg_vals epu_default_val[] = { + /* EPGCR (Event Processor Global Control Register) */ + {EPGCR, 0}, + /* EPECR (Event Processor Event Control Registers) */ + {EPECR0 + EPECR_STRIDE * 0, 0}, + {EPECR0 + EPECR_STRIDE * 1, 0}, + {EPECR0 + EPECR_STRIDE * 2, 0xF0004004}, + {EPECR0 + EPECR_STRIDE * 3, 0x8084}, + {EPECR0 + EPECR_STRIDE * 4, 0x2084}, + {EPECR0 + EPECR_STRIDE * 5, 0x0804}, + {EPECR0 + EPECR_STRIDE * 6, 0x8084}, + {EPECR0 + EPECR_STRIDE * 7, 0x8084}, + {EPECR0 + EPECR_STRIDE * 8, 0x6084}, + {EPECR0 + EPECR_STRIDE * 9, 0x0884}, + {EPECR0 + EPECR_STRIDE * 10, 0x4284}, + {EPECR0 + EPECR_STRIDE * 11, 0x9084}, + {EPECR0 + EPECR_STRIDE * 12, 0x8084}, + {EPECR0 + EPECR_STRIDE * 13, 0x0884}, + {EPECR0 + EPECR_STRIDE * 14, 0x0284}, + {EPECR0 + EPECR_STRIDE * 15, 0x0004}, + /* +* EPEVTCR (Event Processor EVT Pin Control Registers) +* SCU8 triger EVT2, and SCU11 triger EVT9 +*/ + {EPEVTCR0 + EPEVTCR_STRIDE * 0, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 1, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x8001}, + {EPEVTCR0 + EPEVTCR_STRIDE * 3, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 4, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 5, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 6, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 7, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 8, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 9, 0xB001}, + /* EPCMPR (Event Processor Counter Compare Registers) */ + {EPCMPR0 + EPCMPR_STRIDE * 0, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 1, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 2, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 3, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 4, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 5, 0x0020}, + {EPCMPR0 + EPCMPR_STRIDE * 6, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 7, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 8, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 9, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 10, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 11, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 12, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 13, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 14, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 15, 0x00FF}, + /* EPCCR (Event Processor Counter Control Registers) */ + {EPCCR0 + EPCCR_STRIDE * 0, 0}, + {EPCCR0 + EPCCR_STRIDE * 1, 0}, + {EPCCR0 + EPCCR_STRIDE * 2, 0x9284}, + {EPCCR0 + EPCCR_STRIDE * 3, 0}, + {EPCCR0 + EPCCR_STRIDE * 4, 0x9284}, + {EPCCR0
[PATCH v3 2/5] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
In sleep mode, the clocks of e500 cores and unused IP blocks is turned off. The IP blocks which are allowed to wake up the processor are still running. The sleep mode is equal to the Standby state in Linux. Use the command to enter sleep mode: echo standby > /sys/power/state Signed-off-by: Chenhui Zhao <chenhui.z...@nxp.com> --- arch/powerpc/Kconfig | 3 +- arch/powerpc/include/asm/fsl_pm.h | 2 +- arch/powerpc/platforms/85xx/Kconfig| 5 +++ arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/qoriq_pm.c | 59 ++ arch/powerpc/platforms/86xx/Kconfig| 1 + arch/powerpc/sysdev/fsl_rcpm.c | 20 7 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 0a9d439..078d08c 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -242,7 +242,7 @@ config ARCH_HIBERNATION_POSSIBLE config ARCH_SUSPEND_POSSIBLE def_bool y depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ - (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \ + FSL_SOC_BOOKE || PPC_86xx || PPC_PSERIES \ || 44x || 40x config PPC_DCR_NATIVE @@ -778,7 +778,6 @@ config FSL_PCI config FSL_PMC bool - default y depends on SUSPEND && (PPC_85xx || PPC_86xx) help Freescale MPC85xx/MPC86xx power management controller support diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h index 47df55e..e05049b 100644 --- a/arch/powerpc/include/asm/fsl_pm.h +++ b/arch/powerpc/include/asm/fsl_pm.h @@ -34,7 +34,7 @@ struct fsl_pm_ops { void (*cpu_exit_state)(int cpu, int state); void (*cpu_up_prepare)(int cpu); void (*cpu_die)(int cpu); - int (*plat_enter_sleep)(void); + int (*plat_enter_sleep)(int state); void (*freeze_time_base)(bool freeze); /* keep the power of IP blocks during sleep/deep sleep */ diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index e626461..dff2ea6 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -9,6 +9,8 @@ menuconfig FSL_SOC_BOOKE select SERIAL_8250_EXTENDED if SERIAL_8250 select SERIAL_8250_SHARE_IRQ if SERIAL_8250 select FSL_CORENET_RCPM if PPC_E500MC + select FSL_QORIQ_PM if SUSPEND && PPC_E500MC + select FSL_PMC if SUSPEND && !PPC_E500MC default y if FSL_SOC_BOOKE @@ -289,3 +291,6 @@ endif # FSL_SOC_BOOKE config TQM85xx bool + +config FSL_QORIQ_PM + bool diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 7bc86da..fdae28b 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o +obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c new file mode 100644 index 000..c97ef8f --- /dev/null +++ b/arch/powerpc/platforms/85xx/qoriq_pm.c @@ -0,0 +1,59 @@ +/* + * Support Power Management feature + * + * Copyright 2016 Freescale Semiconductor Inc. + * + * Author: Chenhui Zhao <chenhui.z...@nxp.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. + */ + +#include +#include +#include + +#include + +static unsigned int pm_modes; + +static int qoriq_suspend_enter(suspend_state_t state) +{ + int ret = 0; + + switch (state) { + case PM_SUSPEND_STANDBY: + ret = qoriq_pm_ops->plat_enter_sleep(FSL_PM_SLEEP); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int qoriq_suspend_valid(suspend_state_t state) +{ + + if (state == PM_SUSPEND_STANDBY && (pm_modes & FSL_PM_SLEEP)) + return 1; + + return 0; +} + +static const struct platform_suspend_ops qoriq_suspend_ops = { + .valid = qoriq_suspend_valid, + .enter = qoriq_suspend_enter, +}; + +static int __init qoriq_suspend_init(void) +{ + /* support sleep by default */ + pm_modes |= FSL_PM_SLEEP; + + suspend_set_ops(_suspend_ops); + return 0; +} +arch_initcall(qoriq_suspend_init); diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 1afd1e4..09638e0 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -5,6 +5,7 @@ men
[PATCH v3 2/5] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
In sleep mode, the clocks of e500 cores and unused IP blocks is turned off. The IP blocks which are allowed to wake up the processor are still running. The sleep mode is equal to the Standby state in Linux. Use the command to enter sleep mode: echo standby > /sys/power/state Signed-off-by: Chenhui Zhao --- arch/powerpc/Kconfig | 3 +- arch/powerpc/include/asm/fsl_pm.h | 2 +- arch/powerpc/platforms/85xx/Kconfig| 5 +++ arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/qoriq_pm.c | 59 ++ arch/powerpc/platforms/86xx/Kconfig| 1 + arch/powerpc/sysdev/fsl_rcpm.c | 20 7 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 0a9d439..078d08c 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -242,7 +242,7 @@ config ARCH_HIBERNATION_POSSIBLE config ARCH_SUSPEND_POSSIBLE def_bool y depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ - (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \ + FSL_SOC_BOOKE || PPC_86xx || PPC_PSERIES \ || 44x || 40x config PPC_DCR_NATIVE @@ -778,7 +778,6 @@ config FSL_PCI config FSL_PMC bool - default y depends on SUSPEND && (PPC_85xx || PPC_86xx) help Freescale MPC85xx/MPC86xx power management controller support diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h index 47df55e..e05049b 100644 --- a/arch/powerpc/include/asm/fsl_pm.h +++ b/arch/powerpc/include/asm/fsl_pm.h @@ -34,7 +34,7 @@ struct fsl_pm_ops { void (*cpu_exit_state)(int cpu, int state); void (*cpu_up_prepare)(int cpu); void (*cpu_die)(int cpu); - int (*plat_enter_sleep)(void); + int (*plat_enter_sleep)(int state); void (*freeze_time_base)(bool freeze); /* keep the power of IP blocks during sleep/deep sleep */ diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index e626461..dff2ea6 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -9,6 +9,8 @@ menuconfig FSL_SOC_BOOKE select SERIAL_8250_EXTENDED if SERIAL_8250 select SERIAL_8250_SHARE_IRQ if SERIAL_8250 select FSL_CORENET_RCPM if PPC_E500MC + select FSL_QORIQ_PM if SUSPEND && PPC_E500MC + select FSL_PMC if SUSPEND && !PPC_E500MC default y if FSL_SOC_BOOKE @@ -289,3 +291,6 @@ endif # FSL_SOC_BOOKE config TQM85xx bool + +config FSL_QORIQ_PM + bool diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 7bc86da..fdae28b 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o +obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c new file mode 100644 index 000..c97ef8f --- /dev/null +++ b/arch/powerpc/platforms/85xx/qoriq_pm.c @@ -0,0 +1,59 @@ +/* + * Support Power Management feature + * + * Copyright 2016 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 + +static unsigned int pm_modes; + +static int qoriq_suspend_enter(suspend_state_t state) +{ + int ret = 0; + + switch (state) { + case PM_SUSPEND_STANDBY: + ret = qoriq_pm_ops->plat_enter_sleep(FSL_PM_SLEEP); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int qoriq_suspend_valid(suspend_state_t state) +{ + + if (state == PM_SUSPEND_STANDBY && (pm_modes & FSL_PM_SLEEP)) + return 1; + + return 0; +} + +static const struct platform_suspend_ops qoriq_suspend_ops = { + .valid = qoriq_suspend_valid, + .enter = qoriq_suspend_enter, +}; + +static int __init qoriq_suspend_init(void) +{ + /* support sleep by default */ + pm_modes |= FSL_PM_SLEEP; + + suspend_set_ops(_suspend_ops); + return 0; +} +arch_initcall(qoriq_suspend_init); diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 1afd1e4..09638e0 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -5,6 +5,7 @@ menuconfig PPC_86xx select FSL_SOC select
[PATCH v3 5/5] powerpc/pm: save and restore registers during deep sleep
Some CCSR registers will lost during deep sleep. Therefore, should save them before entering deep sleep, and restore them when resuming from deep sleep. Signed-off-by: Tang Yuantian <yuantian.t...@nxp.com> Signed-off-by: Chenhui Zhao <chenhui.z...@nxp.com> --- arch/powerpc/include/asm/fsl_pm.h | 2 + arch/powerpc/platforms/85xx/deepsleep.c | 108 +++- 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h index 48c2631..95601fb 100644 --- a/arch/powerpc/include/asm/fsl_pm.h +++ b/arch/powerpc/include/asm/fsl_pm.h @@ -61,7 +61,9 @@ extern void fsl_dp_enter_low(void *priv); extern void fsl_booke_deep_sleep_resume(void); struct fsl_iomap { + void *ccsr_lcc_base; void *ccsr_scfg_base; + void *ccsr_dcfg_base; void *ccsr_rcpm_base; void *ccsr_ddr_base; void *ccsr_gpio1_base; diff --git a/arch/powerpc/platforms/85xx/deepsleep.c b/arch/powerpc/platforms/85xx/deepsleep.c index 9521d99..71987fd 100644 --- a/arch/powerpc/platforms/85xx/deepsleep.c +++ b/arch/powerpc/platforms/85xx/deepsleep.c @@ -23,6 +23,8 @@ #include "sleep_fsm.h" +#define CCSR_LAW_OFFSET0xC00 + #define CPC_CPCHDBCR0 0x0f00 #define CPC_CPCHDBCR0_SPEC_DIS 0x0800 @@ -41,6 +43,17 @@ #define QORIQ_CPLD_MISCCSR 0x17 #define QORIQ_CPLD_MISCCSR_SLEEPEN 0x40 +#define CCSR_LCC_BSTRH 0x20 +#define CCSR_LCC_BSTRL 0x24 +#define CCSR_LCC_BSTAR 0x28 + +#define CCSR_DCFG_BRR 0xE4 + +#define CCSR_RCPM_PCTBENR 0x1A0 + +/* the target id for the memory complex 1 (MC1) */ +#define MC1_TRGT_ID0x10 + /* 128 bytes buffer for restoring data broke by DDR training initialization */ #define DDR_BUF_SIZE 128 static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64); @@ -50,6 +63,23 @@ static void fsl_dp_iounmap(void); static struct fsl_iomap fsl_dp_priv; +struct fsl_ccsr_law { + u32 lawbarh;/* LAWn base address high */ + u32 lawbarl;/* LAWn base address low */ + u32 lawar; /* LAWn attributes */ + u32 reserved; +}; + +static struct fsl_regs_buffer { + u32 bstrh; + u32 bstrl; + u32 bstar; + u32 brr; + u32 pctbenr; + u32 law_count; + void *law_regs; +} fsl_dp_buffer; + static const struct of_device_id fsl_dp_cpld_ids[] __initconst = { { .compatible = "fsl,t1024-cpld", }, { .compatible = "fsl,t1040rdb-cpld", }, @@ -65,6 +95,60 @@ static const struct of_device_id fsl_dp_fpga_ids[] __initconst = { {} }; +static void fsl_regs_save(struct fsl_iomap *base, + struct fsl_regs_buffer *buffer) +{ + int i; + struct fsl_ccsr_law *src = base->ccsr_lcc_base + CCSR_LAW_OFFSET; + struct fsl_ccsr_law *dst = buffer->law_regs; + + buffer->bstrh = in_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRH); + buffer->bstrl = in_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRL); + buffer->bstar = in_be32(base->ccsr_lcc_base + CCSR_LCC_BSTAR); + buffer->brr = in_be32(base->ccsr_dcfg_base + CCSR_DCFG_BRR); + buffer->pctbenr = in_be32(base->ccsr_rcpm_base + CCSR_RCPM_PCTBENR); + + for (i = 0; i < buffer->law_count; i++) { + dst->lawbarh = in_be32(>lawbarh); + dst->lawbarl = in_be32(>lawbarl); + dst->lawar = in_be32(>lawar); + dst++; + src++; + } +} + +static void fsl_regs_restore(struct fsl_iomap *base, +struct fsl_regs_buffer *buffer) +{ + int i; + u32 attr; + struct fsl_ccsr_law *src = buffer->law_regs; + struct fsl_ccsr_law *dst = base->ccsr_lcc_base + CCSR_LAW_OFFSET; + + out_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRH, buffer->bstrh); + out_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRL, buffer->bstrl); + out_be32(base->ccsr_lcc_base + CCSR_LCC_BSTAR, buffer->bstar); + out_be32(base->ccsr_dcfg_base + CCSR_DCFG_BRR, buffer->brr); + out_be32(base->ccsr_rcpm_base + CCSR_RCPM_PCTBENR, buffer->pctbenr); + + for (i = 0; i < buffer->law_count; i++) { + /* +* If the LAW with the target id of MC1 has been set, +* skip. Because changing it here causes memory +* access error. +*/ + attr = in_be32(>lawar); + if (((attr >> 20) & 0xff) == MC1_TRGT_ID) + continue; + out_be32(>lawar, 0); + out_be32(>lawbarl, src->lawbarl); + out_be32(>lawbarh, src->lawbarh); + out_be32(>lawar, src->lawar); + src++; + dst++; + } +} + static void fsl
[PATCH v3 5/5] powerpc/pm: save and restore registers during deep sleep
Some CCSR registers will lost during deep sleep. Therefore, should save them before entering deep sleep, and restore them when resuming from deep sleep. Signed-off-by: Tang Yuantian Signed-off-by: Chenhui Zhao --- arch/powerpc/include/asm/fsl_pm.h | 2 + arch/powerpc/platforms/85xx/deepsleep.c | 108 +++- 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h index 48c2631..95601fb 100644 --- a/arch/powerpc/include/asm/fsl_pm.h +++ b/arch/powerpc/include/asm/fsl_pm.h @@ -61,7 +61,9 @@ extern void fsl_dp_enter_low(void *priv); extern void fsl_booke_deep_sleep_resume(void); struct fsl_iomap { + void *ccsr_lcc_base; void *ccsr_scfg_base; + void *ccsr_dcfg_base; void *ccsr_rcpm_base; void *ccsr_ddr_base; void *ccsr_gpio1_base; diff --git a/arch/powerpc/platforms/85xx/deepsleep.c b/arch/powerpc/platforms/85xx/deepsleep.c index 9521d99..71987fd 100644 --- a/arch/powerpc/platforms/85xx/deepsleep.c +++ b/arch/powerpc/platforms/85xx/deepsleep.c @@ -23,6 +23,8 @@ #include "sleep_fsm.h" +#define CCSR_LAW_OFFSET0xC00 + #define CPC_CPCHDBCR0 0x0f00 #define CPC_CPCHDBCR0_SPEC_DIS 0x0800 @@ -41,6 +43,17 @@ #define QORIQ_CPLD_MISCCSR 0x17 #define QORIQ_CPLD_MISCCSR_SLEEPEN 0x40 +#define CCSR_LCC_BSTRH 0x20 +#define CCSR_LCC_BSTRL 0x24 +#define CCSR_LCC_BSTAR 0x28 + +#define CCSR_DCFG_BRR 0xE4 + +#define CCSR_RCPM_PCTBENR 0x1A0 + +/* the target id for the memory complex 1 (MC1) */ +#define MC1_TRGT_ID0x10 + /* 128 bytes buffer for restoring data broke by DDR training initialization */ #define DDR_BUF_SIZE 128 static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64); @@ -50,6 +63,23 @@ static void fsl_dp_iounmap(void); static struct fsl_iomap fsl_dp_priv; +struct fsl_ccsr_law { + u32 lawbarh;/* LAWn base address high */ + u32 lawbarl;/* LAWn base address low */ + u32 lawar; /* LAWn attributes */ + u32 reserved; +}; + +static struct fsl_regs_buffer { + u32 bstrh; + u32 bstrl; + u32 bstar; + u32 brr; + u32 pctbenr; + u32 law_count; + void *law_regs; +} fsl_dp_buffer; + static const struct of_device_id fsl_dp_cpld_ids[] __initconst = { { .compatible = "fsl,t1024-cpld", }, { .compatible = "fsl,t1040rdb-cpld", }, @@ -65,6 +95,60 @@ static const struct of_device_id fsl_dp_fpga_ids[] __initconst = { {} }; +static void fsl_regs_save(struct fsl_iomap *base, + struct fsl_regs_buffer *buffer) +{ + int i; + struct fsl_ccsr_law *src = base->ccsr_lcc_base + CCSR_LAW_OFFSET; + struct fsl_ccsr_law *dst = buffer->law_regs; + + buffer->bstrh = in_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRH); + buffer->bstrl = in_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRL); + buffer->bstar = in_be32(base->ccsr_lcc_base + CCSR_LCC_BSTAR); + buffer->brr = in_be32(base->ccsr_dcfg_base + CCSR_DCFG_BRR); + buffer->pctbenr = in_be32(base->ccsr_rcpm_base + CCSR_RCPM_PCTBENR); + + for (i = 0; i < buffer->law_count; i++) { + dst->lawbarh = in_be32(>lawbarh); + dst->lawbarl = in_be32(>lawbarl); + dst->lawar = in_be32(>lawar); + dst++; + src++; + } +} + +static void fsl_regs_restore(struct fsl_iomap *base, +struct fsl_regs_buffer *buffer) +{ + int i; + u32 attr; + struct fsl_ccsr_law *src = buffer->law_regs; + struct fsl_ccsr_law *dst = base->ccsr_lcc_base + CCSR_LAW_OFFSET; + + out_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRH, buffer->bstrh); + out_be32(base->ccsr_lcc_base + CCSR_LCC_BSTRL, buffer->bstrl); + out_be32(base->ccsr_lcc_base + CCSR_LCC_BSTAR, buffer->bstar); + out_be32(base->ccsr_dcfg_base + CCSR_DCFG_BRR, buffer->brr); + out_be32(base->ccsr_rcpm_base + CCSR_RCPM_PCTBENR, buffer->pctbenr); + + for (i = 0; i < buffer->law_count; i++) { + /* +* If the LAW with the target id of MC1 has been set, +* skip. Because changing it here causes memory +* access error. +*/ + attr = in_be32(>lawar); + if (((attr >> 20) & 0xff) == MC1_TRGT_ID) + continue; + out_be32(>lawar, 0); + out_be32(>lawbarl, src->lawbarl); + out_be32(>lawbarh, src->lawbarh); + out_be32(>lawar, src->lawar); + src++; + dst++; + } +} + static void fsl_dp_set_resume_pointer(void) { u32 resume_addr; @@ -132,
[PATCH v3 4/5] 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...@nxp.com> --- arch/powerpc/include/asm/fsl_pm.h | 24 ++ arch/powerpc/kernel/asm-offsets.c | 12 + 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 | 278 ++ arch/powerpc/platforms/85xx/qoriq_pm.c| 25 ++ arch/powerpc/platforms/85xx/t104x_deepsleep.S | 531 ++ arch/powerpc/sysdev/fsl_rcpm.c| 8 +- 9 files changed, 889 insertions(+), 2 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 e05049b..48c2631 100644 --- a/arch/powerpc/include/asm/fsl_pm.h +++ b/arch/powerpc/include/asm/fsl_pm.h @@ -20,6 +20,7 @@ #define PLAT_PM_SLEEP 20 #define PLAT_PM_LPM20 30 +#define PLAT_PM_LPM35 40 #define FSL_PM_SLEEP (1 << 0) #define FSL_PM_DEEP_SLEEP (1 << 1) @@ -48,4 +49,27 @@ extern const struct fsl_pm_ops *qoriq_pm_ops; int __init fsl_rcpm_init(void); +#ifdef CONFIG_FSL_QORIQ_PM +int fsl_enter_deepsleep(void); +int fsl_deepsleep_init(void); +#else +static inline int fsl_enter_deepsleep(void) { return -1; } +static inline int fsl_deepsleep_init(void) { return -1; } +#endif + +extern void fsl_dp_enter_low(void *priv); +extern void fsl_booke_deep_sleep_resume(void); + +struct fsl_iomap { + void *ccsr_scfg_base; + void *ccsr_rcpm_base; + void *ccsr_ddr_base; + void *ccsr_gpio1_base; + void *ccsr_cpc_base; + void *dcsr_epu_base; + void *dcsr_npc_base; + void *dcsr_rcpm_base; + void *cpld_base; + void *fpga_base; +}; #endif /* __PPC_FSL_PM_H */ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 9ea0955..cc488f9 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -68,6 +68,10 @@ #include "../mm/mmu_decl.h" #endif +#ifdef CONFIG_FSL_QORIQ_PM +#include +#endif + int main(void) { DEFINE(THREAD, offsetof(struct task_struct, thread)); @@ -783,5 +787,13 @@ int main(void) DEFINE(PPC_DBELL_SERVER, PPC_DBELL_SERVER); +#ifdef CONFIG_FSL_QORIQ_PM + DEFINE(CCSR_CPC_BASE, offsetof(struct fsl_iomap, ccsr_cpc_base)); + DEFINE(CCSR_GPIO1_BASE, offsetof(struct fsl_iomap, ccsr_gpio1_base)); + DEFINE(CCSR_RCPM_BASE, offsetof(struct fsl_iomap, ccsr_rcpm_base)); + DEFINE(CCSR_DDR_BASE, offsetof(struct fsl_iomap, ccsr_ddr_base)); + DEFINE(CCSR_SCFG_BASE, offsetof(struct fsl_iomap, ccsr_scfg_base)); + DEFINE(DCSR_EPU_BASE, offsetof(struct fsl_iomap, dcsr_epu_base)); +#endif return 0; } diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S index 83dd0f6..659b059 100644 --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S @@ -173,6 +173,10 @@ skpinv:addir6,r6,1 /* Increment */ lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@h ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@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 @@ -215,12 +219,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 2d14774..21fa124 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -829,7 +829,7 @@ _GLOBAL(start_secondary_resume) /* * This sub
[PATCH v3 1/5] powerpc/dts: add mcke-gpios for PM feature
Signed-off-by: Chenhui Zhao <chenhui.z...@nxp.com> --- Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 13 + arch/powerpc/boot/dts/fsl/t1040si-post.dtsi| 3 +++ 2 files changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt index e284e4e..1d44a80 100644 --- a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt +++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt @@ -21,6 +21,10 @@ Required properites: * "fsl,qoriq-rcpm-2.0": for chassis 2.0 rcpm * "fsl,qoriq-rcpm-2.1": for chassis 2.1 rcpm +Optional properites: + - mcke-gpios : The GPIO pin is used for keeping the MCKE signal of DDR modules +low in the LPM35 state on some platforms, such as T1040. + All references to "1.0" and "2.0" refer to the QorIQ chassis version to which the chip complies. Chassis VersionExample Chips @@ -37,6 +41,15 @@ The RCPM node for T4240: fsl,#rcpm-wakeup-cells = <2>; }; +The RCPM node for T1040 (which supports LPM35 state): + rcpm: global-utilities@e2000 { + compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1"; + reg = <0xe2000 0x1000>; + fsl,#rcpm-wakeup-cells = <1>; + mcke-gpios = < 29 GPIO_ACTIVE_HIGH> + }; + + * Freescale RCPM Wakeup Source Device Tree Bindings --- Required fsl,rcpm-wakeup property should be added to a device node if the device diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi index 507649e..f66e7dd 100644 --- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi @@ -33,6 +33,7 @@ */ #include +#include _fbpr { compatible = "fsl,bman-fbpr"; @@ -474,6 +475,8 @@ rcpm: global-utilities@e2000 { compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1"; reg = <0xe2000 0x1000>; + fsl,#rcpm-wakeup-cells = <1>; + mcke-gpios = < 29 GPIO_ACTIVE_HIGH>; }; sfp: sfp@e8000 { -- 1.9.1
[PATCH v3 1/5] powerpc/dts: add mcke-gpios for PM feature
Signed-off-by: Chenhui Zhao --- Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 13 + arch/powerpc/boot/dts/fsl/t1040si-post.dtsi| 3 +++ 2 files changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt index e284e4e..1d44a80 100644 --- a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt +++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt @@ -21,6 +21,10 @@ Required properites: * "fsl,qoriq-rcpm-2.0": for chassis 2.0 rcpm * "fsl,qoriq-rcpm-2.1": for chassis 2.1 rcpm +Optional properites: + - mcke-gpios : The GPIO pin is used for keeping the MCKE signal of DDR modules +low in the LPM35 state on some platforms, such as T1040. + All references to "1.0" and "2.0" refer to the QorIQ chassis version to which the chip complies. Chassis VersionExample Chips @@ -37,6 +41,15 @@ The RCPM node for T4240: fsl,#rcpm-wakeup-cells = <2>; }; +The RCPM node for T1040 (which supports LPM35 state): + rcpm: global-utilities@e2000 { + compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1"; + reg = <0xe2000 0x1000>; + fsl,#rcpm-wakeup-cells = <1>; + mcke-gpios = < 29 GPIO_ACTIVE_HIGH> + }; + + * Freescale RCPM Wakeup Source Device Tree Bindings --- Required fsl,rcpm-wakeup property should be added to a device node if the device diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi index 507649e..f66e7dd 100644 --- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi @@ -33,6 +33,7 @@ */ #include +#include _fbpr { compatible = "fsl,bman-fbpr"; @@ -474,6 +475,8 @@ rcpm: global-utilities@e2000 { compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1"; reg = <0xe2000 0x1000>; + fsl,#rcpm-wakeup-cells = <1>; + mcke-gpios = < 29 GPIO_ACTIVE_HIGH>; }; sfp: sfp@e8000 { -- 1.9.1
[PATCH v3 4/5] 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 | 24 ++ arch/powerpc/kernel/asm-offsets.c | 12 + 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 | 278 ++ arch/powerpc/platforms/85xx/qoriq_pm.c| 25 ++ arch/powerpc/platforms/85xx/t104x_deepsleep.S | 531 ++ arch/powerpc/sysdev/fsl_rcpm.c| 8 +- 9 files changed, 889 insertions(+), 2 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 e05049b..48c2631 100644 --- a/arch/powerpc/include/asm/fsl_pm.h +++ b/arch/powerpc/include/asm/fsl_pm.h @@ -20,6 +20,7 @@ #define PLAT_PM_SLEEP 20 #define PLAT_PM_LPM20 30 +#define PLAT_PM_LPM35 40 #define FSL_PM_SLEEP (1 << 0) #define FSL_PM_DEEP_SLEEP (1 << 1) @@ -48,4 +49,27 @@ extern const struct fsl_pm_ops *qoriq_pm_ops; int __init fsl_rcpm_init(void); +#ifdef CONFIG_FSL_QORIQ_PM +int fsl_enter_deepsleep(void); +int fsl_deepsleep_init(void); +#else +static inline int fsl_enter_deepsleep(void) { return -1; } +static inline int fsl_deepsleep_init(void) { return -1; } +#endif + +extern void fsl_dp_enter_low(void *priv); +extern void fsl_booke_deep_sleep_resume(void); + +struct fsl_iomap { + void *ccsr_scfg_base; + void *ccsr_rcpm_base; + void *ccsr_ddr_base; + void *ccsr_gpio1_base; + void *ccsr_cpc_base; + void *dcsr_epu_base; + void *dcsr_npc_base; + void *dcsr_rcpm_base; + void *cpld_base; + void *fpga_base; +}; #endif /* __PPC_FSL_PM_H */ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 9ea0955..cc488f9 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -68,6 +68,10 @@ #include "../mm/mmu_decl.h" #endif +#ifdef CONFIG_FSL_QORIQ_PM +#include +#endif + int main(void) { DEFINE(THREAD, offsetof(struct task_struct, thread)); @@ -783,5 +787,13 @@ int main(void) DEFINE(PPC_DBELL_SERVER, PPC_DBELL_SERVER); +#ifdef CONFIG_FSL_QORIQ_PM + DEFINE(CCSR_CPC_BASE, offsetof(struct fsl_iomap, ccsr_cpc_base)); + DEFINE(CCSR_GPIO1_BASE, offsetof(struct fsl_iomap, ccsr_gpio1_base)); + DEFINE(CCSR_RCPM_BASE, offsetof(struct fsl_iomap, ccsr_rcpm_base)); + DEFINE(CCSR_DDR_BASE, offsetof(struct fsl_iomap, ccsr_ddr_base)); + DEFINE(CCSR_SCFG_BASE, offsetof(struct fsl_iomap, ccsr_scfg_base)); + DEFINE(DCSR_EPU_BASE, offsetof(struct fsl_iomap, dcsr_epu_base)); +#endif return 0; } diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S index 83dd0f6..659b059 100644 --- a/arch/powerpc/kernel/fsl_booke_entry_mapping.S +++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S @@ -173,6 +173,10 @@ skpinv:addir6,r6,1 /* Increment */ lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@h ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_NEEDED)@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 @@ -215,12 +219,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 2d14774..21fa124 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -829,7 +829,7 @@ _GLOBAL(start_secondary_resume) /* * This subroutine clobbers r11 and r12
[PATCH 2/2] soc: nxp: Add a RCPM driver
The NXP's QorIQ Processors based on ARM Core have a RCPM module (Run Control and Power Management), which performs all device-level tasks associated with power management. This patch mainly implements the wakeup sources configuration before entering LPM20, a low power state of device-level. The devices can be waked up by specified sources, such as Flextimer, GPIO and so on. Signed-off-by: Chenhui Zhao <chenhui.z...@nxp.com> --- drivers/soc/fsl/Makefile | 1 + drivers/soc/fsl/pm/Makefile | 1 + drivers/soc/fsl/pm/ls-rcpm.c | 144 +++ 3 files changed, 146 insertions(+) create mode 100644 drivers/soc/fsl/pm/Makefile create mode 100644 drivers/soc/fsl/pm/ls-rcpm.c diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile index 203307f..b5adbaf 100644 --- a/drivers/soc/fsl/Makefile +++ b/drivers/soc/fsl/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_QUICC_ENGINE) += qe/ obj-$(CONFIG_CPM) += qe/ +obj-$(CONFIG_SUSPEND) += pm/ diff --git a/drivers/soc/fsl/pm/Makefile b/drivers/soc/fsl/pm/Makefile new file mode 100644 index 000..e275d63 --- /dev/null +++ b/drivers/soc/fsl/pm/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ARCH_LAYERSCAPE) += ls-rcpm.o diff --git a/drivers/soc/fsl/pm/ls-rcpm.c b/drivers/soc/fsl/pm/ls-rcpm.c new file mode 100644 index 000..c5f2b97 --- /dev/null +++ b/drivers/soc/fsl/pm/ls-rcpm.c @@ -0,0 +1,144 @@ +/* + * Run Control and Power Management (RCPM) driver + * + * Copyright 2016 Freescale Semiconductor, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#define pr_fmt(fmt) "RCPM: %s: " fmt, __func__ + +#include +#include +#include +#include +#include + +/* So far there are not more than two registers */ +#define RCPM_IPPDEXPCR00x140 +#define RCPM_IPPDEXPCR10x144 +#define RCPM_IPPDEXPCR(x) (RCPM_IPPDEXPCR0 + 4 * x) +#define RCPM_WAKEUP_CELL_MAX_SIZE 2 + +/* it reprents the number of the registers RCPM_IPPDEXPCR */ +static unsigned int rcpm_wakeup_cells; +static void __iomem *rcpm_reg_base; +static u32 ippdexpcr[RCPM_WAKEUP_CELL_MAX_SIZE]; + +static inline void rcpm_reg_write(u32 offset, u32 value) +{ + iowrite32be(value, rcpm_reg_base + offset); +} + +static inline u32 rcpm_reg_read(u32 offset) +{ + return ioread32be(rcpm_reg_base + offset); +} + +static void rcpm_wakeup_fixup(struct device *dev, void *data) +{ + struct device_node *node = dev ? dev->of_node : NULL; + u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1]; + int ret; + int i; + + if (!dev || !node || !device_may_wakeup(dev)) + return; + + /* +* Get the values in the "rcpm-wakeup" property. +* Refer to Documentation/devicetree/bindings/soc/fsl/rcpm.txt +*/ + ret = of_property_read_u32_array(node, "rcpm-wakeup", +value, rcpm_wakeup_cells + 1); + if (ret) + return; + + pr_debug("wakeup source: the device %s\n", node->full_name); + + for (i = 0; i < rcpm_wakeup_cells; i++) + ippdexpcr[i] |= value[i + 1]; +} + +static int rcpm_suspend_prepare(void) +{ + int i; + + for (i = 0; i < rcpm_wakeup_cells; i++) + ippdexpcr[i] = 0; + + dpm_for_each_dev(NULL, rcpm_wakeup_fixup); + + for (i = 0; i < rcpm_wakeup_cells; i++) { + rcpm_reg_write(RCPM_IPPDEXPCR(i), ippdexpcr[i]); + pr_debug("ippdexpcr%d = 0x%x\n", i, ippdexpcr[i]); + } + + return 0; +} + +static int rcpm_suspend_notifier_call(struct notifier_block *bl, + unsigned long state, + void *unused) +{ + switch (state) { + case PM_SUSPEND_PREPARE: + rcpm_suspend_prepare(); + break; + } + + return NOTIFY_DONE; +} + +static const struct of_device_id rcpm_matches[] = { + { + .compatible = "fsl,qoriq-rcpm-2.1", + }, + {} +}; + +static struct notifier_block rcpm_suspend_notifier = { + .notifier_call = rcpm_suspend_notifier_call, +}; + +static int __init layerscape_rcpm_init(void) +{ + struct device_node *np; + int ret; + + np = of_find_matching_node_and_match(NULL, rcpm_matches, NULL); + if (!np) + return -E
[PATCH 2/2] soc: nxp: Add a RCPM driver
The NXP's QorIQ Processors based on ARM Core have a RCPM module (Run Control and Power Management), which performs all device-level tasks associated with power management. This patch mainly implements the wakeup sources configuration before entering LPM20, a low power state of device-level. The devices can be waked up by specified sources, such as Flextimer, GPIO and so on. Signed-off-by: Chenhui Zhao --- drivers/soc/fsl/Makefile | 1 + drivers/soc/fsl/pm/Makefile | 1 + drivers/soc/fsl/pm/ls-rcpm.c | 144 +++ 3 files changed, 146 insertions(+) create mode 100644 drivers/soc/fsl/pm/Makefile create mode 100644 drivers/soc/fsl/pm/ls-rcpm.c diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile index 203307f..b5adbaf 100644 --- a/drivers/soc/fsl/Makefile +++ b/drivers/soc/fsl/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_QUICC_ENGINE) += qe/ obj-$(CONFIG_CPM) += qe/ +obj-$(CONFIG_SUSPEND) += pm/ diff --git a/drivers/soc/fsl/pm/Makefile b/drivers/soc/fsl/pm/Makefile new file mode 100644 index 000..e275d63 --- /dev/null +++ b/drivers/soc/fsl/pm/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ARCH_LAYERSCAPE) += ls-rcpm.o diff --git a/drivers/soc/fsl/pm/ls-rcpm.c b/drivers/soc/fsl/pm/ls-rcpm.c new file mode 100644 index 000..c5f2b97 --- /dev/null +++ b/drivers/soc/fsl/pm/ls-rcpm.c @@ -0,0 +1,144 @@ +/* + * Run Control and Power Management (RCPM) driver + * + * Copyright 2016 Freescale Semiconductor, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#define pr_fmt(fmt) "RCPM: %s: " fmt, __func__ + +#include +#include +#include +#include +#include + +/* So far there are not more than two registers */ +#define RCPM_IPPDEXPCR00x140 +#define RCPM_IPPDEXPCR10x144 +#define RCPM_IPPDEXPCR(x) (RCPM_IPPDEXPCR0 + 4 * x) +#define RCPM_WAKEUP_CELL_MAX_SIZE 2 + +/* it reprents the number of the registers RCPM_IPPDEXPCR */ +static unsigned int rcpm_wakeup_cells; +static void __iomem *rcpm_reg_base; +static u32 ippdexpcr[RCPM_WAKEUP_CELL_MAX_SIZE]; + +static inline void rcpm_reg_write(u32 offset, u32 value) +{ + iowrite32be(value, rcpm_reg_base + offset); +} + +static inline u32 rcpm_reg_read(u32 offset) +{ + return ioread32be(rcpm_reg_base + offset); +} + +static void rcpm_wakeup_fixup(struct device *dev, void *data) +{ + struct device_node *node = dev ? dev->of_node : NULL; + u32 value[RCPM_WAKEUP_CELL_MAX_SIZE + 1]; + int ret; + int i; + + if (!dev || !node || !device_may_wakeup(dev)) + return; + + /* +* Get the values in the "rcpm-wakeup" property. +* Refer to Documentation/devicetree/bindings/soc/fsl/rcpm.txt +*/ + ret = of_property_read_u32_array(node, "rcpm-wakeup", +value, rcpm_wakeup_cells + 1); + if (ret) + return; + + pr_debug("wakeup source: the device %s\n", node->full_name); + + for (i = 0; i < rcpm_wakeup_cells; i++) + ippdexpcr[i] |= value[i + 1]; +} + +static int rcpm_suspend_prepare(void) +{ + int i; + + for (i = 0; i < rcpm_wakeup_cells; i++) + ippdexpcr[i] = 0; + + dpm_for_each_dev(NULL, rcpm_wakeup_fixup); + + for (i = 0; i < rcpm_wakeup_cells; i++) { + rcpm_reg_write(RCPM_IPPDEXPCR(i), ippdexpcr[i]); + pr_debug("ippdexpcr%d = 0x%x\n", i, ippdexpcr[i]); + } + + return 0; +} + +static int rcpm_suspend_notifier_call(struct notifier_block *bl, + unsigned long state, + void *unused) +{ + switch (state) { + case PM_SUSPEND_PREPARE: + rcpm_suspend_prepare(); + break; + } + + return NOTIFY_DONE; +} + +static const struct of_device_id rcpm_matches[] = { + { + .compatible = "fsl,qoriq-rcpm-2.1", + }, + {} +}; + +static struct notifier_block rcpm_suspend_notifier = { + .notifier_call = rcpm_suspend_notifier_call, +}; + +static int __init layerscape_rcpm_init(void) +{ + struct device_node *np; + int ret; + + np = of_find_matching_node_and_match(NULL, rcpm_matches, NULL); + if (!np) + return -ENODEV; + + ret = of_property_read_u32_index(np, "fsl,#rcpm-wakeup-cel
[PATCH 1/2] ARM: dts: ls1043a: add a rcpm node
LS1043A have a RCPM module (Run Control and Power Management), which performs all device-level tasks associated with power management. Signed-off-by: Chenhui Zhao <chenhui.z...@nxp.com> --- arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 ++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index de0323b..43944b7 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -196,6 +196,12 @@ bus-width = <4>; }; + rcpm: rcpm@1ee2000 { + compatible = "fsl,ls1043a-rcpm", "fsl,qoriq-rcpm-2.1"; + reg = <0x0 0x1ee2000 0x0 0x1000>; + fsl,#rcpm-wakeup-cells = <1>; + }; + dspi0: dspi@210 { compatible = "fsl,ls1043a-dspi", "fsl,ls1021a-v1.0-dspi"; #address-cells = <1>; -- 1.9.1
[PATCH 1/2] ARM: dts: ls1043a: add a rcpm node
LS1043A have a RCPM module (Run Control and Power Management), which performs all device-level tasks associated with power management. Signed-off-by: Chenhui Zhao --- arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 ++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index de0323b..43944b7 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -196,6 +196,12 @@ bus-width = <4>; }; + rcpm: rcpm@1ee2000 { + compatible = "fsl,ls1043a-rcpm", "fsl,qoriq-rcpm-2.1"; + reg = <0x0 0x1ee2000 0x0 0x1000>; + fsl,#rcpm-wakeup-cells = <1>; + }; + dspi0: dspi@210 { compatible = "fsl,ls1043a-dspi", "fsl,ls1021a-v1.0-dspi"; #address-cells = <1>; -- 1.9.1
[PATCH] powerpc/dts: fix rcpm compatible string
For T1040, T1042, T1023, and T1024, they should use the compatible string "fsl,qoriq-rcpm-2.1". Signed-off-by: Chenhui Zhao <chenhui.z...@nxp.com> --- arch/powerpc/boot/dts/fsl/t1023si-post.dtsi | 2 +- arch/powerpc/boot/dts/fsl/t1040si-post.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi index 99e421d..6e0b489 100644 --- a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi @@ -263,7 +263,7 @@ }; rcpm: global-utilities@e2000 { - compatible = "fsl,t1023-rcpm", "fsl,qoriq-rcpm-2.0"; + compatible = "fsl,t1023-rcpm", "fsl,qoriq-rcpm-2.1"; reg = <0xe2000 0x1000>; }; diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi index e0f4da5..507649e 100644 --- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi @@ -472,7 +472,7 @@ }; rcpm: global-utilities@e2000 { - compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.0"; + compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1"; reg = <0xe2000 0x1000>; }; -- 1.9.1
[PATCH] powerpc/dts: fix rcpm compatible string
For T1040, T1042, T1023, and T1024, they should use the compatible string "fsl,qoriq-rcpm-2.1". Signed-off-by: Chenhui Zhao --- arch/powerpc/boot/dts/fsl/t1023si-post.dtsi | 2 +- arch/powerpc/boot/dts/fsl/t1040si-post.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi index 99e421d..6e0b489 100644 --- a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi @@ -263,7 +263,7 @@ }; rcpm: global-utilities@e2000 { - compatible = "fsl,t1023-rcpm", "fsl,qoriq-rcpm-2.0"; + compatible = "fsl,t1023-rcpm", "fsl,qoriq-rcpm-2.1"; reg = <0xe2000 0x1000>; }; diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi index e0f4da5..507649e 100644 --- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi @@ -472,7 +472,7 @@ }; rcpm: global-utilities@e2000 { - compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.0"; + compatible = "fsl,t1040-rcpm", "fsl,qoriq-rcpm-2.1"; reg = <0xe2000 0x1000>; }; -- 1.9.1
[PATCH v4 1/6] powerpc/mm: any thread in one core can be the first to setup TLB1
On e6500, in the case of cpu hotplug, either thread in one core may be the first thread initilzing the TLB1. The subsequent threads must not setup it again. The code is derived from the comment of Scott Wood. Signed-off-by: Chenhui Zhao --- Changes for v4: * added CONFIG_BOOKE arch/powerpc/include/asm/cputhreads.h | 8 arch/powerpc/mm/tlb_nohash.c | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h index ba42e46..ea96231 100644 --- a/arch/powerpc/include/asm/cputhreads.h +++ b/arch/powerpc/include/asm/cputhreads.h @@ -94,6 +94,14 @@ static inline int cpu_last_thread_sibling(int cpu) return cpu | (threads_per_core - 1); } +static inline u32 get_tensr(void) +{ +#ifdef CONFIG_BOOKE + if (cpu_has_feature(CPU_FTR_SMT)) + return mfspr(SPRN_TENSR); +#endif + return 1; +} #endif /* _ASM_POWERPC_CPUTHREADS_H */ diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index bb04e4d..f466848 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -640,9 +640,7 @@ static void early_init_this_mmu(void) * transient mapping would cause problems. */ #ifdef CONFIG_SMP - if (cpu != boot_cpuid && - (cpu != cpu_first_thread_sibling(cpu) || -cpu == cpu_first_thread_sibling(boot_cpuid))) + if (hweight32(get_tensr()) > 1) map = false; #endif -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v4 1/6] powerpc/mm: any thread in one core can be the first to setup TLB1
On e6500, in the case of cpu hotplug, either thread in one core may be the first thread initilzing the TLB1. The subsequent threads must not setup it again. The code is derived from the comment of Scott Wood. Signed-off-by: Chenhui Zhao <chenhui.z...@freescale.com> --- Changes for v4: * added CONFIG_BOOKE arch/powerpc/include/asm/cputhreads.h | 8 arch/powerpc/mm/tlb_nohash.c | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h index ba42e46..ea96231 100644 --- a/arch/powerpc/include/asm/cputhreads.h +++ b/arch/powerpc/include/asm/cputhreads.h @@ -94,6 +94,14 @@ static inline int cpu_last_thread_sibling(int cpu) return cpu | (threads_per_core - 1); } +static inline u32 get_tensr(void) +{ +#ifdef CONFIG_BOOKE + if (cpu_has_feature(CPU_FTR_SMT)) + return mfspr(SPRN_TENSR); +#endif + return 1; +} #endif /* _ASM_POWERPC_CPUTHREADS_H */ diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index bb04e4d..f466848 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -640,9 +640,7 @@ static void early_init_this_mmu(void) * transient mapping would cause problems. */ #ifdef CONFIG_SMP - if (cpu != boot_cpuid && - (cpu != cpu_first_thread_sibling(cpu) || -cpu == cpu_first_thread_sibling(boot_cpuid))) + if (hweight32(get_tensr()) > 1) map = false; #endif -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v2,5/5] PowerPC/mpc85xx: Add CPU hotplug support for E6500
On Thu, Aug 27, 2015 at 6:42 AM, Scott Wood wrote: On Wed, Aug 26, 2015 at 08:09:48PM +0800, Chenhui Zhao wrote: + .globl booting_thread_hwid +booting_thread_hwid: + .long INVALID_THREAD_HWID + .align 3 The commit message goes into no detail about the changes you're making to thread handling, nor are there relevant comments. OK. Will add some comments. +/* + * r3 = the thread physical id + */ +_GLOBAL(book3e_stop_thread) + li r4, 1 + sld r4, r4, r3 + mtspr SPRN_TENC, r4 + isync + blr Why did the C code not have an isync, if it's required here? Just make sure "mtspr" has completed before the routine returns. _GLOBAL(fsl_secondary_thread_init) /* Enable branch prediction */ lis r3,BUCSR_INIT@h @@ -197,8 +236,10 @@ _GLOBAL(fsl_secondary_thread_init) * but the low bit right by two bits so that the cpu numbering is * continuous. */ - mfspr r3, SPRN_PIR - rlwimi r3, r3, 30, 2, 30 + bl 10f +10: mflrr5 + addir5,r5,(booting_thread_hwid - 10b) + lwz r3,0(r5) mtspr SPRN_PIR, r3 #endif I assume the reason for this is that, unlike the kexec case, the cpu has been reset so PIR has been reset? Don't make me guess -- document. We can not rely on the value saved in SPRN_PIR. Every time running fsl_secondary_thread_init, SPRN_PIR may not always has a reset value. Using booting_thread_hwid to ensure SPRN_PIR has a correct value. @@ -245,6 +286,30 @@ _GLOBAL(generic_secondary_smp_init) mr r3,r24 mr r4,r25 bl book3e_secondary_core_init + +/* + * If we want to boot Thread1, start Thread1 and stop Thread0. + * Note that only Thread0 will run the piece of code. + */ What ensures that only thread 0 runs this? Especially if we're entering via kdump on thread 1? This piece of code will be executed only when core resets (Thead0 will start first). Thead1 will run fsl_secondary_thread_init() to start. How can kdump run this on Thread1? I know little about kexec. s/the piece/this piece/ + LOAD_REG_ADDR(r3, booting_thread_hwid) + lwz r4, 0(r3) + cmpwi r4, INVALID_THREAD_HWID + beq 20f + cmpwr4, r24 + beq 20f Do all cores get released from the spin table before the first thread gets kicked? Yes. + + /* start Thread1 */ + LOAD_REG_ADDR(r5, fsl_secondary_thread_init) + ld r4, 0(r5) + li r3, 1 + bl book3e_start_thread + + /* stop Thread0 */ + li r3, 0 + bl book3e_stop_thread +10: + b 10b +20: #endif generic_secondary_common_init: diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 73eb994..61f68ad 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -181,17 +181,11 @@ static inline u32 read_spin_table_addr_l(void *spin_table) static void wake_hw_thread(void *info) { void fsl_secondary_thread_init(void); - unsigned long imsr1, inia1; - int nr = *(const int *)info; + unsigned long inia; + int hw_cpu = get_hard_smp_processor_id(*(const int *)info); - imsr1 = MSR_KERNEL; - inia1 = *(unsigned long *)fsl_secondary_thread_init; - - mttmr(TMRN_IMSR1, imsr1); - mttmr(TMRN_INIA1, inia1); - mtspr(SPRN_TENS, TEN_THREAD(1)); - - smp_generic_kick_cpu(nr); + inia = *(unsigned long *)fsl_secondary_thread_init; + book3e_start_thread(cpu_thread_in_core(hw_cpu), inia); } #endif @@ -279,7 +273,6 @@ static int smp_85xx_kick_cpu(int nr) int ret = 0; #ifdef CONFIG_PPC64 int primary = nr; - int primary_hw = get_hard_smp_processor_id(primary); #endif WARN_ON(nr < 0 || nr >= num_possible_cpus()); @@ -287,33 +280,43 @@ static int smp_85xx_kick_cpu(int nr) pr_debug("kick CPU #%d\n", nr); #ifdef CONFIG_PPC64 + booting_thread_hwid = INVALID_THREAD_HWID; /* Threads don't use the spin table */ - if (cpu_thread_in_core(nr) != 0) { - int primary = cpu_first_thread_sibling(nr); + if (threads_per_core == 2) { + booting_thread_hwid = get_hard_smp_processor_id(nr); What does setting booting_thread_hwid to INVALID_THREAD_HWID here accomplish? If threads_per_core != 2 it would never have been set to anything else, and if threads_per_core == 2 you immediately overwrite it. booting_thread_hwid is valid only for the case that one core has two threads (e6500). For e5500 and e500mc, one core one thread, "booting_thread_hwid" is invalid. "booting_thread_hwid" will determine starting which thread in generic_secondary_smp_init(). + primary = cpu_first_thread_sibling(nr);
Re: [PATCH v2,4/5] PowerPC/mpc85xx: Add hotplug support on E5500 and E500MC cores
On Thu, Aug 27, 2015 at 4:55 AM, Scott Wood wrote: On Wed, Aug 26, 2015 at 08:09:47PM +0800, Chenhui Zhao wrote: +int check_cpu_dead(unsigned int cpu) +{ + return per_cpu(cpu_state, cpu) == CPU_DEAD; +} I'm not sure this needs to be a function versus open-coded, but if you do want to make it a function, make it more obvious from the caller side by changing it to: bool is_cpu_dead(unsigned int cpu); Otherwise if I see "if (check_cpu_dead(cpu))" I don't know if the if-block is executed if the CPU is dead or if it isn't. OK. diff --git a/arch/powerpc/platforms/85xx/smp.h b/arch/powerpc/platforms/85xx/smp.h index 0b20ae3..8ee19a3 100644 --- a/arch/powerpc/platforms/85xx/smp.h +++ b/arch/powerpc/platforms/85xx/smp.h @@ -6,6 +6,7 @@ #ifdef CONFIG_SMP void __init mpc85xx_smp_init(void); int __init mpc85xx_setup_pmc(void); +int __init fsl_rcpm_init(void); #else Why wasn't this added in the patch that added fsl_rcpm_init()? -Scott Will move it to there. Thanks, -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v2,5/5] PowerPC/mpc85xx: Add CPU hotplug support for E6500
On Thu, Aug 27, 2015 at 6:42 AM, Scott Wood scottw...@freescale.com wrote: On Wed, Aug 26, 2015 at 08:09:48PM +0800, Chenhui Zhao wrote: + .globl booting_thread_hwid +booting_thread_hwid: + .long INVALID_THREAD_HWID + .align 3 The commit message goes into no detail about the changes you're making to thread handling, nor are there relevant comments. OK. Will add some comments. +/* + * r3 = the thread physical id + */ +_GLOBAL(book3e_stop_thread) + li r4, 1 + sld r4, r4, r3 + mtspr SPRN_TENC, r4 + isync + blr Why did the C code not have an isync, if it's required here? Just make sure mtspr has completed before the routine returns. _GLOBAL(fsl_secondary_thread_init) /* Enable branch prediction */ lis r3,BUCSR_INIT@h @@ -197,8 +236,10 @@ _GLOBAL(fsl_secondary_thread_init) * but the low bit right by two bits so that the cpu numbering is * continuous. */ - mfspr r3, SPRN_PIR - rlwimi r3, r3, 30, 2, 30 + bl 10f +10: mflrr5 + addir5,r5,(booting_thread_hwid - 10b) + lwz r3,0(r5) mtspr SPRN_PIR, r3 #endif I assume the reason for this is that, unlike the kexec case, the cpu has been reset so PIR has been reset? Don't make me guess -- document. We can not rely on the value saved in SPRN_PIR. Every time running fsl_secondary_thread_init, SPRN_PIR may not always has a reset value. Using booting_thread_hwid to ensure SPRN_PIR has a correct value. @@ -245,6 +286,30 @@ _GLOBAL(generic_secondary_smp_init) mr r3,r24 mr r4,r25 bl book3e_secondary_core_init + +/* + * If we want to boot Thread1, start Thread1 and stop Thread0. + * Note that only Thread0 will run the piece of code. + */ What ensures that only thread 0 runs this? Especially if we're entering via kdump on thread 1? This piece of code will be executed only when core resets (Thead0 will start first). Thead1 will run fsl_secondary_thread_init() to start. How can kdump run this on Thread1? I know little about kexec. s/the piece/this piece/ + LOAD_REG_ADDR(r3, booting_thread_hwid) + lwz r4, 0(r3) + cmpwi r4, INVALID_THREAD_HWID + beq 20f + cmpwr4, r24 + beq 20f Do all cores get released from the spin table before the first thread gets kicked? Yes. + + /* start Thread1 */ + LOAD_REG_ADDR(r5, fsl_secondary_thread_init) + ld r4, 0(r5) + li r3, 1 + bl book3e_start_thread + + /* stop Thread0 */ + li r3, 0 + bl book3e_stop_thread +10: + b 10b +20: #endif generic_secondary_common_init: diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 73eb994..61f68ad 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -181,17 +181,11 @@ static inline u32 read_spin_table_addr_l(void *spin_table) static void wake_hw_thread(void *info) { void fsl_secondary_thread_init(void); - unsigned long imsr1, inia1; - int nr = *(const int *)info; + unsigned long inia; + int hw_cpu = get_hard_smp_processor_id(*(const int *)info); - imsr1 = MSR_KERNEL; - inia1 = *(unsigned long *)fsl_secondary_thread_init; - - mttmr(TMRN_IMSR1, imsr1); - mttmr(TMRN_INIA1, inia1); - mtspr(SPRN_TENS, TEN_THREAD(1)); - - smp_generic_kick_cpu(nr); + inia = *(unsigned long *)fsl_secondary_thread_init; + book3e_start_thread(cpu_thread_in_core(hw_cpu), inia); } #endif @@ -279,7 +273,6 @@ static int smp_85xx_kick_cpu(int nr) int ret = 0; #ifdef CONFIG_PPC64 int primary = nr; - int primary_hw = get_hard_smp_processor_id(primary); #endif WARN_ON(nr 0 || nr = num_possible_cpus()); @@ -287,33 +280,43 @@ static int smp_85xx_kick_cpu(int nr) pr_debug(kick CPU #%d\n, nr); #ifdef CONFIG_PPC64 + booting_thread_hwid = INVALID_THREAD_HWID; /* Threads don't use the spin table */ - if (cpu_thread_in_core(nr) != 0) { - int primary = cpu_first_thread_sibling(nr); + if (threads_per_core == 2) { + booting_thread_hwid = get_hard_smp_processor_id(nr); What does setting booting_thread_hwid to INVALID_THREAD_HWID here accomplish? If threads_per_core != 2 it would never have been set to anything else, and if threads_per_core == 2 you immediately overwrite it. booting_thread_hwid is valid only for the case that one core has two threads (e6500). For e5500 and e500mc, one core one thread, booting_thread_hwid is invalid. booting_thread_hwid will determine starting which thread in generic_secondary_smp_init(). + primary = cpu_first_thread_sibling(nr); if (WARN_ON_ONCE(!cpu_has_feature(CPU_FTR_SMT
Re: [PATCH v2,4/5] PowerPC/mpc85xx: Add hotplug support on E5500 and E500MC cores
On Thu, Aug 27, 2015 at 4:55 AM, Scott Wood scottw...@freescale.com wrote: On Wed, Aug 26, 2015 at 08:09:47PM +0800, Chenhui Zhao wrote: +int check_cpu_dead(unsigned int cpu) +{ + return per_cpu(cpu_state, cpu) == CPU_DEAD; +} I'm not sure this needs to be a function versus open-coded, but if you do want to make it a function, make it more obvious from the caller side by changing it to: bool is_cpu_dead(unsigned int cpu); Otherwise if I see if (check_cpu_dead(cpu)) I don't know if the if-block is executed if the CPU is dead or if it isn't. OK. diff --git a/arch/powerpc/platforms/85xx/smp.h b/arch/powerpc/platforms/85xx/smp.h index 0b20ae3..8ee19a3 100644 --- a/arch/powerpc/platforms/85xx/smp.h +++ b/arch/powerpc/platforms/85xx/smp.h @@ -6,6 +6,7 @@ #ifdef CONFIG_SMP void __init mpc85xx_smp_init(void); int __init mpc85xx_setup_pmc(void); +int __init fsl_rcpm_init(void); #else Why wasn't this added in the patch that added fsl_rcpm_init()? -Scott Will move it to there. Thanks, -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v2,3/5] Powerpc: mpc85xx: refactor the PM operations
Freescale CoreNet-based and Non-CoreNet-based platforms require different PM operations. This patch extracted existing PM operations on Non-CoreNet-based platforms to a new file which can accommodate both platforms. In this way, PM operation codes are clearer structurally. Signed-off-by: Chenhui Zhao Signed-off-by: Tang Yuantian --- major changes for v2: * moved mpc85xx_cpu_die() * added qoriq_pm_ops->cpu_die() in smp_85xx_mach_cpu_die(). it puts the dying cpu in a low power mode arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c | 106 +++ arch/powerpc/platforms/85xx/smp.c| 74 +-- arch/powerpc/platforms/85xx/smp.h| 1 + 4 files changed, 127 insertions(+), 55 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 1fe7fb9..7bc86da 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -2,6 +2,7 @@ # Makefile for the PowerPC 85xx linux kernel. # obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c b/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c new file mode 100644 index 000..ed356dd --- /dev/null +++ b/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c @@ -0,0 +1,106 @@ +/* + * MPC85xx PM operators + * + * Copyright 2015 Freescale Semiconductor Inc. + * + * 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. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include + +#include +#include +#include + +static struct ccsr_guts __iomem *guts; + +static void mpc85xx_irq_mask(int cpu) +{ + +} + +static void mpc85xx_irq_unmask(int cpu) +{ + +} + +static void mpc85xx_cpu_die(int cpu) +{ + u32 tmp; + + tmp = (mfspr(SPRN_HID0) & ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP; + mtspr(SPRN_HID0, tmp); + + /* Enter NAP mode. */ + tmp = mfmsr(); + tmp |= MSR_WE; + asm volatile( + "msync\n" + "mtmsr %0\n" + "isync\n" + : + : "r" (tmp)); +} + +static void mpc85xx_cpu_up_prepare(int cpu) +{ + +} + +static void mpc85xx_freeze_time_base(bool freeze) +{ + uint32_t mask; + + mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1; + if (freeze) + setbits32(>devdisr, mask); + else + clrbits32(>devdisr, mask); + + in_be32(>devdisr); +} + +static const struct of_device_id mpc85xx_smp_guts_ids[] = { + { .compatible = "fsl,mpc8572-guts", }, + { .compatible = "fsl,p1020-guts", }, + { .compatible = "fsl,p1021-guts", }, + { .compatible = "fsl,p1022-guts", }, + { .compatible = "fsl,p1023-guts", }, + { .compatible = "fsl,p2020-guts", }, + { .compatible = "fsl,bsc9132-guts", }, + {}, +}; + +static const struct fsl_pm_ops mpc85xx_pm_ops = { + .freeze_time_base = mpc85xx_freeze_time_base, + .irq_mask = mpc85xx_irq_mask, + .irq_unmask = mpc85xx_irq_unmask, + .cpu_die = mpc85xx_cpu_die, + .cpu_up_prepare = mpc85xx_cpu_up_prepare, +}; + +int __init mpc85xx_setup_pmc(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); + if (np) { + guts = of_iomap(np, 0); + of_node_put(np); + if (!guts) { + pr_err("Could not map guts node address\n"); + return -ENOMEM; + } + } + + qoriq_pm_ops = _pm_ops; + + return 0; +} diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 0b75e8e..f9552b8 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -2,7 +2,7 @@ * Author: Andy Fleming *Kumar Gala * - * Copyright 2006-2008, 2011-2012 Freescale Semiconductor Inc. + * Copyright 2006-2008, 2011-2012, 2015 Freescale Semiconductor Inc. * * 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 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -26,9 +25,9 @@ #include #include #include -#include #include #include +#include #include #include @@ -43,24 +42,11 @@ struct epapr_spin_table { u32 pir; }; -static struct ccsr_guts __iomem *
[PATCH v2,2/5] powerpc/rcpm: add RCPM driver
There is a RCPM (Run Control/Power Management) in Freescale QorIQ series processors. The device performs tasks associated with device run control and power management. The driver implements some features: mask/unmask irq, enter/exit low power states, freeze time base, etc. Signed-off-by: Chenhui Zhao Signed-off-by: Tang Yuantian --- major changes for v2: * rcpm_v1_cpu_die() and rcpm_v2_cpu_die() will be executed by the dying cpu. this way, more stable Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 44 +++ arch/powerpc/include/asm/fsl_guts.h| 105 ++ arch/powerpc/include/asm/fsl_pm.h | 50 +++ arch/powerpc/platforms/85xx/Kconfig| 1 + arch/powerpc/platforms/85xx/common.c | 3 + arch/powerpc/sysdev/Kconfig| 5 + arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/fsl_rcpm.c | 390 + 8 files changed, 599 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/rcpm.txt create mode 100644 arch/powerpc/include/asm/fsl_pm.h create mode 100644 arch/powerpc/sysdev/fsl_rcpm.c diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt new file mode 100644 index 000..dc52f70 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt @@ -0,0 +1,44 @@ +* Run Control and Power Management + +The RCPM performs all device-level tasks associated with device run control +and power management. + +Required properites: + - reg : Offset and length of the register set of RCPM block. + - compatible : Sould contain a chip-specific RCPM block compatible string + and (if applicable) may contain a chassis-version RCPM compatible string. + Chip-specific strings are of the form "fsl,-rcpm", such as: + * "fsl,p2041-rcpm" + * "fsl,p3041-rcpm" + * "fsl,p4080-rcpm" + * "fsl,p5020-rcpm" + * "fsl,p5040-rcpm" + * "fsl,t4240-rcpm" + * "fsl,b4420-rcpm" + * "fsl,b4860-rcpm" + + Chassis-version RCPM strings include: + * "fsl,qoriq-rcpm-1.0": for chassis 1.0 rcpm + * "fsl,qoriq-rcpm-2.0": for chassis 2.0 rcpm + * "fsl,qoriq-rcpm-2.1": for chassis 2.1 rcpm + +All references to "1.0" and "2.0" refer to the QorIQ chassis version to +which the chip complies. +Chassis VersionExample Chips +------ +1.0p4080, p5020, p5040, p2041, p3041 +2.0t4240, b4860, b4420 +2.1t1040 + +Example: +The RCPM node for T4240: + rcpm: global-utilities@e2000 { + compatible = "fsl,t4240-rcpm", "fsl,qoriq-rcpm-2.0"; + reg = <0xe2000 0x1000>; + }; + +The RCPM node for P4080: + rcpm: global-utilities@e2000 { + compatible = "fsl,qoriq-rcpm-1.0"; + reg = <0xe2000 0x1000>; + }; diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h index 43b6bb1..a67413c 100644 --- a/arch/powerpc/include/asm/fsl_guts.h +++ b/arch/powerpc/include/asm/fsl_guts.h @@ -188,5 +188,110 @@ static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts, #endif +struct ccsr_rcpm_v1 { + u8 res[4]; + __be32 cdozsr; /* 0x0004 Core Doze Status Register */ + u8 res0008[4]; + __be32 cdozcr; /* 0x000c Core Doze Control Register */ + u8 res0010[4]; + __be32 cnapsr; /* 0x0014 Core Nap Status Register */ + u8 res0018[4]; + __be32 cnapcr; /* 0x001c Core Nap Control Register */ + u8 res0020[4]; + __be32 cdozpsr;/* 0x0024 Core Doze Previous Status Register */ + u8 res0028[4]; + __be32 cnappsr;/* 0x002c Core Nap Previous Status Register */ + u8 res0030[4]; + __be32 cwaitsr;/* 0x0034 Core Wait Status Register */ + u8 res0038[4]; + __be32 cwdtdsr;/* 0x003c Core Watchdog Detect Status Register */ + __be32 powmgtcsr; /* 0x0040 PM Control Register */ +#define RCPM_POWMGTCSR_SLP 0x0002 + u8 res0044[12]; + __be32 ippdexpcr; /* 0x0050 IP Powerdown Exception Control Register */ + u8 res0054[16]; + __be32 cpmimr; /* 0x0064 Core PM IRQ Mask Register */ + u8 res0068[4]; + __be32 cpmcimr;/* 0x006c Core PM Critical IRQ Mask Register */ + u8 res0070[4]; + __be32 cpmmcmr;/* 0x0074 Core PM Machine Check Mask Register */ + u8 res0078[4]; + __be32 cpmnmimr; /* 0x007c Core PM NMI Mask Register */ + u8
[PATCH v2,4/5] PowerPC/mpc85xx: Add hotplug support on E5500 and E500MC cores
Freescale E500MC and E5500 core-based platforms, like P4080, T1040, support disabling/enabling CPU dynamically. This patch adds this feature on those platforms. Signed-off-by: Chenhui Zhao Signed-off-by: Tang Yuantian --- major changes for v2: * factor out smp_85xx_start_cpu() * move fsl_rcpm_init() into mpc85xx_smp_init() due to the init sequence * add hard_irq_disable() after local_irq_save(). for platforms that implement lazy enabling/disabling of interrupts, call hard_irq_disable() to ensure interrupts are disabled physically. arch/powerpc/Kconfig | 2 +- arch/powerpc/include/asm/smp.h| 3 + arch/powerpc/kernel/smp.c | 7 +- arch/powerpc/platforms/85xx/smp.c | 193 ++ arch/powerpc/platforms/85xx/smp.h | 1 + 5 files changed, 122 insertions(+), 84 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 5ef2711..dd9e252 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -386,7 +386,7 @@ config SWIOTLB config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" depends on SMP && (PPC_PSERIES || \ - PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC)) + PPC_PMAC || PPC_POWERNV || FSL_SOC_BOOKE) ---help--- Say Y here to be able to disable and re-enable individual CPUs at runtime on SMP machines. diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 825663c..4ff5b71 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -67,6 +67,9 @@ void generic_cpu_die(unsigned int cpu); void generic_set_cpu_dead(unsigned int cpu); void generic_set_cpu_up(unsigned int cpu); int generic_check_cpu_restart(unsigned int cpu); +int check_cpu_dead(unsigned int cpu); +#else +#define generic_set_cpu_up(i) do { } while (0) #endif #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index ec9ec20..95111f2 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -427,7 +427,7 @@ void generic_cpu_die(unsigned int cpu) for (i = 0; i < 100; i++) { smp_rmb(); - if (per_cpu(cpu_state, cpu) == CPU_DEAD) + if (check_cpu_dead(cpu)) return; msleep(100); } @@ -454,6 +454,11 @@ int generic_check_cpu_restart(unsigned int cpu) return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE; } +int check_cpu_dead(unsigned int cpu) +{ + return per_cpu(cpu_state, cpu) == CPU_DEAD; +} + static bool secondaries_inhibited(void) { return kvm_hv_mode_active(); diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index f9552b8..73eb994 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -10,6 +10,8 @@ * option) any later version. */ +#define pr_fmt(fmt) "smp: %s: " fmt, __func__ + #include #include #include @@ -52,6 +54,7 @@ static void mpc85xx_give_timebase(void) unsigned long flags; local_irq_save(flags); + hard_irq_disable(); while (!tb_req) barrier(); @@ -100,6 +103,7 @@ static void mpc85xx_take_timebase(void) unsigned long flags; local_irq_save(flags); + hard_irq_disable(); tb_req = 1; while (!tb_valid) @@ -135,8 +139,31 @@ static void smp_85xx_mach_cpu_die(void) while (1) ; } + +static void qoriq_cpu_kill(unsigned int cpu) +{ + int i; + + for (i = 0; i < 500; i++) { + if (check_cpu_dead(cpu)) { +#ifdef CONFIG_PPC64 + paca[cpu].cpu_start = 0; +#endif + return; + } + msleep(20); + } + pr_err("CPU%d didn't die...\n", cpu); +} #endif +/* + * To keep it compatible with old boot program which uses + * cache-inhibit spin table, we need to flush the cache + * before accessing spin table to invalidate any staled data. + * We also need to flush the cache after writing to spin + * table to push data out. + */ static inline void flush_spin_table(void *spin_table) { flush_dcache_range((ulong)spin_table, @@ -168,51 +195,20 @@ static void wake_hw_thread(void *info) } #endif -static int smp_85xx_kick_cpu(int nr) +static int smp_85xx_start_cpu(int cpu) { - unsigned long flags; - const u64 *cpu_rel_addr; - __iomem struct epapr_spin_table *spin_table; + int ret = 0; struct device_node *np; - int hw_cpu = get_hard_smp_processor_id(nr); + const u64 *cpu_rel_addr; + unsigned long flags; int ioremappable; - int ret = 0; - - WARN_ON(nr < 0 || nr >= NR_CPUS); - WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS); - - pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr); - -#ifdef CONFIG_PPC64 - /* T
[PATCH v2,5/5] PowerPC/mpc85xx: Add CPU hotplug support for E6500
Support Freescale E6500 core-based platforms, like t4240. Support disabling/enabling individual CPU thread dynamically. Signed-off-by: Chenhui Zhao --- major changes for v2: * start Thread1 by Thread0 when we want to boot Thread1 only replacing the method of changing cpu physical id arch/powerpc/include/asm/cputhreads.h | 9 + arch/powerpc/include/asm/smp.h| 1 + arch/powerpc/kernel/head_64.S | 69 ++- arch/powerpc/platforms/85xx/smp.c | 53 ++- arch/powerpc/sysdev/fsl_rcpm.c| 2 +- 5 files changed, 106 insertions(+), 28 deletions(-) diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h index ba42e46..9920f61 100644 --- a/arch/powerpc/include/asm/cputhreads.h +++ b/arch/powerpc/include/asm/cputhreads.h @@ -1,6 +1,7 @@ #ifndef _ASM_POWERPC_CPUTHREADS_H #define _ASM_POWERPC_CPUTHREADS_H +#ifndef __ASSEMBLY__ #include /* @@ -95,6 +96,14 @@ static inline int cpu_last_thread_sibling(int cpu) } +#ifdef CONFIG_PPC_BOOK3E +void book3e_start_thread(int thread, unsigned long addr); +void book3e_stop_thread(int thread); +#endif + +#endif /* __ASSEMBLY__ */ + +#define INVALID_THREAD_HWID0x0fff #endif /* _ASM_POWERPC_CPUTHREADS_H */ diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 4ff5b71..a1faa4c 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -200,6 +200,7 @@ extern void generic_secondary_thread_init(void); extern unsigned long __secondary_hold_spinloop; extern unsigned long __secondary_hold_acknowledge; extern char __secondary_hold; +extern unsigned int booting_thread_hwid; extern void __early_start(void); #endif /* __ASSEMBLY__ */ diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index d48125d..6df2aa4 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -40,6 +40,7 @@ #include #include #include +#include /* The physical memory is laid out such that the secondary processor * spin code sits at 0x...0x00ff. On server, the vectors follow @@ -181,6 +182,44 @@ exception_marker: #endif #ifdef CONFIG_PPC_BOOK3E + .globl booting_thread_hwid +booting_thread_hwid: + .long INVALID_THREAD_HWID + .align 3 +/* + * start threads in the same cpu + * input parameters: + * r3 = the thread physical id + * r4 = the entry point where thread starts + */ +_GLOBAL(book3e_start_thread) + LOAD_REG_IMMEDIATE(r5, MSR_KERNEL) + cmpi0, r3, 0 + bne 10f + mttmr TMRN_IMSR0, r5 + mttmr TMRN_INIA0, r4 + b 11f +10: + mttmr TMRN_IMSR1, r5 + mttmr TMRN_INIA1, r4 +11: + isync + li r6, 1 + sld r6, r6, r3 + mtspr SPRN_TENS, r6 + isync + blr + +/* + * r3 = the thread physical id + */ +_GLOBAL(book3e_stop_thread) + li r4, 1 + sld r4, r4, r3 + mtspr SPRN_TENC, r4 + isync + blr + _GLOBAL(fsl_secondary_thread_init) /* Enable branch prediction */ lis r3,BUCSR_INIT@h @@ -197,8 +236,10 @@ _GLOBAL(fsl_secondary_thread_init) * but the low bit right by two bits so that the cpu numbering is * continuous. */ - mfspr r3, SPRN_PIR - rlwimi r3, r3, 30, 2, 30 + bl 10f +10:mflrr5 + addir5,r5,(booting_thread_hwid - 10b) + lwz r3,0(r5) mtspr SPRN_PIR, r3 #endif @@ -245,6 +286,30 @@ _GLOBAL(generic_secondary_smp_init) mr r3,r24 mr r4,r25 bl book3e_secondary_core_init + +/* + * If we want to boot Thread1, start Thread1 and stop Thread0. + * Note that only Thread0 will run the piece of code. + */ + LOAD_REG_ADDR(r3, booting_thread_hwid) + lwz r4, 0(r3) + cmpwi r4, INVALID_THREAD_HWID + beq 20f + cmpwr4, r24 + beq 20f + + /* start Thread1 */ + LOAD_REG_ADDR(r5, fsl_secondary_thread_init) + ld r4, 0(r5) + li r3, 1 + bl book3e_start_thread + + /* stop Thread0 */ + li r3, 0 + bl book3e_stop_thread +10: + b 10b +20: #endif generic_secondary_common_init: diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 73eb994..61f68ad 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -181,17 +181,11 @@ static inline u32 read_spin_table_addr_l(void *spin_table) static void wake_hw_thread(void *info) { void fsl_secondary_thread_init(void); - unsigned long imsr1, inia1; - int nr = *(const int *)info; + unsigned long inia; + int hw_cpu = get_hard_smp_processor_id(*(const int *)info); - imsr1 = MSR_KERNEL; - inia1 = *(unsigned long *)fsl_secondary_thread_init; - - mttmr(TMRN_IMSR1, imsr1
[PATCH v2,1/5] powerpc/cache: add cache flush operation for various e500
Various e500 core have different cache architecture, so they need different cache flush operations. Therefore, add a callback function cpu_flush_caches to the struct cpu_spec. The cache flush operation for the specific kind of e500 is selected at init time. The callback function will flush all caches inside the current cpu. Signed-off-by: Chenhui Zhao Signed-off-by: Tang Yuantian --- arch/powerpc/include/asm/cacheflush.h | 2 - arch/powerpc/include/asm/cputable.h | 11 +++ arch/powerpc/kernel/asm-offsets.c | 3 + arch/powerpc/kernel/cpu_setup_fsl_booke.S | 112 ++ arch/powerpc/kernel/cputable.c| 4 ++ arch/powerpc/kernel/head_fsl_booke.S | 74 arch/powerpc/platforms/85xx/smp.c | 5 +- 7 files changed, 133 insertions(+), 78 deletions(-) diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 30b35ff..729fde4 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -30,8 +30,6 @@ extern void flush_dcache_page(struct page *page); #define flush_dcache_mmap_lock(mapping)do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) -extern void __flush_disable_L1(void); - extern void flush_icache_range(unsigned long, unsigned long); extern void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, unsigned long addr, diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index b118072..d89b04a 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -43,6 +43,13 @@ extern int machine_check_e500(struct pt_regs *regs); extern int machine_check_e200(struct pt_regs *regs); extern int machine_check_47x(struct pt_regs *regs); +#if defined(CONFIG_E500) +extern void cpu_down_flush_e500v2(void); +extern void cpu_down_flush_e500mc(void); +extern void cpu_down_flush_e5500(void); +extern void cpu_down_flush_e6500(void); +#endif + /* NOTE WELL: Update identify_cpu() if fields are added or removed! */ struct cpu_spec { /* CPU is matched via (PVR & pvr_mask) == pvr_value */ @@ -59,6 +66,10 @@ struct cpu_spec { unsigned inticache_bsize; unsigned intdcache_bsize; +#if defined(CONFIG_E500) + /* flush caches inside the current cpu */ + void (*cpu_down_flush)(void); +#endif /* number of performance monitor counters */ unsigned intnum_pmcs; enum powerpc_pmc_type pmc_type; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 9823057..17b672d 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -373,6 +373,9 @@ int main(void) DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore)); +#if defined(CONFIG_E500) + DEFINE(CPU_DOWN_FLUSH, offsetof(struct cpu_spec, cpu_down_flush)); +#endif DEFINE(pbe_address, offsetof(struct pbe, address)); DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S index dddba3e..462aed9 100644 --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S @@ -13,11 +13,13 @@ * */ +#include #include #include #include #include #include +#include _GLOBAL(__e500_icache_setup) mfspr r0, SPRN_L1CSR1 @@ -233,3 +235,113 @@ _GLOBAL(__setup_cpu_e5500) mtlrr5 blr #endif + +/* flush L1 date cache, it can apply to e500v2, e500mc and e5500 */ +_GLOBAL(flush_dcache_L1) + mfmsr r10 + wrteei 0 + + mfspr r3,SPRN_L1CFG0 + rlwinm r5,r3,9,3 /* Extract cache block size */ + twlgti r5,1/* Only 32 and 64 byte cache blocks +* are currently defined. +*/ + li r4,32 + subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) - +* log2(number of ways) +*/ + slw r5,r4,r5/* r5 = cache block size */ + + rlwinm r7,r3,0,0xff/* Extract number of KiB in the cache */ + mulli r7,r7,13/* An 8-way cache will require 13 +* loads per set. +*/ + slw r7,r7,r6 + + /* save off HID0 and set DCFA */ + mfspr r8,SPRN_HID0 + ori r9,r8,HID0_DCFA@l + mtspr SPRN_HID0,r9 + isync + + LOAD_REG_IMMEDIATE(r6, KERNELBASE) + mr r4, r6 + mtctr r7 + +1: lwz r3,0(r4)/* Load... */ + add r4,r
[PATCH v2,3/5] Powerpc: mpc85xx: refactor the PM operations
Freescale CoreNet-based and Non-CoreNet-based platforms require different PM operations. This patch extracted existing PM operations on Non-CoreNet-based platforms to a new file which can accommodate both platforms. In this way, PM operation codes are clearer structurally. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com Signed-off-by: Tang Yuantian yuantian.t...@feescale.com --- major changes for v2: * moved mpc85xx_cpu_die() * added qoriq_pm_ops-cpu_die() in smp_85xx_mach_cpu_die(). it puts the dying cpu in a low power mode arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c | 106 +++ arch/powerpc/platforms/85xx/smp.c| 74 +-- arch/powerpc/platforms/85xx/smp.h| 1 + 4 files changed, 127 insertions(+), 55 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 1fe7fb9..7bc86da 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -2,6 +2,7 @@ # Makefile for the PowerPC 85xx linux kernel. # obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c b/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c new file mode 100644 index 000..ed356dd --- /dev/null +++ b/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c @@ -0,0 +1,106 @@ +/* + * MPC85xx PM operators + * + * Copyright 2015 Freescale Semiconductor Inc. + * + * 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. + */ + +#define pr_fmt(fmt) %s: fmt, __func__ + +#include linux/kernel.h +#include linux/of.h +#include linux/of_address.h + +#include asm/io.h +#include asm/fsl_guts.h +#include asm/fsl_pm.h + +static struct ccsr_guts __iomem *guts; + +static void mpc85xx_irq_mask(int cpu) +{ + +} + +static void mpc85xx_irq_unmask(int cpu) +{ + +} + +static void mpc85xx_cpu_die(int cpu) +{ + u32 tmp; + + tmp = (mfspr(SPRN_HID0) ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP; + mtspr(SPRN_HID0, tmp); + + /* Enter NAP mode. */ + tmp = mfmsr(); + tmp |= MSR_WE; + asm volatile( + msync\n + mtmsr %0\n + isync\n + : + : r (tmp)); +} + +static void mpc85xx_cpu_up_prepare(int cpu) +{ + +} + +static void mpc85xx_freeze_time_base(bool freeze) +{ + uint32_t mask; + + mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1; + if (freeze) + setbits32(guts-devdisr, mask); + else + clrbits32(guts-devdisr, mask); + + in_be32(guts-devdisr); +} + +static const struct of_device_id mpc85xx_smp_guts_ids[] = { + { .compatible = fsl,mpc8572-guts, }, + { .compatible = fsl,p1020-guts, }, + { .compatible = fsl,p1021-guts, }, + { .compatible = fsl,p1022-guts, }, + { .compatible = fsl,p1023-guts, }, + { .compatible = fsl,p2020-guts, }, + { .compatible = fsl,bsc9132-guts, }, + {}, +}; + +static const struct fsl_pm_ops mpc85xx_pm_ops = { + .freeze_time_base = mpc85xx_freeze_time_base, + .irq_mask = mpc85xx_irq_mask, + .irq_unmask = mpc85xx_irq_unmask, + .cpu_die = mpc85xx_cpu_die, + .cpu_up_prepare = mpc85xx_cpu_up_prepare, +}; + +int __init mpc85xx_setup_pmc(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); + if (np) { + guts = of_iomap(np, 0); + of_node_put(np); + if (!guts) { + pr_err(Could not map guts node address\n); + return -ENOMEM; + } + } + + qoriq_pm_ops = mpc85xx_pm_ops; + + return 0; +} diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 0b75e8e..f9552b8 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -2,7 +2,7 @@ * Author: Andy Fleming aflem...@freescale.com *Kumar Gala ga...@kernel.crashing.org * - * Copyright 2006-2008, 2011-2012 Freescale Semiconductor Inc. + * Copyright 2006-2008, 2011-2012, 2015 Freescale Semiconductor Inc. * * 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 @@ -15,7 +15,6 @@ #include linux/init.h #include linux/delay.h #include linux/of.h -#include linux/of_address.h #include linux/kexec.h #include linux/highmem.h #include linux/cpu.h @@ -26,9 +25,9 @@ #include asm/mpic.h #include asm/cacheflush.h #include asm/dbell.h -#include asm/fsl_guts.h #include asm
[PATCH v2,4/5] PowerPC/mpc85xx: Add hotplug support on E5500 and E500MC cores
Freescale E500MC and E5500 core-based platforms, like P4080, T1040, support disabling/enabling CPU dynamically. This patch adds this feature on those platforms. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com Signed-off-by: Tang Yuantian yuantian.t...@feescale.com --- major changes for v2: * factor out smp_85xx_start_cpu() * move fsl_rcpm_init() into mpc85xx_smp_init() due to the init sequence * add hard_irq_disable() after local_irq_save(). for platforms that implement lazy enabling/disabling of interrupts, call hard_irq_disable() to ensure interrupts are disabled physically. arch/powerpc/Kconfig | 2 +- arch/powerpc/include/asm/smp.h| 3 + arch/powerpc/kernel/smp.c | 7 +- arch/powerpc/platforms/85xx/smp.c | 193 ++ arch/powerpc/platforms/85xx/smp.h | 1 + 5 files changed, 122 insertions(+), 84 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 5ef2711..dd9e252 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -386,7 +386,7 @@ config SWIOTLB config HOTPLUG_CPU bool Support for enabling/disabling CPUs depends on SMP (PPC_PSERIES || \ - PPC_PMAC || PPC_POWERNV || (PPC_85xx !PPC_E500MC)) + PPC_PMAC || PPC_POWERNV || FSL_SOC_BOOKE) ---help--- Say Y here to be able to disable and re-enable individual CPUs at runtime on SMP machines. diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 825663c..4ff5b71 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -67,6 +67,9 @@ void generic_cpu_die(unsigned int cpu); void generic_set_cpu_dead(unsigned int cpu); void generic_set_cpu_up(unsigned int cpu); int generic_check_cpu_restart(unsigned int cpu); +int check_cpu_dead(unsigned int cpu); +#else +#define generic_set_cpu_up(i) do { } while (0) #endif #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index ec9ec20..95111f2 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -427,7 +427,7 @@ void generic_cpu_die(unsigned int cpu) for (i = 0; i 100; i++) { smp_rmb(); - if (per_cpu(cpu_state, cpu) == CPU_DEAD) + if (check_cpu_dead(cpu)) return; msleep(100); } @@ -454,6 +454,11 @@ int generic_check_cpu_restart(unsigned int cpu) return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE; } +int check_cpu_dead(unsigned int cpu) +{ + return per_cpu(cpu_state, cpu) == CPU_DEAD; +} + static bool secondaries_inhibited(void) { return kvm_hv_mode_active(); diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index f9552b8..73eb994 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -10,6 +10,8 @@ * option) any later version. */ +#define pr_fmt(fmt) smp: %s: fmt, __func__ + #include linux/stddef.h #include linux/kernel.h #include linux/init.h @@ -52,6 +54,7 @@ static void mpc85xx_give_timebase(void) unsigned long flags; local_irq_save(flags); + hard_irq_disable(); while (!tb_req) barrier(); @@ -100,6 +103,7 @@ static void mpc85xx_take_timebase(void) unsigned long flags; local_irq_save(flags); + hard_irq_disable(); tb_req = 1; while (!tb_valid) @@ -135,8 +139,31 @@ static void smp_85xx_mach_cpu_die(void) while (1) ; } + +static void qoriq_cpu_kill(unsigned int cpu) +{ + int i; + + for (i = 0; i 500; i++) { + if (check_cpu_dead(cpu)) { +#ifdef CONFIG_PPC64 + paca[cpu].cpu_start = 0; +#endif + return; + } + msleep(20); + } + pr_err(CPU%d didn't die...\n, cpu); +} #endif +/* + * To keep it compatible with old boot program which uses + * cache-inhibit spin table, we need to flush the cache + * before accessing spin table to invalidate any staled data. + * We also need to flush the cache after writing to spin + * table to push data out. + */ static inline void flush_spin_table(void *spin_table) { flush_dcache_range((ulong)spin_table, @@ -168,51 +195,20 @@ static void wake_hw_thread(void *info) } #endif -static int smp_85xx_kick_cpu(int nr) +static int smp_85xx_start_cpu(int cpu) { - unsigned long flags; - const u64 *cpu_rel_addr; - __iomem struct epapr_spin_table *spin_table; + int ret = 0; struct device_node *np; - int hw_cpu = get_hard_smp_processor_id(nr); + const u64 *cpu_rel_addr; + unsigned long flags; int ioremappable; - int ret = 0; - - WARN_ON(nr 0 || nr = NR_CPUS); - WARN_ON(hw_cpu 0 || hw_cpu = NR_CPUS); - - pr_debug(smp_85xx_kick_cpu: kick CPU #%d\n, nr); - -#ifdef CONFIG_PPC64 - /* Threads don't
[PATCH v2,5/5] PowerPC/mpc85xx: Add CPU hotplug support for E6500
Support Freescale E6500 core-based platforms, like t4240. Support disabling/enabling individual CPU thread dynamically. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- major changes for v2: * start Thread1 by Thread0 when we want to boot Thread1 only replacing the method of changing cpu physical id arch/powerpc/include/asm/cputhreads.h | 9 + arch/powerpc/include/asm/smp.h| 1 + arch/powerpc/kernel/head_64.S | 69 ++- arch/powerpc/platforms/85xx/smp.c | 53 ++- arch/powerpc/sysdev/fsl_rcpm.c| 2 +- 5 files changed, 106 insertions(+), 28 deletions(-) diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h index ba42e46..9920f61 100644 --- a/arch/powerpc/include/asm/cputhreads.h +++ b/arch/powerpc/include/asm/cputhreads.h @@ -1,6 +1,7 @@ #ifndef _ASM_POWERPC_CPUTHREADS_H #define _ASM_POWERPC_CPUTHREADS_H +#ifndef __ASSEMBLY__ #include linux/cpumask.h /* @@ -95,6 +96,14 @@ static inline int cpu_last_thread_sibling(int cpu) } +#ifdef CONFIG_PPC_BOOK3E +void book3e_start_thread(int thread, unsigned long addr); +void book3e_stop_thread(int thread); +#endif + +#endif /* __ASSEMBLY__ */ + +#define INVALID_THREAD_HWID0x0fff #endif /* _ASM_POWERPC_CPUTHREADS_H */ diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 4ff5b71..a1faa4c 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -200,6 +200,7 @@ extern void generic_secondary_thread_init(void); extern unsigned long __secondary_hold_spinloop; extern unsigned long __secondary_hold_acknowledge; extern char __secondary_hold; +extern unsigned int booting_thread_hwid; extern void __early_start(void); #endif /* __ASSEMBLY__ */ diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index d48125d..6df2aa4 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -40,6 +40,7 @@ #include asm/kvm_book3s_asm.h #include asm/ptrace.h #include asm/hw_irq.h +#include asm/cputhreads.h /* The physical memory is laid out such that the secondary processor * spin code sits at 0x...0x00ff. On server, the vectors follow @@ -181,6 +182,44 @@ exception_marker: #endif #ifdef CONFIG_PPC_BOOK3E + .globl booting_thread_hwid +booting_thread_hwid: + .long INVALID_THREAD_HWID + .align 3 +/* + * start threads in the same cpu + * input parameters: + * r3 = the thread physical id + * r4 = the entry point where thread starts + */ +_GLOBAL(book3e_start_thread) + LOAD_REG_IMMEDIATE(r5, MSR_KERNEL) + cmpi0, r3, 0 + bne 10f + mttmr TMRN_IMSR0, r5 + mttmr TMRN_INIA0, r4 + b 11f +10: + mttmr TMRN_IMSR1, r5 + mttmr TMRN_INIA1, r4 +11: + isync + li r6, 1 + sld r6, r6, r3 + mtspr SPRN_TENS, r6 + isync + blr + +/* + * r3 = the thread physical id + */ +_GLOBAL(book3e_stop_thread) + li r4, 1 + sld r4, r4, r3 + mtspr SPRN_TENC, r4 + isync + blr + _GLOBAL(fsl_secondary_thread_init) /* Enable branch prediction */ lis r3,BUCSR_INIT@h @@ -197,8 +236,10 @@ _GLOBAL(fsl_secondary_thread_init) * but the low bit right by two bits so that the cpu numbering is * continuous. */ - mfspr r3, SPRN_PIR - rlwimi r3, r3, 30, 2, 30 + bl 10f +10:mflrr5 + addir5,r5,(booting_thread_hwid - 10b) + lwz r3,0(r5) mtspr SPRN_PIR, r3 #endif @@ -245,6 +286,30 @@ _GLOBAL(generic_secondary_smp_init) mr r3,r24 mr r4,r25 bl book3e_secondary_core_init + +/* + * If we want to boot Thread1, start Thread1 and stop Thread0. + * Note that only Thread0 will run the piece of code. + */ + LOAD_REG_ADDR(r3, booting_thread_hwid) + lwz r4, 0(r3) + cmpwi r4, INVALID_THREAD_HWID + beq 20f + cmpwr4, r24 + beq 20f + + /* start Thread1 */ + LOAD_REG_ADDR(r5, fsl_secondary_thread_init) + ld r4, 0(r5) + li r3, 1 + bl book3e_start_thread + + /* stop Thread0 */ + li r3, 0 + bl book3e_stop_thread +10: + b 10b +20: #endif generic_secondary_common_init: diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 73eb994..61f68ad 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -181,17 +181,11 @@ static inline u32 read_spin_table_addr_l(void *spin_table) static void wake_hw_thread(void *info) { void fsl_secondary_thread_init(void); - unsigned long imsr1, inia1; - int nr = *(const int *)info; + unsigned long inia; + int hw_cpu = get_hard_smp_processor_id(*(const int *)info); - imsr1 = MSR_KERNEL
[PATCH v2,1/5] powerpc/cache: add cache flush operation for various e500
Various e500 core have different cache architecture, so they need different cache flush operations. Therefore, add a callback function cpu_flush_caches to the struct cpu_spec. The cache flush operation for the specific kind of e500 is selected at init time. The callback function will flush all caches inside the current cpu. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com Signed-off-by: Tang Yuantian yuantian.t...@feescale.com --- arch/powerpc/include/asm/cacheflush.h | 2 - arch/powerpc/include/asm/cputable.h | 11 +++ arch/powerpc/kernel/asm-offsets.c | 3 + arch/powerpc/kernel/cpu_setup_fsl_booke.S | 112 ++ arch/powerpc/kernel/cputable.c| 4 ++ arch/powerpc/kernel/head_fsl_booke.S | 74 arch/powerpc/platforms/85xx/smp.c | 5 +- 7 files changed, 133 insertions(+), 78 deletions(-) diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 30b35ff..729fde4 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -30,8 +30,6 @@ extern void flush_dcache_page(struct page *page); #define flush_dcache_mmap_lock(mapping)do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) -extern void __flush_disable_L1(void); - extern void flush_icache_range(unsigned long, unsigned long); extern void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, unsigned long addr, diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index b118072..d89b04a 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -43,6 +43,13 @@ extern int machine_check_e500(struct pt_regs *regs); extern int machine_check_e200(struct pt_regs *regs); extern int machine_check_47x(struct pt_regs *regs); +#if defined(CONFIG_E500) +extern void cpu_down_flush_e500v2(void); +extern void cpu_down_flush_e500mc(void); +extern void cpu_down_flush_e5500(void); +extern void cpu_down_flush_e6500(void); +#endif + /* NOTE WELL: Update identify_cpu() if fields are added or removed! */ struct cpu_spec { /* CPU is matched via (PVR pvr_mask) == pvr_value */ @@ -59,6 +66,10 @@ struct cpu_spec { unsigned inticache_bsize; unsigned intdcache_bsize; +#if defined(CONFIG_E500) + /* flush caches inside the current cpu */ + void (*cpu_down_flush)(void); +#endif /* number of performance monitor counters */ unsigned intnum_pmcs; enum powerpc_pmc_type pmc_type; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 9823057..17b672d 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -373,6 +373,9 @@ int main(void) DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore)); +#if defined(CONFIG_E500) + DEFINE(CPU_DOWN_FLUSH, offsetof(struct cpu_spec, cpu_down_flush)); +#endif DEFINE(pbe_address, offsetof(struct pbe, address)); DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S index dddba3e..462aed9 100644 --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S @@ -13,11 +13,13 @@ * */ +#include asm/page.h #include asm/processor.h #include asm/cputable.h #include asm/ppc_asm.h #include asm/mmu-book3e.h #include asm/asm-offsets.h +#include asm/mpc85xx.h _GLOBAL(__e500_icache_setup) mfspr r0, SPRN_L1CSR1 @@ -233,3 +235,113 @@ _GLOBAL(__setup_cpu_e5500) mtlrr5 blr #endif + +/* flush L1 date cache, it can apply to e500v2, e500mc and e5500 */ +_GLOBAL(flush_dcache_L1) + mfmsr r10 + wrteei 0 + + mfspr r3,SPRN_L1CFG0 + rlwinm r5,r3,9,3 /* Extract cache block size */ + twlgti r5,1/* Only 32 and 64 byte cache blocks +* are currently defined. +*/ + li r4,32 + subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) - +* log2(number of ways) +*/ + slw r5,r4,r5/* r5 = cache block size */ + + rlwinm r7,r3,0,0xff/* Extract number of KiB in the cache */ + mulli r7,r7,13/* An 8-way cache will require 13 +* loads per set. +*/ + slw r7,r7,r6 + + /* save off HID0 and set DCFA */ + mfspr r8,SPRN_HID0 + ori r9,r8,HID0_DCFA@l + mtspr SPRN_HID0,r9 + isync
[PATCH v2,2/5] powerpc/rcpm: add RCPM driver
There is a RCPM (Run Control/Power Management) in Freescale QorIQ series processors. The device performs tasks associated with device run control and power management. The driver implements some features: mask/unmask irq, enter/exit low power states, freeze time base, etc. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com Signed-off-by: Tang Yuantian yuantian.t...@freescale.com --- major changes for v2: * rcpm_v1_cpu_die() and rcpm_v2_cpu_die() will be executed by the dying cpu. this way, more stable Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 44 +++ arch/powerpc/include/asm/fsl_guts.h| 105 ++ arch/powerpc/include/asm/fsl_pm.h | 50 +++ arch/powerpc/platforms/85xx/Kconfig| 1 + arch/powerpc/platforms/85xx/common.c | 3 + arch/powerpc/sysdev/Kconfig| 5 + arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/fsl_rcpm.c | 390 + 8 files changed, 599 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/rcpm.txt create mode 100644 arch/powerpc/include/asm/fsl_pm.h create mode 100644 arch/powerpc/sysdev/fsl_rcpm.c diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt new file mode 100644 index 000..dc52f70 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt @@ -0,0 +1,44 @@ +* Run Control and Power Management + +The RCPM performs all device-level tasks associated with device run control +and power management. + +Required properites: + - reg : Offset and length of the register set of RCPM block. + - compatible : Sould contain a chip-specific RCPM block compatible string + and (if applicable) may contain a chassis-version RCPM compatible string. + Chip-specific strings are of the form fsl,chip-rcpm, such as: + * fsl,p2041-rcpm + * fsl,p3041-rcpm + * fsl,p4080-rcpm + * fsl,p5020-rcpm + * fsl,p5040-rcpm + * fsl,t4240-rcpm + * fsl,b4420-rcpm + * fsl,b4860-rcpm + + Chassis-version RCPM strings include: + * fsl,qoriq-rcpm-1.0: for chassis 1.0 rcpm + * fsl,qoriq-rcpm-2.0: for chassis 2.0 rcpm + * fsl,qoriq-rcpm-2.1: for chassis 2.1 rcpm + +All references to 1.0 and 2.0 refer to the QorIQ chassis version to +which the chip complies. +Chassis VersionExample Chips +------ +1.0p4080, p5020, p5040, p2041, p3041 +2.0t4240, b4860, b4420 +2.1t1040 + +Example: +The RCPM node for T4240: + rcpm: global-utilities@e2000 { + compatible = fsl,t4240-rcpm, fsl,qoriq-rcpm-2.0; + reg = 0xe2000 0x1000; + }; + +The RCPM node for P4080: + rcpm: global-utilities@e2000 { + compatible = fsl,qoriq-rcpm-1.0; + reg = 0xe2000 0x1000; + }; diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h index 43b6bb1..a67413c 100644 --- a/arch/powerpc/include/asm/fsl_guts.h +++ b/arch/powerpc/include/asm/fsl_guts.h @@ -188,5 +188,110 @@ static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts, #endif +struct ccsr_rcpm_v1 { + u8 res[4]; + __be32 cdozsr; /* 0x0004 Core Doze Status Register */ + u8 res0008[4]; + __be32 cdozcr; /* 0x000c Core Doze Control Register */ + u8 res0010[4]; + __be32 cnapsr; /* 0x0014 Core Nap Status Register */ + u8 res0018[4]; + __be32 cnapcr; /* 0x001c Core Nap Control Register */ + u8 res0020[4]; + __be32 cdozpsr;/* 0x0024 Core Doze Previous Status Register */ + u8 res0028[4]; + __be32 cnappsr;/* 0x002c Core Nap Previous Status Register */ + u8 res0030[4]; + __be32 cwaitsr;/* 0x0034 Core Wait Status Register */ + u8 res0038[4]; + __be32 cwdtdsr;/* 0x003c Core Watchdog Detect Status Register */ + __be32 powmgtcsr; /* 0x0040 PM ControlStatus Register */ +#define RCPM_POWMGTCSR_SLP 0x0002 + u8 res0044[12]; + __be32 ippdexpcr; /* 0x0050 IP Powerdown Exception Control Register */ + u8 res0054[16]; + __be32 cpmimr; /* 0x0064 Core PM IRQ Mask Register */ + u8 res0068[4]; + __be32 cpmcimr;/* 0x006c Core PM Critical IRQ Mask Register */ + u8 res0070[4]; + __be32 cpmmcmr;/* 0x0074 Core PM Machine Check Mask Register */ + u8 res0078[4]; + __be32 cpmnmimr; /* 0x007c Core PM NMI Mask Register */ + u8 res0080[4]; + __be32 ctbenr; /* 0x0084 Core Time Base Enable Register */ + u8 res0088[4]; + __be32 ctbckselr; /* 0x008c Core
Re: [PATCH 1/3] Powerpc: mpc85xx: refactor the PM operations
On Fri, Aug 7, 2015 at 2:02 AM, Scott Wood wrote: On Thu, 2015-08-06 at 13:54 +0800, Chenhui Zhao wrote: On Thu, Aug 6, 2015 at 1:46 PM, Scott Wood wrote: > On Thu, 2015-08-06 at 12:20 +0800, Chenhui Zhao wrote: > > On Thu, Aug 6, 2015 at 10:57 AM, Scott Wood > > > > wrote: > > > On Wed, 2015-08-05 at 18:11 +0800, Chenhui Zhao wrote: > > > > On Tue, Aug 4, 2015 at 4:26 AM, Scott Wood > > > > > > wrote: > > > > > On Mon, 2015-08-03 at 19:32 +0800, Chenhui Zhao wrote: > > > > > > > > > > > > > > > > > > On Sat, Aug 1, 2015 at 7:59 AM, Scott Wood > > > > > > > > > > wrote: > > > > > > > > > > > > > > > > > > > Could you explain irq_mask()? Why would there still be > > IRQs > > > > > > destined > > > > > > > for > > > > > > > this CPU at this point? > > > > > > > > > > > > This function just masks irq by setting the registers in > > RCPM > > > > (for > > > > > > example, RCPM_CPMIMR, RCPM_CPMCIMR). Actually, all irqs to > > > > this CPU > > > > > > have been migrated to other CPUs. > > > > > > > > > > So why do we need to set those bits in RCPM? Is it just > > caution? > > > > > > > > Setting these bits can mask interrupts signalled to RCPM from > > MPIC > > > > as a > > > > means of > > > > waking up from a lower power state. So, cores will not be > > waked up > > > > unexpectedly. > > > > > > Why would the MPIC be signalling those interrupts if they've been > > > masked at > > > the MPIC? > > > > > > -Scott > > > > > > > The interrupts to RCPM from MPIC are IRQ, Machine Check, NMI and > > Critical interrupts. Some of them didn't be masked in MPIC. > > What interrupt could actually happen to a sleeping cpu that this > protects > against? > > -Scott Not sure. Maybe spurious interrupts or hardware exceptions. Spurious interrupts happen due to race conditions. They don't happen because the MPIC is bored and decides to ring a CPU's doorbell and hide in the bushes. If by "hardware exceptions" you mean machine checks, how would such a machine check be generated by a core that is off? However, setting them make sure dead cpus can not be waked up unexpectedly. I'm not seeing enough value here to warrant resurrecting the old sleep node stuff. -Scott My guess maybe not accurate. My point is that electronic parts don't always work as expected. Taking preventative measures can make the system more robust. In addition, this step is required in deep sleep procedure. -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/3] Powerpc: mpc85xx: refactor the PM operations
On Fri, Aug 7, 2015 at 2:02 AM, Scott Wood scottw...@freescale.com wrote: On Thu, 2015-08-06 at 13:54 +0800, Chenhui Zhao wrote: On Thu, Aug 6, 2015 at 1:46 PM, Scott Wood scottw...@freescale.com wrote: On Thu, 2015-08-06 at 12:20 +0800, Chenhui Zhao wrote: On Thu, Aug 6, 2015 at 10:57 AM, Scott Wood scottw...@freescale.com wrote: On Wed, 2015-08-05 at 18:11 +0800, Chenhui Zhao wrote: On Tue, Aug 4, 2015 at 4:26 AM, Scott Wood scottw...@freescale.com wrote: On Mon, 2015-08-03 at 19:32 +0800, Chenhui Zhao wrote: On Sat, Aug 1, 2015 at 7:59 AM, Scott Wood scottw...@freescale.com wrote: Could you explain irq_mask()? Why would there still be IRQs destined for this CPU at this point? This function just masks irq by setting the registers in RCPM (for example, RCPM_CPMIMR, RCPM_CPMCIMR). Actually, all irqs to this CPU have been migrated to other CPUs. So why do we need to set those bits in RCPM? Is it just caution? Setting these bits can mask interrupts signalled to RCPM from MPIC as a means of waking up from a lower power state. So, cores will not be waked up unexpectedly. Why would the MPIC be signalling those interrupts if they've been masked at the MPIC? -Scott The interrupts to RCPM from MPIC are IRQ, Machine Check, NMI and Critical interrupts. Some of them didn't be masked in MPIC. What interrupt could actually happen to a sleeping cpu that this protects against? -Scott Not sure. Maybe spurious interrupts or hardware exceptions. Spurious interrupts happen due to race conditions. They don't happen because the MPIC is bored and decides to ring a CPU's doorbell and hide in the bushes. If by hardware exceptions you mean machine checks, how would such a machine check be generated by a core that is off? However, setting them make sure dead cpus can not be waked up unexpectedly. I'm not seeing enough value here to warrant resurrecting the old sleep node stuff. -Scott My guess maybe not accurate. My point is that electronic parts don't always work as expected. Taking preventative measures can make the system more robust. In addition, this step is required in deep sleep procedure. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/3] Powerpc: mpc85xx: refactor the PM operations
On Thu, Aug 6, 2015 at 1:46 PM, Scott Wood wrote: On Thu, 2015-08-06 at 12:20 +0800, Chenhui Zhao wrote: On Thu, Aug 6, 2015 at 10:57 AM, Scott Wood wrote: > On Wed, 2015-08-05 at 18:11 +0800, Chenhui Zhao wrote: > > On Tue, Aug 4, 2015 at 4:26 AM, Scott Wood > > wrote: > > > On Mon, 2015-08-03 at 19:32 +0800, Chenhui Zhao wrote: > > > > > > > > > > > > On Sat, Aug 1, 2015 at 7:59 AM, Scott Wood > > > > > > wrote: > > > > > > > > > > > > > Could you explain irq_mask()? Why would there still be IRQs > > > > destined > > > > > for > > > > > this CPU at this point? > > > > > > > > This function just masks irq by setting the registers in RCPM > > (for > > > > example, RCPM_CPMIMR, RCPM_CPMCIMR). Actually, all irqs to > > this CPU > > > > have been migrated to other CPUs. > > > > > > So why do we need to set those bits in RCPM? Is it just caution? > > > > Setting these bits can mask interrupts signalled to RCPM from MPIC > > as a > > means of > > waking up from a lower power state. So, cores will not be waked up > > unexpectedly. > > Why would the MPIC be signalling those interrupts if they've been > masked at > the MPIC? > > -Scott > The interrupts to RCPM from MPIC are IRQ, Machine Check, NMI and Critical interrupts. Some of them didn't be masked in MPIC. What interrupt could actually happen to a sleeping cpu that this protects against? -Scott Not sure. Maybe spurious interrupts or hardware exceptions. However, setting them make sure dead cpus can not be waked up unexpectedly. -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 3/3] PowerPC/mpc85xx: Add hotplug support on E6500 cores
On Thu, Aug 6, 2015 at 11:16 AM, Scott Wood wrote: On Wed, 2015-08-05 at 19:08 +0800, Chenhui Zhao wrote: On Sat, Aug 1, 2015 at 8:22 AM, Scott Wood wrote: > On Fri, 2015-07-31 at 17:20 +0800, b29983@freescale.comwrote: > > + /* > > + * If both threads are offline, reset core to start. > > + * When core is up, Thread 0 always gets up first, > > + * so bind the current logical cpu with Thread 0. > > + */ > > + if (hw_cpu != cpu_first_thread_sibling(hw_cpu)) { > > + int hw_cpu1, hw_cpu2; > > + > > + hw_cpu1 = get_hard_smp_processor_id(primary); > > + hw_cpu2 = get_hard_smp_processor_id(primary + > > 1); > > + set_hard_smp_processor_id(primary, hw_cpu2); > > + set_hard_smp_processor_id(primary + 1, > > hw_cpu1); > > + /* get new physical cpu id */ > > + hw_cpu = get_hard_smp_processor_id(nr); > > NACK as discussed in http://patchwork.ozlabs.org/patch/454944/ > > -Scott You said, There's no need for this. I have booting from a thread1, and having it kick its thread0, working locally without messing with the hwid/cpu mapping. I still have questions here. After a core reset, how can you boot Thread1 of the core first. As I know, Thread0 boots up first by default. So the issue isn't that thread1 comes up first, but that you *want* thread1 to come up first and it won't. I don't think this remapping is an acceptable answer, though. Instead, if you need only thread1 to come up, start the core, have thread0 start thread1, and then send thread0 into whatever waiting state it would be in if thread1 had never been offlined. -Scott Remapping is a concise solution. what's the harm of it? Keeping things simple is good in my opinion. -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/3] Powerpc: mpc85xx: refactor the PM operations
On Thu, Aug 6, 2015 at 10:57 AM, Scott Wood wrote: On Wed, 2015-08-05 at 18:11 +0800, Chenhui Zhao wrote: On Tue, Aug 4, 2015 at 4:26 AM, Scott Wood wrote: > On Mon, 2015-08-03 at 19:32 +0800, Chenhui Zhao wrote: > > > > > > On Sat, Aug 1, 2015 at 7:59 AM, Scott Wood > > wrote: > > > > > > > Could you explain irq_mask()? Why would there still be IRQs > > destined > > > for > > > this CPU at this point? > > > > This function just masks irq by setting the registers in RCPM (for > > example, RCPM_CPMIMR, RCPM_CPMCIMR). Actually, all irqs to this CPU > > have been migrated to other CPUs. > > So why do we need to set those bits in RCPM? Is it just caution? Setting these bits can mask interrupts signalled to RCPM from MPIC as a means of waking up from a lower power state. So, cores will not be waked up unexpectedly. Why would the MPIC be signalling those interrupts if they've been masked at the MPIC? -Scott The interrupts to RCPM from MPIC are IRQ, Machine Check, NMI and Critical interrupts. Some of them didn't be masked in MPIC. -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 3/3] PowerPC/mpc85xx: Add hotplug support on E6500 cores
On Sat, Aug 1, 2015 at 8:22 AM, Scott Wood wrote: On Fri, 2015-07-31 at 17:20 +0800, b29...@freescale.com wrote: diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 7f0dadb..8652a49 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -189,15 +189,22 @@ static inline u32 read_spin_table_addr_l(void *spin_table) static void wake_hw_thread(void *info) { void fsl_secondary_thread_init(void); - unsigned long imsr1, inia1; + unsigned long imsr, inia; int nr = *(const int *)info; - - imsr1 = MSR_KERNEL; - inia1 = *(unsigned long *)fsl_secondary_thread_init; - - mttmr(TMRN_IMSR1, imsr1); - mttmr(TMRN_INIA1, inia1); - mtspr(SPRN_TENS, TEN_THREAD(1)); + int hw_cpu = get_hard_smp_processor_id(nr); + int thread_idx = cpu_thread_in_core(hw_cpu); + + booting_cpu_hwid = (u32)hw_cpu; Unnecessary cast. Please explain why you need booting_cpu_hwid. + imsr = MSR_KERNEL; + inia = *(unsigned long *)fsl_secondary_thread_init; + if (thread_idx == 0) { + mttmr(TMRN_IMSR0, imsr); + mttmr(TMRN_INIA0, inia); + } else { + mttmr(TMRN_IMSR1, imsr); + mttmr(TMRN_INIA1, inia); + } + mtspr(SPRN_TENS, TEN_THREAD(thread_idx)); Please rebase this on top of http://patchwork.ozlabs.org/patch/496952/ OK. + /* + * If both threads are offline, reset core to start. + * When core is up, Thread 0 always gets up first, + * so bind the current logical cpu with Thread 0. + */ + if (hw_cpu != cpu_first_thread_sibling(hw_cpu)) { + int hw_cpu1, hw_cpu2; + + hw_cpu1 = get_hard_smp_processor_id(primary); + hw_cpu2 = get_hard_smp_processor_id(primary + 1); + set_hard_smp_processor_id(primary, hw_cpu2); + set_hard_smp_processor_id(primary + 1, hw_cpu1); + /* get new physical cpu id */ + hw_cpu = get_hard_smp_processor_id(nr); NACK as discussed in http://patchwork.ozlabs.org/patch/454944/ -Scott You said, There's no need for this. I have booting from a thread1, and having it kick its thread0, working locally without messing with the hwid/cpu mapping. I still have questions here. After a core reset, how can you boot Thread1 of the core first. As I know, Thread0 boots up first by default. -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 2/3] PowerPC/mpc85xx: Add hotplug support on E5500 and E500MC cores
On Tue, Aug 4, 2015 at 5:18 AM, Scott Wood wrote: [Added linuxppc-...@lists.ozlabs.org. Besides that list being required for review of PPC patches, it feeds the patchwork that I use to track and apply patches.] On Mon, 2015-08-03 at 19:52 +0800, Chenhui Zhao wrote: On Sat, Aug 1, 2015 at 8:14 AM, Scott Wood wrote: > On Fri, 2015-07-31 at 17:20 +0800, b29983@freescale.comwrote: > > From: Tang Yuantian > > > > Freescale E500MC and E5500 core-based platforms, like P4080, T1040, > > support disabling/enabling CPU dynamically. > > This patch adds this feature on those platforms. > > > > Signed-off-by: Chenhui Zhao > > Signed-off-by: Tang Yuantian +{ > > + int i; > > + > > + for (i = 0; i < 5; i++) { > > + if (generic_check_cpu_dead(cpu)) { > > + qoriq_pm_ops->cpu_die(cpu); > > +#ifdef CONFIG_PPC64 > > + paca[cpu].cpu_start = 0; > > +#endif > > + return; > > + } > > + udelay(10); > > + } > > + pr_err("%s: CPU%d didn't die...\n", __func__, cpu); > > +} > > Only 500ms timeout, versus 10sec in generic_cpu_die()? The process is fast. Maybe 10 second is too large. Is it fast 100% of the time? What if the CPU you intend to die is in a long critical section? What harm is there to having a longer timeout, similar to what other platforms use? Will change the max timeout to 10 seconds. > > > #endif > > > > static inline void flush_spin_table(void *spin_table) > > @@ -246,11 +267,7 @@ static int smp_85xx_kick_cpu(int nr) > >spin_table = phys_to_virt(*cpu_rel_addr); > > > >local_irq_save(flags); > > -#ifdef CONFIG_PPC32 > > #ifdef CONFIG_HOTPLUG_CPU > > - /* Corresponding to generic_set_cpu_dead() */ > > - generic_set_cpu_up(nr); > > - > >if (system_state == SYSTEM_RUNNING) { > >/* > > * To keep it compatible with old boot program which > > uses > > @@ -263,6 +280,7 @@ static int smp_85xx_kick_cpu(int nr) > >out_be32(_table->addr_l, 0); > >flush_spin_table(spin_table); > > > > + qoriq_pm_ops->cpu_up(nr); > > Again, is it possible to get here without a valid qoriq_pm_ops (i.e. > is there > anything stopping the user from trying to initiate CPU hotplug)? > > -Scott For every platform running this code, should has a valid qoriq_pm_ops. If not valid, it's a bug. How do you prevent this code from running when there is no valid qoriq_pm_ops? -Scott Will check if qoriq_pm_ops is valid. -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/3] Powerpc: mpc85xx: refactor the PM operations
On Tue, Aug 4, 2015 at 4:26 AM, Scott Wood wrote: On Mon, 2015-08-03 at 19:32 +0800, Chenhui Zhao wrote: > On Sat, Aug 1, 2015 at 7:59 AM, Scott Wood wrote: > > Could you explain irq_mask()? Why would there still be IRQs destined > for > this CPU at this point? This function just masks irq by setting the registers in RCPM (for example, RCPM_CPMIMR, RCPM_CPMCIMR). Actually, all irqs to this CPU have been migrated to other CPUs. So why do we need to set those bits in RCPM? Is it just caution? Setting these bits can mask interrupts signalled to RCPM from MPIC as a means of waking up from a lower power state. So, cores will not be waked up unexpectedly. > @@ -431,21 +415,9 @@ void __init mpc85xx_smp_init(void) > >smp_85xx_ops.probe = NULL; > >} > > > > - np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); > > - if (np) { > > - guts = of_iomap(np, 0); > > - of_node_put(np); > > - if (!guts) { > > - pr_err("%s: Could not map guts node > > address\n", > > - > > __func__); > > - return; > > - } > > - smp_85xx_ops.give_timebase = mpc85xx_give_timebase; > > - smp_85xx_ops.take_timebase = mpc85xx_take_timebase; > > #ifdef CONFIG_HOTPLUG_CPU > > - ppc_md.cpu_die = smp_85xx_mach_cpu_die; > > + ppc_md.cpu_die = qoriq_cpu_dying; > > #endif > > Shouldn't you make sure there's a valid qoriq_pm_ops before setting > cpu_die()? Or make sure that qoriq_cpu_dying() works regardless. > > -Scott This patch is just for e500v2. The following patches will handle the case of e500mc, e5500 and e6500. What stops a user from trying to use cpu hotplug on unsupported cpus, or in a virtualized environment, and crashing here? -Scott Will set these callback functions only if qoriq_pm_ops is valid. -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/3] Powerpc: mpc85xx: refactor the PM operations
On Tue, Aug 4, 2015 at 4:26 AM, Scott Wood scottw...@freescale.com wrote: On Mon, 2015-08-03 at 19:32 +0800, Chenhui Zhao wrote: On Sat, Aug 1, 2015 at 7:59 AM, Scott Wood scottw...@freescale.com wrote: Could you explain irq_mask()? Why would there still be IRQs destined for this CPU at this point? This function just masks irq by setting the registers in RCPM (for example, RCPM_CPMIMR, RCPM_CPMCIMR). Actually, all irqs to this CPU have been migrated to other CPUs. So why do we need to set those bits in RCPM? Is it just caution? Setting these bits can mask interrupts signalled to RCPM from MPIC as a means of waking up from a lower power state. So, cores will not be waked up unexpectedly. @@ -431,21 +415,9 @@ void __init mpc85xx_smp_init(void) smp_85xx_ops.probe = NULL; } - np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); - if (np) { - guts = of_iomap(np, 0); - of_node_put(np); - if (!guts) { - pr_err(%s: Could not map guts node address\n, - __func__); - return; - } - smp_85xx_ops.give_timebase = mpc85xx_give_timebase; - smp_85xx_ops.take_timebase = mpc85xx_take_timebase; #ifdef CONFIG_HOTPLUG_CPU - ppc_md.cpu_die = smp_85xx_mach_cpu_die; + ppc_md.cpu_die = qoriq_cpu_dying; #endif Shouldn't you make sure there's a valid qoriq_pm_ops before setting cpu_die()? Or make sure that qoriq_cpu_dying() works regardless. -Scott This patch is just for e500v2. The following patches will handle the case of e500mc, e5500 and e6500. What stops a user from trying to use cpu hotplug on unsupported cpus, or in a virtualized environment, and crashing here? -Scott Will set these callback functions only if qoriq_pm_ops is valid. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 2/3] PowerPC/mpc85xx: Add hotplug support on E5500 and E500MC cores
On Tue, Aug 4, 2015 at 5:18 AM, Scott Wood scottw...@freescale.com wrote: [Added linuxppc-...@lists.ozlabs.org. Besides that list being required for review of PPC patches, it feeds the patchwork that I use to track and apply patches.] On Mon, 2015-08-03 at 19:52 +0800, Chenhui Zhao wrote: On Sat, Aug 1, 2015 at 8:14 AM, Scott Wood scottw...@freescale.com wrote: On Fri, 2015-07-31 at 17:20 +0800, b29983@freescale.comwrote: From: Tang Yuantian yuantian.t...@freescale.com Freescale E500MC and E5500 core-based platforms, like P4080, T1040, support disabling/enabling CPU dynamically. This patch adds this feature on those platforms. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com Signed-off-by: Tang Yuantian yuantian.t...@feescale.com +{ + int i; + + for (i = 0; i 5; i++) { + if (generic_check_cpu_dead(cpu)) { + qoriq_pm_ops-cpu_die(cpu); +#ifdef CONFIG_PPC64 + paca[cpu].cpu_start = 0; +#endif + return; + } + udelay(10); + } + pr_err(%s: CPU%d didn't die...\n, __func__, cpu); +} Only 500ms timeout, versus 10sec in generic_cpu_die()? The process is fast. Maybe 10 second is too large. Is it fast 100% of the time? What if the CPU you intend to die is in a long critical section? What harm is there to having a longer timeout, similar to what other platforms use? Will change the max timeout to 10 seconds. #endif static inline void flush_spin_table(void *spin_table) @@ -246,11 +267,7 @@ static int smp_85xx_kick_cpu(int nr) spin_table = phys_to_virt(*cpu_rel_addr); local_irq_save(flags); -#ifdef CONFIG_PPC32 #ifdef CONFIG_HOTPLUG_CPU - /* Corresponding to generic_set_cpu_dead() */ - generic_set_cpu_up(nr); - if (system_state == SYSTEM_RUNNING) { /* * To keep it compatible with old boot program which uses @@ -263,6 +280,7 @@ static int smp_85xx_kick_cpu(int nr) out_be32(spin_table-addr_l, 0); flush_spin_table(spin_table); + qoriq_pm_ops-cpu_up(nr); Again, is it possible to get here without a valid qoriq_pm_ops (i.e. is there anything stopping the user from trying to initiate CPU hotplug)? -Scott For every platform running this code, should has a valid qoriq_pm_ops. If not valid, it's a bug. How do you prevent this code from running when there is no valid qoriq_pm_ops? -Scott Will check if qoriq_pm_ops is valid. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 3/3] PowerPC/mpc85xx: Add hotplug support on E6500 cores
On Sat, Aug 1, 2015 at 8:22 AM, Scott Wood scottw...@freescale.com wrote: On Fri, 2015-07-31 at 17:20 +0800, b29...@freescale.com wrote: diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 7f0dadb..8652a49 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -189,15 +189,22 @@ static inline u32 read_spin_table_addr_l(void *spin_table) static void wake_hw_thread(void *info) { void fsl_secondary_thread_init(void); - unsigned long imsr1, inia1; + unsigned long imsr, inia; int nr = *(const int *)info; - - imsr1 = MSR_KERNEL; - inia1 = *(unsigned long *)fsl_secondary_thread_init; - - mttmr(TMRN_IMSR1, imsr1); - mttmr(TMRN_INIA1, inia1); - mtspr(SPRN_TENS, TEN_THREAD(1)); + int hw_cpu = get_hard_smp_processor_id(nr); + int thread_idx = cpu_thread_in_core(hw_cpu); + + booting_cpu_hwid = (u32)hw_cpu; Unnecessary cast. Please explain why you need booting_cpu_hwid. + imsr = MSR_KERNEL; + inia = *(unsigned long *)fsl_secondary_thread_init; + if (thread_idx == 0) { + mttmr(TMRN_IMSR0, imsr); + mttmr(TMRN_INIA0, inia); + } else { + mttmr(TMRN_IMSR1, imsr); + mttmr(TMRN_INIA1, inia); + } + mtspr(SPRN_TENS, TEN_THREAD(thread_idx)); Please rebase this on top of http://patchwork.ozlabs.org/patch/496952/ OK. + /* + * If both threads are offline, reset core to start. + * When core is up, Thread 0 always gets up first, + * so bind the current logical cpu with Thread 0. + */ + if (hw_cpu != cpu_first_thread_sibling(hw_cpu)) { + int hw_cpu1, hw_cpu2; + + hw_cpu1 = get_hard_smp_processor_id(primary); + hw_cpu2 = get_hard_smp_processor_id(primary + 1); + set_hard_smp_processor_id(primary, hw_cpu2); + set_hard_smp_processor_id(primary + 1, hw_cpu1); + /* get new physical cpu id */ + hw_cpu = get_hard_smp_processor_id(nr); NACK as discussed in http://patchwork.ozlabs.org/patch/454944/ -Scott You said, There's no need for this. I have booting from a thread1, and having it kick its thread0, working locally without messing with the hwid/cpu mapping. I still have questions here. After a core reset, how can you boot Thread1 of the core first. As I know, Thread0 boots up first by default. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/3] Powerpc: mpc85xx: refactor the PM operations
On Thu, Aug 6, 2015 at 1:46 PM, Scott Wood scottw...@freescale.com wrote: On Thu, 2015-08-06 at 12:20 +0800, Chenhui Zhao wrote: On Thu, Aug 6, 2015 at 10:57 AM, Scott Wood scottw...@freescale.com wrote: On Wed, 2015-08-05 at 18:11 +0800, Chenhui Zhao wrote: On Tue, Aug 4, 2015 at 4:26 AM, Scott Wood scottw...@freescale.com wrote: On Mon, 2015-08-03 at 19:32 +0800, Chenhui Zhao wrote: On Sat, Aug 1, 2015 at 7:59 AM, Scott Wood scottw...@freescale.com wrote: Could you explain irq_mask()? Why would there still be IRQs destined for this CPU at this point? This function just masks irq by setting the registers in RCPM (for example, RCPM_CPMIMR, RCPM_CPMCIMR). Actually, all irqs to this CPU have been migrated to other CPUs. So why do we need to set those bits in RCPM? Is it just caution? Setting these bits can mask interrupts signalled to RCPM from MPIC as a means of waking up from a lower power state. So, cores will not be waked up unexpectedly. Why would the MPIC be signalling those interrupts if they've been masked at the MPIC? -Scott The interrupts to RCPM from MPIC are IRQ, Machine Check, NMI and Critical interrupts. Some of them didn't be masked in MPIC. What interrupt could actually happen to a sleeping cpu that this protects against? -Scott Not sure. Maybe spurious interrupts or hardware exceptions. However, setting them make sure dead cpus can not be waked up unexpectedly. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/3] Powerpc: mpc85xx: refactor the PM operations
On Thu, Aug 6, 2015 at 10:57 AM, Scott Wood scottw...@freescale.com wrote: On Wed, 2015-08-05 at 18:11 +0800, Chenhui Zhao wrote: On Tue, Aug 4, 2015 at 4:26 AM, Scott Wood scottw...@freescale.com wrote: On Mon, 2015-08-03 at 19:32 +0800, Chenhui Zhao wrote: On Sat, Aug 1, 2015 at 7:59 AM, Scott Wood scottw...@freescale.com wrote: Could you explain irq_mask()? Why would there still be IRQs destined for this CPU at this point? This function just masks irq by setting the registers in RCPM (for example, RCPM_CPMIMR, RCPM_CPMCIMR). Actually, all irqs to this CPU have been migrated to other CPUs. So why do we need to set those bits in RCPM? Is it just caution? Setting these bits can mask interrupts signalled to RCPM from MPIC as a means of waking up from a lower power state. So, cores will not be waked up unexpectedly. Why would the MPIC be signalling those interrupts if they've been masked at the MPIC? -Scott The interrupts to RCPM from MPIC are IRQ, Machine Check, NMI and Critical interrupts. Some of them didn't be masked in MPIC. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 3/3] PowerPC/mpc85xx: Add hotplug support on E6500 cores
On Thu, Aug 6, 2015 at 11:16 AM, Scott Wood scottw...@freescale.com wrote: On Wed, 2015-08-05 at 19:08 +0800, Chenhui Zhao wrote: On Sat, Aug 1, 2015 at 8:22 AM, Scott Wood scottw...@freescale.com wrote: On Fri, 2015-07-31 at 17:20 +0800, b29983@freescale.comwrote: + /* + * If both threads are offline, reset core to start. + * When core is up, Thread 0 always gets up first, + * so bind the current logical cpu with Thread 0. + */ + if (hw_cpu != cpu_first_thread_sibling(hw_cpu)) { + int hw_cpu1, hw_cpu2; + + hw_cpu1 = get_hard_smp_processor_id(primary); + hw_cpu2 = get_hard_smp_processor_id(primary + 1); + set_hard_smp_processor_id(primary, hw_cpu2); + set_hard_smp_processor_id(primary + 1, hw_cpu1); + /* get new physical cpu id */ + hw_cpu = get_hard_smp_processor_id(nr); NACK as discussed in http://patchwork.ozlabs.org/patch/454944/ -Scott You said, There's no need for this. I have booting from a thread1, and having it kick its thread0, working locally without messing with the hwid/cpu mapping. I still have questions here. After a core reset, how can you boot Thread1 of the core first. As I know, Thread0 boots up first by default. So the issue isn't that thread1 comes up first, but that you *want* thread1 to come up first and it won't. I don't think this remapping is an acceptable answer, though. Instead, if you need only thread1 to come up, start the core, have thread0 start thread1, and then send thread0 into whatever waiting state it would be in if thread1 had never been offlined. -Scott Remapping is a concise solution. what's the harm of it? Keeping things simple is good in my opinion. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v5] powerpc/rcpm: add RCPM driver
On Tue, Aug 4, 2015 at 4:23 AM, Scott Wood wrote: On Mon, 2015-08-03 at 19:14 +0800, Chenhui Zhao wrote: On Sat, Aug 1, 2015 at 8:45 AM, Scott Wood wrote: > On Fri, 2015-06-26 at 15:44 +0800, Yuantian.Tang@freescale.comwrote: > > +static void rcpm_v1_set_ip_power(bool enable, u32 *mask) > > +{ > > + if (enable) > > + setbits32(_v1_regs->ippdexpcr, *mask); > > + else > > + clrbits32(_v1_regs->ippdexpcr, *mask); > > +} > > + > > +static void rcpm_v2_set_ip_power(bool enable, u32 *mask) > > +{ > > + if (enable) > > + setbits32(_v2_regs->ippdexpcr[0], *mask); > > + else > > + clrbits32(_v2_regs->ippdexpcr[0], *mask); > > +} > > Why do these take "u32 *mask" instead of "u32 mask"? > > -Scott I think it can be used in the case where there are several mask values. When would that be? -Scott So far, only use one register, even though the register name is "IPPDEXPCRn" (has "n" suffix) in T4 RM. OK. Just change the parameter to "u32 mask". -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 3/4] powerpc: pm: add EPU FSM configuration for deep sleep
On Sat, Aug 1, 2015 at 8:41 AM, Scott Wood wrote: On Fri, 2015-07-31 at 20:53 +0800, Chenhui Zhao wrote: In the last stage of deep sleep, software will trigger a Finite State Machine (FSM) to control the hardware precedure, such as board isolation, killing PLLs, removing power, and so on. When the system is waked up by an interrupt, the FSM controls the hardware to complete the early resume precedure. This patch configure the EPU FSM preparing for deep sleep. Signed-off-by: Chenhui Zhao --- arch/powerpc/platforms/85xx/Makefile| 2 +- arch/powerpc/platforms/85xx/sleep_fsm.c | 256 arch/powerpc/platforms/85xx/sleep_fsm.h | 104 + 3 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.c create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.h When I asked why this was in drivers/platform[1], you said it was to share with LS1, and that the values used were the same -- so why did you move it to arch/powerpc? There are some changes. LS1 will use PSCI (Power State Coordination Interface) to implement deep sleep. So these code just used by PowerPC. [1] Note that other proposed patches create a drivers/soc/fsl instead of drivers/platform/fsl... We need one of them, not both. +void fsl_fsm_setup(void __iomem *base, struct fsm_reg_vals *val) +{ + struct fsm_reg_vals *data = val; + + BUG_ON(!base || !data); This BUG_ON is useless. If one of those is NULL you'll get an oops anyway. diff --git a/arch/powerpc/platforms/85xx/sleep_fsm.h b/arch/powerpc/platforms/85xx/sleep_fsm.h new file mode 100644 index 000..2c60b40 --- /dev/null +++ b/arch/powerpc/platforms/85xx/sleep_fsm.h @@ -0,0 +1,104 @@ +/* + * Freescale deep sleep FSM (finite-state machine) configuration + * + * Copyright 2015 Freescale Semiconductor Inc. + * + * 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. + */ +#ifndef _FSL_SLEEP_FSM_H +#define _FSL_SLEEP_FSM_H + +#define FSL_STRIDE_4B4 +#define FSL_STRIDE_8B8 Why not just use 4/8 directly? +/* Block offsets */ +#define RCPM_BLOCK_OFFSET0x00022000 +#define EPU_BLOCK_OFFSET 0x +#define NPC_BLOCK_OFFSET 0x1000 I thought you said OK to not putting these offsets in the kernel source... -Scott OK. Will change them. -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 2/3] PowerPC/mpc85xx: Add hotplug support on E5500 and E500MC cores
On Sat, Aug 1, 2015 at 8:14 AM, Scott Wood wrote: On Fri, 2015-07-31 at 17:20 +0800, b29...@freescale.com wrote: From: Tang Yuantian Freescale E500MC and E5500 core-based platforms, like P4080, T1040, support disabling/enabling CPU dynamically. This patch adds this feature on those platforms. Signed-off-by: Chenhui Zhao Signed-off-by: Tang Yuantian --- arch/powerpc/Kconfig | 2 +- arch/powerpc/include/asm/smp.h| 1 + arch/powerpc/kernel/smp.c | 5 + arch/powerpc/platforms/85xx/smp.c | 39 --- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 5ef2711..dd9e252 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -386,7 +386,7 @@ config SWIOTLB config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" depends on SMP && (PPC_PSERIES || \ - PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC)) + PPC_PMAC || PPC_POWERNV || FSL_SOC_BOOKE) ---help--- Say Y here to be able to disable and re-enable individual CPUs at runtime on SMP machines. diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 825663c..bf37d17 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -67,6 +67,7 @@ void generic_cpu_die(unsigned int cpu); void generic_set_cpu_dead(unsigned int cpu); void generic_set_cpu_up(unsigned int cpu); int generic_check_cpu_restart(unsigned int cpu); +int generic_check_cpu_dead(unsigned int cpu); #endif #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index ec9ec20..2cca27a 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -454,6 +454,11 @@ int generic_check_cpu_restart(unsigned int cpu) return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE; } +int generic_check_cpu_dead(unsigned int cpu) +{ + return per_cpu(cpu_state, cpu) == CPU_DEAD; +} Is there a non-generic check_cpu_dead()? NO, just follow the name "generic_check_cpu_restart()". It gets open-coded in generic_cpu_die()... Either open-code it elsewhere, or call it check_cpu_dead() and use it everywhere there's a CPU_DEAD check. + static bool secondaries_inhibited(void) { return kvm_hv_mode_active(); diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 6811a5b..7f0dadb 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -42,6 +42,7 @@ struct epapr_spin_table { u32 pir; }; +#ifdef CONFIG_HOTPLUG_CPU static u64 timebase; static int tb_req; static int tb_valid; @@ -111,7 +112,7 @@ static void mpc85xx_take_timebase(void) local_irq_restore(flags); } -#ifdef CONFIG_HOTPLUG_CPU +#ifndef CONFIG_PPC_E500MC static void e500_cpu_idle(void) What happens if we bisect to patch 1/3 and run this on e500mc? Please move the ifdef to that patch. OK. { u32 tmp; @@ -127,6 +128,7 @@ static void e500_cpu_idle(void) mtmsr(tmp); isync(); } +#endif static void qoriq_cpu_dying(void) { @@ -144,11 +146,30 @@ static void qoriq_cpu_dying(void) generic_set_cpu_dead(cpu); +#ifndef CONFIG_PPC_E500MC e500_cpu_idle(); +#endif while (1) ; } + +static void qoriq_real_cpu_die(unsigned int cpu) Real as opposed to...? It's hard to find a good name. :) +{ + int i; + + for (i = 0; i < 5; i++) { + if (generic_check_cpu_dead(cpu)) { + qoriq_pm_ops->cpu_die(cpu); +#ifdef CONFIG_PPC64 + paca[cpu].cpu_start = 0; +#endif + return; + } + udelay(10); + } + pr_err("%s: CPU%d didn't die...\n", __func__, cpu); +} Only 500ms timeout, versus 10sec in generic_cpu_die()? The process is fast. Maybe 10 second is too large. #endif static inline void flush_spin_table(void *spin_table) @@ -246,11 +267,7 @@ static int smp_85xx_kick_cpu(int nr) spin_table = phys_to_virt(*cpu_rel_addr); local_irq_save(flags); -#ifdef CONFIG_PPC32 #ifdef CONFIG_HOTPLUG_CPU - /* Corresponding to generic_set_cpu_dead() */ - generic_set_cpu_up(nr); - if (system_state == SYSTEM_RUNNING) { /* * To keep it compatible with old boot program which uses @@ -263,6 +280,7 @@ static int smp_85xx_kick_cpu(int nr) out_be32(_table->addr_l, 0); flush_spin_table(spin_table); + qoriq_pm_ops->cpu_up(nr); Again, is it possible to get here without a valid qoriq_pm_ops (i.e. is there anything stopping the user from trying to initiate CPU hotplug)? -Scott For every platform running this code, should has a
Re: [PATCH 1/3] Powerpc: mpc85xx: refactor the PM operations
On Sat, Aug 1, 2015 at 7:59 AM, Scott Wood wrote: On Fri, 2015-07-31 at 17:20 +0800, b29...@freescale.com wrote: @@ -71,7 +56,7 @@ static void mpc85xx_give_timebase(void) barrier(); tb_req = 0; - mpc85xx_timebase_freeze(1); + qoriq_pm_ops->freeze_time_base(1); freeze_time_base() takes a bool. Use true/false. OK. #ifdef CONFIG_PPC64 /* * e5500/e6500 have a workaround for erratum A-006958 in place @@ -104,7 +89,7 @@ static void mpc85xx_give_timebase(void) while (tb_valid) barrier(); - mpc85xx_timebase_freeze(0); + qoriq_pm_ops->freeze_time_base(0); local_irq_restore(flags); } @@ -127,20 +112,10 @@ static void mpc85xx_take_timebase(void) } #ifdef CONFIG_HOTPLUG_CPU -static void smp_85xx_mach_cpu_die(void) +static void e500_cpu_idle(void) This is not the function that gets called during normal cpu idle, and it shouldn't be named to look like it is. Sorry, it's a typo. It shoule be "e500_cpu_die". { - unsigned int cpu = smp_processor_id(); u32 tmp; - local_irq_disable(); - idle_task_exit(); - generic_set_cpu_dead(cpu); - mb(); - - mtspr(SPRN_TCR, 0); - - cur_cpu_spec->cpu_down_flush(); - tmp = (mfspr(SPRN_HID0) & ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP; mtspr(SPRN_HID0, tmp); isync(); @@ -151,6 +126,25 @@ static void smp_85xx_mach_cpu_die(void) mb(); mtmsr(tmp); isync(); +} + +static void qoriq_cpu_dying(void) +{ + unsigned int cpu = smp_processor_id(); + + hard_irq_disable(); + /* mask all irqs to prevent cpu wakeup */ + qoriq_pm_ops->irq_mask(cpu); + idle_task_exit(); + + mtspr(SPRN_TCR, 0); + mtspr(SPRN_TSR, mfspr(SPRN_TSR)); + + cur_cpu_spec->cpu_down_flush(); + + generic_set_cpu_dead(cpu); + + e500_cpu_idle(); Why is something that claims to be applicable to all qoriq directly calling an e500v2-specific function? Added "#ifndef CONFIG_PPC_E500MC" in the following patch. Could you explain irq_mask()? Why would there still be IRQs destined for this CPU at this point? This function just masks irq by setting the registers in RCPM (for example, RCPM_CPMIMR, RCPM_CPMCIMR). Actually, all irqs to this CPU have been migrated to other CPUs. @@ -431,21 +415,9 @@ void __init mpc85xx_smp_init(void) smp_85xx_ops.probe = NULL; } - np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); - if (np) { - guts = of_iomap(np, 0); - of_node_put(np); - if (!guts) { - pr_err("%s: Could not map guts node address\n", - __func__); - return; - } - smp_85xx_ops.give_timebase = mpc85xx_give_timebase; - smp_85xx_ops.take_timebase = mpc85xx_take_timebase; #ifdef CONFIG_HOTPLUG_CPU - ppc_md.cpu_die = smp_85xx_mach_cpu_die; + ppc_md.cpu_die = qoriq_cpu_dying; #endif Shouldn't you make sure there's a valid qoriq_pm_ops before setting cpu_die()? Or make sure that qoriq_cpu_dying() works regardless. -Scott This patch is just for e500v2. The following patches will handle the case of e500mc, e5500 and e6500. -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v5] powerpc/rcpm: add RCPM driver
On Sat, Aug 1, 2015 at 8:45 AM, Scott Wood wrote: On Fri, 2015-06-26 at 15:44 +0800, yuantian.t...@freescale.com wrote: +static void rcpm_v1_set_ip_power(bool enable, u32 *mask) +{ + if (enable) + setbits32(_v1_regs->ippdexpcr, *mask); + else + clrbits32(_v1_regs->ippdexpcr, *mask); +} + +static void rcpm_v2_set_ip_power(bool enable, u32 *mask) +{ + if (enable) + setbits32(_v2_regs->ippdexpcr[0], *mask); + else + clrbits32(_v2_regs->ippdexpcr[0], *mask); +} Why do these take "u32 *mask" instead of "u32 mask"? -Scott I think it can be used in the case where there are several mask values. -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH] powerpc/85xx: add sleep and deep sleep support
On Sat, Aug 1, 2015 at 10:57 AM, Scott Wood wrote: On Fri, 2015-07-24 at 20:46 +0800, Chenhui Zhao wrote: +static void mpc85xx_pmc_set_wake(struct device *dev, void *enable) { int ret; + u32 value[2]; + + if (!device_may_wakeup(dev)) + return; + + if (!pmc_regs) { + dev_err(dev, "%s: PMC is unavailable\n", __func__); + return; + } + + ret = of_property_read_u32_array(dev->of_node, "sleep", value, 2); This will crash on any device without an of_node. Add this before this line: if (!dev->of_node) return; + if (ret) { + dev_dbg(dev, "%s: Can not find the \"sleep\" property.\n", + __func__); + return; + } + + if (*(int *)enable) + pmc_pmcdr_mask &= ~value[1]; + else + pmc_pmcdr_mask |= value[1]; + + if ((value[1] & 0xe0) && (pmc_flag & PMC_LOSSLESS)) + pmc_powmgtcsr = POWMGTCSR_LOSSLESS; +} What is 0xe0? -Scott This is a mask value for the register PMCDR, which includes all bits corresponding to eTSEC. Will use a macro instead. -Chenhui -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v5] powerpc/rcpm: add RCPM driver
On Tue, Aug 4, 2015 at 4:23 AM, Scott Wood scottw...@freescale.com wrote: On Mon, 2015-08-03 at 19:14 +0800, Chenhui Zhao wrote: On Sat, Aug 1, 2015 at 8:45 AM, Scott Wood scottw...@freescale.com wrote: On Fri, 2015-06-26 at 15:44 +0800, Yuantian.Tang@freescale.comwrote: +static void rcpm_v1_set_ip_power(bool enable, u32 *mask) +{ + if (enable) + setbits32(rcpm_v1_regs-ippdexpcr, *mask); + else + clrbits32(rcpm_v1_regs-ippdexpcr, *mask); +} + +static void rcpm_v2_set_ip_power(bool enable, u32 *mask) +{ + if (enable) + setbits32(rcpm_v2_regs-ippdexpcr[0], *mask); + else + clrbits32(rcpm_v2_regs-ippdexpcr[0], *mask); +} Why do these take u32 *mask instead of u32 mask? -Scott I think it can be used in the case where there are several mask values. When would that be? -Scott So far, only use one register, even though the register name is IPPDEXPCRn (has n suffix) in T4 RM. OK. Just change the parameter to u32 mask. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH] powerpc/85xx: add sleep and deep sleep support
On Sat, Aug 1, 2015 at 10:57 AM, Scott Wood scottw...@freescale.com wrote: On Fri, 2015-07-24 at 20:46 +0800, Chenhui Zhao wrote: +static void mpc85xx_pmc_set_wake(struct device *dev, void *enable) { int ret; + u32 value[2]; + + if (!device_may_wakeup(dev)) + return; + + if (!pmc_regs) { + dev_err(dev, %s: PMC is unavailable\n, __func__); + return; + } + + ret = of_property_read_u32_array(dev-of_node, sleep, value, 2); This will crash on any device without an of_node. Add this before this line: if (!dev-of_node) return; + if (ret) { + dev_dbg(dev, %s: Can not find the \sleep\ property.\n, + __func__); + return; + } + + if (*(int *)enable) + pmc_pmcdr_mask = ~value[1]; + else + pmc_pmcdr_mask |= value[1]; + + if ((value[1] 0xe0) (pmc_flag PMC_LOSSLESS)) + pmc_powmgtcsr = POWMGTCSR_LOSSLESS; +} What is 0xe0? -Scott This is a mask value for the register PMCDR, which includes all bits corresponding to eTSEC. Will use a macro instead. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v5] powerpc/rcpm: add RCPM driver
On Sat, Aug 1, 2015 at 8:45 AM, Scott Wood scottw...@freescale.com wrote: On Fri, 2015-06-26 at 15:44 +0800, yuantian.t...@freescale.com wrote: +static void rcpm_v1_set_ip_power(bool enable, u32 *mask) +{ + if (enable) + setbits32(rcpm_v1_regs-ippdexpcr, *mask); + else + clrbits32(rcpm_v1_regs-ippdexpcr, *mask); +} + +static void rcpm_v2_set_ip_power(bool enable, u32 *mask) +{ + if (enable) + setbits32(rcpm_v2_regs-ippdexpcr[0], *mask); + else + clrbits32(rcpm_v2_regs-ippdexpcr[0], *mask); +} Why do these take u32 *mask instead of u32 mask? -Scott I think it can be used in the case where there are several mask values. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/3] Powerpc: mpc85xx: refactor the PM operations
On Sat, Aug 1, 2015 at 7:59 AM, Scott Wood scottw...@freescale.com wrote: On Fri, 2015-07-31 at 17:20 +0800, b29...@freescale.com wrote: @@ -71,7 +56,7 @@ static void mpc85xx_give_timebase(void) barrier(); tb_req = 0; - mpc85xx_timebase_freeze(1); + qoriq_pm_ops-freeze_time_base(1); freeze_time_base() takes a bool. Use true/false. OK. #ifdef CONFIG_PPC64 /* * e5500/e6500 have a workaround for erratum A-006958 in place @@ -104,7 +89,7 @@ static void mpc85xx_give_timebase(void) while (tb_valid) barrier(); - mpc85xx_timebase_freeze(0); + qoriq_pm_ops-freeze_time_base(0); local_irq_restore(flags); } @@ -127,20 +112,10 @@ static void mpc85xx_take_timebase(void) } #ifdef CONFIG_HOTPLUG_CPU -static void smp_85xx_mach_cpu_die(void) +static void e500_cpu_idle(void) This is not the function that gets called during normal cpu idle, and it shouldn't be named to look like it is. Sorry, it's a typo. It shoule be e500_cpu_die. { - unsigned int cpu = smp_processor_id(); u32 tmp; - local_irq_disable(); - idle_task_exit(); - generic_set_cpu_dead(cpu); - mb(); - - mtspr(SPRN_TCR, 0); - - cur_cpu_spec-cpu_down_flush(); - tmp = (mfspr(SPRN_HID0) ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP; mtspr(SPRN_HID0, tmp); isync(); @@ -151,6 +126,25 @@ static void smp_85xx_mach_cpu_die(void) mb(); mtmsr(tmp); isync(); +} + +static void qoriq_cpu_dying(void) +{ + unsigned int cpu = smp_processor_id(); + + hard_irq_disable(); + /* mask all irqs to prevent cpu wakeup */ + qoriq_pm_ops-irq_mask(cpu); + idle_task_exit(); + + mtspr(SPRN_TCR, 0); + mtspr(SPRN_TSR, mfspr(SPRN_TSR)); + + cur_cpu_spec-cpu_down_flush(); + + generic_set_cpu_dead(cpu); + + e500_cpu_idle(); Why is something that claims to be applicable to all qoriq directly calling an e500v2-specific function? Added #ifndef CONFIG_PPC_E500MC in the following patch. Could you explain irq_mask()? Why would there still be IRQs destined for this CPU at this point? This function just masks irq by setting the registers in RCPM (for example, RCPM_CPMIMR, RCPM_CPMCIMR). Actually, all irqs to this CPU have been migrated to other CPUs. @@ -431,21 +415,9 @@ void __init mpc85xx_smp_init(void) smp_85xx_ops.probe = NULL; } - np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); - if (np) { - guts = of_iomap(np, 0); - of_node_put(np); - if (!guts) { - pr_err(%s: Could not map guts node address\n, - __func__); - return; - } - smp_85xx_ops.give_timebase = mpc85xx_give_timebase; - smp_85xx_ops.take_timebase = mpc85xx_take_timebase; #ifdef CONFIG_HOTPLUG_CPU - ppc_md.cpu_die = smp_85xx_mach_cpu_die; + ppc_md.cpu_die = qoriq_cpu_dying; #endif Shouldn't you make sure there's a valid qoriq_pm_ops before setting cpu_die()? Or make sure that qoriq_cpu_dying() works regardless. -Scott This patch is just for e500v2. The following patches will handle the case of e500mc, e5500 and e6500. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 2/3] PowerPC/mpc85xx: Add hotplug support on E5500 and E500MC cores
On Sat, Aug 1, 2015 at 8:14 AM, Scott Wood scottw...@freescale.com wrote: On Fri, 2015-07-31 at 17:20 +0800, b29...@freescale.com wrote: From: Tang Yuantian yuantian.t...@freescale.com Freescale E500MC and E5500 core-based platforms, like P4080, T1040, support disabling/enabling CPU dynamically. This patch adds this feature on those platforms. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com Signed-off-by: Tang Yuantian yuantian.t...@feescale.com --- arch/powerpc/Kconfig | 2 +- arch/powerpc/include/asm/smp.h| 1 + arch/powerpc/kernel/smp.c | 5 + arch/powerpc/platforms/85xx/smp.c | 39 --- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 5ef2711..dd9e252 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -386,7 +386,7 @@ config SWIOTLB config HOTPLUG_CPU bool Support for enabling/disabling CPUs depends on SMP (PPC_PSERIES || \ - PPC_PMAC || PPC_POWERNV || (PPC_85xx !PPC_E500MC)) + PPC_PMAC || PPC_POWERNV || FSL_SOC_BOOKE) ---help--- Say Y here to be able to disable and re-enable individual CPUs at runtime on SMP machines. diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 825663c..bf37d17 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -67,6 +67,7 @@ void generic_cpu_die(unsigned int cpu); void generic_set_cpu_dead(unsigned int cpu); void generic_set_cpu_up(unsigned int cpu); int generic_check_cpu_restart(unsigned int cpu); +int generic_check_cpu_dead(unsigned int cpu); #endif #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index ec9ec20..2cca27a 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -454,6 +454,11 @@ int generic_check_cpu_restart(unsigned int cpu) return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE; } +int generic_check_cpu_dead(unsigned int cpu) +{ + return per_cpu(cpu_state, cpu) == CPU_DEAD; +} Is there a non-generic check_cpu_dead()? NO, just follow the name generic_check_cpu_restart(). It gets open-coded in generic_cpu_die()... Either open-code it elsewhere, or call it check_cpu_dead() and use it everywhere there's a CPU_DEAD check. + static bool secondaries_inhibited(void) { return kvm_hv_mode_active(); diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 6811a5b..7f0dadb 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -42,6 +42,7 @@ struct epapr_spin_table { u32 pir; }; +#ifdef CONFIG_HOTPLUG_CPU static u64 timebase; static int tb_req; static int tb_valid; @@ -111,7 +112,7 @@ static void mpc85xx_take_timebase(void) local_irq_restore(flags); } -#ifdef CONFIG_HOTPLUG_CPU +#ifndef CONFIG_PPC_E500MC static void e500_cpu_idle(void) What happens if we bisect to patch 1/3 and run this on e500mc? Please move the ifdef to that patch. OK. { u32 tmp; @@ -127,6 +128,7 @@ static void e500_cpu_idle(void) mtmsr(tmp); isync(); } +#endif static void qoriq_cpu_dying(void) { @@ -144,11 +146,30 @@ static void qoriq_cpu_dying(void) generic_set_cpu_dead(cpu); +#ifndef CONFIG_PPC_E500MC e500_cpu_idle(); +#endif while (1) ; } + +static void qoriq_real_cpu_die(unsigned int cpu) Real as opposed to...? It's hard to find a good name. :) +{ + int i; + + for (i = 0; i 5; i++) { + if (generic_check_cpu_dead(cpu)) { + qoriq_pm_ops-cpu_die(cpu); +#ifdef CONFIG_PPC64 + paca[cpu].cpu_start = 0; +#endif + return; + } + udelay(10); + } + pr_err(%s: CPU%d didn't die...\n, __func__, cpu); +} Only 500ms timeout, versus 10sec in generic_cpu_die()? The process is fast. Maybe 10 second is too large. #endif static inline void flush_spin_table(void *spin_table) @@ -246,11 +267,7 @@ static int smp_85xx_kick_cpu(int nr) spin_table = phys_to_virt(*cpu_rel_addr); local_irq_save(flags); -#ifdef CONFIG_PPC32 #ifdef CONFIG_HOTPLUG_CPU - /* Corresponding to generic_set_cpu_dead() */ - generic_set_cpu_up(nr); - if (system_state == SYSTEM_RUNNING) { /* * To keep it compatible with old boot program which uses @@ -263,6 +280,7 @@ static int smp_85xx_kick_cpu(int nr) out_be32(spin_table-addr_l, 0); flush_spin_table(spin_table); + qoriq_pm_ops-cpu_up(nr); Again, is it possible to get here without a valid qoriq_pm_ops (i.e. is there anything stopping the user from trying to initiate CPU hotplug)? -Scott For every platform running
Re: [PATCH 3/4] powerpc: pm: add EPU FSM configuration for deep sleep
On Sat, Aug 1, 2015 at 8:41 AM, Scott Wood scottw...@freescale.com wrote: On Fri, 2015-07-31 at 20:53 +0800, Chenhui Zhao wrote: In the last stage of deep sleep, software will trigger a Finite State Machine (FSM) to control the hardware precedure, such as board isolation, killing PLLs, removing power, and so on. When the system is waked up by an interrupt, the FSM controls the hardware to complete the early resume precedure. This patch configure the EPU FSM preparing for deep sleep. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/powerpc/platforms/85xx/Makefile| 2 +- arch/powerpc/platforms/85xx/sleep_fsm.c | 256 arch/powerpc/platforms/85xx/sleep_fsm.h | 104 + 3 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.c create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.h When I asked why this was in drivers/platform[1], you said it was to share with LS1, and that the values used were the same -- so why did you move it to arch/powerpc? There are some changes. LS1 will use PSCI (Power State Coordination Interface) to implement deep sleep. So these code just used by PowerPC. [1] Note that other proposed patches create a drivers/soc/fsl instead of drivers/platform/fsl... We need one of them, not both. +void fsl_fsm_setup(void __iomem *base, struct fsm_reg_vals *val) +{ + struct fsm_reg_vals *data = val; + + BUG_ON(!base || !data); This BUG_ON is useless. If one of those is NULL you'll get an oops anyway. diff --git a/arch/powerpc/platforms/85xx/sleep_fsm.h b/arch/powerpc/platforms/85xx/sleep_fsm.h new file mode 100644 index 000..2c60b40 --- /dev/null +++ b/arch/powerpc/platforms/85xx/sleep_fsm.h @@ -0,0 +1,104 @@ +/* + * Freescale deep sleep FSM (finite-state machine) configuration + * + * Copyright 2015 Freescale Semiconductor Inc. + * + * 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. + */ +#ifndef _FSL_SLEEP_FSM_H +#define _FSL_SLEEP_FSM_H + +#define FSL_STRIDE_4B4 +#define FSL_STRIDE_8B8 Why not just use 4/8 directly? +/* Block offsets */ +#define RCPM_BLOCK_OFFSET0x00022000 +#define EPU_BLOCK_OFFSET 0x +#define NPC_BLOCK_OFFSET 0x1000 I thought you said OK to not putting these offsets in the kernel source... -Scott OK. Will change them. -Chenhui -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/4] powerpc: get the physical base address of DCSR
Add get_dcsrbase() to get the physical base address of DCSR. Signed-off-by: Chenhui Zhao --- arch/powerpc/sysdev/fsl_soc.c | 31 +++ arch/powerpc/sysdev/fsl_soc.h | 1 + 2 files changed, 32 insertions(+) diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 99269c0..ffb7c1c 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -45,6 +45,37 @@ extern void init_fcc_ioports(struct fs_platform_info*); extern void init_fec_ioports(struct fs_platform_info*); extern void init_smc_ioports(struct fs_uart_platform_info*); static phys_addr_t immrbase = -1; +static phys_addr_t dcsrbase = -1; + +phys_addr_t get_dcsrbase(void) +{ + struct device_node *np; + const __be32 *prop; + int size; + u32 naddr; + + if (dcsrbase != -1) + return dcsrbase; + + np = of_find_compatible_node(NULL, NULL, "fsl,dcsr"); + if (!np) + return -1; + + prop = of_get_property(np, "#address-cells", ); + if (prop && size == 4) + naddr = be32_to_cpup(prop); + else + naddr = 2; + + prop = of_get_property(np, "ranges", NULL); + if (prop) + dcsrbase = of_translate_address(np, prop + naddr); + + of_node_put(np); + + return dcsrbase; +} +EXPORT_SYMBOL(get_dcsrbase); phys_addr_t get_immrbase(void) { diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 4c5a19e..5fdd3a5 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h @@ -6,6 +6,7 @@ struct spi_device; +extern phys_addr_t get_dcsrbase(void); extern phys_addr_t get_immrbase(void); #if defined(CONFIG_CPM2) || defined(CONFIG_QUICC_ENGINE) || defined(CONFIG_8xx) extern u32 get_brgfreq(void); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 3/4] powerpc: pm: add EPU FSM configuration for deep sleep
In the last stage of deep sleep, software will trigger a Finite State Machine (FSM) to control the hardware precedure, such as board isolation, killing PLLs, removing power, and so on. When the system is waked up by an interrupt, the FSM controls the hardware to complete the early resume precedure. This patch configure the EPU FSM preparing for deep sleep. Signed-off-by: Chenhui Zhao --- arch/powerpc/platforms/85xx/Makefile| 2 +- arch/powerpc/platforms/85xx/sleep_fsm.c | 256 arch/powerpc/platforms/85xx/sleep_fsm.h | 104 + 3 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.c create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.h diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index fdae28b..87fb847 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o -obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o +obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o sleep_fsm.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/sleep_fsm.c b/arch/powerpc/platforms/85xx/sleep_fsm.c new file mode 100644 index 000..2e81d37 --- /dev/null +++ b/arch/powerpc/platforms/85xx/sleep_fsm.c @@ -0,0 +1,256 @@ +/* + * Freescale deep sleep FSM (finite-state machine) configuration + * + * Copyright 2015 Freescale Semiconductor Inc. + * + * Author: Hongbo Zhang + * 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 "sleep_fsm.h" +/* + * These values are from chip's reference manual. For example, + * the values for T1040 can be found in "8.4.3.8 Programming + * supporting deep sleep mode" of Chapter 8 "Run Control and + * Power Management (RCPM)". + * The default value can be applied to T104x, LS1021. + */ +struct fsm_reg_vals epu_default_val[] = { + /* EPGCR (Event Processor Global Control Register) */ + {EPGCR, 0}, + /* EPECR (Event Processor Event Control Registers) */ + {EPECR0 + EPECR_STRIDE * 0, 0}, + {EPECR0 + EPECR_STRIDE * 1, 0}, + {EPECR0 + EPECR_STRIDE * 2, 0xF0004004}, + {EPECR0 + EPECR_STRIDE * 3, 0x8084}, + {EPECR0 + EPECR_STRIDE * 4, 0x2084}, + {EPECR0 + EPECR_STRIDE * 5, 0x0804}, + {EPECR0 + EPECR_STRIDE * 6, 0x8084}, + {EPECR0 + EPECR_STRIDE * 7, 0x8084}, + {EPECR0 + EPECR_STRIDE * 8, 0x6084}, + {EPECR0 + EPECR_STRIDE * 9, 0x0884}, + {EPECR0 + EPECR_STRIDE * 10, 0x4284}, + {EPECR0 + EPECR_STRIDE * 11, 0x9084}, + {EPECR0 + EPECR_STRIDE * 12, 0x8084}, + {EPECR0 + EPECR_STRIDE * 13, 0x0884}, + {EPECR0 + EPECR_STRIDE * 14, 0x0284}, + {EPECR0 + EPECR_STRIDE * 15, 0x0004}, + /* +* EPEVTCR (Event Processor EVT Pin Control Registers) +* SCU8 triger EVT2, and SCU11 triger EVT9 +*/ + {EPEVTCR0 + EPEVTCR_STRIDE * 0, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 1, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x8001}, + {EPEVTCR0 + EPEVTCR_STRIDE * 3, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 4, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 5, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 6, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 7, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 8, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 9, 0xB001}, + /* EPCMPR (Event Processor Counter Compare Registers) */ + {EPCMPR0 + EPCMPR_STRIDE * 0, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 1, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 2, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 3, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 4, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 5, 0x0020}, + {EPCMPR0 + EPCMPR_STRIDE * 6, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 7, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 8, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 9, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 10, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 11, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 12, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 13, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 14, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 15, 0x00FF}, + /* EPCCR (Event Processor Counter Control Registers) */ + {EPCCR0 + EPCCR_STRIDE * 0, 0}, + {EPCCR0 + EPCCR_STRIDE * 1, 0}, + {EPCCR0 + EPCCR_STRIDE * 2, 0x9284}, + {EPCCR0 + EPCCR_STRIDE * 3, 0}, + {EPCCR0 + EPCCR_STRIDE * 4, 0x9284}, + {EPCCR0 + EPCCR_STRIDE * 5, 0x9284}, + {EPCCR0 + EPCCR_STRIDE * 6, 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 1/4] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
In sleep mode, the clocks of e500 cores and unused IP blocks is turned off. The IP blocks which are allowed to wake up the processor are still running. The sleep mode is equal to the Standby state in Linux. Use the command to enter sleep mode: echo standby > /sys/power/state Signed-off-by: Chenhui Zhao --- Note: This patch set is based on CPU hotplug patches. arch/powerpc/Kconfig | 3 +- arch/powerpc/platforms/85xx/Kconfig| 5 +++ arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/qoriq_pm.c | 59 ++ arch/powerpc/platforms/86xx/Kconfig| 1 + 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index dd9e252..57bbbfb 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -233,7 +233,7 @@ config ARCH_HIBERNATION_POSSIBLE config ARCH_SUSPEND_POSSIBLE def_bool y depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ - (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \ + FSL_SOC_BOOKE || PPC_86xx || PPC_PSERIES \ || 44x || 40x config PPC_DCR_NATIVE @@ -753,7 +753,6 @@ config FSL_PCI config FSL_PMC bool - default y depends on SUSPEND && (PPC_85xx || PPC_86xx) help Freescale MPC85xx/MPC86xx power management controller support diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index e626461..dff2ea6 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -9,6 +9,8 @@ menuconfig FSL_SOC_BOOKE select SERIAL_8250_EXTENDED if SERIAL_8250 select SERIAL_8250_SHARE_IRQ if SERIAL_8250 select FSL_CORENET_RCPM if PPC_E500MC + select FSL_QORIQ_PM if SUSPEND && PPC_E500MC + select FSL_PMC if SUSPEND && !PPC_E500MC default y if FSL_SOC_BOOKE @@ -289,3 +291,6 @@ endif # FSL_SOC_BOOKE config TQM85xx bool + +config FSL_QORIQ_PM + bool diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 7bc86da..fdae28b 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o +obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c new file mode 100644 index 000..27ec337 --- /dev/null +++ b/arch/powerpc/platforms/85xx/qoriq_pm.c @@ -0,0 +1,59 @@ +/* + * Support Power Management feature + * + * Copyright 2014-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 + +static int qoriq_suspend_enter(suspend_state_t state) +{ + int ret = 0; + + switch (state) { + case PM_SUSPEND_STANDBY: + cur_cpu_spec->cpu_down_flush(); + ret = qoriq_pm_ops->plat_enter_sleep(); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int qoriq_suspend_valid(suspend_state_t state) +{ + unsigned int pm_modes; + + pm_modes = qoriq_pm_ops->get_pm_modes(); + + if ((state == PM_SUSPEND_STANDBY) && (pm_modes & FSL_PM_SLEEP)) + return 1; + + return 0; +} + +static const struct platform_suspend_ops qoriq_suspend_ops = { + .valid = qoriq_suspend_valid, + .enter = qoriq_suspend_enter, +}; + +static int __init qoriq_suspend_init(void) +{ + suspend_set_ops(_suspend_ops); + + return 0; +} +arch_initcall(qoriq_suspend_init); diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 1afd1e4..09638e0 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -5,6 +5,7 @@ menuconfig PPC_86xx select FSL_SOC select ALTIVEC select ARCH_WANT_OPTIONAL_GPIOLIB + select FSL_PMC if SUSPEND help The Freescale E600 SoCs have 74xx cores. -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/4] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
In sleep mode, the clocks of e500 cores and unused IP blocks is turned off. The IP blocks which are allowed to wake up the processor are still running. The sleep mode is equal to the Standby state in Linux. Use the command to enter sleep mode: echo standby /sys/power/state Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- Note: This patch set is based on CPU hotplug patches. arch/powerpc/Kconfig | 3 +- arch/powerpc/platforms/85xx/Kconfig| 5 +++ arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/qoriq_pm.c | 59 ++ arch/powerpc/platforms/86xx/Kconfig| 1 + 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index dd9e252..57bbbfb 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -233,7 +233,7 @@ config ARCH_HIBERNATION_POSSIBLE config ARCH_SUSPEND_POSSIBLE def_bool y depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ - (PPC_85xx !PPC_E500MC) || PPC_86xx || PPC_PSERIES \ + FSL_SOC_BOOKE || PPC_86xx || PPC_PSERIES \ || 44x || 40x config PPC_DCR_NATIVE @@ -753,7 +753,6 @@ config FSL_PCI config FSL_PMC bool - default y depends on SUSPEND (PPC_85xx || PPC_86xx) help Freescale MPC85xx/MPC86xx power management controller support diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index e626461..dff2ea6 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -9,6 +9,8 @@ menuconfig FSL_SOC_BOOKE select SERIAL_8250_EXTENDED if SERIAL_8250 select SERIAL_8250_SHARE_IRQ if SERIAL_8250 select FSL_CORENET_RCPM if PPC_E500MC + select FSL_QORIQ_PM if SUSPEND PPC_E500MC + select FSL_PMC if SUSPEND !PPC_E500MC default y if FSL_SOC_BOOKE @@ -289,3 +291,6 @@ endif # FSL_SOC_BOOKE config TQM85xx bool + +config FSL_QORIQ_PM + bool diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 7bc86da..fdae28b 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o +obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c new file mode 100644 index 000..27ec337 --- /dev/null +++ b/arch/powerpc/platforms/85xx/qoriq_pm.c @@ -0,0 +1,59 @@ +/* + * Support Power Management feature + * + * Copyright 2014-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. + */ + +#include linux/kernel.h +#include linux/suspend.h +#include linux/of_platform.h + +#include asm/fsl_pm.h + +static int qoriq_suspend_enter(suspend_state_t state) +{ + int ret = 0; + + switch (state) { + case PM_SUSPEND_STANDBY: + cur_cpu_spec-cpu_down_flush(); + ret = qoriq_pm_ops-plat_enter_sleep(); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int qoriq_suspend_valid(suspend_state_t state) +{ + unsigned int pm_modes; + + pm_modes = qoriq_pm_ops-get_pm_modes(); + + if ((state == PM_SUSPEND_STANDBY) (pm_modes FSL_PM_SLEEP)) + return 1; + + return 0; +} + +static const struct platform_suspend_ops qoriq_suspend_ops = { + .valid = qoriq_suspend_valid, + .enter = qoriq_suspend_enter, +}; + +static int __init qoriq_suspend_init(void) +{ + suspend_set_ops(qoriq_suspend_ops); + + return 0; +} +arch_initcall(qoriq_suspend_init); diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 1afd1e4..09638e0 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -5,6 +5,7 @@ menuconfig PPC_86xx select FSL_SOC select ALTIVEC select ARCH_WANT_OPTIONAL_GPIOLIB + select FSL_PMC if SUSPEND help The Freescale E600 SoCs have 74xx cores. -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[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
[PATCH 3/4] powerpc: pm: add EPU FSM configuration for deep sleep
In the last stage of deep sleep, software will trigger a Finite State Machine (FSM) to control the hardware precedure, such as board isolation, killing PLLs, removing power, and so on. When the system is waked up by an interrupt, the FSM controls the hardware to complete the early resume precedure. This patch configure the EPU FSM preparing for deep sleep. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/powerpc/platforms/85xx/Makefile| 2 +- arch/powerpc/platforms/85xx/sleep_fsm.c | 256 arch/powerpc/platforms/85xx/sleep_fsm.h | 104 + 3 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.c create mode 100644 arch/powerpc/platforms/85xx/sleep_fsm.h diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index fdae28b..87fb847 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_FSL_PMC)+= mpc85xx_pm_ops.o -obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o +obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o sleep_fsm.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/sleep_fsm.c b/arch/powerpc/platforms/85xx/sleep_fsm.c new file mode 100644 index 000..2e81d37 --- /dev/null +++ b/arch/powerpc/platforms/85xx/sleep_fsm.c @@ -0,0 +1,256 @@ +/* + * Freescale deep sleep FSM (finite-state machine) configuration + * + * Copyright 2015 Freescale Semiconductor Inc. + * + * Author: Hongbo Zhang hongbo.zh...@freescale.com + * 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. + */ + +#include linux/kernel.h +#include linux/io.h +#include linux/types.h + +#include sleep_fsm.h +/* + * These values are from chip's reference manual. For example, + * the values for T1040 can be found in 8.4.3.8 Programming + * supporting deep sleep mode of Chapter 8 Run Control and + * Power Management (RCPM). + * The default value can be applied to T104x, LS1021. + */ +struct fsm_reg_vals epu_default_val[] = { + /* EPGCR (Event Processor Global Control Register) */ + {EPGCR, 0}, + /* EPECR (Event Processor Event Control Registers) */ + {EPECR0 + EPECR_STRIDE * 0, 0}, + {EPECR0 + EPECR_STRIDE * 1, 0}, + {EPECR0 + EPECR_STRIDE * 2, 0xF0004004}, + {EPECR0 + EPECR_STRIDE * 3, 0x8084}, + {EPECR0 + EPECR_STRIDE * 4, 0x2084}, + {EPECR0 + EPECR_STRIDE * 5, 0x0804}, + {EPECR0 + EPECR_STRIDE * 6, 0x8084}, + {EPECR0 + EPECR_STRIDE * 7, 0x8084}, + {EPECR0 + EPECR_STRIDE * 8, 0x6084}, + {EPECR0 + EPECR_STRIDE * 9, 0x0884}, + {EPECR0 + EPECR_STRIDE * 10, 0x4284}, + {EPECR0 + EPECR_STRIDE * 11, 0x9084}, + {EPECR0 + EPECR_STRIDE * 12, 0x8084}, + {EPECR0 + EPECR_STRIDE * 13, 0x0884}, + {EPECR0 + EPECR_STRIDE * 14, 0x0284}, + {EPECR0 + EPECR_STRIDE * 15, 0x0004}, + /* +* EPEVTCR (Event Processor EVT Pin Control Registers) +* SCU8 triger EVT2, and SCU11 triger EVT9 +*/ + {EPEVTCR0 + EPEVTCR_STRIDE * 0, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 1, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x8001}, + {EPEVTCR0 + EPEVTCR_STRIDE * 3, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 4, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 5, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 6, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 7, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 8, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 9, 0xB001}, + /* EPCMPR (Event Processor Counter Compare Registers) */ + {EPCMPR0 + EPCMPR_STRIDE * 0, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 1, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 2, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 3, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 4, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 5, 0x0020}, + {EPCMPR0 + EPCMPR_STRIDE * 6, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 7, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 8, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 9, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 10, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 11, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 12, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 13, 0}, + {EPCMPR0 + EPCMPR_STRIDE * 14, 0x00FF}, + {EPCMPR0 + EPCMPR_STRIDE * 15, 0x00FF}, + /* EPCCR (Event Processor Counter Control Registers) */ + {EPCCR0 + EPCCR_STRIDE * 0, 0}, + {EPCCR0 + EPCCR_STRIDE * 1, 0}, + {EPCCR0 + EPCCR_STRIDE * 2, 0x9284}, + {EPCCR0 + EPCCR_STRIDE * 3, 0}, + {EPCCR0 + EPCCR_STRIDE * 4, 0x9284
[PATCH 2/4] powerpc: get the physical base address of DCSR
Add get_dcsrbase() to get the physical base address of DCSR. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/powerpc/sysdev/fsl_soc.c | 31 +++ arch/powerpc/sysdev/fsl_soc.h | 1 + 2 files changed, 32 insertions(+) diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 99269c0..ffb7c1c 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -45,6 +45,37 @@ extern void init_fcc_ioports(struct fs_platform_info*); extern void init_fec_ioports(struct fs_platform_info*); extern void init_smc_ioports(struct fs_uart_platform_info*); static phys_addr_t immrbase = -1; +static phys_addr_t dcsrbase = -1; + +phys_addr_t get_dcsrbase(void) +{ + struct device_node *np; + const __be32 *prop; + int size; + u32 naddr; + + if (dcsrbase != -1) + return dcsrbase; + + np = of_find_compatible_node(NULL, NULL, fsl,dcsr); + if (!np) + return -1; + + prop = of_get_property(np, #address-cells, size); + if (prop size == 4) + naddr = be32_to_cpup(prop); + else + naddr = 2; + + prop = of_get_property(np, ranges, NULL); + if (prop) + dcsrbase = of_translate_address(np, prop + naddr); + + of_node_put(np); + + return dcsrbase; +} +EXPORT_SYMBOL(get_dcsrbase); phys_addr_t get_immrbase(void) { diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 4c5a19e..5fdd3a5 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h @@ -6,6 +6,7 @@ struct spi_device; +extern phys_addr_t get_dcsrbase(void); extern phys_addr_t get_immrbase(void); #if defined(CONFIG_CPM2) || defined(CONFIG_QUICC_ENGINE) || defined(CONFIG_8xx) extern u32 get_brgfreq(void); -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] powerpc/85xx: add sleep and deep sleep support
In sleep PM mode, the clocks of e500 core and unused IP blocks is turned off. IP blocks which are allowed to wake up the processor are still running. Some Freescale chips like MPC8536 and P1022 has deep sleep PM mode in addtion to the sleep PM mode. While in deep sleep PM mode, additionally, the power supply is removed from e500 core and most IP blocks. Only the blocks needed to wake up the chip out of deep sleep are ON. This patch supports 32-bit and 36-bit address space. The sleep mode is equal to the Standby state in Linux. The deep sleep mode is equal to the Suspend-to-RAM state of Linux Power Management. Command to enter sleep mode. echo standby > /sys/power/state Command to enter deep sleep mode. echo mem > /sys/power/state Signed-off-by: Li Yang Signed-off-by: Chenhui Zhao --- arch/powerpc/include/asm/cacheflush.h | 5 + arch/powerpc/platforms/85xx/Makefile| 3 + arch/powerpc/platforms/85xx/pmc_deepsleep.S | 645 arch/powerpc/sysdev/fsl_pmc.c | 146 ++- arch/powerpc/sysdev/fsl_soc.h | 5 + 5 files changed, 785 insertions(+), 19 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/pmc_deepsleep.S diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 30b35ff..9ec4c31 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -31,6 +31,11 @@ extern void flush_dcache_page(struct page *page); #define flush_dcache_mmap_unlock(mapping) do { } while (0) extern void __flush_disable_L1(void); +#ifdef CONFIG_FSL_BOOKE +extern void flush_dcache_L1(void); +#else +#define flush_dcache_L1() do { } while (0) +#endif extern void flush_icache_range(unsigned long, unsigned long); extern void flush_icache_user_range(struct vm_area_struct *vma, diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 1fe7fb9..d187253 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -2,6 +2,9 @@ # Makefile for the PowerPC 85xx linux kernel. # obj-$(CONFIG_SMP) += smp.o +ifneq ($(CONFIG_PPC_E500MC),y) +obj-$(CONFIG_SUSPEND) += pmc_deepsleep.o +endif obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/pmc_deepsleep.S b/arch/powerpc/platforms/85xx/pmc_deepsleep.S new file mode 100644 index 000..57fd4f4 --- /dev/null +++ b/arch/powerpc/platforms/85xx/pmc_deepsleep.S @@ -0,0 +1,645 @@ +/* + * Enter and leave deep sleep/sleep state on MPC85xx + * + * Author: Scott Wood + * + * Copyright 2006-2015 Freescale Semiconductor Inc. + * + * 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 + +#define SS_TB 0x00 +#define SS_HID 0x08 /* 2 HIDs */ +#define SS_IAC 0x10 /* 2 IACs */ +#define SS_DAC 0x18 /* 2 DACs */ +#define SS_DBCR0x20 /* 3 DBCRs */ +#define SS_PID 0x2c /* 3 PIDs */ +#define SS_SPRG0x38 /* 8 SPRGs */ +#define SS_IVOR0x58 /* 20 interrupt vectors */ +#define SS_TCR 0xa8 +#define SS_BUCSR 0xac +#define SS_L1CSR 0xb0 /* 2 L1CSRs */ +#define SS_MSR 0xb8 +#define SS_USPRG 0xbc +#define SS_GPREG 0xc0 /* r12-r31 */ +#define SS_LR 0x110 +#define SS_CR 0x114 +#define SS_SP 0x118 +#define SS_CURRENT 0x11c +#define SS_IVPR0x120 +#define SS_BPTR0x124 + + +#define STATE_SAVE_SIZE 0x128 + + .section .data + .align 5 +mpc85xx_sleep_save_area: + .space STATE_SAVE_SIZE +ccsrbase_low: + .long 0 +ccsrbase_high: + .long 0 +powmgtreq: + .long 0 + + .section .text + + /* r3 = virtual address of L2 controller, WIMG = 01xx */ +flush_disable_L2: + /* It's a write-through cache, so only invalidation is needed. */ + mbar + isync + lwz r4, 0(r3) + li r5, 1 + rlwimi r4, r5, 30, 0xc000 + stw r4, 0(r3) + + /* Wait for the invalidate to finish */ +1: lwz r4, 0(r3) + andis. r4, r4, 0x4000 + bne 1b + mbar + + blr + + /* r3 = virtual address of L2 controller, WIMG = 01xx */ +invalidate_enable_L2: + mbar + isync + lwz r4, 0(r3) + li r5, 3 + rlwimi r4, r5, 30, 0xc000 + stw r4, 0(r3) + + /* Wait for the invalidate to finish */ +1: lwz r4, 0(r3) + andis. r4, r4, 0x4000 + bne 1b + mbar + + blr + + /* +* r3 = high word of physical address of CCSR +* r4 = low word of physical address of CCSR +* r5 = JOG or deep sleep r
[PATCH] powerpc/85xx: add sleep and deep sleep support
In sleep PM mode, the clocks of e500 core and unused IP blocks is turned off. IP blocks which are allowed to wake up the processor are still running. Some Freescale chips like MPC8536 and P1022 has deep sleep PM mode in addtion to the sleep PM mode. While in deep sleep PM mode, additionally, the power supply is removed from e500 core and most IP blocks. Only the blocks needed to wake up the chip out of deep sleep are ON. This patch supports 32-bit and 36-bit address space. The sleep mode is equal to the Standby state in Linux. The deep sleep mode is equal to the Suspend-to-RAM state of Linux Power Management. Command to enter sleep mode. echo standby /sys/power/state Command to enter deep sleep mode. echo mem /sys/power/state Signed-off-by: Li Yang le...@freescale.com Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/powerpc/include/asm/cacheflush.h | 5 + arch/powerpc/platforms/85xx/Makefile| 3 + arch/powerpc/platforms/85xx/pmc_deepsleep.S | 645 arch/powerpc/sysdev/fsl_pmc.c | 146 ++- arch/powerpc/sysdev/fsl_soc.h | 5 + 5 files changed, 785 insertions(+), 19 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/pmc_deepsleep.S diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 30b35ff..9ec4c31 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -31,6 +31,11 @@ extern void flush_dcache_page(struct page *page); #define flush_dcache_mmap_unlock(mapping) do { } while (0) extern void __flush_disable_L1(void); +#ifdef CONFIG_FSL_BOOKE +extern void flush_dcache_L1(void); +#else +#define flush_dcache_L1() do { } while (0) +#endif extern void flush_icache_range(unsigned long, unsigned long); extern void flush_icache_user_range(struct vm_area_struct *vma, diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 1fe7fb9..d187253 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -2,6 +2,9 @@ # Makefile for the PowerPC 85xx linux kernel. # obj-$(CONFIG_SMP) += smp.o +ifneq ($(CONFIG_PPC_E500MC),y) +obj-$(CONFIG_SUSPEND) += pmc_deepsleep.o +endif obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/pmc_deepsleep.S b/arch/powerpc/platforms/85xx/pmc_deepsleep.S new file mode 100644 index 000..57fd4f4 --- /dev/null +++ b/arch/powerpc/platforms/85xx/pmc_deepsleep.S @@ -0,0 +1,645 @@ +/* + * Enter and leave deep sleep/sleep state on MPC85xx + * + * Author: Scott Wood scottw...@freescale.com + * + * Copyright 2006-2015 Freescale Semiconductor Inc. + * + * 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 asm/page.h +#include asm/ppc_asm.h +#include asm/reg.h +#include asm/asm-offsets.h + +#define SS_TB 0x00 +#define SS_HID 0x08 /* 2 HIDs */ +#define SS_IAC 0x10 /* 2 IACs */ +#define SS_DAC 0x18 /* 2 DACs */ +#define SS_DBCR0x20 /* 3 DBCRs */ +#define SS_PID 0x2c /* 3 PIDs */ +#define SS_SPRG0x38 /* 8 SPRGs */ +#define SS_IVOR0x58 /* 20 interrupt vectors */ +#define SS_TCR 0xa8 +#define SS_BUCSR 0xac +#define SS_L1CSR 0xb0 /* 2 L1CSRs */ +#define SS_MSR 0xb8 +#define SS_USPRG 0xbc +#define SS_GPREG 0xc0 /* r12-r31 */ +#define SS_LR 0x110 +#define SS_CR 0x114 +#define SS_SP 0x118 +#define SS_CURRENT 0x11c +#define SS_IVPR0x120 +#define SS_BPTR0x124 + + +#define STATE_SAVE_SIZE 0x128 + + .section .data + .align 5 +mpc85xx_sleep_save_area: + .space STATE_SAVE_SIZE +ccsrbase_low: + .long 0 +ccsrbase_high: + .long 0 +powmgtreq: + .long 0 + + .section .text + + /* r3 = virtual address of L2 controller, WIMG = 01xx */ +flush_disable_L2: + /* It's a write-through cache, so only invalidation is needed. */ + mbar + isync + lwz r4, 0(r3) + li r5, 1 + rlwimi r4, r5, 30, 0xc000 + stw r4, 0(r3) + + /* Wait for the invalidate to finish */ +1: lwz r4, 0(r3) + andis. r4, r4, 0x4000 + bne 1b + mbar + + blr + + /* r3 = virtual address of L2 controller, WIMG = 01xx */ +invalidate_enable_L2: + mbar + isync + lwz r4, 0(r3) + li r5, 3 + rlwimi r4, r5, 30, 0xc000 + stw r4, 0(r3) + + /* Wait for the invalidate to finish */ +1: lwz r4, 0(r3) + andis. r4, r4, 0x4000 + bne 1b + mbar + + blr + + /* +* r3 = high word of physical
[PATCH] powerpc/corenet: use the mixed mode of MPIC when enabling CPU hotplug
Core reset may cause issue if using the proxy mode of MPIC. Use the mixed mode of MPIC if enabling CPU hotplug. Signed-off-by: Chenhui Zhao --- arch/powerpc/platforms/85xx/corenet_generic.c | 8 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c index bd839dc..0119224 100644 --- a/arch/powerpc/platforms/85xx/corenet_generic.c +++ b/arch/powerpc/platforms/85xx/corenet_generic.c @@ -212,7 +212,15 @@ define_machine(corenet_generic) { .pcibios_fixup_bus = fsl_pcibios_fixup_bus, .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif +/* + * Core reset may cause issue if using the proxy mode of MPIC. + * So, use the mixed mode of MPIC if enabling CPU hotplug. + */ +#ifdef CONFIG_HOTPLUG_CPU + .get_irq= mpic_get_irq, +#else .get_irq= mpic_get_coreint_irq, +#endif .restart= fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] powerpc/corenet: use the mixed mode of MPIC when enabling CPU hotplug
Core reset may cause issue if using the proxy mode of MPIC. Use the mixed mode of MPIC if enabling CPU hotplug. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/powerpc/platforms/85xx/corenet_generic.c | 8 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c index bd839dc..0119224 100644 --- a/arch/powerpc/platforms/85xx/corenet_generic.c +++ b/arch/powerpc/platforms/85xx/corenet_generic.c @@ -212,7 +212,15 @@ define_machine(corenet_generic) { .pcibios_fixup_bus = fsl_pcibios_fixup_bus, .pcibios_fixup_phb = fsl_pcibios_fixup_phb, #endif +/* + * Core reset may cause issue if using the proxy mode of MPIC. + * So, use the mixed mode of MPIC if enabling CPU hotplug. + */ +#ifdef CONFIG_HOTPLUG_CPU + .get_irq= mpic_get_irq, +#else .get_irq= mpic_get_coreint_irq, +#endif .restart= fsl_rstcr_restart, .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/4] powerpc/rcpm: add RCPM driver
There is a RCPM (Run Control/Power Management) in Freescale QorIQ series processors. The device performs tasks associated with device run control and power management. The driver implements some features: mask/unmask irq, enter/exit low power states, freeze time base, etc. Signed-off-by: Chenhui Zhao --- Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 23 ++ arch/powerpc/include/asm/fsl_guts.h| 105 ++ arch/powerpc/include/asm/fsl_pm.h | 49 +++ arch/powerpc/platforms/85xx/Kconfig| 1 + arch/powerpc/sysdev/Kconfig| 5 + arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/fsl_rcpm.c | 353 + 7 files changed, 537 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/rcpm.txt create mode 100644 arch/powerpc/include/asm/fsl_pm.h create mode 100644 arch/powerpc/sysdev/fsl_rcpm.c diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt new file mode 100644 index 000..8c21b6c --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt @@ -0,0 +1,23 @@ +* Run Control and Power Management + +The RCPM performs all device-level tasks associated with device run control +and power management. + +Required properites: + - reg : Offset and length of the register set of RCPM block. + - compatible : Specifies the compatibility list for the RCPM. The type +should be string, such as "fsl,qoriq-rcpm-1.0", "fsl,qoriq-rcpm-2.0". + +Example: +The RCPM node for T4240: + rcpm: global-utilities@e2000 { + compatible = "fsl,t4240-rcpm", "fsl,qoriq-rcpm-2.0"; + reg = <0xe2000 0x1000>; + }; + +The RCPM node for P4080: + rcpm: global-utilities@e2000 { + compatible = "fsl,qoriq-rcpm-1.0"; + reg = <0xe2000 0x1000>; + #sleep-cells = <1>; + }; diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h index 43b6bb1..96018ee 100644 --- a/arch/powerpc/include/asm/fsl_guts.h +++ b/arch/powerpc/include/asm/fsl_guts.h @@ -188,5 +188,110 @@ static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts, #endif +struct ccsr_rcpm_v1 { + u8 res[4]; + __be32 cdozsr; /* 0x0004 Core Doze Status Register */ + u8 res0008[4]; + __be32 cdozcr; /* 0x000c Core Doze Control Register */ + u8 res0010[4]; + __be32 cnapsr; /* 0x0014 Core Nap Status Register */ + u8 res0018[4]; + __be32 cnapcr; /* 0x001c Core Nap Control Register */ + u8 res0020[4]; + __be32 cdozpsr;/* 0x0024 Core Doze Previous Status Register */ + u8 res0028[4]; + __be32 cnappsr;/* 0x002c Core Nap Previous Status Register */ + u8 res0030[4]; + __be32 cwaitsr;/* 0x0034 Core Wait Status Register */ + u8 res0038[4]; + __be32 cwdtdsr;/* 0x003c Core Watchdog Detect Status Register */ + __be32 powmgtcsr; /* 0x0040 Power Management Control Register */ +#define RCPM_POWMGTCSR_SLP 0x0002 + u8 res0044[12]; + __be32 ippdexpcr; /* 0x0050 IP Powerdown Exception Control Register */ + u8 res0054[16]; + __be32 cpmimr; /* 0x0064 Core PM IRQ Mask Register */ + u8 res0068[4]; + __be32 cpmcimr;/* 0x006c Core PM Critical IRQ Mask Register */ + u8 res0070[4]; + __be32 cpmmcmr;/* 0x0074 Core PM Machine Check Mask Register */ + u8 res0078[4]; + __be32 cpmnmimr; /* 0x007c Core PM NMI Mask Register */ + u8 res0080[4]; + __be32 ctbenr; /* 0x0084 Core Time Base Enable Register */ + u8 res0088[4]; + __be32 ctbckselr; /* 0x008c Core Time Base Clock Select Register */ + u8 res0090[4]; + __be32 ctbhltcr; /* 0x0094 Core Time Base Halt Control Register */ + u8 res0098[4]; + __be32 cmcpmaskcr; /* 0x00a4 Core Machine Check Mask Register */ +}; + +struct ccsr_rcpm_v2 { + u8 res_00[12]; + __be32 tph10sr0; /* Thread PH10 Status Register */ + u8 res_10[12]; + __be32 tph10setr0; /* Thread PH10 Set Control Register */ + u8 res_20[12]; + __be32 tph10clrr0; /* Thread PH10 Clear Control Register */ + u8 res_30[12]; + __be32 tph10psr0; /* Thread PH10 Previous Status Register */ + u8 res_40[12]; + __be32 twaitsr0; /* Thread Wait Status Register */ + u8 res_50[96]; + __be32 pcph15sr; /* Physical Core PH15 Status Register */ + __be32 pcph15setr; /* Physical Core PH15 Set Control Register */ + __be32 pcph15clrr; /* Physical Core PH15 Clear Control Re
[PATCH 3/4] powerpc: support CPU hotplug for e500mc, e5500 and e6500
Implemented CPU hotplug on e500mc, e5500 and e6500, and support multiple threads mode and 64-bits mode. For e6500 with two threads, if one thread is online, it can enable/disable the other thread in the same core. If two threads of one core are offline, the core will enter the PH20 state (a low power state). When the core is up again, Thread0 is up first, and it will be bound with the present booting cpu. This way, all CPUs can hotplug separately. Signed-off-by: Chenhui Zhao --- arch/powerpc/Kconfig | 2 +- arch/powerpc/include/asm/fsl_pm.h | 4 + arch/powerpc/include/asm/smp.h| 2 + arch/powerpc/kernel/head_64.S | 20 +++-- arch/powerpc/kernel/smp.c | 5 ++ arch/powerpc/platforms/85xx/smp.c | 182 +- arch/powerpc/sysdev/fsl_rcpm.c| 56 7 files changed, 220 insertions(+), 51 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 22b0940..9846c83 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -380,7 +380,7 @@ config SWIOTLB config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" depends on SMP && (PPC_PSERIES || \ - PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC)) + PPC_PMAC || PPC_POWERNV || FSL_SOC_BOOKE) ---help--- Say Y here to be able to disable and re-enable individual CPUs at runtime on SMP machines. diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h index bbe6089..579f495 100644 --- a/arch/powerpc/include/asm/fsl_pm.h +++ b/arch/powerpc/include/asm/fsl_pm.h @@ -34,6 +34,10 @@ struct fsl_pm_ops { void (*cpu_enter_state)(int cpu, int state); /* exit the CPU from the specified state */ void (*cpu_exit_state)(int cpu, int state); + /* cpu up */ + void (*cpu_up)(int cpu); + /* cpu die */ + void (*cpu_die)(int cpu); /* place the platform in the sleep state */ int (*plat_enter_sleep)(void); /* freeze the time base */ diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index d607df5..1e500ed 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -67,6 +67,7 @@ void generic_cpu_die(unsigned int cpu); void generic_set_cpu_dead(unsigned int cpu); void generic_set_cpu_up(unsigned int cpu); int generic_check_cpu_restart(unsigned int cpu); +int generic_check_cpu_dead(unsigned int cpu); #endif #ifdef CONFIG_PPC64 @@ -198,6 +199,7 @@ extern void generic_secondary_thread_init(void); extern unsigned long __secondary_hold_spinloop; extern unsigned long __secondary_hold_acknowledge; extern char __secondary_hold; +extern unsigned int __cur_boot_cpu; extern void __early_start(void); #endif /* __ASSEMBLY__ */ diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index d48125d..ac89050 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -181,6 +181,10 @@ exception_marker: #endif #ifdef CONFIG_PPC_BOOK3E + .globl __cur_boot_cpu +__cur_boot_cpu: + .long 0x0 + .align 3 _GLOBAL(fsl_secondary_thread_init) /* Enable branch prediction */ lis r3,BUCSR_INIT@h @@ -189,16 +193,14 @@ _GLOBAL(fsl_secondary_thread_init) isync /* -* Fix PIR to match the linear numbering in the device tree. -* -* On e6500, the reset value of PIR uses the low three bits for -* the thread within a core, and the upper bits for the core -* number. There are two threads per core, so shift everything -* but the low bit right by two bits so that the cpu numbering is -* continuous. +* The current thread has been in 64-bit mode, +* see the value of TMRN_IMSR. +* compute the address of __cur_boot_cpu */ - mfspr r3, SPRN_PIR - rlwimi r3, r3, 30, 2, 30 + bl 10f +10:mflrr22 + addir22,r22,(__cur_boot_cpu - 10b) + lwz r3,0(r22) mtspr SPRN_PIR, r3 #endif diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index ec9ec20..2cca27a 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -454,6 +454,11 @@ int generic_check_cpu_restart(unsigned int cpu) return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE; } +int generic_check_cpu_dead(unsigned int cpu) +{ + return per_cpu(cpu_state, cpu) == CPU_DEAD; +} + static bool secondaries_inhibited(void) { return kvm_hv_mode_active(); diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index fba474f..f51441b 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -2,7 +2,7 @@ * Author: Andy Fleming *Kumar Gala * - * Copyright 2006-2008, 2011-2012 Freescale Semiconductor Inc. + * Copyright 2006-2008, 2011-2012, 2015 Freescale Semiconductor
[PATCH 1/4] powerpc/cache: add cache flush operation for various e500
Various e500 core have different cache architecture, so they need different cache flush operations. Therefore, add a callback function cpu_flush_caches to the struct cpu_spec. The cache flush operation for the specific kind of e500 is selected at init time. The callback function will flush all caches inside the current cpu. Signed-off-by: Chenhui Zhao --- arch/powerpc/include/asm/cacheflush.h | 2 - arch/powerpc/include/asm/cputable.h | 11 +++ arch/powerpc/kernel/asm-offsets.c | 3 + arch/powerpc/kernel/cpu_setup_fsl_booke.S | 114 +- arch/powerpc/kernel/cputable.c| 4 ++ arch/powerpc/kernel/head_fsl_booke.S | 74 --- arch/powerpc/platforms/85xx/smp.c | 3 +- 7 files changed, 133 insertions(+), 78 deletions(-) diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 30b35ff..729fde4 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -30,8 +30,6 @@ extern void flush_dcache_page(struct page *page); #define flush_dcache_mmap_lock(mapping)do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) -extern void __flush_disable_L1(void); - extern void flush_icache_range(unsigned long, unsigned long); extern void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, unsigned long addr, diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 5cf5a6d..c776efe4 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -43,6 +43,13 @@ extern int machine_check_e500(struct pt_regs *regs); extern int machine_check_e200(struct pt_regs *regs); extern int machine_check_47x(struct pt_regs *regs); +#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC) +extern void __flush_caches_e500v2(void); +extern void __flush_caches_e500mc(void); +extern void __flush_caches_e5500(void); +extern void __flush_caches_e6500(void); +#endif + /* NOTE WELL: Update identify_cpu() if fields are added or removed! */ struct cpu_spec { /* CPU is matched via (PVR & pvr_mask) == pvr_value */ @@ -59,6 +66,10 @@ struct cpu_spec { unsigned inticache_bsize; unsigned intdcache_bsize; +#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC) + /* flush caches inside the current cpu */ + void (*cpu_flush_caches)(void); +#endif /* number of performance monitor counters */ unsigned intnum_pmcs; enum powerpc_pmc_type pmc_type; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 4717859..9567930 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -372,6 +372,9 @@ int main(void) DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore)); +#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC) + DEFINE(CPU_FLUSH_CACHES, offsetof(struct cpu_spec, cpu_flush_caches)); +#endif DEFINE(pbe_address, offsetof(struct pbe, address)); DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S index dddba3e..c8c251f 100644 --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S @@ -1,7 +1,7 @@ /* * This file contains low level CPU setup functions. * Kumar Gala - * Copyright 2009 Freescale Semiconductor, Inc. + * Copyright 2009, 2015 Freescale Semiconductor, Inc. * * Based on cpu_setup_6xx code by * Benjamin Herrenschmidt @@ -13,11 +13,13 @@ * */ +#include #include #include #include #include #include +#include _GLOBAL(__e500_icache_setup) mfspr r0, SPRN_L1CSR1 @@ -233,3 +235,113 @@ _GLOBAL(__setup_cpu_e5500) mtlrr5 blr #endif + +/* flush L1 date cache, it can apply to e500v2, e500mc and e5500 */ +_GLOBAL(flush_dcache_L1) + mfmsr r10 + wrteei 0 + + mfspr r3,SPRN_L1CFG0 + rlwinm r5,r3,9,3 /* Extract cache block size */ + twlgti r5,1/* Only 32 and 64 byte cache blocks +* are currently defined. +*/ + li r4,32 + subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) - +* log2(number of ways) +*/ + slw r5,r4,r5/* r5 = cache block size */ + + rlwinm r7,r3,0,0xff/* Extract number of KiB in the cache */ + mulli r7,r7,13/* An 8-way cache will require 13 +* loads per
[PATCH 4/4] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
In sleep mode, the clocks of e500 cores and unused IP blocks is turned off. The IP blocks which are allowed to wake up the processor are still running. The sleep mode is equal to the Standby state in Linux. Use the command to enter sleep mode: echo standby > /sys/power/state Signed-off-by: Chenhui Zhao --- arch/powerpc/Kconfig | 3 +- arch/powerpc/platforms/85xx/Kconfig| 5 +++ arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/qoriq_pm.c | 59 ++ arch/powerpc/platforms/86xx/Kconfig| 1 + 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 9846c83..162eb53 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -233,7 +233,7 @@ config ARCH_HIBERNATION_POSSIBLE config ARCH_SUSPEND_POSSIBLE def_bool y depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ - (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \ + FSL_SOC_BOOKE || PPC_86xx || PPC_PSERIES \ || 44x || 40x config PPC_DCR_NATIVE @@ -747,7 +747,6 @@ config FSL_PCI config FSL_PMC bool - default y depends on SUSPEND && (PPC_85xx || PPC_86xx) help Freescale MPC85xx/MPC86xx power management controller support diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index ae1b8a2..b7c762e 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -9,6 +9,8 @@ menuconfig FSL_SOC_BOOKE select SERIAL_8250_EXTENDED if SERIAL_8250 select SERIAL_8250_SHARE_IRQ if SERIAL_8250 select FSL_CORENET_RCPM if PPC_E500MC + select FSL_QORIQ_PM if SUSPEND && PPC_E500MC + select FSL_PMC if SUSPEND && !PPC_E500MC default y if FSL_SOC_BOOKE @@ -289,3 +291,6 @@ endif # FSL_SOC_BOOKE config TQM85xx bool + +config FSL_QORIQ_PM + bool diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 1fe7fb9..65dfb60 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -2,6 +2,7 @@ # Makefile for the PowerPC 85xx linux kernel. # obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c new file mode 100644 index 000..7594f08 --- /dev/null +++ b/arch/powerpc/platforms/85xx/qoriq_pm.c @@ -0,0 +1,59 @@ +/* + * Support Power Management feature + * + * Copyright 2014-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 + +static int qoriq_suspend_enter(suspend_state_t state) +{ + int ret = 0; + + switch (state) { + case PM_SUSPEND_STANDBY: + cur_cpu_spec->cpu_flush_caches(); + ret = qoriq_pm_ops->plat_enter_sleep(); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int qoriq_suspend_valid(suspend_state_t state) +{ + unsigned int pm_modes; + + pm_modes = qoriq_pm_ops->get_pm_modes(); + + if ((state == PM_SUSPEND_STANDBY) && (pm_modes & FSL_PM_SLEEP)) + return 1; + + return 0; +} + +static const struct platform_suspend_ops qoriq_suspend_ops = { + .valid = qoriq_suspend_valid, + .enter = qoriq_suspend_enter, +}; + +static int __init qoriq_suspend_init(void) +{ + suspend_set_ops(_suspend_ops); + + return 0; +} +arch_initcall(qoriq_suspend_init); diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 1afd1e4..09638e0 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -5,6 +5,7 @@ menuconfig PPC_86xx select FSL_SOC select ALTIVEC select ARCH_WANT_OPTIONAL_GPIOLIB + select FSL_PMC if SUSPEND help The Freescale E600 SoCs have 74xx cores. -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 3/4] powerpc: support CPU hotplug for e500mc, e5500 and e6500
Implemented CPU hotplug on e500mc, e5500 and e6500, and support multiple threads mode and 64-bits mode. For e6500 with two threads, if one thread is online, it can enable/disable the other thread in the same core. If two threads of one core are offline, the core will enter the PH20 state (a low power state). When the core is up again, Thread0 is up first, and it will be bound with the present booting cpu. This way, all CPUs can hotplug separately. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/powerpc/Kconfig | 2 +- arch/powerpc/include/asm/fsl_pm.h | 4 + arch/powerpc/include/asm/smp.h| 2 + arch/powerpc/kernel/head_64.S | 20 +++-- arch/powerpc/kernel/smp.c | 5 ++ arch/powerpc/platforms/85xx/smp.c | 182 +- arch/powerpc/sysdev/fsl_rcpm.c| 56 7 files changed, 220 insertions(+), 51 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 22b0940..9846c83 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -380,7 +380,7 @@ config SWIOTLB config HOTPLUG_CPU bool Support for enabling/disabling CPUs depends on SMP (PPC_PSERIES || \ - PPC_PMAC || PPC_POWERNV || (PPC_85xx !PPC_E500MC)) + PPC_PMAC || PPC_POWERNV || FSL_SOC_BOOKE) ---help--- Say Y here to be able to disable and re-enable individual CPUs at runtime on SMP machines. diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h index bbe6089..579f495 100644 --- a/arch/powerpc/include/asm/fsl_pm.h +++ b/arch/powerpc/include/asm/fsl_pm.h @@ -34,6 +34,10 @@ struct fsl_pm_ops { void (*cpu_enter_state)(int cpu, int state); /* exit the CPU from the specified state */ void (*cpu_exit_state)(int cpu, int state); + /* cpu up */ + void (*cpu_up)(int cpu); + /* cpu die */ + void (*cpu_die)(int cpu); /* place the platform in the sleep state */ int (*plat_enter_sleep)(void); /* freeze the time base */ diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index d607df5..1e500ed 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -67,6 +67,7 @@ void generic_cpu_die(unsigned int cpu); void generic_set_cpu_dead(unsigned int cpu); void generic_set_cpu_up(unsigned int cpu); int generic_check_cpu_restart(unsigned int cpu); +int generic_check_cpu_dead(unsigned int cpu); #endif #ifdef CONFIG_PPC64 @@ -198,6 +199,7 @@ extern void generic_secondary_thread_init(void); extern unsigned long __secondary_hold_spinloop; extern unsigned long __secondary_hold_acknowledge; extern char __secondary_hold; +extern unsigned int __cur_boot_cpu; extern void __early_start(void); #endif /* __ASSEMBLY__ */ diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index d48125d..ac89050 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -181,6 +181,10 @@ exception_marker: #endif #ifdef CONFIG_PPC_BOOK3E + .globl __cur_boot_cpu +__cur_boot_cpu: + .long 0x0 + .align 3 _GLOBAL(fsl_secondary_thread_init) /* Enable branch prediction */ lis r3,BUCSR_INIT@h @@ -189,16 +193,14 @@ _GLOBAL(fsl_secondary_thread_init) isync /* -* Fix PIR to match the linear numbering in the device tree. -* -* On e6500, the reset value of PIR uses the low three bits for -* the thread within a core, and the upper bits for the core -* number. There are two threads per core, so shift everything -* but the low bit right by two bits so that the cpu numbering is -* continuous. +* The current thread has been in 64-bit mode, +* see the value of TMRN_IMSR. +* compute the address of __cur_boot_cpu */ - mfspr r3, SPRN_PIR - rlwimi r3, r3, 30, 2, 30 + bl 10f +10:mflrr22 + addir22,r22,(__cur_boot_cpu - 10b) + lwz r3,0(r22) mtspr SPRN_PIR, r3 #endif diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index ec9ec20..2cca27a 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -454,6 +454,11 @@ int generic_check_cpu_restart(unsigned int cpu) return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE; } +int generic_check_cpu_dead(unsigned int cpu) +{ + return per_cpu(cpu_state, cpu) == CPU_DEAD; +} + static bool secondaries_inhibited(void) { return kvm_hv_mode_active(); diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index fba474f..f51441b 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -2,7 +2,7 @@ * Author: Andy Fleming aflem...@freescale.com *Kumar Gala ga...@kernel.crashing.org * - * Copyright 2006-2008, 2011-2012 Freescale Semiconductor Inc. + * Copyright 2006-2008
[PATCH 2/4] powerpc/rcpm: add RCPM driver
There is a RCPM (Run Control/Power Management) in Freescale QorIQ series processors. The device performs tasks associated with device run control and power management. The driver implements some features: mask/unmask irq, enter/exit low power states, freeze time base, etc. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- Documentation/devicetree/bindings/soc/fsl/rcpm.txt | 23 ++ arch/powerpc/include/asm/fsl_guts.h| 105 ++ arch/powerpc/include/asm/fsl_pm.h | 49 +++ arch/powerpc/platforms/85xx/Kconfig| 1 + arch/powerpc/sysdev/Kconfig| 5 + arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/fsl_rcpm.c | 353 + 7 files changed, 537 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/rcpm.txt create mode 100644 arch/powerpc/include/asm/fsl_pm.h create mode 100644 arch/powerpc/sysdev/fsl_rcpm.c diff --git a/Documentation/devicetree/bindings/soc/fsl/rcpm.txt b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt new file mode 100644 index 000..8c21b6c --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/rcpm.txt @@ -0,0 +1,23 @@ +* Run Control and Power Management + +The RCPM performs all device-level tasks associated with device run control +and power management. + +Required properites: + - reg : Offset and length of the register set of RCPM block. + - compatible : Specifies the compatibility list for the RCPM. The type +should be string, such as fsl,qoriq-rcpm-1.0, fsl,qoriq-rcpm-2.0. + +Example: +The RCPM node for T4240: + rcpm: global-utilities@e2000 { + compatible = fsl,t4240-rcpm, fsl,qoriq-rcpm-2.0; + reg = 0xe2000 0x1000; + }; + +The RCPM node for P4080: + rcpm: global-utilities@e2000 { + compatible = fsl,qoriq-rcpm-1.0; + reg = 0xe2000 0x1000; + #sleep-cells = 1; + }; diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h index 43b6bb1..96018ee 100644 --- a/arch/powerpc/include/asm/fsl_guts.h +++ b/arch/powerpc/include/asm/fsl_guts.h @@ -188,5 +188,110 @@ static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts, #endif +struct ccsr_rcpm_v1 { + u8 res[4]; + __be32 cdozsr; /* 0x0004 Core Doze Status Register */ + u8 res0008[4]; + __be32 cdozcr; /* 0x000c Core Doze Control Register */ + u8 res0010[4]; + __be32 cnapsr; /* 0x0014 Core Nap Status Register */ + u8 res0018[4]; + __be32 cnapcr; /* 0x001c Core Nap Control Register */ + u8 res0020[4]; + __be32 cdozpsr;/* 0x0024 Core Doze Previous Status Register */ + u8 res0028[4]; + __be32 cnappsr;/* 0x002c Core Nap Previous Status Register */ + u8 res0030[4]; + __be32 cwaitsr;/* 0x0034 Core Wait Status Register */ + u8 res0038[4]; + __be32 cwdtdsr;/* 0x003c Core Watchdog Detect Status Register */ + __be32 powmgtcsr; /* 0x0040 Power Management ControlStatus Register */ +#define RCPM_POWMGTCSR_SLP 0x0002 + u8 res0044[12]; + __be32 ippdexpcr; /* 0x0050 IP Powerdown Exception Control Register */ + u8 res0054[16]; + __be32 cpmimr; /* 0x0064 Core PM IRQ Mask Register */ + u8 res0068[4]; + __be32 cpmcimr;/* 0x006c Core PM Critical IRQ Mask Register */ + u8 res0070[4]; + __be32 cpmmcmr;/* 0x0074 Core PM Machine Check Mask Register */ + u8 res0078[4]; + __be32 cpmnmimr; /* 0x007c Core PM NMI Mask Register */ + u8 res0080[4]; + __be32 ctbenr; /* 0x0084 Core Time Base Enable Register */ + u8 res0088[4]; + __be32 ctbckselr; /* 0x008c Core Time Base Clock Select Register */ + u8 res0090[4]; + __be32 ctbhltcr; /* 0x0094 Core Time Base Halt Control Register */ + u8 res0098[4]; + __be32 cmcpmaskcr; /* 0x00a4 Core Machine Check Mask Register */ +}; + +struct ccsr_rcpm_v2 { + u8 res_00[12]; + __be32 tph10sr0; /* Thread PH10 Status Register */ + u8 res_10[12]; + __be32 tph10setr0; /* Thread PH10 Set Control Register */ + u8 res_20[12]; + __be32 tph10clrr0; /* Thread PH10 Clear Control Register */ + u8 res_30[12]; + __be32 tph10psr0; /* Thread PH10 Previous Status Register */ + u8 res_40[12]; + __be32 twaitsr0; /* Thread Wait Status Register */ + u8 res_50[96]; + __be32 pcph15sr; /* Physical Core PH15 Status Register */ + __be32 pcph15setr; /* Physical Core PH15 Set Control Register */ + __be32 pcph15clrr; /* Physical Core PH15 Clear Control Register */ + __be32 pcph15psr; /* Physical
[PATCH 4/4] powerpc/85xx: support sleep feature on QorIQ SoCs with RCPM
In sleep mode, the clocks of e500 cores and unused IP blocks is turned off. The IP blocks which are allowed to wake up the processor are still running. The sleep mode is equal to the Standby state in Linux. Use the command to enter sleep mode: echo standby /sys/power/state Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/powerpc/Kconfig | 3 +- arch/powerpc/platforms/85xx/Kconfig| 5 +++ arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/qoriq_pm.c | 59 ++ arch/powerpc/platforms/86xx/Kconfig| 1 + 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/qoriq_pm.c diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 9846c83..162eb53 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -233,7 +233,7 @@ config ARCH_HIBERNATION_POSSIBLE config ARCH_SUSPEND_POSSIBLE def_bool y depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ - (PPC_85xx !PPC_E500MC) || PPC_86xx || PPC_PSERIES \ + FSL_SOC_BOOKE || PPC_86xx || PPC_PSERIES \ || 44x || 40x config PPC_DCR_NATIVE @@ -747,7 +747,6 @@ config FSL_PCI config FSL_PMC bool - default y depends on SUSPEND (PPC_85xx || PPC_86xx) help Freescale MPC85xx/MPC86xx power management controller support diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index ae1b8a2..b7c762e 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -9,6 +9,8 @@ menuconfig FSL_SOC_BOOKE select SERIAL_8250_EXTENDED if SERIAL_8250 select SERIAL_8250_SHARE_IRQ if SERIAL_8250 select FSL_CORENET_RCPM if PPC_E500MC + select FSL_QORIQ_PM if SUSPEND PPC_E500MC + select FSL_PMC if SUSPEND !PPC_E500MC default y if FSL_SOC_BOOKE @@ -289,3 +291,6 @@ endif # FSL_SOC_BOOKE config TQM85xx bool + +config FSL_QORIQ_PM + bool diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 1fe7fb9..65dfb60 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -2,6 +2,7 @@ # Makefile for the PowerPC 85xx linux kernel. # obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_FSL_QORIQ_PM) += qoriq_pm.o obj-y += common.o diff --git a/arch/powerpc/platforms/85xx/qoriq_pm.c b/arch/powerpc/platforms/85xx/qoriq_pm.c new file mode 100644 index 000..7594f08 --- /dev/null +++ b/arch/powerpc/platforms/85xx/qoriq_pm.c @@ -0,0 +1,59 @@ +/* + * Support Power Management feature + * + * Copyright 2014-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. + */ + +#include linux/kernel.h +#include linux/suspend.h +#include linux/of_platform.h + +#include asm/fsl_pm.h + +static int qoriq_suspend_enter(suspend_state_t state) +{ + int ret = 0; + + switch (state) { + case PM_SUSPEND_STANDBY: + cur_cpu_spec-cpu_flush_caches(); + ret = qoriq_pm_ops-plat_enter_sleep(); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int qoriq_suspend_valid(suspend_state_t state) +{ + unsigned int pm_modes; + + pm_modes = qoriq_pm_ops-get_pm_modes(); + + if ((state == PM_SUSPEND_STANDBY) (pm_modes FSL_PM_SLEEP)) + return 1; + + return 0; +} + +static const struct platform_suspend_ops qoriq_suspend_ops = { + .valid = qoriq_suspend_valid, + .enter = qoriq_suspend_enter, +}; + +static int __init qoriq_suspend_init(void) +{ + suspend_set_ops(qoriq_suspend_ops); + + return 0; +} +arch_initcall(qoriq_suspend_init); diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 1afd1e4..09638e0 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -5,6 +5,7 @@ menuconfig PPC_86xx select FSL_SOC select ALTIVEC select ARCH_WANT_OPTIONAL_GPIOLIB + select FSL_PMC if SUSPEND help The Freescale E600 SoCs have 74xx cores. -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/4] powerpc/cache: add cache flush operation for various e500
Various e500 core have different cache architecture, so they need different cache flush operations. Therefore, add a callback function cpu_flush_caches to the struct cpu_spec. The cache flush operation for the specific kind of e500 is selected at init time. The callback function will flush all caches inside the current cpu. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/powerpc/include/asm/cacheflush.h | 2 - arch/powerpc/include/asm/cputable.h | 11 +++ arch/powerpc/kernel/asm-offsets.c | 3 + arch/powerpc/kernel/cpu_setup_fsl_booke.S | 114 +- arch/powerpc/kernel/cputable.c| 4 ++ arch/powerpc/kernel/head_fsl_booke.S | 74 --- arch/powerpc/platforms/85xx/smp.c | 3 +- 7 files changed, 133 insertions(+), 78 deletions(-) diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 30b35ff..729fde4 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -30,8 +30,6 @@ extern void flush_dcache_page(struct page *page); #define flush_dcache_mmap_lock(mapping)do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) -extern void __flush_disable_L1(void); - extern void flush_icache_range(unsigned long, unsigned long); extern void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, unsigned long addr, diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 5cf5a6d..c776efe4 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -43,6 +43,13 @@ extern int machine_check_e500(struct pt_regs *regs); extern int machine_check_e200(struct pt_regs *regs); extern int machine_check_47x(struct pt_regs *regs); +#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC) +extern void __flush_caches_e500v2(void); +extern void __flush_caches_e500mc(void); +extern void __flush_caches_e5500(void); +extern void __flush_caches_e6500(void); +#endif + /* NOTE WELL: Update identify_cpu() if fields are added or removed! */ struct cpu_spec { /* CPU is matched via (PVR pvr_mask) == pvr_value */ @@ -59,6 +66,10 @@ struct cpu_spec { unsigned inticache_bsize; unsigned intdcache_bsize; +#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC) + /* flush caches inside the current cpu */ + void (*cpu_flush_caches)(void); +#endif /* number of performance monitor counters */ unsigned intnum_pmcs; enum powerpc_pmc_type pmc_type; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 4717859..9567930 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -372,6 +372,9 @@ int main(void) DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore)); +#if defined(CONFIG_E500) || defined(CONFIG_PPC_E500MC) + DEFINE(CPU_FLUSH_CACHES, offsetof(struct cpu_spec, cpu_flush_caches)); +#endif DEFINE(pbe_address, offsetof(struct pbe, address)); DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S index dddba3e..c8c251f 100644 --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S @@ -1,7 +1,7 @@ /* * This file contains low level CPU setup functions. * Kumar Gala ga...@kernel.crashing.org - * Copyright 2009 Freescale Semiconductor, Inc. + * Copyright 2009, 2015 Freescale Semiconductor, Inc. * * Based on cpu_setup_6xx code by * Benjamin Herrenschmidt b...@kernel.crashing.org @@ -13,11 +13,13 @@ * */ +#include asm/page.h #include asm/processor.h #include asm/cputable.h #include asm/ppc_asm.h #include asm/mmu-book3e.h #include asm/asm-offsets.h +#include asm/mpc85xx.h _GLOBAL(__e500_icache_setup) mfspr r0, SPRN_L1CSR1 @@ -233,3 +235,113 @@ _GLOBAL(__setup_cpu_e5500) mtlrr5 blr #endif + +/* flush L1 date cache, it can apply to e500v2, e500mc and e5500 */ +_GLOBAL(flush_dcache_L1) + mfmsr r10 + wrteei 0 + + mfspr r3,SPRN_L1CFG0 + rlwinm r5,r3,9,3 /* Extract cache block size */ + twlgti r5,1/* Only 32 and 64 byte cache blocks +* are currently defined. +*/ + li r4,32 + subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) - +* log2(number of ways) +*/ + slw r5,r4,r5/* r5 = cache block size */ + + rlwinm r7,r3,0,0xff/* Extract number of KiB
[PATCH 4/4] arm: ls1021a: set wakeup devices dynamically for sleep/deep sleep
If a device works as a wakeup source, it will keep working in the period of sleep/deep sleep. This patch sets the wakeup devices according to the wakeup attribute of device. Signed-off-by: Chenhui Zhao --- arch/arm/boot/dts/ls1021a.dtsi | 2 + arch/arm/mach-imx/pm-ls1.c | 101 + 2 files changed, 103 insertions(+) diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index 0c51ce0..64534c0 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -136,6 +136,7 @@ sdhci,auto-cmd12; big-endian; bus-width = <4>; + sleep = < 0x0080 0x0>; status = "disabled"; }; @@ -289,6 +290,7 @@ interrupts = ; clocks = <>; clock-names = "ipg"; + sleep = < 0x0 0x4000>; status = "disabled"; }; diff --git a/arch/arm/mach-imx/pm-ls1.c b/arch/arm/mach-imx/pm-ls1.c index 4f9ca80..b11fcb2 100644 --- a/arch/arm/mach-imx/pm-ls1.c +++ b/arch/arm/mach-imx/pm-ls1.c @@ -35,6 +35,13 @@ #define CCSR_SCFG_DPSLPCR 0 #define CCSR_SCFG_DPSLPCR_VAL 0x1 #define CCSR_SCFG_PMCINTECR0x160 +#define CCSR_SCFG_PMCINTECR_LPUART 0x4000 +#define CCSR_SCFG_PMCINTECR_FTM0x2000 +#define CCSR_SCFG_PMCINTECR_GPIO 0x1000 +#define CCSR_SCFG_PMCINTECR_IRQ0 0x0800 +#define CCSR_SCFG_PMCINTECR_IRQ1 0x0400 +#define CCSR_SCFG_PMCINTECR_ETSECRXG0 0x0080 +#define CCSR_SCFG_PMCINTECR_ETSECRXG1 0x0040 #define CCSR_SCFG_PMCINTLECR 0x164 #define CCSR_SCFG_PMCINTSR 0x168 #define CCSR_SCFG_SPARECR2 0x504 @@ -50,7 +57,11 @@ #define CCSR_RCPM_CLPCL10SETR 0x1c4 #define CCSR_RCPM_CLPCL10SETR_C0 0x1 #define CCSR_RCPM_IPPDEXPCR0 0x140 +#define CCSR_RCPM_IPPDEXPCR0_ETSEC 0x8000 +#define CCSR_RCPM_IPPDEXPCR0_GPIO 0x0040 #define CCSR_RCPM_IPPDEXPCR1 0x144 +#define CCSR_RCPM_IPPDEXPCR1_LPUART0x4000 +#define CCSR_RCPM_IPPDEXPCR1_FLEXTIMER 0x2000 #define QIXIS_CTL_SYS 0x5 #define QIXIS_CTL_SYS_EVTSW_MASK 0x0c @@ -64,6 +75,10 @@ /* use the last page of SRAM */ #define SRAM_CODE_BASE_PHY (OCRAM_BASE + OCRAM_SIZE - PAGE_SIZE) +#define SLEEP_ARRAY_SIZE 3 + +static u32 ippdexpcr0, ippdexpcr1; + struct ls1_pm_baseaddr { void __iomem *rcpm; void __iomem *epu; @@ -242,6 +257,49 @@ static void ls1_board_resume(void) iowrite8(tmp, ls1_pm_base.fpga + QIXIS_CTL_SYS); } +static void ls1_setup_pmc_int(void) +{ + u32 pmcintecr; + + pmcintecr = 0; + if (ippdexpcr0 & CCSR_RCPM_IPPDEXPCR0_ETSEC) + pmcintecr |= CCSR_SCFG_PMCINTECR_ETSECRXG0 | + CCSR_SCFG_PMCINTECR_ETSECRXG1; + + if (ippdexpcr0 & CCSR_RCPM_IPPDEXPCR0_GPIO) + pmcintecr |= CCSR_SCFG_PMCINTECR_GPIO; + + if (ippdexpcr1 & CCSR_RCPM_IPPDEXPCR1_LPUART) + pmcintecr |= CCSR_SCFG_PMCINTECR_LPUART; + + if (ippdexpcr1 & CCSR_RCPM_IPPDEXPCR1_FLEXTIMER) + pmcintecr |= CCSR_SCFG_PMCINTECR_FTM; + + /* always set external IRQ pins as wakeup source */ + pmcintecr |= CCSR_SCFG_PMCINTECR_IRQ0 | CCSR_SCFG_PMCINTECR_IRQ1; + + /* enable wakeup interrupt during deep sleep */ + iowrite32be(pmcintecr, ls1_pm_base.scfg + CCSR_SCFG_PMCINTECR); + iowrite32be(0, ls1_pm_base.scfg + CCSR_SCFG_PMCINTLECR); + /* clear PMC interrupt status */ + iowrite32be(0x, ls1_pm_base.scfg + CCSR_SCFG_PMCINTSR); +} + +static void ls1_clear_pmc_int(void) +{ + /* disable wakeup interrupt during deep sleep */ + iowrite32be(0, ls1_pm_base.scfg + CCSR_SCFG_PMCINTECR); + /* clear PMC interrupt status */ + iowrite32be(0x, ls1_pm_base.scfg + CCSR_SCFG_PMCINTSR); +} + +/* set IP powerdown exception, make them work during sleep/deep sleep */ +static void ls1_set_powerdown(void) +{ + iowrite32be(ippdexpcr0, ls1_pm_base.rcpm + CCSR_RCPM_IPPDEXPCR0); + iowrite32be(ippdexpcr1, ls1_pm_base.rcpm + CCSR_RCPM_IPPDEXPCR1); +} + static void ls1_enter_deepsleep(void) { /* save DDR data */ @@ -265,8 +323,12 @@ static void ls1_enter_deepsleep(void) /* copy the last stage code to sram */ ls1_copy_sram_code(); + ls1_setup_pmc_int(); + cpu_suspend(SRAM_CODE_BASE_PHY, ls1_start_deepsleep); + ls1_clear_pmc_int(); + /* disable Warm Device Reset */ ls1_clrsetbits_be32(ls1_pm_base.scfg + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_VAL, 0); @@ -274,10 +336,45 @@ static void ls1_enter_deepsleep(void) ls1_board_resume(); } +static vo
[PATCH 1/4] fsl: add EPU FSM configuration for deep sleep
T104x, T1024 and LS1021 of Freescale have a Finite State Machine (FSM) to control the hardware precedure in deep sleep. Software will start the FSM to enter deep sleep after finishing prepare work. Then, when receiving a wakeup event, the FSM will restore the SoC to work. This driver configures and clears the FSM registers for deep sleep. Note that the sequence of clearing the FSM registers does matter, should follow the sequence mentioned in the reference manual. Signed-off-by: Chenhui Zhao --- drivers/platform/Kconfig | 2 + drivers/platform/Makefile| 1 + drivers/platform/fsl/Kconfig | 11 ++ drivers/platform/fsl/Makefile| 5 + drivers/platform/fsl/sleep_fsm.c | 263 +++ drivers/platform/fsl/sleep_fsm.h | 104 6 files changed, 386 insertions(+) create mode 100644 drivers/platform/fsl/Kconfig create mode 100644 drivers/platform/fsl/Makefile create mode 100644 drivers/platform/fsl/sleep_fsm.c create mode 100644 drivers/platform/fsl/sleep_fsm.h diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 09fde58..85e3c95 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -6,3 +6,5 @@ source "drivers/platform/goldfish/Kconfig" endif source "drivers/platform/chrome/Kconfig" + +source "drivers/platform/fsl/Kconfig" diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile index 3656b7b..37c6f72 100644 --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_X86) += x86/ obj-$(CONFIG_OLPC) += olpc/ obj-$(CONFIG_GOLDFISH) += goldfish/ obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ +obj-$(CONFIG_FSL_SOC) += fsl/ diff --git a/drivers/platform/fsl/Kconfig b/drivers/platform/fsl/Kconfig new file mode 100644 index 000..a1ea46e --- /dev/null +++ b/drivers/platform/fsl/Kconfig @@ -0,0 +1,11 @@ +# +# Freescale Specific Power Management Drivers +# + +config FSL_SLEEP_FSM + bool + help + This driver configures a hardware FSM (Finite State Machine) used in deep sleep. + The FSM finishes clean-ups at the last stage of entering deep sleep, and also + wakes up system when a wake up event happens. So far, T104x, T1024 and LS1021 + need this. diff --git a/drivers/platform/fsl/Makefile b/drivers/platform/fsl/Makefile new file mode 100644 index 000..d99ca0e --- /dev/null +++ b/drivers/platform/fsl/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for linux/drivers/platform/fsl +# Freescale Specific Power Management Drivers +# +obj-$(CONFIG_FSL_SLEEP_FSM)+= sleep_fsm.o diff --git a/drivers/platform/fsl/sleep_fsm.c b/drivers/platform/fsl/sleep_fsm.c new file mode 100644 index 000..0a0480a --- /dev/null +++ b/drivers/platform/fsl/sleep_fsm.c @@ -0,0 +1,263 @@ +/* + * Freescale deep sleep FSM (finite-state machine) configuration + * + * Copyright 2014-2015 Freescale Semiconductor Inc. + * + * Author: Hongbo Zhang + * 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 "sleep_fsm.h" +/* + * These values are from chip's reference manual. For example, + * the values for T1040 can be found in "8.4.3.8 Programming + * supporting deep sleep mode" of Chapter 8 "Run Control and + * Power Management (RCPM)". + * The default value can be applied to T104x, T1024 and LS1021. + */ +struct fsm_reg_vals epu_default_val[] = { + /* EPGCR (Event Processor Global Control Register) */ + {EPGCR, 0}, + /* EPECR (Event Processor Event Control Registers) */ + {EPECR0 + EPECR_STRIDE * 0, 0}, + {EPECR0 + EPECR_STRIDE * 1, 0}, + {EPECR0 + EPECR_STRIDE * 2, 0xF0004004}, + {EPECR0 + EPECR_STRIDE * 3, 0x8084}, + {EPECR0 + EPECR_STRIDE * 4, 0x2084}, + {EPECR0 + EPECR_STRIDE * 5, 0x0804}, + {EPECR0 + EPECR_STRIDE * 6, 0x8084}, + {EPECR0 + EPECR_STRIDE * 7, 0x8084}, + {EPECR0 + EPECR_STRIDE * 8, 0x6084}, + {EPECR0 + EPECR_STRIDE * 9, 0x0884}, + {EPECR0 + EPECR_STRIDE * 10, 0x4284}, + {EPECR0 + EPECR_STRIDE * 11, 0x9084}, + {EPECR0 + EPECR_STRIDE * 12, 0x8084}, + {EPECR0 + EPECR_STRIDE * 13, 0x0884}, + {EPECR0 + EPECR_STRIDE * 14, 0x0284}, + {EPECR0 + EPECR_STRIDE * 15, 0x0004}, + /* +* EPEVTCR (Event Processor EVT Pin Control Registers) +* SCU8 triger EVT2, and SCU11 triger EVT9 +*/ + {EPEVTCR0 + EPEVTCR_STRIDE * 0, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 1, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x8001}, + {EPEVTCR0 + EPEVTCR_STRIDE * 3, 0}, +
[PATCH 3/4] arm: ls1021a: add deep sleep support
The ls1021a SoC supports deep sleep feature that can switch off most parts of the SoC when it is in deep sleep state. The DDR controller will also be powered off in deep sleep. Therefore, copy the last stage code to enter deep sleep to SRAM and run it with disabling MMU and caches. Signed-off-by: Chenhui Zhao --- arch/arm/mach-imx/Kconfig | 1 + arch/arm/mach-imx/Makefile| 2 + arch/arm/mach-imx/pm-ls1.c| 374 ++ arch/arm/mach-imx/sleep-ls1.S | 137 arch/arm/mach-imx/sleep-ls1.h | 19 +++ 5 files changed, 533 insertions(+) create mode 100644 arch/arm/mach-imx/pm-ls1.c create mode 100644 arch/arm/mach-imx/sleep-ls1.S create mode 100644 arch/arm/mach-imx/sleep-ls1.h diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index e8627e0..c10acff 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -664,6 +664,7 @@ config SOC_LS1021A select HAVE_ARM_ARCH_TIMER select PCI_DOMAINS if PCI select ZONE_DMA if ARM_LPAE + select FSL_SLEEP_FSM if PM help This enable support for Freescale LS1021A processor. diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index f5ac685..358adf4 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -101,6 +101,8 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o mach-imx6sx.o ifeq ($(CONFIG_SUSPEND),y) AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o +AFLAGS_sleep-ls1.o :=-Wa,-march=armv7-a +obj-$(CONFIG_SOC_LS1021A) += pm-ls1.o sleep-ls1.o endif obj-$(CONFIG_SOC_IMX6) += pm-imx6.o diff --git a/arch/arm/mach-imx/pm-ls1.c b/arch/arm/mach-imx/pm-ls1.c new file mode 100644 index 000..4f9ca80 --- /dev/null +++ b/arch/arm/mach-imx/pm-ls1.c @@ -0,0 +1,374 @@ +/* + * Support deep sleep feature for LS1 + * + * Copyright 2014-2015 Freescale Semiconductor Inc. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "sleep-ls1.h" + +#define FSL_SLEEP 0x1 +#define FSL_DEEP_SLEEP 0x2 + +#define DCSR_EPU_EPSMCR15 0x278 +#define DCSR_EPU_EPECR00x300 +#define DCSR_RCPM_CG1CR0 0x31c +#define DCSR_RCPM_CSTTACR0 0xb00 + +#define CCSR_SCFG_DPSLPCR 0 +#define CCSR_SCFG_DPSLPCR_VAL 0x1 +#define CCSR_SCFG_PMCINTECR0x160 +#define CCSR_SCFG_PMCINTLECR 0x164 +#define CCSR_SCFG_PMCINTSR 0x168 +#define CCSR_SCFG_SPARECR2 0x504 +#define CCSR_SCFG_SPARECR3 0x508 + +#define CCSR_DCFG_CRSTSR 0x400 +#define CCSR_DCFG_CRSTSR_VAL 0x0008 + +#define CCSR_RCPM_POWMGTCSR0x130 +#define CCSR_RCPM_POWMGTCSR_LPM20_REQ 0x0010 +#define CCSR_RCPM_POWMGTCSR_LPM20_ST 0x0200 +#define CCSR_RCPM_POWMGTCSR_P_LPM20_ST 0x0100 +#define CCSR_RCPM_CLPCL10SETR 0x1c4 +#define CCSR_RCPM_CLPCL10SETR_C0 0x1 +#define CCSR_RCPM_IPPDEXPCR0 0x140 +#define CCSR_RCPM_IPPDEXPCR1 0x144 + +#define QIXIS_CTL_SYS 0x5 +#define QIXIS_CTL_SYS_EVTSW_MASK 0x0c +#define QIXIS_CTL_SYS_EVTSW_IRQ0x04 + +#define QIXIS_PWR_CTL2 0x21 +#define QIXIS_PWR_CTL2_PCTL0x2 + +#define OCRAM_BASE 0x1000 +#define OCRAM_SIZE 0x1 /* 64K */ +/* use the last page of SRAM */ +#define SRAM_CODE_BASE_PHY (OCRAM_BASE + OCRAM_SIZE - PAGE_SIZE) + +struct ls1_pm_baseaddr { + void __iomem *rcpm; + void __iomem *epu; + void __iomem *dcsr_rcpm1; + void __iomem *scfg; + void __iomem *dcfg; + void __iomem *fpga; + void __iomem *sram; +}; + +/* 128 bytes buffer for restoring data broke by DDR training initialization */ +#define DDR_BUF_SIZE 128 +static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64); +static struct ls1_pm_baseaddr ls1_pm_base; +/* supported sleep modes by the present platform */ +static unsigned int sleep_modes; +static suspend_state_t ls1_pm_state; + +static inline void ls1_clrsetbits_be32(void __iomem *addr, u32 mask, u32 val) +{ + u32 tmp; + + tmp = ioread32be(addr); + tmp = (tmp & ~mask) | val; + iowrite32be(tmp, addr); +} + +static void __iomem *of_iomap_str(const char *compatible) +{ + struct device_node *np; + void __iomem *base; + + np = of_find_compatible_node(NULL, NULL, compatible); + if (!np) { + pr_err("%s: can not find the compatible \"%s\"\n", + __func__, compatible); + return NULL; + } + + base = of_iomap(np, 0); + of_node_put(np); +
[PATCH 2/4] arm: ls1021a: add dts nodes required by deep sleep
Add RCPM and DCSR nodes. Signed-off-by: Chenhui Zhao --- arch/arm/boot/dts/ls1021a-qds.dts | 6 +- arch/arm/boot/dts/ls1021a.dtsi| 117 ++ 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/ls1021a-qds.dts b/arch/arm/boot/dts/ls1021a-qds.dts index 9c5e16b..6903f43 100644 --- a/arch/arm/boot/dts/ls1021a-qds.dts +++ b/arch/arm/boot/dts/ls1021a-qds.dts @@ -157,7 +157,7 @@ fpga: board-control@3,0 { #address-cells = <1>; #size-cells = <1>; - compatible = "simple-bus"; + compatible = "fsl,ls1021aqds-fpga", "simple-bus"; reg = <0x3 0x0 0x100>; bank-width = <1>; device-width = <1>; @@ -238,3 +238,7 @@ { status = "okay"; }; + + { + fsl,deep-sleep; +}; diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index c70bb27..0c51ce0 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -183,6 +183,11 @@ }; }; + rcpm: rcpm@1ee2000 { + compatible = "fsl,ls1021a-rcpm", "fsl,qoriq-rcpm-2.1"; + reg = <0x0 0x1ee2000 0x0 0x1>; + }; + dspi0: dspi@210 { compatible = "fsl,vf610-dspi"; #address-cells = <1>; @@ -406,4 +411,116 @@ dr_mode = "host"; }; }; + + dcsr { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,dcsr", "simple-bus"; + ranges = <0x0 0x0 0x2000 0x100>; + + dcsr-epu@0 { + compatible = "fsl,ls1021a-dcsr-epu"; + reg = <0x0 0x1>; + }; + + dcsr-gdi@10 { + compatible = "fsl,ls1021a-dcsr-gdi"; + reg = <0x10 0x1>; + }; + + dcsr-dddi@12 { + compatible = "fsl,ls1021a-dcsr-dddi"; + reg = <0x12 0x1>; + }; + + dcsr-dcfg@22 { + compatible = "fsl,ls1021a-dcsr-dcfg"; + reg = <0x22 0x1000>; + }; + + dcsr-clock@221000 { + compatible = "fsl,ls1021a-dcsr-clock"; + reg = <0x221000 0x1000>; + }; + + dcsr-rcpm@222000 { + compatible = "fsl,ls1021a-dcsr-rcpm"; + reg = <0x222000 0x1000 0x223000 0x1000>; + }; + + dcsr-ccp@225000 { + compatible = "fsl,ls1021a-dcsr-ccp"; + reg = <0x225000 0x1000>; + }; + + dcsr-fusectrl@226000 { + compatible = "fsl,ls1021a-dcsr-fusectrl"; + reg = <0x226000 0x1000>; + }; + + dcsr-dap@30 { + compatible = "fsl,ls1021a-dcsr-dap"; + reg = <0x30 0x1>; + }; + + dcsr-cstf@35 { + compatible = "fsl,ls1021a-dcsr-cstf"; + reg = <0x35 0x1000 0x3a7000 0x1000>; + }; + + dcsr-a7rom@36 { + compatible = "fsl,ls1021a-dcsr-a7rom"; + reg = <0x36 0x1>; + }; + + dcsr-a7cpu@37 { + compatible = "fsl,ls1021a-dcsr-a7cpu"; + reg = <0x37 0x8000>; + }; + + dcsr-a7cti@378000 { + compatible = "fsl,ls1021a-dcsr-a7cti"; + reg = <0x378000 0x4000>; + }; + + dcsr-etm@37c000 { + compatible = "fsl,ls1021a-dcsr-etm"; + reg = <0x37c000 0x1000 0x37d000 0x3000>; + }; + + dcsr-hugorom@3a { + compatible = "fsl,ls1021a-dcsr-hugorom"; + reg = <0x3a 0x1000>; + }; + + dcsr-etf@3a1000 { + compatible = "fsl,ls1021a-dcsr-etf"; + reg = <0x3a1000 0x1000 0x3a2000 0x1000>; + }; + + dcsr-etr@3a3000 { + compatible = "fsl,ls1021a
[PATCH 4/4] arm: ls1021a: set wakeup devices dynamically for sleep/deep sleep
If a device works as a wakeup source, it will keep working in the period of sleep/deep sleep. This patch sets the wakeup devices according to the wakeup attribute of device. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/arm/boot/dts/ls1021a.dtsi | 2 + arch/arm/mach-imx/pm-ls1.c | 101 + 2 files changed, 103 insertions(+) diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index 0c51ce0..64534c0 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -136,6 +136,7 @@ sdhci,auto-cmd12; big-endian; bus-width = 4; + sleep = rcpm 0x0080 0x0; status = disabled; }; @@ -289,6 +290,7 @@ interrupts = GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH; clocks = sysclk; clock-names = ipg; + sleep = rcpm 0x0 0x4000; status = disabled; }; diff --git a/arch/arm/mach-imx/pm-ls1.c b/arch/arm/mach-imx/pm-ls1.c index 4f9ca80..b11fcb2 100644 --- a/arch/arm/mach-imx/pm-ls1.c +++ b/arch/arm/mach-imx/pm-ls1.c @@ -35,6 +35,13 @@ #define CCSR_SCFG_DPSLPCR 0 #define CCSR_SCFG_DPSLPCR_VAL 0x1 #define CCSR_SCFG_PMCINTECR0x160 +#define CCSR_SCFG_PMCINTECR_LPUART 0x4000 +#define CCSR_SCFG_PMCINTECR_FTM0x2000 +#define CCSR_SCFG_PMCINTECR_GPIO 0x1000 +#define CCSR_SCFG_PMCINTECR_IRQ0 0x0800 +#define CCSR_SCFG_PMCINTECR_IRQ1 0x0400 +#define CCSR_SCFG_PMCINTECR_ETSECRXG0 0x0080 +#define CCSR_SCFG_PMCINTECR_ETSECRXG1 0x0040 #define CCSR_SCFG_PMCINTLECR 0x164 #define CCSR_SCFG_PMCINTSR 0x168 #define CCSR_SCFG_SPARECR2 0x504 @@ -50,7 +57,11 @@ #define CCSR_RCPM_CLPCL10SETR 0x1c4 #define CCSR_RCPM_CLPCL10SETR_C0 0x1 #define CCSR_RCPM_IPPDEXPCR0 0x140 +#define CCSR_RCPM_IPPDEXPCR0_ETSEC 0x8000 +#define CCSR_RCPM_IPPDEXPCR0_GPIO 0x0040 #define CCSR_RCPM_IPPDEXPCR1 0x144 +#define CCSR_RCPM_IPPDEXPCR1_LPUART0x4000 +#define CCSR_RCPM_IPPDEXPCR1_FLEXTIMER 0x2000 #define QIXIS_CTL_SYS 0x5 #define QIXIS_CTL_SYS_EVTSW_MASK 0x0c @@ -64,6 +75,10 @@ /* use the last page of SRAM */ #define SRAM_CODE_BASE_PHY (OCRAM_BASE + OCRAM_SIZE - PAGE_SIZE) +#define SLEEP_ARRAY_SIZE 3 + +static u32 ippdexpcr0, ippdexpcr1; + struct ls1_pm_baseaddr { void __iomem *rcpm; void __iomem *epu; @@ -242,6 +257,49 @@ static void ls1_board_resume(void) iowrite8(tmp, ls1_pm_base.fpga + QIXIS_CTL_SYS); } +static void ls1_setup_pmc_int(void) +{ + u32 pmcintecr; + + pmcintecr = 0; + if (ippdexpcr0 CCSR_RCPM_IPPDEXPCR0_ETSEC) + pmcintecr |= CCSR_SCFG_PMCINTECR_ETSECRXG0 | + CCSR_SCFG_PMCINTECR_ETSECRXG1; + + if (ippdexpcr0 CCSR_RCPM_IPPDEXPCR0_GPIO) + pmcintecr |= CCSR_SCFG_PMCINTECR_GPIO; + + if (ippdexpcr1 CCSR_RCPM_IPPDEXPCR1_LPUART) + pmcintecr |= CCSR_SCFG_PMCINTECR_LPUART; + + if (ippdexpcr1 CCSR_RCPM_IPPDEXPCR1_FLEXTIMER) + pmcintecr |= CCSR_SCFG_PMCINTECR_FTM; + + /* always set external IRQ pins as wakeup source */ + pmcintecr |= CCSR_SCFG_PMCINTECR_IRQ0 | CCSR_SCFG_PMCINTECR_IRQ1; + + /* enable wakeup interrupt during deep sleep */ + iowrite32be(pmcintecr, ls1_pm_base.scfg + CCSR_SCFG_PMCINTECR); + iowrite32be(0, ls1_pm_base.scfg + CCSR_SCFG_PMCINTLECR); + /* clear PMC interrupt status */ + iowrite32be(0x, ls1_pm_base.scfg + CCSR_SCFG_PMCINTSR); +} + +static void ls1_clear_pmc_int(void) +{ + /* disable wakeup interrupt during deep sleep */ + iowrite32be(0, ls1_pm_base.scfg + CCSR_SCFG_PMCINTECR); + /* clear PMC interrupt status */ + iowrite32be(0x, ls1_pm_base.scfg + CCSR_SCFG_PMCINTSR); +} + +/* set IP powerdown exception, make them work during sleep/deep sleep */ +static void ls1_set_powerdown(void) +{ + iowrite32be(ippdexpcr0, ls1_pm_base.rcpm + CCSR_RCPM_IPPDEXPCR0); + iowrite32be(ippdexpcr1, ls1_pm_base.rcpm + CCSR_RCPM_IPPDEXPCR1); +} + static void ls1_enter_deepsleep(void) { /* save DDR data */ @@ -265,8 +323,12 @@ static void ls1_enter_deepsleep(void) /* copy the last stage code to sram */ ls1_copy_sram_code(); + ls1_setup_pmc_int(); + cpu_suspend(SRAM_CODE_BASE_PHY, ls1_start_deepsleep); + ls1_clear_pmc_int(); + /* disable Warm Device Reset */ ls1_clrsetbits_be32(ls1_pm_base.scfg + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_VAL, 0); @@ -274,10 +336,45 @@ static void ls1_enter_deepsleep(void) ls1_board_resume(); } +static void ls1_set_power_except
[PATCH 2/4] arm: ls1021a: add dts nodes required by deep sleep
Add RCPM and DCSR nodes. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/arm/boot/dts/ls1021a-qds.dts | 6 +- arch/arm/boot/dts/ls1021a.dtsi| 117 ++ 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/ls1021a-qds.dts b/arch/arm/boot/dts/ls1021a-qds.dts index 9c5e16b..6903f43 100644 --- a/arch/arm/boot/dts/ls1021a-qds.dts +++ b/arch/arm/boot/dts/ls1021a-qds.dts @@ -157,7 +157,7 @@ fpga: board-control@3,0 { #address-cells = 1; #size-cells = 1; - compatible = simple-bus; + compatible = fsl,ls1021aqds-fpga, simple-bus; reg = 0x3 0x0 0x100; bank-width = 1; device-width = 1; @@ -238,3 +238,7 @@ uart1 { status = okay; }; + +rcpm { + fsl,deep-sleep; +}; diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index c70bb27..0c51ce0 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -183,6 +183,11 @@ }; }; + rcpm: rcpm@1ee2000 { + compatible = fsl,ls1021a-rcpm, fsl,qoriq-rcpm-2.1; + reg = 0x0 0x1ee2000 0x0 0x1; + }; + dspi0: dspi@210 { compatible = fsl,vf610-dspi; #address-cells = 1; @@ -406,4 +411,116 @@ dr_mode = host; }; }; + + dcsr { + #address-cells = 1; + #size-cells = 1; + compatible = fsl,dcsr, simple-bus; + ranges = 0x0 0x0 0x2000 0x100; + + dcsr-epu@0 { + compatible = fsl,ls1021a-dcsr-epu; + reg = 0x0 0x1; + }; + + dcsr-gdi@10 { + compatible = fsl,ls1021a-dcsr-gdi; + reg = 0x10 0x1; + }; + + dcsr-dddi@12 { + compatible = fsl,ls1021a-dcsr-dddi; + reg = 0x12 0x1; + }; + + dcsr-dcfg@22 { + compatible = fsl,ls1021a-dcsr-dcfg; + reg = 0x22 0x1000; + }; + + dcsr-clock@221000 { + compatible = fsl,ls1021a-dcsr-clock; + reg = 0x221000 0x1000; + }; + + dcsr-rcpm@222000 { + compatible = fsl,ls1021a-dcsr-rcpm; + reg = 0x222000 0x1000 0x223000 0x1000; + }; + + dcsr-ccp@225000 { + compatible = fsl,ls1021a-dcsr-ccp; + reg = 0x225000 0x1000; + }; + + dcsr-fusectrl@226000 { + compatible = fsl,ls1021a-dcsr-fusectrl; + reg = 0x226000 0x1000; + }; + + dcsr-dap@30 { + compatible = fsl,ls1021a-dcsr-dap; + reg = 0x30 0x1; + }; + + dcsr-cstf@35 { + compatible = fsl,ls1021a-dcsr-cstf; + reg = 0x35 0x1000 0x3a7000 0x1000; + }; + + dcsr-a7rom@36 { + compatible = fsl,ls1021a-dcsr-a7rom; + reg = 0x36 0x1; + }; + + dcsr-a7cpu@37 { + compatible = fsl,ls1021a-dcsr-a7cpu; + reg = 0x37 0x8000; + }; + + dcsr-a7cti@378000 { + compatible = fsl,ls1021a-dcsr-a7cti; + reg = 0x378000 0x4000; + }; + + dcsr-etm@37c000 { + compatible = fsl,ls1021a-dcsr-etm; + reg = 0x37c000 0x1000 0x37d000 0x3000; + }; + + dcsr-hugorom@3a { + compatible = fsl,ls1021a-dcsr-hugorom; + reg = 0x3a 0x1000; + }; + + dcsr-etf@3a1000 { + compatible = fsl,ls1021a-dcsr-etf; + reg = 0x3a1000 0x1000 0x3a2000 0x1000; + }; + + dcsr-etr@3a3000 { + compatible = fsl,ls1021a-dcsr-etr; + reg = 0x3a3000 0x1000; + }; + + dcsr-cti@3a4000 { + compatible = fsl,ls1021a-dcsr-cti; + reg = 0x3a4000 0x1000 0x3a5000 0x1000 0x3a6000 0x1000; + }; + + dcsr-atbrepl@3a8000 { + compatible = fsl,ls1021a-dcsr-atbrepl; + reg = 0x3a8000 0x1000; + }; + + dcsr-tsgen-ctrl@3a9000
[PATCH 3/4] arm: ls1021a: add deep sleep support
The ls1021a SoC supports deep sleep feature that can switch off most parts of the SoC when it is in deep sleep state. The DDR controller will also be powered off in deep sleep. Therefore, copy the last stage code to enter deep sleep to SRAM and run it with disabling MMU and caches. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- arch/arm/mach-imx/Kconfig | 1 + arch/arm/mach-imx/Makefile| 2 + arch/arm/mach-imx/pm-ls1.c| 374 ++ arch/arm/mach-imx/sleep-ls1.S | 137 arch/arm/mach-imx/sleep-ls1.h | 19 +++ 5 files changed, 533 insertions(+) create mode 100644 arch/arm/mach-imx/pm-ls1.c create mode 100644 arch/arm/mach-imx/sleep-ls1.S create mode 100644 arch/arm/mach-imx/sleep-ls1.h diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index e8627e0..c10acff 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -664,6 +664,7 @@ config SOC_LS1021A select HAVE_ARM_ARCH_TIMER select PCI_DOMAINS if PCI select ZONE_DMA if ARM_LPAE + select FSL_SLEEP_FSM if PM help This enable support for Freescale LS1021A processor. diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index f5ac685..358adf4 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -101,6 +101,8 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o mach-imx6sx.o ifeq ($(CONFIG_SUSPEND),y) AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o +AFLAGS_sleep-ls1.o :=-Wa,-march=armv7-a +obj-$(CONFIG_SOC_LS1021A) += pm-ls1.o sleep-ls1.o endif obj-$(CONFIG_SOC_IMX6) += pm-imx6.o diff --git a/arch/arm/mach-imx/pm-ls1.c b/arch/arm/mach-imx/pm-ls1.c new file mode 100644 index 000..4f9ca80 --- /dev/null +++ b/arch/arm/mach-imx/pm-ls1.c @@ -0,0 +1,374 @@ +/* + * Support deep sleep feature for LS1 + * + * Copyright 2014-2015 Freescale Semiconductor Inc. + * + * 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 linux/kernel.h +#include linux/suspend.h +#include linux/io.h +#include linux/of_platform.h +#include linux/of_address.h +#include linux/cpu_pm.h +#include asm/suspend.h +#include asm/delay.h +#include asm/cp15.h +#include asm/cacheflush.h +#include asm/idmap.h + +#include common.h +#include sleep-ls1.h + +#define FSL_SLEEP 0x1 +#define FSL_DEEP_SLEEP 0x2 + +#define DCSR_EPU_EPSMCR15 0x278 +#define DCSR_EPU_EPECR00x300 +#define DCSR_RCPM_CG1CR0 0x31c +#define DCSR_RCPM_CSTTACR0 0xb00 + +#define CCSR_SCFG_DPSLPCR 0 +#define CCSR_SCFG_DPSLPCR_VAL 0x1 +#define CCSR_SCFG_PMCINTECR0x160 +#define CCSR_SCFG_PMCINTLECR 0x164 +#define CCSR_SCFG_PMCINTSR 0x168 +#define CCSR_SCFG_SPARECR2 0x504 +#define CCSR_SCFG_SPARECR3 0x508 + +#define CCSR_DCFG_CRSTSR 0x400 +#define CCSR_DCFG_CRSTSR_VAL 0x0008 + +#define CCSR_RCPM_POWMGTCSR0x130 +#define CCSR_RCPM_POWMGTCSR_LPM20_REQ 0x0010 +#define CCSR_RCPM_POWMGTCSR_LPM20_ST 0x0200 +#define CCSR_RCPM_POWMGTCSR_P_LPM20_ST 0x0100 +#define CCSR_RCPM_CLPCL10SETR 0x1c4 +#define CCSR_RCPM_CLPCL10SETR_C0 0x1 +#define CCSR_RCPM_IPPDEXPCR0 0x140 +#define CCSR_RCPM_IPPDEXPCR1 0x144 + +#define QIXIS_CTL_SYS 0x5 +#define QIXIS_CTL_SYS_EVTSW_MASK 0x0c +#define QIXIS_CTL_SYS_EVTSW_IRQ0x04 + +#define QIXIS_PWR_CTL2 0x21 +#define QIXIS_PWR_CTL2_PCTL0x2 + +#define OCRAM_BASE 0x1000 +#define OCRAM_SIZE 0x1 /* 64K */ +/* use the last page of SRAM */ +#define SRAM_CODE_BASE_PHY (OCRAM_BASE + OCRAM_SIZE - PAGE_SIZE) + +struct ls1_pm_baseaddr { + void __iomem *rcpm; + void __iomem *epu; + void __iomem *dcsr_rcpm1; + void __iomem *scfg; + void __iomem *dcfg; + void __iomem *fpga; + void __iomem *sram; +}; + +/* 128 bytes buffer for restoring data broke by DDR training initialization */ +#define DDR_BUF_SIZE 128 +static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64); +static struct ls1_pm_baseaddr ls1_pm_base; +/* supported sleep modes by the present platform */ +static unsigned int sleep_modes; +static suspend_state_t ls1_pm_state; + +static inline void ls1_clrsetbits_be32(void __iomem *addr, u32 mask, u32 val) +{ + u32 tmp; + + tmp = ioread32be(addr); + tmp = (tmp ~mask) | val; + iowrite32be(tmp, addr); +} + +static void __iomem *of_iomap_str(const char *compatible) +{ + struct device_node *np; + void __iomem *base; + + np = of_find_compatible_node(NULL, NULL, compatible); + if (!np) { + pr_err(%s: can not find the compatible \%s\\n, + __func__
[PATCH 1/4] fsl: add EPU FSM configuration for deep sleep
T104x, T1024 and LS1021 of Freescale have a Finite State Machine (FSM) to control the hardware precedure in deep sleep. Software will start the FSM to enter deep sleep after finishing prepare work. Then, when receiving a wakeup event, the FSM will restore the SoC to work. This driver configures and clears the FSM registers for deep sleep. Note that the sequence of clearing the FSM registers does matter, should follow the sequence mentioned in the reference manual. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- drivers/platform/Kconfig | 2 + drivers/platform/Makefile| 1 + drivers/platform/fsl/Kconfig | 11 ++ drivers/platform/fsl/Makefile| 5 + drivers/platform/fsl/sleep_fsm.c | 263 +++ drivers/platform/fsl/sleep_fsm.h | 104 6 files changed, 386 insertions(+) create mode 100644 drivers/platform/fsl/Kconfig create mode 100644 drivers/platform/fsl/Makefile create mode 100644 drivers/platform/fsl/sleep_fsm.c create mode 100644 drivers/platform/fsl/sleep_fsm.h diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 09fde58..85e3c95 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -6,3 +6,5 @@ source drivers/platform/goldfish/Kconfig endif source drivers/platform/chrome/Kconfig + +source drivers/platform/fsl/Kconfig diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile index 3656b7b..37c6f72 100644 --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_X86) += x86/ obj-$(CONFIG_OLPC) += olpc/ obj-$(CONFIG_GOLDFISH) += goldfish/ obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ +obj-$(CONFIG_FSL_SOC) += fsl/ diff --git a/drivers/platform/fsl/Kconfig b/drivers/platform/fsl/Kconfig new file mode 100644 index 000..a1ea46e --- /dev/null +++ b/drivers/platform/fsl/Kconfig @@ -0,0 +1,11 @@ +# +# Freescale Specific Power Management Drivers +# + +config FSL_SLEEP_FSM + bool + help + This driver configures a hardware FSM (Finite State Machine) used in deep sleep. + The FSM finishes clean-ups at the last stage of entering deep sleep, and also + wakes up system when a wake up event happens. So far, T104x, T1024 and LS1021 + need this. diff --git a/drivers/platform/fsl/Makefile b/drivers/platform/fsl/Makefile new file mode 100644 index 000..d99ca0e --- /dev/null +++ b/drivers/platform/fsl/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for linux/drivers/platform/fsl +# Freescale Specific Power Management Drivers +# +obj-$(CONFIG_FSL_SLEEP_FSM)+= sleep_fsm.o diff --git a/drivers/platform/fsl/sleep_fsm.c b/drivers/platform/fsl/sleep_fsm.c new file mode 100644 index 000..0a0480a --- /dev/null +++ b/drivers/platform/fsl/sleep_fsm.c @@ -0,0 +1,263 @@ +/* + * Freescale deep sleep FSM (finite-state machine) configuration + * + * Copyright 2014-2015 Freescale Semiconductor Inc. + * + * Author: Hongbo Zhang hongbo.zh...@freescale.com + * 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. + */ + +#include linux/kernel.h +#include linux/io.h +#include linux/types.h + +#include sleep_fsm.h +/* + * These values are from chip's reference manual. For example, + * the values for T1040 can be found in 8.4.3.8 Programming + * supporting deep sleep mode of Chapter 8 Run Control and + * Power Management (RCPM). + * The default value can be applied to T104x, T1024 and LS1021. + */ +struct fsm_reg_vals epu_default_val[] = { + /* EPGCR (Event Processor Global Control Register) */ + {EPGCR, 0}, + /* EPECR (Event Processor Event Control Registers) */ + {EPECR0 + EPECR_STRIDE * 0, 0}, + {EPECR0 + EPECR_STRIDE * 1, 0}, + {EPECR0 + EPECR_STRIDE * 2, 0xF0004004}, + {EPECR0 + EPECR_STRIDE * 3, 0x8084}, + {EPECR0 + EPECR_STRIDE * 4, 0x2084}, + {EPECR0 + EPECR_STRIDE * 5, 0x0804}, + {EPECR0 + EPECR_STRIDE * 6, 0x8084}, + {EPECR0 + EPECR_STRIDE * 7, 0x8084}, + {EPECR0 + EPECR_STRIDE * 8, 0x6084}, + {EPECR0 + EPECR_STRIDE * 9, 0x0884}, + {EPECR0 + EPECR_STRIDE * 10, 0x4284}, + {EPECR0 + EPECR_STRIDE * 11, 0x9084}, + {EPECR0 + EPECR_STRIDE * 12, 0x8084}, + {EPECR0 + EPECR_STRIDE * 13, 0x0884}, + {EPECR0 + EPECR_STRIDE * 14, 0x0284}, + {EPECR0 + EPECR_STRIDE * 15, 0x0004}, + /* +* EPEVTCR (Event Processor EVT Pin Control Registers) +* SCU8 triger EVT2, and SCU11 triger EVT9 +*/ + {EPEVTCR0 + EPEVTCR_STRIDE * 0, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 1, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x8001
[PATCH v2 1/2] pm: add FSM configuration for deep sleep
For some Freescale's SoCs which support deep sleep, such as T1040, LS1021, software will start a Finite State Machine (FSM) to control the hardware precedure to enter deep sleep and return from it. This patch configures parameters of the FSM preparing for deep sleep. Signed-off-by: Chenhui Zhao --- Changes for v2: * use iowrite32be() drivers/platform/Kconfig |1 + drivers/platform/Makefile|1 + drivers/platform/fsl/Kconfig | 10 ++ drivers/platform/fsl/Makefile|5 + drivers/platform/fsl/sleep_fsm.c | 269 ++ drivers/platform/fsl/sleep_fsm.h | 106 +++ 6 files changed, 392 insertions(+), 0 deletions(-) create mode 100644 drivers/platform/fsl/Kconfig create mode 100644 drivers/platform/fsl/Makefile create mode 100644 drivers/platform/fsl/sleep_fsm.c create mode 100644 drivers/platform/fsl/sleep_fsm.h diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 69616ae..54ada25 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -5,3 +5,4 @@ if GOLDFISH source "drivers/platform/goldfish/Kconfig" endif +source "drivers/platform/fsl/Kconfig" diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile index 8a44a4c..d0cce95 100644 --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_X86) += x86/ obj-$(CONFIG_OLPC) += olpc/ obj-$(CONFIG_GOLDFISH) += goldfish/ +obj-$(CONFIG_FSL_SOC) += fsl/ diff --git a/drivers/platform/fsl/Kconfig b/drivers/platform/fsl/Kconfig new file mode 100644 index 000..72ed053 --- /dev/null +++ b/drivers/platform/fsl/Kconfig @@ -0,0 +1,10 @@ +# +# Freescale Specific Power Management Drivers +# + +config FSL_SLEEP_FSM + bool + help + This driver configures a hardware FSM (Finite State Machine) for deep sleep. + The FSM is used to finish clean-ups at the last stage of system entering deep + sleep, and also wakes up system when a wake up event happens. diff --git a/drivers/platform/fsl/Makefile b/drivers/platform/fsl/Makefile new file mode 100644 index 000..d99ca0e --- /dev/null +++ b/drivers/platform/fsl/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for linux/drivers/platform/fsl +# Freescale Specific Power Management Drivers +# +obj-$(CONFIG_FSL_SLEEP_FSM)+= sleep_fsm.o diff --git a/drivers/platform/fsl/sleep_fsm.c b/drivers/platform/fsl/sleep_fsm.c new file mode 100644 index 000..32616ad --- /dev/null +++ b/drivers/platform/fsl/sleep_fsm.c @@ -0,0 +1,269 @@ +/* + * Freescale deep sleep FSM (finite-state machine) configuration + * + * Copyright 2014 Freescale Semiconductor Inc. + * + * 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 "sleep_fsm.h" +/* + * These values are from chip's reference manual. For example, + * the values for T1040 can be found in "8.4.3.8 Programming + * supporting deep sleep mode" of Chapter 8 "Run Control and + * Power Management (RCPM)". + * The default value can be applied to T104x, LS1021. + */ +struct fsm_reg_vals epu_default_val[] = { + /* EPGCR (Event Processor Global Control Register) */ + {EPGCR, 0}, + /* EPECR (Event Processor Event Control Registers) */ + {EPECR0 + EPECR_STRIDE * 0, 0}, + {EPECR0 + EPECR_STRIDE * 1, 0}, + {EPECR0 + EPECR_STRIDE * 2, 0xF0004004}, + {EPECR0 + EPECR_STRIDE * 3, 0x8084}, + {EPECR0 + EPECR_STRIDE * 4, 0x2084}, + {EPECR0 + EPECR_STRIDE * 5, 0x0804}, + {EPECR0 + EPECR_STRIDE * 6, 0x8084}, + {EPECR0 + EPECR_STRIDE * 7, 0x8084}, + {EPECR0 + EPECR_STRIDE * 8, 0x6084}, + {EPECR0 + EPECR_STRIDE * 9, 0x0884}, + {EPECR0 + EPECR_STRIDE * 10, 0x4284}, + {EPECR0 + EPECR_STRIDE * 11, 0x9084}, + {EPECR0 + EPECR_STRIDE * 12, 0x8084}, + {EPECR0 + EPECR_STRIDE * 13, 0x0884}, + {EPECR0 + EPECR_STRIDE * 14, 0x0284}, + {EPECR0 + EPECR_STRIDE * 15, 0x0004}, + /* +* EPEVTCR (Event Processor EVT Pin Control Registers) +* SCU8 triger EVT2, and SCU11 triger EVT9 +*/ + {EPEVTCR0 + EPEVTCR_STRIDE * 0, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 1, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x8001}, + {EPEVTCR0 + EPEVTCR_STRIDE * 3, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 4, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 5, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 6, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 7, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 8, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 9, 0xB001}, + /* EPCMPR (Event Processor Counter Compare Reg
[PATCH v2 2/2] arm: pm: add deep sleep support for LS1
LS1 supports deep sleep feature that can switch off most parts of the SoC when it is in deep sleep state. The DDR controller will also be powered off in deep sleep. Therefore, copy the last stage code to enter deep sleep to SRAM and run it with disabling MMU and caches. Signed-off-by: Chenhui Zhao --- Changes for v2: * use identity mapping to smooth the process of disabling MMU * change the value of registers arch/arm/mach-imx/Kconfig |1 + arch/arm/mach-imx/Makefile|1 + arch/arm/mach-imx/pm-ls1.c| 341 + arch/arm/mach-imx/sleep-ls1.S | 132 4 files changed, 475 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-imx/pm-ls1.c create mode 100644 arch/arm/mach-imx/sleep-ls1.S diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index b85534c..716bb1b 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -866,6 +866,7 @@ config SOC_LS1021A select HAVE_SMP select ARCH_LAYERSCAPE select ZONE_DMA if ARM_LPAE + select FSL_SLEEP_FSM if PM help This enable support for Freescale Layerscape LS1021A processor. diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 41b8044..9931528 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -102,6 +102,7 @@ obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o ifeq ($(CONFIG_PM),y) obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o +obj-$(CONFIG_SOC_LS1021A) += pm-ls1.o sleep-ls1.o endif # i.MX5 based machines diff --git a/arch/arm/mach-imx/pm-ls1.c b/arch/arm/mach-imx/pm-ls1.c new file mode 100644 index 000..8fd7aee --- /dev/null +++ b/arch/arm/mach-imx/pm-ls1.c @@ -0,0 +1,341 @@ +/* + * Support deep sleep feature for LS1 + * + * Copyright 2014 Freescale Semiconductor Inc. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define FSL_SLEEP 0x1 +#define FSL_DEEP_SLEEP 0x2 + +#define DCSR_EPU_EPSMCR15 0x278 +#define DCSR_EPU_EPECR00x300 +#define DCSR_RCPM_CG1CR0 0x31c +#define DCSR_RCPM_CSTTACR0 0xb00 + +#define CCSR_SCFG_DPSLPCR 0 +#define CCSR_SCFG_DPSLPCR_VAL 0x1 +#define CCSR_SCFG_SPARECR2 0x504 +#define CCSR_SCFG_SPARECR3 0x508 + +#define CCSR_DCFG_CRSTSR 0x400 +#define CCSR_DCFG_CRSTSR_VAL 0x0008 + +#define CCSR_RCPM_POWMGTCSR0x130 +#define CCSR_RCPM_POWMGTCSR_LPM20_REQ 0x0010 +#define CCSR_RCPM_POWMGTCSR_LPM20_ST 0x0200 +#define CCSR_RCPM_POWMGTCSR_P_LPM20_ST 0x0100 +#define CCSR_RCPM_CLPCL10SETR 0x1c4 +#define CCSR_RCPM_CLPCL10SETR_C0 0x1 + +#define OCRAM_BASE 0x1000 +#define OCRAM_SIZE 0x1 /* 64K */ +/* use the last page of SRAM */ +#define SRAM_CODE_BASE_PHY (OCRAM_BASE + OCRAM_SIZE - PAGE_SIZE) + +struct ls1_pm_baseaddr { + void __iomem *epu; + void __iomem *dcsr_rcpm1; + void __iomem *dcsr_rcpm2; + void __iomem *rcpm; + void __iomem *scfg; + void __iomem *dcfg; + void __iomem *fpga; + void __iomem *sram; +}; + +/* 128 bytes buffer for restoring data broke by DDR training initialization */ +#define DDR_BUF_SIZE 128 +static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64); +static struct ls1_pm_baseaddr ls1_pm_base; +/* supported sleep modes by the present platform */ +static unsigned int sleep_modes; + +extern void ls1_do_deepsleep(unsigned long addr); +extern void ls1_start_fsm(void); +extern void ls1_deepsleep_resume(void); +extern void ls1021a_set_secondary_entry(void); +extern int ls1_sram_code_size; +extern void fsl_epu_setup_default(void __iomem *epu_base); + +static void ls1_pm_iomap(void) +{ + struct device_node *np; + void *base; + + np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcsr-epu"); + base = of_iomap(np, 0); + BUG_ON(!base); + ls1_pm_base.epu = base; + + np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcsr-rcpm"); + base = of_iomap(np, 0); + BUG_ON(!base); + ls1_pm_base.dcsr_rcpm1 = base; + base = of_iomap(np, 1); + BUG_ON(!base); + ls1_pm_base.dcsr_rcpm2 = base; + + np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-scfg"); + base = of_iomap(np, 0); + BUG_ON(!base); + ls1_pm_base.scfg = base; + + np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcfg"); + base = of_iomap(np, 0); + BUG_ON(!base); + ls1_pm_base.dcfg = base; + + np = of_find_compatible_node(NULL, NULL,
[PATCH v2 2/2] arm: pm: add deep sleep support for LS1
LS1 supports deep sleep feature that can switch off most parts of the SoC when it is in deep sleep state. The DDR controller will also be powered off in deep sleep. Therefore, copy the last stage code to enter deep sleep to SRAM and run it with disabling MMU and caches. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- Changes for v2: * use identity mapping to smooth the process of disabling MMU * change the value of registers arch/arm/mach-imx/Kconfig |1 + arch/arm/mach-imx/Makefile|1 + arch/arm/mach-imx/pm-ls1.c| 341 + arch/arm/mach-imx/sleep-ls1.S | 132 4 files changed, 475 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-imx/pm-ls1.c create mode 100644 arch/arm/mach-imx/sleep-ls1.S diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index b85534c..716bb1b 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -866,6 +866,7 @@ config SOC_LS1021A select HAVE_SMP select ARCH_LAYERSCAPE select ZONE_DMA if ARM_LPAE + select FSL_SLEEP_FSM if PM help This enable support for Freescale Layerscape LS1021A processor. diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 41b8044..9931528 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -102,6 +102,7 @@ obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o ifeq ($(CONFIG_PM),y) obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o +obj-$(CONFIG_SOC_LS1021A) += pm-ls1.o sleep-ls1.o endif # i.MX5 based machines diff --git a/arch/arm/mach-imx/pm-ls1.c b/arch/arm/mach-imx/pm-ls1.c new file mode 100644 index 000..8fd7aee --- /dev/null +++ b/arch/arm/mach-imx/pm-ls1.c @@ -0,0 +1,341 @@ +/* + * Support deep sleep feature for LS1 + * + * Copyright 2014 Freescale Semiconductor Inc. + * + * 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 linux/kernel.h +#include linux/suspend.h +#include linux/io.h +#include linux/of_platform.h +#include linux/of_address.h +#include linux/cpu_pm.h +#include asm/suspend.h +#include asm/delay.h +#include asm/cp15.h +#include asm/cacheflush.h +#include asm/idmap.h + +#include common.h + +#define FSL_SLEEP 0x1 +#define FSL_DEEP_SLEEP 0x2 + +#define DCSR_EPU_EPSMCR15 0x278 +#define DCSR_EPU_EPECR00x300 +#define DCSR_RCPM_CG1CR0 0x31c +#define DCSR_RCPM_CSTTACR0 0xb00 + +#define CCSR_SCFG_DPSLPCR 0 +#define CCSR_SCFG_DPSLPCR_VAL 0x1 +#define CCSR_SCFG_SPARECR2 0x504 +#define CCSR_SCFG_SPARECR3 0x508 + +#define CCSR_DCFG_CRSTSR 0x400 +#define CCSR_DCFG_CRSTSR_VAL 0x0008 + +#define CCSR_RCPM_POWMGTCSR0x130 +#define CCSR_RCPM_POWMGTCSR_LPM20_REQ 0x0010 +#define CCSR_RCPM_POWMGTCSR_LPM20_ST 0x0200 +#define CCSR_RCPM_POWMGTCSR_P_LPM20_ST 0x0100 +#define CCSR_RCPM_CLPCL10SETR 0x1c4 +#define CCSR_RCPM_CLPCL10SETR_C0 0x1 + +#define OCRAM_BASE 0x1000 +#define OCRAM_SIZE 0x1 /* 64K */ +/* use the last page of SRAM */ +#define SRAM_CODE_BASE_PHY (OCRAM_BASE + OCRAM_SIZE - PAGE_SIZE) + +struct ls1_pm_baseaddr { + void __iomem *epu; + void __iomem *dcsr_rcpm1; + void __iomem *dcsr_rcpm2; + void __iomem *rcpm; + void __iomem *scfg; + void __iomem *dcfg; + void __iomem *fpga; + void __iomem *sram; +}; + +/* 128 bytes buffer for restoring data broke by DDR training initialization */ +#define DDR_BUF_SIZE 128 +static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64); +static struct ls1_pm_baseaddr ls1_pm_base; +/* supported sleep modes by the present platform */ +static unsigned int sleep_modes; + +extern void ls1_do_deepsleep(unsigned long addr); +extern void ls1_start_fsm(void); +extern void ls1_deepsleep_resume(void); +extern void ls1021a_set_secondary_entry(void); +extern int ls1_sram_code_size; +extern void fsl_epu_setup_default(void __iomem *epu_base); + +static void ls1_pm_iomap(void) +{ + struct device_node *np; + void *base; + + np = of_find_compatible_node(NULL, NULL, fsl,ls1021a-dcsr-epu); + base = of_iomap(np, 0); + BUG_ON(!base); + ls1_pm_base.epu = base; + + np = of_find_compatible_node(NULL, NULL, fsl,ls1021a-dcsr-rcpm); + base = of_iomap(np, 0); + BUG_ON(!base); + ls1_pm_base.dcsr_rcpm1 = base; + base = of_iomap(np, 1); + BUG_ON(!base); + ls1_pm_base.dcsr_rcpm2 = base; + + np = of_find_compatible_node(NULL, NULL, fsl,ls1021a-scfg); + base = of_iomap(np, 0); + BUG_ON(!base); + ls1_pm_base.scfg = base; + + np = of_find_compatible_node(NULL, NULL, fsl,ls1021a-dcfg); + base = of_iomap
[PATCH v2 1/2] pm: add FSM configuration for deep sleep
For some Freescale's SoCs which support deep sleep, such as T1040, LS1021, software will start a Finite State Machine (FSM) to control the hardware precedure to enter deep sleep and return from it. This patch configures parameters of the FSM preparing for deep sleep. Signed-off-by: Chenhui Zhao chenhui.z...@freescale.com --- Changes for v2: * use iowrite32be() drivers/platform/Kconfig |1 + drivers/platform/Makefile|1 + drivers/platform/fsl/Kconfig | 10 ++ drivers/platform/fsl/Makefile|5 + drivers/platform/fsl/sleep_fsm.c | 269 ++ drivers/platform/fsl/sleep_fsm.h | 106 +++ 6 files changed, 392 insertions(+), 0 deletions(-) create mode 100644 drivers/platform/fsl/Kconfig create mode 100644 drivers/platform/fsl/Makefile create mode 100644 drivers/platform/fsl/sleep_fsm.c create mode 100644 drivers/platform/fsl/sleep_fsm.h diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 69616ae..54ada25 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -5,3 +5,4 @@ if GOLDFISH source drivers/platform/goldfish/Kconfig endif +source drivers/platform/fsl/Kconfig diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile index 8a44a4c..d0cce95 100644 --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_X86) += x86/ obj-$(CONFIG_OLPC) += olpc/ obj-$(CONFIG_GOLDFISH) += goldfish/ +obj-$(CONFIG_FSL_SOC) += fsl/ diff --git a/drivers/platform/fsl/Kconfig b/drivers/platform/fsl/Kconfig new file mode 100644 index 000..72ed053 --- /dev/null +++ b/drivers/platform/fsl/Kconfig @@ -0,0 +1,10 @@ +# +# Freescale Specific Power Management Drivers +# + +config FSL_SLEEP_FSM + bool + help + This driver configures a hardware FSM (Finite State Machine) for deep sleep. + The FSM is used to finish clean-ups at the last stage of system entering deep + sleep, and also wakes up system when a wake up event happens. diff --git a/drivers/platform/fsl/Makefile b/drivers/platform/fsl/Makefile new file mode 100644 index 000..d99ca0e --- /dev/null +++ b/drivers/platform/fsl/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for linux/drivers/platform/fsl +# Freescale Specific Power Management Drivers +# +obj-$(CONFIG_FSL_SLEEP_FSM)+= sleep_fsm.o diff --git a/drivers/platform/fsl/sleep_fsm.c b/drivers/platform/fsl/sleep_fsm.c new file mode 100644 index 000..32616ad --- /dev/null +++ b/drivers/platform/fsl/sleep_fsm.c @@ -0,0 +1,269 @@ +/* + * Freescale deep sleep FSM (finite-state machine) configuration + * + * Copyright 2014 Freescale Semiconductor Inc. + * + * 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 linux/kernel.h +#include linux/io.h +#include linux/types.h + +#include sleep_fsm.h +/* + * These values are from chip's reference manual. For example, + * the values for T1040 can be found in 8.4.3.8 Programming + * supporting deep sleep mode of Chapter 8 Run Control and + * Power Management (RCPM). + * The default value can be applied to T104x, LS1021. + */ +struct fsm_reg_vals epu_default_val[] = { + /* EPGCR (Event Processor Global Control Register) */ + {EPGCR, 0}, + /* EPECR (Event Processor Event Control Registers) */ + {EPECR0 + EPECR_STRIDE * 0, 0}, + {EPECR0 + EPECR_STRIDE * 1, 0}, + {EPECR0 + EPECR_STRIDE * 2, 0xF0004004}, + {EPECR0 + EPECR_STRIDE * 3, 0x8084}, + {EPECR0 + EPECR_STRIDE * 4, 0x2084}, + {EPECR0 + EPECR_STRIDE * 5, 0x0804}, + {EPECR0 + EPECR_STRIDE * 6, 0x8084}, + {EPECR0 + EPECR_STRIDE * 7, 0x8084}, + {EPECR0 + EPECR_STRIDE * 8, 0x6084}, + {EPECR0 + EPECR_STRIDE * 9, 0x0884}, + {EPECR0 + EPECR_STRIDE * 10, 0x4284}, + {EPECR0 + EPECR_STRIDE * 11, 0x9084}, + {EPECR0 + EPECR_STRIDE * 12, 0x8084}, + {EPECR0 + EPECR_STRIDE * 13, 0x0884}, + {EPECR0 + EPECR_STRIDE * 14, 0x0284}, + {EPECR0 + EPECR_STRIDE * 15, 0x0004}, + /* +* EPEVTCR (Event Processor EVT Pin Control Registers) +* SCU8 triger EVT2, and SCU11 triger EVT9 +*/ + {EPEVTCR0 + EPEVTCR_STRIDE * 0, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 1, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x8001}, + {EPEVTCR0 + EPEVTCR_STRIDE * 3, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 4, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 5, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 6, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 7, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 8, 0}, + {EPEVTCR0 + EPEVTCR_STRIDE * 9, 0xB001}, + /* EPCMPR (Event Processor Counter Compare Registers