diff options
author | Jonas Aaberg <jonas.aberg@stericsson.com> | 2011-09-13 13:32:39 +0200 |
---|---|---|
committer | Jonas ABERG <jonas.aberg@stericsson.com> | 2011-09-29 08:34:43 +0200 |
commit | 0cddfb2b35dbb6f054bfdbc486a4f84dfe8efd1a (patch) | |
tree | 92f5496786ff9c69b70863cab991792d81e0bfee /arch/arm/mach-ux500/pm | |
parent | 2c1d6edf73274e56e3194dac75c59e82e88688bd (diff) |
ARM: ux500: Remove powersave
Since we don't know really the status of powersave related
feature on this development track, let's remove everything,
except:
- prcmu driver: New location, which is the same as linux-next
- cpufreq: new location, same as linux-next
- regulator: keep as is for the moment, needed for the system to work.
- clocks: same as for regulator.
- pm-runtime: keep it as is.
Later patches will re-add powersave, based upon what exists on SI
u8500-android-2.3_v3.15
MTU from plat-nomadik is now used instead of own copy in mach.
Change-Id: I8ceaa65e5e0905fcd85bf8e793b4a5ab2d2df64c
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32048
Diffstat (limited to 'arch/arm/mach-ux500/pm')
25 files changed, 1 insertions, 6777 deletions
diff --git a/arch/arm/mach-ux500/pm/Kconfig b/arch/arm/mach-ux500/pm/Kconfig deleted file mode 100644 index 22a677b4f0c..00000000000 --- a/arch/arm/mach-ux500/pm/Kconfig +++ /dev/null @@ -1,101 +0,0 @@ -config UX500_CPUFREQ - tristate "CPUFreq support" - depends on (UX500_SOC_DB8500 || UX500_SOC_DB5500) && CPU_FREQ && PM - default y - help - Add support for CPU Frequency scaling for Ux500 SOCs. - ARM power domains operating points can be set - dynamically. It depends on CPUfreq and PM subsystem. - -config U8500_CPUIDLE - tristate "CPUIdle support" - depends on CPU_IDLE && (U5500_PRCMU || U8500_PRCMU) && !RTC_DRV_PL031 && PM - default y - select GENERIC_CLOCKEVENTS_BROADCAST - select UX500_CONTEXT - help - Add support for CPUIdle for U8500. - -config U8500_CPUIDLE_DEEPEST_STATE - int "Deepest sleep state" - default 4 if UX500_SOC_DB8500 - default 1 if UX500_SOC_DB5500 - depends on U8500_CPUIDLE - help - Set deepest sleep state. See the cstate struct in cpuidle.c. - Default is ApSleep. - -config U8500_CPUIDLE_APDEEPIDLE - bool "CPUIdle ApDeepIdle" - depends on U8500_CPUIDLE - help - Adds the power level ApDeepIdle, where APE is powered on while - ARM is powered off. Default n. - -config U8500_CPUIDLE_DEBUG - bool "CPUIdle debug" - depends on U8500_CPUIDLE && DEBUG_FS - help - Add debugging support for CPUIdle for U8500. - -config UX500_SUSPEND - bool "Suspend to mem and standby support" - depends on (UX500_SOC_DB8500 || UX500_SOC_DB5500) && PM - select UX500_CONTEXT - help - Add support for suspend. - -config UX500_SUSPEND_STANDBY - bool "Suspend Standby goes to ApSleep" - depends on UX500_SUSPEND - help - If yes, echo standby > /sys/power/state puts the system into ApSleep. - -config UX500_SUSPEND_MEM - bool "Suspend Mem goes to ApDeepSleep" - depends on UX500_SUSPEND - help - If yes, echo mem > /sys/power/state puts the system into ApDeepSleep else - it will do the same as echo standby > /sys/power/state. - -config UX500_SUSPEND_DBG - bool "Suspend debug" - depends on UX500_SUSPEND && DEBUG_FS - help - Add debug support for suspend. - -config UX500_SUSPEND_DBG_WAKE_ON_UART - bool "Suspend wakes on console UART" - depends on UX500_SUSPEND_DBG - help - Wake up on uart interrupts. Makes it possible for the console to wake up system. - -config UX500_CONSOLE_UART_GPIO_PIN - int "The pin number of the console UART GPIO pin" - default 29 - depends on UX500_SUSPEND_DBG_WAKE_ON_UART || U8500_CPUIDLE_DEBUG - help - GPIO pin number of the GPIO pin connected to the console UART RX line. - -config UX500_CONTEXT - bool "Context save/restore support for UX500" - depends on (UX500_SOC_DB8500 || UX500_SOC_DB5500) && PM - help - This is needed for ApSleep and deeper sleep states. - -config UX500_USECASE_GOVERNOR - bool "UX500 use-case governor" - depends on (UX500_SOC_DB8500 || UX500_SOC_DB5500) && \ - (CPU_FREQ && CPU_IDLE && HOTPLUG_CPU && \ - EARLYSUSPEND && UX500_L2X0_PREFETCH_CTRL && PM) - default y - help - Adjusts CPU_IDLE, CPU_FREQ, HOTPLUG_CPU and L2 cache parameters - -config UX500_PM_PERFORMANCE - bool "Performance supervision" - depends on UX500_PRCMU_QOS_POWER - default y - help - Enable supervision of events which may require a boost - of platform performance. diff --git a/arch/arm/mach-ux500/pm/Makefile b/arch/arm/mach-ux500/pm/Makefile index 2d191ff8081..1bf6415307b 100644 --- a/arch/arm/mach-ux500/pm/Makefile +++ b/arch/arm/mach-ux500/pm/Makefile @@ -1,22 +1,4 @@ # # Power save related files # -obj-y := pm.o runtime.o no_suspend.o - -obj-$(CONFIG_U8500_CPUIDLE) += cpuidle.o timer.o -obj-$(CONFIG_U8500_CPUIDLE_DEBUG) += cpuidle_dbg.o -obj-$(CONFIG_UX500_CONTEXT) += context.o context_arm.o context-db8500.o context-db5500.o -obj-$(CONFIG_UX500_CPUFREQ) += cpufreq.o -obj-$(CONFIG_UX500_SUSPEND) += suspend.o -obj-$(CONFIG_UX500_SUSPEND_DBG) += suspend_dbg.o -obj-$(CONFIG_UX500_USECASE_GOVERNOR) += usecase_gov.o - -ifeq ($(CONFIG_UX500_SOC_DB8500), y) -obj-$(CONFIG_UX500_CPUFREQ) += cpufreq-db8500.o -endif - -ifeq ($(CONFIG_UX500_SOC_DB5500), y) -obj-$(CONFIG_UX500_CPUFREQ) += cpufreq-db5500.o -endif - -obj-$(CONFIG_UX500_PM_PERFORMANCE) += performance.o +obj-y := runtime.o no_suspend.o diff --git a/arch/arm/mach-ux500/pm/context-db5500.c b/arch/arm/mach-ux500/pm/context-db5500.c deleted file mode 100644 index 78904d3486e..00000000000 --- a/arch/arm/mach-ux500/pm/context-db5500.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>, - * Rickard Andersson <rickard.andersson@stericsson.com>, - * Sundar Iyer <sundar.iyer@stericsson.com>, - * ST-Ericsson. - * License terms: GNU General Public License (GPL) version 2 - * - */ - -#include <linux/io.h> - -#include <mach/hardware.h> - -#include "context.h" - -/* These registers are DB5500 specific */ -#define NODE_HIBW1_ESRAM_IN_0_PRIORITY 0x0 -#define NODE_HIBW1_ESRAM_IN_1_PRIORITY 0x4 - -#define NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT 0x18 -#define NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT 0x1C -#define NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT 0x20 - -#define NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT 0x24 -#define NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT 0x28 -#define NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT 0x2C - -#define NODE_HIBW1_DDR_IN_0_PRIORITY 0x400 -#define NODE_HIBW1_DDR_IN_1_PRIORITY 0x404 -#define NODE_HIBW1_DDR_IN_2_PRIORITY 0x408 - -#define NODE_HIBW1_DDR_IN_0_LIMIT 0x424 -#define NODE_HIBW1_DDR_IN_1_LIMIT 0x428 -#define NODE_HIBW1_DDR_IN_2_LIMIT 0x42C - -#define NODE_HIBW1_DDR_OUT_0_PRIORITY 0x430 - -#define NODE_HIBW2_ESRAM_IN_0_PRIORITY 0x800 -#define NODE_HIBW2_ESRAM_IN_1_PRIORITY 0x804 - -#define NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT 0x818 -#define NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT 0x81C -#define NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT 0x820 - -#define NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT 0x824 -#define NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT 0x828 -#define NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT 0x82C - -#define NODE_HIBW2_DDR_IN_0_PRIORITY 0xC00 -#define NODE_HIBW2_DDR_IN_1_PRIORITY 0xC04 -#define NODE_HIBW2_DDR_IN_2_PRIORITY 0xC08 -#define NODE_HIBW2_DDR_IN_3_PRIORITY 0xC0C - -#define NODE_HIBW2_DDR_IN_0_LIMIT 0xC30 -#define NODE_HIBW2_DDR_IN_1_LIMIT 0xC34 -#define NODE_HIBW2_DDR_IN_2_LIMIT 0xC38 -#define NODE_HIBW2_DDR_IN_3_LIMIT 0xC3C - -#define NODE_HIBW2_DDR_OUT_0_PRIORITY 0xC40 - -#define NODE_ESRAM0_IN_0_PRIORITY 0x1000 -#define NODE_ESRAM0_IN_1_PRIORITY 0x1004 -#define NODE_ESRAM0_IN_2_PRIORITY 0x1008 - -#define NODE_ESRAM0_IN_0_LIMIT 0x1024 -#define NODE_ESRAM0_IN_1_LIMIT 0x1028 -#define NODE_ESRAM0_IN_2_LIMIT 0x102C -#define NODE_ESRAM0_OUT_0_PRIORITY 0x1030 - -#define NODE_ESRAM1_2_IN_0_PRIORITY 0x1400 -#define NODE_ESRAM1_2_IN_1_PRIORITY 0x1404 -#define NODE_ESRAM1_2_IN_2_PRIORITY 0x1408 - -#define NODE_ESRAM1_2_IN_0_ARB_1_LIMIT 0x1424 -#define NODE_ESRAM1_2_IN_1_ARB_1_LIMIT 0x1428 -#define NODE_ESRAM1_2_IN_2_ARB_1_LIMIT 0x142C -#define NODE_ESRAM1_2_OUT_0_PRIORITY 0x1430 - -#define NODE_ESRAM3_4_IN_0_PRIORITY 0x1800 -#define NODE_ESRAM3_4_IN_1_PRIORITY 0x1804 -#define NODE_ESRAM3_4_IN_2_PRIORITY 0x1808 - -#define NODE_ESRAM3_4_IN_0_ARB_1_LIMIT 0x1824 -#define NODE_ESRAM3_4_IN_1_ARB_1_LIMIT 0x1828 -#define NODE_ESRAM3_4_IN_2_ARB_1_LIMIT 0x182C -#define NODE_ESRAM3_4_OUT_0_PRIORITY 0x1830 - -/* - * Save ICN (Interconnect or Interconnect nodes) configuration registers - * TODO: This can be optimized, for example if we have - * a static ICN configuration. - */ - -static struct { - void __iomem *base; - u32 hibw1_esram_in_pri[2]; - u32 hibw1_esram_in0_arb[3]; - u32 hibw1_esram_in1_arb[3]; - u32 hibw1_ddr_in_prio[3]; - u32 hibw1_ddr_in_limit[3]; - u32 hibw1_ddr_out_prio_reg; - - /* HiBw2 node registers */ - u32 hibw2_esram_in_pri[2]; - u32 hibw2_esram_in0_arblimit[3]; - u32 hibw2_esram_in1_arblimit[3]; - u32 hibw2_ddr_in_prio[4]; - u32 hibw2_ddr_in_limit[4]; - u32 hibw2_ddr_out_prio_reg; - - /* ESRAM node registers */ - u32 esram_in_prio[3]; - u32 esram_in_lim[3]; - u32 esram_out_prio_reg; - - u32 esram12_in_prio[3]; - u32 esram12_in_arb_lim[3]; - u32 esram12_out_prio_reg; - - u32 esram34_in_prio[3]; - u32 esram34_in_arb_lim[3]; - u32 esram34_out_prio; -} context_icn; - - -void u5500_context_save_icn(void) -{ - /* hibw1 */ - context_icn.hibw1_esram_in_pri[0] = - readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_PRIORITY); - context_icn.hibw1_esram_in_pri[1] = - readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_PRIORITY); - - context_icn.hibw1_esram_in0_arb[0] = - readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT); - context_icn.hibw1_esram_in0_arb[1] = - readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT); - context_icn.hibw1_esram_in0_arb[2] = - readl(context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT); - - context_icn.hibw1_esram_in1_arb[0] = - readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT); - context_icn.hibw1_esram_in1_arb[1] = - readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT); - context_icn.hibw1_esram_in1_arb[2] = - readl(context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT); - - context_icn.hibw1_ddr_in_prio[0] = - readl(context_icn.base + NODE_HIBW1_DDR_IN_0_PRIORITY); - context_icn.hibw1_ddr_in_prio[1] = - readl(context_icn.base + NODE_HIBW1_DDR_IN_1_PRIORITY); - context_icn.hibw1_ddr_in_prio[2] = - readl(context_icn.base + NODE_HIBW1_DDR_IN_2_PRIORITY); - - context_icn.hibw1_ddr_in_limit[0] = - readl(context_icn.base + NODE_HIBW1_DDR_IN_0_LIMIT); - context_icn.hibw1_ddr_in_limit[1] = - readl(context_icn.base + NODE_HIBW1_DDR_IN_1_LIMIT); - context_icn.hibw1_ddr_in_limit[2] = - readl(context_icn.base + NODE_HIBW1_DDR_IN_2_LIMIT); - - context_icn.hibw1_ddr_out_prio_reg = - readl(context_icn.base + NODE_HIBW1_DDR_OUT_0_PRIORITY); - - /* hibw2 */ - context_icn.hibw2_esram_in_pri[0] = - readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_PRIORITY); - context_icn.hibw2_esram_in_pri[1] = - readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_PRIORITY); - - context_icn.hibw2_esram_in0_arblimit[0] = - readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT); - context_icn.hibw2_esram_in0_arblimit[1] = - readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT); - context_icn.hibw2_esram_in0_arblimit[2] = - readl(context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT); - - context_icn.hibw2_esram_in1_arblimit[0] = - readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT); - context_icn.hibw2_esram_in1_arblimit[1] = - readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT); - context_icn.hibw2_esram_in1_arblimit[2] = - readl(context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT); - - context_icn.hibw2_ddr_in_prio[0] = - readl(context_icn.base + NODE_HIBW2_DDR_IN_0_PRIORITY); - context_icn.hibw2_ddr_in_prio[1] = - readl(context_icn.base + NODE_HIBW2_DDR_IN_1_PRIORITY); - context_icn.hibw2_ddr_in_prio[2] = - readl(context_icn.base + NODE_HIBW2_DDR_IN_2_PRIORITY); - context_icn.hibw2_ddr_in_prio[3] = - readl(context_icn.base + NODE_HIBW2_DDR_IN_3_PRIORITY); - - context_icn.hibw2_ddr_in_limit[0] = - readl(context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT); - context_icn.hibw2_ddr_in_limit[1] = - readl(context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT); - context_icn.hibw2_ddr_in_limit[2] = - readl(context_icn.base + NODE_HIBW2_DDR_IN_2_LIMIT); - context_icn.hibw2_ddr_in_limit[3] = - readl(context_icn.base + NODE_HIBW2_DDR_IN_3_LIMIT); - - context_icn.hibw2_ddr_out_prio_reg = - readl(context_icn.base + NODE_HIBW2_DDR_OUT_0_PRIORITY); - - /* ESRAM0 */ - context_icn.esram_in_prio[0] = - readl(context_icn.base + NODE_ESRAM0_IN_0_PRIORITY); - context_icn.esram_in_prio[1] = - readl(context_icn.base + NODE_ESRAM0_IN_1_PRIORITY); - context_icn.esram_in_prio[2] = - readl(context_icn.base + NODE_ESRAM0_IN_2_PRIORITY); - - context_icn.esram_in_lim[0] = - readl(context_icn.base + NODE_ESRAM0_IN_0_LIMIT); - context_icn.esram_in_lim[1] = - readl(context_icn.base + NODE_ESRAM0_IN_1_LIMIT); - context_icn.esram_in_lim[2] = - readl(context_icn.base + NODE_ESRAM0_IN_2_LIMIT); - - context_icn.esram_out_prio_reg = - readl(context_icn.base + NODE_ESRAM0_OUT_0_PRIORITY); - - /* ESRAM1-2 */ - context_icn.esram12_in_prio[0] = - readl(context_icn.base + NODE_ESRAM1_2_IN_0_PRIORITY); - context_icn.esram12_in_prio[1] = - readl(context_icn.base + NODE_ESRAM1_2_IN_1_PRIORITY); - context_icn.esram12_in_prio[2] = - readl(context_icn.base + NODE_ESRAM1_2_IN_2_PRIORITY); - - context_icn.esram12_in_arb_lim[0] = - readl(context_icn.base + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT); - context_icn.esram12_in_arb_lim[1] = - readl(context_icn.base + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT); - context_icn.esram12_in_arb_lim[2] = - readl(context_icn.base + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT); - - context_icn.esram12_out_prio_reg = - readl(context_icn.base + NODE_ESRAM1_2_OUT_0_PRIORITY); - - /* ESRAM3-4 */ - context_icn.esram34_in_prio[0] = - readl(context_icn.base + NODE_ESRAM3_4_IN_0_PRIORITY); - context_icn.esram34_in_prio[1] = - readl(context_icn.base + NODE_ESRAM3_4_IN_1_PRIORITY); - context_icn.esram34_in_prio[2] = - readl(context_icn.base + NODE_ESRAM3_4_IN_2_PRIORITY); - - context_icn.esram34_in_arb_lim[0] = - readl(context_icn.base + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT); - context_icn.esram34_in_arb_lim[1] = - readl(context_icn.base + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT); - context_icn.esram34_in_arb_lim[2] = - readl(context_icn.base + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT); - - context_icn.esram34_out_prio = - readl(context_icn.base + NODE_ESRAM3_4_OUT_0_PRIORITY); -} - -/* - * Restore ICN configuration registers - */ -void u5500_context_restore_icn(void) -{ - - /* hibw1 */ - writel(context_icn.hibw1_esram_in_pri[0], - context_icn.base + NODE_HIBW1_ESRAM_IN_0_PRIORITY); - writel(context_icn.hibw1_esram_in_pri[1], - context_icn.base + NODE_HIBW1_ESRAM_IN_1_PRIORITY); - - writel(context_icn.hibw1_esram_in0_arb[0], - context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT); - writel(context_icn.hibw1_esram_in0_arb[1], - context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT); - writel(context_icn.hibw1_esram_in0_arb[2], - context_icn.base + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT); - - writel(context_icn.hibw1_esram_in1_arb[0], - context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT); - writel(context_icn.hibw1_esram_in1_arb[1], - context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT); - writel(context_icn.hibw1_esram_in1_arb[2], - context_icn.base + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT); - - writel(context_icn.hibw1_ddr_in_prio[0], - context_icn.base + NODE_HIBW1_DDR_IN_0_PRIORITY); - writel(context_icn.hibw1_ddr_in_prio[1], - context_icn.base + NODE_HIBW1_DDR_IN_1_PRIORITY); - writel(context_icn.hibw1_ddr_in_prio[2], - context_icn.base + NODE_HIBW1_DDR_IN_2_PRIORITY); - - writel(context_icn.hibw1_ddr_in_limit[0], - context_icn.base + NODE_HIBW1_DDR_IN_0_LIMIT); - writel(context_icn.hibw1_ddr_in_limit[1], - context_icn.base + NODE_HIBW1_DDR_IN_1_LIMIT); - writel(context_icn.hibw1_ddr_in_limit[2], - context_icn.base + NODE_HIBW1_DDR_IN_2_LIMIT); - - writel(context_icn.hibw1_ddr_out_prio_reg, - context_icn.base + NODE_HIBW1_DDR_OUT_0_PRIORITY); - - /* hibw2 */ - writel(context_icn.hibw2_esram_in_pri[0], - context_icn.base + NODE_HIBW2_ESRAM_IN_0_PRIORITY); - writel(context_icn.hibw2_esram_in_pri[1], - context_icn.base + NODE_HIBW2_ESRAM_IN_1_PRIORITY); - - writel(context_icn.hibw2_esram_in0_arblimit[0], - context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT); - writel(context_icn.hibw2_esram_in0_arblimit[1], - context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT); - writel(context_icn.hibw2_esram_in0_arblimit[2], - context_icn.base + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT); - - writel(context_icn.hibw2_esram_in1_arblimit[0], - context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT); - writel(context_icn.hibw2_esram_in1_arblimit[1], - context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT); - writel(context_icn.hibw2_esram_in1_arblimit[2], - context_icn.base + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT); - - writel(context_icn.hibw2_ddr_in_prio[0], - context_icn.base + NODE_HIBW2_DDR_IN_0_PRIORITY); - writel(context_icn.hibw2_ddr_in_prio[1], - context_icn.base + NODE_HIBW2_DDR_IN_1_PRIORITY); - writel(context_icn.hibw2_ddr_in_prio[2], - context_icn.base + NODE_HIBW2_DDR_IN_2_PRIORITY); - writel(context_icn.hibw2_ddr_in_prio[3], - context_icn.base + NODE_HIBW2_DDR_IN_3_PRIORITY); - - writel(context_icn.hibw2_ddr_in_limit[0], - context_icn.base + NODE_HIBW2_DDR_IN_0_LIMIT); - writel(context_icn.hibw2_ddr_in_limit[1], - context_icn.base + NODE_HIBW2_DDR_IN_1_LIMIT); - writel(context_icn.hibw2_ddr_in_limit[2], - context_icn.base + NODE_HIBW2_DDR_IN_2_LIMIT); - writel(context_icn.hibw2_ddr_in_limit[3], - context_icn.base + NODE_HIBW2_DDR_IN_3_LIMIT); - - writel(context_icn.hibw2_ddr_out_prio_reg, - context_icn.base + NODE_HIBW2_DDR_OUT_0_PRIORITY); - - /* ESRAM0 */ - writel(context_icn.esram_in_prio[0], - context_icn.base + NODE_ESRAM0_IN_0_PRIORITY); - writel(context_icn.esram_in_prio[1], - context_icn.base + NODE_ESRAM0_IN_1_PRIORITY); - writel(context_icn.esram_in_prio[2], - context_icn.base + NODE_ESRAM0_IN_2_PRIORITY); - - writel(context_icn.esram_in_lim[0], - context_icn.base + NODE_ESRAM0_IN_0_LIMIT); - writel(context_icn.esram_in_lim[1], - context_icn.base + NODE_ESRAM0_IN_1_LIMIT); - writel(context_icn.esram_in_lim[2], - context_icn.base + NODE_ESRAM0_IN_2_LIMIT); - - writel(context_icn.esram_out_prio_reg, - context_icn.base + NODE_ESRAM0_OUT_0_PRIORITY); - - /* ESRAM1-2 */ - writel(context_icn.esram12_in_prio[0], - context_icn.base + NODE_ESRAM1_2_IN_0_PRIORITY); - writel(context_icn.esram12_in_prio[1], - context_icn.base + NODE_ESRAM1_2_IN_1_PRIORITY); - writel(context_icn.esram12_in_prio[2], - context_icn.base + NODE_ESRAM1_2_IN_2_PRIORITY); - - writel(context_icn.esram12_in_arb_lim[0], - context_icn.base + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT); - writel(context_icn.esram12_in_arb_lim[1], - context_icn.base + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT); - writel(context_icn.esram12_in_arb_lim[2], - context_icn.base + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT); - - writel(context_icn.esram12_out_prio_reg, - context_icn.base + NODE_ESRAM1_2_OUT_0_PRIORITY); - - /* ESRAM3-4 */ - writel(context_icn.esram34_in_prio[0], - context_icn.base + NODE_ESRAM3_4_IN_0_PRIORITY); - writel(context_icn.esram34_in_prio[1], - context_icn.base + NODE_ESRAM3_4_IN_1_PRIORITY); - writel(context_icn.esram34_in_prio[2], - context_icn.base + NODE_ESRAM3_4_IN_2_PRIORITY); - - writel(context_icn.esram34_in_arb_lim[0], - context_icn.base + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT); - writel(context_icn.esram34_in_arb_lim[1], - context_icn.base + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT); - writel(context_icn.esram34_in_arb_lim[2], - context_icn.base + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT); - - writel(context_icn.esram34_out_prio, - context_icn.base + NODE_ESRAM3_4_OUT_0_PRIORITY); - -} - -void u5500_context_init(void) -{ - context_icn.base = ioremap(U5500_ICN_BASE, SZ_8K); -} diff --git a/arch/arm/mach-ux500/pm/context-db8500.c b/arch/arm/mach-ux500/pm/context-db8500.c deleted file mode 100644 index ad21163917d..00000000000 --- a/arch/arm/mach-ux500/pm/context-db8500.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Copyright (C) STMicroelectronics 2009 - * Copyright (C) ST-Ericsson SA 2010-2011 - * - * License Terms: GNU General Public License v2 - * Author: Sundar Iyer for ST-Ericsson - * - */ - -#include <linux/io.h> - -#include <mach/hardware.h> - -#include "context.h" - -/* - * ST-Interconnect context - */ - -/* priority, bw limiter register offsets */ -#define NODE_HIBW1_ESRAM_IN_0_PRIORITY 0x00 -#define NODE_HIBW1_ESRAM_IN_1_PRIORITY 0x04 -#define NODE_HIBW1_ESRAM_IN_2_PRIORITY 0x08 -#define NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT 0x24 -#define NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT 0x28 -#define NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT 0x2C -#define NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT 0x30 -#define NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT 0x34 -#define NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT 0x38 -#define NODE_HIBW1_ESRAM_IN_2_ARB_1_LIMIT 0x3C -#define NODE_HIBW1_ESRAM_IN_2_ARB_2_LIMIT 0x40 -#define NODE_HIBW1_ESRAM_IN_2_ARB_3_LIMIT 0x44 -#define NODE_HIBW1_DDR_IN_0_PRIORITY 0x400 -#define NODE_HIBW1_DDR_IN_1_PRIORITY 0x404 -#define NODE_HIBW1_DDR_IN_2_PRIORITY 0x408 -#define NODE_HIBW1_DDR_IN_0_LIMIT 0x424 -#define NODE_HIBW1_DDR_IN_1_LIMIT 0x428 -#define NODE_HIBW1_DDR_IN_2_LIMIT 0x42C -#define NODE_HIBW1_DDR_OUT_0_PRIORITY 0x430 -#define NODE_HIBW2_ESRAM_IN_0_PRIORITY 0x800 -#define NODE_HIBW2_ESRAM_IN_1_PRIORITY 0x804 -#define NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT 0x818 -#define NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT 0x81C -#define NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT 0x820 -#define NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT 0x824 -#define NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT 0x828 -#define NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT 0x82C -#define NODE_HIBW2_DDR_IN_0_PRIORITY 0xC00 -#define NODE_HIBW2_DDR_IN_1_PRIORITY 0xC04 -#define NODE_HIBW2_DDR_IN_2_PRIORITY 0xC08 - -#define NODE_HIBW2_DDR_IN_0_LIMIT 0xC24 -#define NODE_HIBW2_DDR_IN_1_LIMIT 0xC28 -#define NODE_HIBW2_DDR_IN_2_LIMIT 0xC2C -#define NODE_HIBW2_DDR_OUT_0_PRIORITY 0xC30 - -/* - * Note the following addresses are presented in - * db8500 design spec v3.1 and v3.3, table 10. - * But their addresses are not the same as in the - * description. The addresses in the description - * of each registers are correct. - * NODE_HIBW2_DDR_IN_3_LIMIT is only present in v1. - * - * Faulty registers addresses in table 10: - * NODE_HIBW2_DDR_IN_2_LIMIT 0xC38 - * NODE_HIBW2_DDR_IN_3_LIMIT 0xC3C - * NODE_HIBW2_DDR_OUT_0_PRIORITY 0xC40 - */ - -#define NODE_ESRAM0_IN_0_PRIORITY 0x1000 -#define NODE_ESRAM0_IN_1_PRIORITY 0x1004 -#define NODE_ESRAM0_IN_2_PRIORITY 0x1008 -#define NODE_ESRAM0_IN_3_PRIORITY 0x100C -#define NODE_ESRAM0_IN_0_LIMIT 0x1030 -#define NODE_ESRAM0_IN_1_LIMIT 0x1034 -#define NODE_ESRAM0_IN_2_LIMIT 0x1038 -#define NODE_ESRAM0_IN_3_LIMIT 0x103C -/* common */ -#define NODE_ESRAM1_2_IN_0_PRIORITY 0x1400 -#define NODE_ESRAM1_2_IN_1_PRIORITY 0x1404 -#define NODE_ESRAM1_2_IN_2_PRIORITY 0x1408 -#define NODE_ESRAM1_2_IN_3_PRIORITY 0x140C -#define NODE_ESRAM1_2_IN_0_ARB_1_LIMIT 0x1430 -#define NODE_ESRAM1_2_IN_0_ARB_2_LIMIT 0x1434 -#define NODE_ESRAM1_2_IN_1_ARB_1_LIMIT 0x1438 -#define NODE_ESRAM1_2_IN_1_ARB_2_LIMIT 0x143C -#define NODE_ESRAM1_2_IN_2_ARB_1_LIMIT 0x1440 -#define NODE_ESRAM1_2_IN_2_ARB_2_LIMIT 0x1444 -#define NODE_ESRAM1_2_IN_3_ARB_1_LIMIT 0x1448 -#define NODE_ESRAM1_2_IN_3_ARB_2_LIMIT 0x144C - -#define NODE_ESRAM3_4_IN_0_PRIORITY 0x1800 -#define NODE_ESRAM3_4_IN_1_PRIORITY 0x1804 -#define NODE_ESRAM3_4_IN_2_PRIORITY 0x1808 -#define NODE_ESRAM3_4_IN_3_PRIORITY 0x180C -#define NODE_ESRAM3_4_IN_0_ARB_1_LIMIT 0x1830 -#define NODE_ESRAM3_4_IN_0_ARB_2_LIMIT 0x1834 -#define NODE_ESRAM3_4_IN_1_ARB_1_LIMIT 0x1838 -#define NODE_ESRAM3_4_IN_1_ARB_2_LIMIT 0x183C -#define NODE_ESRAM3_4_IN_2_ARB_1_LIMIT 0x1840 -#define NODE_ESRAM3_4_IN_2_ARB_2_LIMIT 0x1844 -#define NODE_ESRAM3_4_IN_3_ARB_1_LIMIT 0x1848 -#define NODE_ESRAM3_4_IN_3_ARB_2_LIMIT 0x184C - -static struct { - void __iomem *base; - u32 hibw1_esram_in_pri[3]; - u32 hibw1_esram_in0_arb[3]; - u32 hibw1_esram_in1_arb[3]; - u32 hibw1_esram_in2_arb[3]; - u32 hibw1_ddr_in_prio[3]; - u32 hibw1_ddr_in_limit[3]; - u32 hibw1_ddr_out_prio; - - /* HiBw2 node registers */ - u32 hibw2_esram_in_pri[2]; - u32 hibw2_esram_in0_arblimit[3]; - u32 hibw2_esram_in1_arblimit[3]; - u32 hibw2_ddr_in_prio[4]; - u32 hibw2_ddr_in_limit[4]; - u32 hibw2_ddr_out_prio; - - /* ESRAM node registers */ - u32 esram_in_prio[4]; - u32 esram_in_lim[4]; - u32 esram0_in_prio[4]; - u32 esram0_in_lim[4]; - u32 esram12_in_prio[4]; - u32 esram12_in_arb_lim[8]; - u32 esram34_in_prio[4]; - u32 esram34_in_arb_lim[8]; -} context_icn; - -/** - * u8500_context_save_icn() - save ICN context - * - */ -void u8500_context_save_icn(void) -{ - void __iomem *b = context_icn.base; - - context_icn.hibw1_esram_in_pri[0] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_0_PRIORITY); - context_icn.hibw1_esram_in_pri[1] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_1_PRIORITY); - context_icn.hibw1_esram_in_pri[2] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_2_PRIORITY); - - context_icn.hibw1_esram_in0_arb[0] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT); - context_icn.hibw1_esram_in0_arb[1] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT); - context_icn.hibw1_esram_in0_arb[2] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT); - - context_icn.hibw1_esram_in1_arb[0] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT); - context_icn.hibw1_esram_in1_arb[1] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT); - context_icn.hibw1_esram_in1_arb[2] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT); - - context_icn.hibw1_esram_in2_arb[0] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_2_ARB_1_LIMIT); - context_icn.hibw1_esram_in2_arb[1] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_2_ARB_2_LIMIT); - context_icn.hibw1_esram_in2_arb[2] = - readl_relaxed(b + NODE_HIBW1_ESRAM_IN_2_ARB_3_LIMIT); - - context_icn.hibw1_ddr_in_prio[0] = - readl_relaxed(b + NODE_HIBW1_DDR_IN_0_PRIORITY); - context_icn.hibw1_ddr_in_prio[1] = - readl_relaxed(b + NODE_HIBW1_DDR_IN_1_PRIORITY); - context_icn.hibw1_ddr_in_prio[2] = - readl_relaxed(b + NODE_HIBW1_DDR_IN_2_PRIORITY); - - context_icn.hibw1_ddr_in_limit[0] = - readl_relaxed(b + NODE_HIBW1_DDR_IN_0_LIMIT); - context_icn.hibw1_ddr_in_limit[1] = - readl_relaxed(b + NODE_HIBW1_DDR_IN_1_LIMIT); - context_icn.hibw1_ddr_in_limit[2] = - readl_relaxed(b + NODE_HIBW1_DDR_IN_2_LIMIT); - - context_icn.hibw1_ddr_out_prio = - readl_relaxed(b + NODE_HIBW1_DDR_OUT_0_PRIORITY); - - context_icn.hibw2_esram_in_pri[0] = - readl_relaxed(b + NODE_HIBW2_ESRAM_IN_0_PRIORITY); - context_icn.hibw2_esram_in_pri[1] = - readl_relaxed(b + NODE_HIBW2_ESRAM_IN_1_PRIORITY); - - context_icn.hibw2_esram_in0_arblimit[0] = - readl_relaxed(b + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT); - context_icn.hibw2_esram_in0_arblimit[1] = - readl_relaxed(b + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT); - context_icn.hibw2_esram_in0_arblimit[2] = - readl_relaxed(b + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT); - - context_icn.hibw2_esram_in1_arblimit[0] = - readl_relaxed(b + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT); - context_icn.hibw2_esram_in1_arblimit[1] = - readl_relaxed(b + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT); - context_icn.hibw2_esram_in1_arblimit[2] = - readl_relaxed(b + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT); - - context_icn.hibw2_ddr_in_prio[0] = - readl_relaxed(b + NODE_HIBW2_DDR_IN_0_PRIORITY); - context_icn.hibw2_ddr_in_prio[1] = - readl_relaxed(b + NODE_HIBW2_DDR_IN_1_PRIORITY); - context_icn.hibw2_ddr_in_prio[2] = - readl_relaxed(b + NODE_HIBW2_DDR_IN_2_PRIORITY); - - context_icn.hibw2_ddr_in_limit[0] = - readl_relaxed(b + NODE_HIBW2_DDR_IN_0_LIMIT); - context_icn.hibw2_ddr_in_limit[1] = - readl_relaxed(b + NODE_HIBW2_DDR_IN_1_LIMIT); - - context_icn.hibw2_ddr_in_limit[2] = - readl_relaxed(b + NODE_HIBW2_DDR_IN_2_LIMIT); - - context_icn.hibw2_ddr_out_prio = - readl_relaxed(b + NODE_HIBW2_DDR_OUT_0_PRIORITY); - - context_icn.esram0_in_prio[0] = - readl_relaxed(b + NODE_ESRAM0_IN_0_PRIORITY); - context_icn.esram0_in_prio[1] = - readl_relaxed(b + NODE_ESRAM0_IN_1_PRIORITY); - context_icn.esram0_in_prio[2] = - readl_relaxed(b + NODE_ESRAM0_IN_2_PRIORITY); - context_icn.esram0_in_prio[3] = - readl_relaxed(b + NODE_ESRAM0_IN_3_PRIORITY); - - context_icn.esram0_in_lim[0] = - readl_relaxed(b + NODE_ESRAM0_IN_0_LIMIT); - context_icn.esram0_in_lim[1] = - readl_relaxed(b + NODE_ESRAM0_IN_1_LIMIT); - context_icn.esram0_in_lim[2] = - readl_relaxed(b + NODE_ESRAM0_IN_2_LIMIT); - context_icn.esram0_in_lim[3] = - readl_relaxed(b + NODE_ESRAM0_IN_3_LIMIT); - - context_icn.esram12_in_prio[0] = - readl_relaxed(b + NODE_ESRAM1_2_IN_0_PRIORITY); - context_icn.esram12_in_prio[1] = - readl_relaxed(b + NODE_ESRAM1_2_IN_1_PRIORITY); - context_icn.esram12_in_prio[2] = - readl_relaxed(b + NODE_ESRAM1_2_IN_2_PRIORITY); - context_icn.esram12_in_prio[3] = - readl_relaxed(b + NODE_ESRAM1_2_IN_3_PRIORITY); - - context_icn.esram12_in_arb_lim[0] = - readl_relaxed(b + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT); - context_icn.esram12_in_arb_lim[1] = - readl_relaxed(b + NODE_ESRAM1_2_IN_0_ARB_2_LIMIT); - context_icn.esram12_in_arb_lim[2] = - readl_relaxed(b + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT); - context_icn.esram12_in_arb_lim[3] = - readl_relaxed(b + NODE_ESRAM1_2_IN_1_ARB_2_LIMIT); - context_icn.esram12_in_arb_lim[4] = - readl_relaxed(b + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT); - context_icn.esram12_in_arb_lim[5] = - readl_relaxed(b + NODE_ESRAM1_2_IN_2_ARB_2_LIMIT); - context_icn.esram12_in_arb_lim[6] = - readl_relaxed(b + NODE_ESRAM1_2_IN_3_ARB_1_LIMIT); - context_icn.esram12_in_arb_lim[7] = - readl_relaxed(b + NODE_ESRAM1_2_IN_3_ARB_2_LIMIT); - - context_icn.esram34_in_prio[0] = - readl_relaxed(b + NODE_ESRAM3_4_IN_0_PRIORITY); - context_icn.esram34_in_prio[1] = - readl_relaxed(b + NODE_ESRAM3_4_IN_1_PRIORITY); - context_icn.esram34_in_prio[2] = - readl_relaxed(b + NODE_ESRAM3_4_IN_2_PRIORITY); - context_icn.esram34_in_prio[3] = - readl_relaxed(b + NODE_ESRAM3_4_IN_3_PRIORITY); - - context_icn.esram34_in_arb_lim[0] = - readl_relaxed(b + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT); - context_icn.esram34_in_arb_lim[1] = - readl_relaxed(b + NODE_ESRAM3_4_IN_0_ARB_2_LIMIT); - context_icn.esram34_in_arb_lim[2] = - readl_relaxed(b + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT); - context_icn.esram34_in_arb_lim[3] = - readl_relaxed(b + NODE_ESRAM3_4_IN_1_ARB_2_LIMIT); - context_icn.esram34_in_arb_lim[4] = - readl_relaxed(b + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT); - context_icn.esram34_in_arb_lim[5] = - readl_relaxed(b + NODE_ESRAM3_4_IN_2_ARB_2_LIMIT); - context_icn.esram34_in_arb_lim[6] = - readl_relaxed(b + NODE_ESRAM3_4_IN_3_ARB_1_LIMIT); - context_icn.esram34_in_arb_lim[7] = - readl_relaxed(b + NODE_ESRAM3_4_IN_3_ARB_2_LIMIT); -} - -/** - * u8500_context_restore_icn() - restore ICN context - * - */ -void u8500_context_restore_icn(void) -{ - void __iomem *b = context_icn.base; - - writel_relaxed(context_icn.hibw1_esram_in_pri[0], - b + NODE_HIBW1_ESRAM_IN_0_PRIORITY); - writel_relaxed(context_icn.hibw1_esram_in_pri[1], - b + NODE_HIBW1_ESRAM_IN_1_PRIORITY); - writel_relaxed(context_icn.hibw1_esram_in_pri[2], - b + NODE_HIBW1_ESRAM_IN_2_PRIORITY); - - writel_relaxed(context_icn.hibw1_esram_in0_arb[0], - b + NODE_HIBW1_ESRAM_IN_0_ARB_1_LIMIT); - writel_relaxed(context_icn.hibw1_esram_in0_arb[1], - b + NODE_HIBW1_ESRAM_IN_0_ARB_2_LIMIT); - writel_relaxed(context_icn.hibw1_esram_in0_arb[2], - b + NODE_HIBW1_ESRAM_IN_0_ARB_3_LIMIT); - - writel_relaxed(context_icn.hibw1_esram_in1_arb[0], - b + NODE_HIBW1_ESRAM_IN_1_ARB_1_LIMIT); - writel_relaxed(context_icn.hibw1_esram_in1_arb[1], - b + NODE_HIBW1_ESRAM_IN_1_ARB_2_LIMIT); - writel_relaxed(context_icn.hibw1_esram_in1_arb[2], - b + NODE_HIBW1_ESRAM_IN_1_ARB_3_LIMIT); - - writel_relaxed(context_icn.hibw1_esram_in2_arb[0], - b + NODE_HIBW1_ESRAM_IN_2_ARB_1_LIMIT); - writel_relaxed(context_icn.hibw1_esram_in2_arb[1], - b + NODE_HIBW1_ESRAM_IN_2_ARB_2_LIMIT); - writel_relaxed(context_icn.hibw1_esram_in2_arb[2], - b + NODE_HIBW1_ESRAM_IN_2_ARB_3_LIMIT); - - writel_relaxed(context_icn.hibw1_ddr_in_prio[0], - b + NODE_HIBW1_DDR_IN_0_PRIORITY); - writel_relaxed(context_icn.hibw1_ddr_in_prio[1], - b + NODE_HIBW1_DDR_IN_1_PRIORITY); - writel_relaxed(context_icn.hibw1_ddr_in_prio[2], - b + NODE_HIBW1_DDR_IN_2_PRIORITY); - - writel_relaxed(context_icn.hibw1_ddr_in_limit[0], - b + NODE_HIBW1_DDR_IN_0_LIMIT); - writel_relaxed(context_icn.hibw1_ddr_in_limit[1], - b + NODE_HIBW1_DDR_IN_1_LIMIT); - writel_relaxed(context_icn.hibw1_ddr_in_limit[2], - b + NODE_HIBW1_DDR_IN_2_LIMIT); - - writel_relaxed(context_icn.hibw1_ddr_out_prio, - b + NODE_HIBW1_DDR_OUT_0_PRIORITY); - - writel_relaxed(context_icn.hibw2_esram_in_pri[0], - b + NODE_HIBW2_ESRAM_IN_0_PRIORITY); - writel_relaxed(context_icn.hibw2_esram_in_pri[1], - b + NODE_HIBW2_ESRAM_IN_1_PRIORITY); - - writel_relaxed(context_icn.hibw2_esram_in0_arblimit[0], - b + NODE_HIBW2_ESRAM_IN_0_ARB_1_LIMIT); - writel_relaxed(context_icn.hibw2_esram_in0_arblimit[1], - b + NODE_HIBW2_ESRAM_IN_0_ARB_2_LIMIT); - writel_relaxed(context_icn.hibw2_esram_in0_arblimit[2], - b + NODE_HIBW2_ESRAM_IN_0_ARB_3_LIMIT); - - writel_relaxed(context_icn.hibw2_esram_in1_arblimit[0], - b + NODE_HIBW2_ESRAM_IN_1_ARB_1_LIMIT); - writel_relaxed(context_icn.hibw2_esram_in1_arblimit[1], - b + NODE_HIBW2_ESRAM_IN_1_ARB_2_LIMIT); - writel_relaxed(context_icn.hibw2_esram_in1_arblimit[2], - b + NODE_HIBW2_ESRAM_IN_1_ARB_3_LIMIT); - - writel_relaxed(context_icn.hibw2_ddr_in_prio[0], - b + NODE_HIBW2_DDR_IN_0_PRIORITY); - writel_relaxed(context_icn.hibw2_ddr_in_prio[1], - b + NODE_HIBW2_DDR_IN_1_PRIORITY); - writel_relaxed(context_icn.hibw2_ddr_in_prio[2], - b + NODE_HIBW2_DDR_IN_2_PRIORITY); - writel_relaxed(context_icn.hibw2_ddr_in_limit[0], - b + NODE_HIBW2_DDR_IN_0_LIMIT); - writel_relaxed(context_icn.hibw2_ddr_in_limit[1], - b + NODE_HIBW2_DDR_IN_1_LIMIT); - writel_relaxed(context_icn.hibw2_ddr_in_limit[2], - b + NODE_HIBW2_DDR_IN_2_LIMIT); - writel_relaxed(context_icn.hibw2_ddr_out_prio, - b + NODE_HIBW2_DDR_OUT_0_PRIORITY); - - writel_relaxed(context_icn.esram0_in_prio[0], - b + NODE_ESRAM0_IN_0_PRIORITY); - writel_relaxed(context_icn.esram0_in_prio[1], - b + NODE_ESRAM0_IN_1_PRIORITY); - writel_relaxed(context_icn.esram0_in_prio[2], - b + NODE_ESRAM0_IN_2_PRIORITY); - writel_relaxed(context_icn.esram0_in_prio[3], - b + NODE_ESRAM0_IN_3_PRIORITY); - - writel_relaxed(context_icn.esram0_in_lim[0], - b + NODE_ESRAM0_IN_0_LIMIT); - writel_relaxed(context_icn.esram0_in_lim[1], - b + NODE_ESRAM0_IN_1_LIMIT); - writel_relaxed(context_icn.esram0_in_lim[2], - b + NODE_ESRAM0_IN_2_LIMIT); - writel_relaxed(context_icn.esram0_in_lim[3], - b + NODE_ESRAM0_IN_3_LIMIT); - - writel_relaxed(context_icn.esram12_in_prio[0], - b + NODE_ESRAM1_2_IN_0_PRIORITY); - writel_relaxed(context_icn.esram12_in_prio[1], - b + NODE_ESRAM1_2_IN_1_PRIORITY); - writel_relaxed(context_icn.esram12_in_prio[2], - b + NODE_ESRAM1_2_IN_2_PRIORITY); - writel_relaxed(context_icn.esram12_in_prio[3], - b + NODE_ESRAM1_2_IN_3_PRIORITY); - - writel_relaxed(context_icn.esram12_in_arb_lim[0], - b + NODE_ESRAM1_2_IN_0_ARB_1_LIMIT); - writel_relaxed(context_icn.esram12_in_arb_lim[1], - b + NODE_ESRAM1_2_IN_0_ARB_2_LIMIT); - writel_relaxed(context_icn.esram12_in_arb_lim[2], - b + NODE_ESRAM1_2_IN_1_ARB_1_LIMIT); - writel_relaxed(context_icn.esram12_in_arb_lim[3], - b + NODE_ESRAM1_2_IN_1_ARB_2_LIMIT); - writel_relaxed(context_icn.esram12_in_arb_lim[4], - b + NODE_ESRAM1_2_IN_2_ARB_1_LIMIT); - writel_relaxed(context_icn.esram12_in_arb_lim[5], - b + NODE_ESRAM1_2_IN_2_ARB_2_LIMIT); - writel_relaxed(context_icn.esram12_in_arb_lim[6], - b + NODE_ESRAM1_2_IN_3_ARB_1_LIMIT); - writel_relaxed(context_icn.esram12_in_arb_lim[7], - b + NODE_ESRAM1_2_IN_3_ARB_2_LIMIT); - - writel_relaxed(context_icn.esram34_in_prio[0], - b + NODE_ESRAM3_4_IN_0_PRIORITY); - writel_relaxed(context_icn.esram34_in_prio[1], - b + NODE_ESRAM3_4_IN_1_PRIORITY); - writel_relaxed(context_icn.esram34_in_prio[2], - b + NODE_ESRAM3_4_IN_2_PRIORITY); - writel_relaxed(context_icn.esram34_in_prio[3], - b + NODE_ESRAM3_4_IN_3_PRIORITY); - - writel_relaxed(context_icn.esram34_in_arb_lim[0], - b + NODE_ESRAM3_4_IN_0_ARB_1_LIMIT); - writel_relaxed(context_icn.esram34_in_arb_lim[1], - b + NODE_ESRAM3_4_IN_0_ARB_2_LIMIT); - writel_relaxed(context_icn.esram34_in_arb_lim[2], - b + NODE_ESRAM3_4_IN_1_ARB_1_LIMIT); - writel_relaxed(context_icn.esram34_in_arb_lim[3], - b + NODE_ESRAM3_4_IN_1_ARB_2_LIMIT); - writel_relaxed(context_icn.esram34_in_arb_lim[4], - b + NODE_ESRAM3_4_IN_2_ARB_1_LIMIT); - writel_relaxed(context_icn.esram34_in_arb_lim[5], - b + NODE_ESRAM3_4_IN_2_ARB_2_LIMIT); - writel_relaxed(context_icn.esram34_in_arb_lim[6], - b + NODE_ESRAM3_4_IN_3_ARB_1_LIMIT); - writel_relaxed(context_icn.esram34_in_arb_lim[7], - b + NODE_ESRAM3_4_IN_3_ARB_2_LIMIT); -} - -void u8500_context_init(void) -{ - context_icn.base = ioremap(U8500_ICN_BASE, SZ_8K); -} diff --git a/arch/arm/mach-ux500/pm/context.c b/arch/arm/mach-ux500/pm/context.c deleted file mode 100644 index 7e4687eb6f4..00000000000 --- a/arch/arm/mach-ux500/pm/context.c +++ /dev/null @@ -1,986 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010-2011 - * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>, - * Rickard Andersson <rickard.andersson@stericsson.com>, - * Jonas Aaberg <jonas.aberg@stericsson.com>, - * Sundar Iyer for ST-Ericsson. - * License terms: GNU General Public License (GPL) version 2 - * - */ - -#include <linux/init.h> -#include <linux/io.h> -#include <linux/smp.h> -#include <linux/percpu.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/device.h> -#include <linux/notifier.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/gpio/nomadik.h> -#include <asm/hardware/gic.h> - -#include <mach/hardware.h> -#include <mach/irqs.h> -#include <mach/scu.h> - -#include "context.h" -#include "pm.h" -#include "../product.h" - -#define GPIO_NUM_BANKS 9 -#define GPIO_NUM_SAVE_REGISTERS 7 - -/* - * TODO: - * - Use the "UX500*"-macros instead where possible - */ - -#define U8500_BACKUPRAM_SIZE SZ_64K - -#define U8500_PUBLIC_BOOT_ROM_BASE (U8500_BOOT_ROM_BASE + 0x17000) -#define U5500_PUBLIC_BOOT_ROM_BASE (U5500_BOOT_ROM_BASE + 0x18000) - -/* - * Special dedicated addresses in backup RAM. The 5500 addresses are identical - * to the 8500 ones. - */ -#define U8500_EXT_RAM_LOC_BACKUPRAM_ADDR 0x80151FDC -#define U8500_CPU0_CP15_CR_BACKUPRAM_ADDR 0x80151F80 -#define U8500_CPU1_CP15_CR_BACKUPRAM_ADDR 0x80151FA0 - -#define U8500_CPU0_BACKUPRAM_ADDR_PUBLIC_BOOT_ROM_LOG_ADDR 0x80151FD8 -#define U8500_CPU1_BACKUPRAM_ADDR_PUBLIC_BOOT_ROM_LOG_ADDR 0x80151FE0 - -#define GIC_DIST_ENABLE_NS 0x0 - -/* 32 interrupts fits in 4 bytes */ -#define GIC_DIST_ENABLE_SET_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - \ - IRQ_SHPI_START) / 32) -#define GIC_DIST_ENABLE_SET_CPU_NUM (IRQ_SHPI_START / 32) -#define GIC_DIST_ENABLE_SET_SPI0 GIC_DIST_ENABLE_SET -#define GIC_DIST_ENABLE_SET_SPI32 (GIC_DIST_ENABLE_SET + IRQ_SHPI_START / 8) - -#define GIC_DIST_ENABLE_CLEAR_0 GIC_DIST_ENABLE_CLEAR -#define GIC_DIST_ENABLE_CLEAR_32 (GIC_DIST_ENABLE_CLEAR + 4) -#define GIC_DIST_ENABLE_CLEAR_64 (GIC_DIST_ENABLE_CLEAR + 8) -#define GIC_DIST_ENABLE_CLEAR_96 (GIC_DIST_ENABLE_CLEAR + 12) -#define GIC_DIST_ENABLE_CLEAR_128 (GIC_DIST_ENABLE_CLEAR + 16) - -#define GIC_DIST_PRI_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - IRQ_SHPI_START) / 4) -#define GIC_DIST_PRI_CPU_NUM (IRQ_SHPI_START / 4) -#define GIC_DIST_PRI_SPI0 GIC_DIST_PRI -#define GIC_DIST_PRI_SPI32 (GIC_DIST_PRI + IRQ_SHPI_START) - -#define GIC_DIST_SPI_TARGET_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - \ - IRQ_SHPI_START) / 4) -#define GIC_DIST_SPI_TARGET_CPU_NUM (IRQ_SHPI_START / 4) -#define GIC_DIST_SPI_TARGET_SPI0 GIC_DIST_TARGET -#define GIC_DIST_SPI_TARGET_SPI32 (GIC_DIST_TARGET + IRQ_SHPI_START) - -/* 16 interrupts per 4 bytes */ -#define GIC_DIST_CONFIG_COMMON_NUM ((DBX500_NR_INTERNAL_IRQS - IRQ_SHPI_START) \ - / 16) -#define GIC_DIST_CONFIG_CPU_NUM (IRQ_SHPI_START / 16) -#define GIC_DIST_CONFIG_SPI0 GIC_DIST_CONFIG -#define GIC_DIST_CONFIG_SPI32 (GIC_DIST_CONFIG + IRQ_SHPI_START / 4) - -/* TODO! Move STM reg offsets to suitable place */ -#define STM_CR_OFFSET 0x00 -#define STM_MMC_OFFSET 0x08 -#define STM_TER_OFFSET 0x10 - -#define U5500_PRCMU_DBG_PWRCTRL (U5500_PRCMU_BASE + 0x4AC) -#define PRCMU_DBG_PWRCTRL_A9DBGCLKEN (1 << 4) - -#define TPIU_PORT_SIZE 0x4 -#define TPIU_TRIGGER_COUNTER 0x104 -#define TPIU_TRIGGER_MULTIPLIER 0x108 -#define TPIU_CURRENT_TEST_PATTERN 0x204 -#define TPIU_TEST_PATTERN_REPEAT 0x208 -#define TPIU_FORMATTER 0x304 -#define TPIU_FORMATTER_SYNC 0x308 -#define TPIU_LOCK_ACCESS_REGISTER 0xFB0 - -#define TPIU_UNLOCK_CODE 0xc5acce55 - -#define SCU_FILTER_STARTADDR 0x40 -#define SCU_FILTER_ENDADDR 0x44 -#define SCU_ACCESS_CTRL_SAC 0x50 - -/* - * Periph clock cluster context - */ -#define PRCC_BCK_EN 0x00 -#define PRCC_KCK_EN 0x08 -#define PRCC_BCK_STATUS 0x10 -#define PRCC_KCK_STATUS 0x14 - -/* The context of the Trace Port Interface Unit (TPIU) */ -static struct { - void __iomem *base; - u32 port_size; - u32 trigger_counter; - u32 trigger_multiplier; - u32 current_test_pattern; - u32 test_pattern_repeat; - u32 formatter; - u32 formatter_sync; -} context_tpiu; - -static struct { - void __iomem *base; - u32 cr; - u32 mmc; - u32 ter; -} context_stm_ape; - -struct context_gic_cpu { - void __iomem *base; - u32 ctrl; - u32 primask; - u32 binpoint; -}; -static DEFINE_PER_CPU(struct context_gic_cpu, context_gic_cpu); - -static struct { - void __iomem *base; - u32 ns; - u32 enable_set[GIC_DIST_ENABLE_SET_COMMON_NUM]; /* IRQ 32 to 160 */ - u32 priority_level[GIC_DIST_PRI_COMMON_NUM]; - u32 spi_target[GIC_DIST_SPI_TARGET_COMMON_NUM]; - u32 config[GIC_DIST_CONFIG_COMMON_NUM]; -} context_gic_dist_common; - -struct context_gic_dist_cpu { - void __iomem *base; - u32 enable_set[GIC_DIST_ENABLE_SET_CPU_NUM]; /* IRQ 0 to 31 */ - u32 priority_level[GIC_DIST_PRI_CPU_NUM]; - u32 spi_target[GIC_DIST_SPI_TARGET_CPU_NUM]; - u32 config[GIC_DIST_CONFIG_CPU_NUM]; -}; -static DEFINE_PER_CPU(struct context_gic_dist_cpu, context_gic_dist_cpu); - -static struct { - void __iomem *base; - u32 ctrl; - u32 cpu_pwrstatus; - u32 inv_all_nonsecure; - u32 filter_start_addr; - u32 filter_end_addr; - u32 access_ctrl_sac; -} context_scu; - -#define UX500_NR_PRCC_BANKS 5 -static struct { - void __iomem *base; - struct clk *clk; - u32 bus_clk; - u32 kern_clk; -} context_prcc[UX500_NR_PRCC_BANKS]; - -static u32 backup_sram_storage[NR_CPUS] = { - IO_ADDRESS(U8500_CPU0_CP15_CR_BACKUPRAM_ADDR), - IO_ADDRESS(U8500_CPU1_CP15_CR_BACKUPRAM_ADDR), -}; - -static u32 gpio_bankaddr[GPIO_NUM_BANKS] = {IO_ADDRESS(U8500_GPIOBANK0_BASE), - IO_ADDRESS(U8500_GPIOBANK1_BASE), - IO_ADDRESS(U8500_GPIOBANK2_BASE), - IO_ADDRESS(U8500_GPIOBANK3_BASE), - IO_ADDRESS(U8500_GPIOBANK4_BASE), - IO_ADDRESS(U8500_GPIOBANK5_BASE), - IO_ADDRESS(U8500_GPIOBANK6_BASE), - IO_ADDRESS(U8500_GPIOBANK7_BASE), - IO_ADDRESS(U8500_GPIOBANK8_BASE) -}; - -static u32 gpio_save[GPIO_NUM_BANKS][GPIO_NUM_SAVE_REGISTERS]; - -/* - * Stacks and stack pointers - */ -static DEFINE_PER_CPU(u32[128], varm_registers_backup_stack); -static DEFINE_PER_CPU(u32 *, varm_registers_pointer); - -static DEFINE_PER_CPU(u32[128], varm_cp15_backup_stack); -static DEFINE_PER_CPU(u32 *, varm_cp15_pointer); - - -static ATOMIC_NOTIFIER_HEAD(context_ape_notifier_list); -static ATOMIC_NOTIFIER_HEAD(context_arm_notifier_list); - -/* - * Register a simple callback for handling vape context save/restore - */ -int context_ape_notifier_register(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&context_ape_notifier_list, nb); -} -EXPORT_SYMBOL(context_ape_notifier_register); - -/* - * Remove a previously registered callback - */ -int context_ape_notifier_unregister(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&context_ape_notifier_list, - nb); -} -EXPORT_SYMBOL(context_ape_notifier_unregister); - -/* - * Register a simple callback for handling varm context save/restore - */ -int context_arm_notifier_register(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&context_arm_notifier_list, nb); -} -EXPORT_SYMBOL(context_arm_notifier_register); - -/* - * Remove a previously registered callback - */ -int context_arm_notifier_unregister(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&context_arm_notifier_list, - nb); -} -EXPORT_SYMBOL(context_arm_notifier_unregister); - -static void save_prcc(void) -{ - int i; - - for (i = 0; i < UX500_NR_PRCC_BANKS; i++) { - clk_enable(context_prcc[i].clk); - - context_prcc[i].bus_clk = - readl(context_prcc[i].base + PRCC_BCK_STATUS); - context_prcc[i].kern_clk = - readl(context_prcc[i].base + PRCC_KCK_STATUS); - - clk_disable(context_prcc[i].clk); - } -} - -static void restore_prcc(void) -{ - int i; - - for (i = 0; i < UX500_NR_PRCC_BANKS; i++) { - clk_enable(context_prcc[i].clk); - - writel(context_prcc[i].bus_clk, - context_prcc[i].base + PRCC_BCK_EN); - writel(context_prcc[i].kern_clk, - context_prcc[i].base + PRCC_KCK_EN); - - clk_disable(context_prcc[i].clk); - } -} - -static void save_stm_ape(void) -{ - /* - * TODO: Check with PRCMU developers how STM is handled by PRCMU - * firmware. According to DB5500 design spec there is a "flush" - * mechanism supposed to be used by the PRCMU before power down, - * PRCMU fw might save/restore the following three registers - * at the same time. - */ - context_stm_ape.cr = readl(context_stm_ape.base + - STM_CR_OFFSET); - context_stm_ape.mmc = readl(context_stm_ape.base + - STM_MMC_OFFSET); - context_stm_ape.ter = readl(context_stm_ape.base + - STM_TER_OFFSET); -} - -static void restore_stm_ape(void) -{ - writel(context_stm_ape.ter, - context_stm_ape.base + STM_TER_OFFSET); - writel(context_stm_ape.mmc, - context_stm_ape.base + STM_MMC_OFFSET); - writel(context_stm_ape.cr, - context_stm_ape.base + STM_CR_OFFSET); -} - -static bool tpiu_clocked(void) -{ -#ifdef CONFIG_UX500_DEBUG_NO_LAUTERBACH - return false; -#else - if (cpu_is_u5500()) - return readl_relaxed(__io_address(U5500_PRCMU_DBG_PWRCTRL)) - & PRCMU_DBG_PWRCTRL_A9DBGCLKEN; - - if (cpu_is_u8500()) - return ux500_jtag_enabled(); - - return true; -#endif -} - -/* - * Save the context of the Trace Port Interface Unit (TPIU). - * Saving/restoring is needed for the PTM tracing to work together - * with the sleep states ApSleep and ApDeepSleep. - */ -static void save_tpiu(void) -{ - if (!tpiu_clocked()) - return; - - context_tpiu.port_size = readl(context_tpiu.base + - TPIU_PORT_SIZE); - context_tpiu.trigger_counter = readl(context_tpiu.base + - TPIU_TRIGGER_COUNTER); - context_tpiu.trigger_multiplier = readl(context_tpiu.base + - TPIU_TRIGGER_MULTIPLIER); - context_tpiu.current_test_pattern = readl(context_tpiu.base + - TPIU_CURRENT_TEST_PATTERN); - context_tpiu.test_pattern_repeat = readl(context_tpiu.base + - TPIU_TEST_PATTERN_REPEAT); - context_tpiu.formatter = readl(context_tpiu.base + - TPIU_FORMATTER); - context_tpiu.formatter_sync = readl(context_tpiu.base + - TPIU_FORMATTER_SYNC); -} - -/* - * Restore the context of the Trace Port Interface Unit (TPIU). - * Saving/restoring is needed for the PTM tracing to work together - * with the sleep states ApSleep and ApDeepSleep. - */ -static void restore_tpiu(void) -{ - if (!tpiu_clocked()) - return; - - writel(TPIU_UNLOCK_CODE, - context_tpiu.base + TPIU_LOCK_ACCESS_REGISTER); - - writel(context_tpiu.port_size, - context_tpiu.base + TPIU_PORT_SIZE); - writel(context_tpiu.trigger_counter, - context_tpiu.base + TPIU_TRIGGER_COUNTER); - writel(context_tpiu.trigger_multiplier, - context_tpiu.base + TPIU_TRIGGER_MULTIPLIER); - writel(context_tpiu.current_test_pattern, - context_tpiu.base + TPIU_CURRENT_TEST_PATTERN); - writel(context_tpiu.test_pattern_repeat, - context_tpiu.base + TPIU_TEST_PATTERN_REPEAT); - writel(context_tpiu.formatter, - context_tpiu.base + TPIU_FORMATTER); - writel(context_tpiu.formatter_sync, - context_tpiu.base + TPIU_FORMATTER_SYNC); -} - -/* - * Save GIC CPU IF registers - * - * This is per cpu so it needs to be called for each one. - */ - -static void save_gic_if_cpu(struct context_gic_cpu *c_gic_cpu) -{ - c_gic_cpu->ctrl = readl_relaxed(c_gic_cpu->base + GIC_CPU_CTRL); - c_gic_cpu->primask = readl_relaxed(c_gic_cpu->base + GIC_CPU_PRIMASK); - c_gic_cpu->binpoint = readl_relaxed(c_gic_cpu->base + GIC_CPU_BINPOINT); -} - -/* - * Restore GIC CPU IF registers - * - * This is per cpu so it needs to be called for each one. - */ -static void restore_gic_if_cpu(struct context_gic_cpu *c_gic_cpu) -{ - writel_relaxed(c_gic_cpu->ctrl, c_gic_cpu->base + GIC_CPU_CTRL); - writel_relaxed(c_gic_cpu->primask, c_gic_cpu->base + GIC_CPU_PRIMASK); - writel_relaxed(c_gic_cpu->binpoint, c_gic_cpu->base + GIC_CPU_BINPOINT); -} - -/* - * Save GIC Distributor Common registers - * - * This context is common. Only one CPU needs to call. - * - * Save SPI (Shared Peripheral Interrupt) settings, IRQ 32-159. - */ - -static void save_gic_dist_common(void) -{ - int i; - - context_gic_dist_common.ns = readl_relaxed(context_gic_dist_common.base - + GIC_DIST_ENABLE_NS); - - for (i = 0; i < GIC_DIST_ENABLE_SET_COMMON_NUM; i++) - context_gic_dist_common.enable_set[i] = - readl_relaxed(context_gic_dist_common.base + - GIC_DIST_ENABLE_SET_SPI32 + i * 4); - - for (i = 0; i < GIC_DIST_PRI_COMMON_NUM; i++) - context_gic_dist_common.priority_level[i] = - readl_relaxed(context_gic_dist_common.base + - GIC_DIST_PRI_SPI32 + i * 4); - - for (i = 0; i < GIC_DIST_SPI_TARGET_COMMON_NUM; i++) - context_gic_dist_common.spi_target[i] = - readl_relaxed(context_gic_dist_common.base + - GIC_DIST_SPI_TARGET_SPI32 + i * 4); - - for (i = 0; i < GIC_DIST_CONFIG_COMMON_NUM; i++) - context_gic_dist_common.config[i] = - readl_relaxed(context_gic_dist_common.base + - GIC_DIST_CONFIG_SPI32 + i * 4); -} - -/* - * Restore GIC Distributor Common registers - * - * This context is common. Only one CPU needs to call. - * - * Save SPI (Shared Peripheral Interrupt) settings, IRQ 32-159. - */ -static void restore_gic_dist_common(void) -{ - - int i; - - for (i = 0; i < GIC_DIST_CONFIG_COMMON_NUM; i++) - writel_relaxed(context_gic_dist_common.config[i], - context_gic_dist_common.base + - GIC_DIST_CONFIG_SPI32 + i * 4); - - for (i = 0; i < GIC_DIST_SPI_TARGET_COMMON_NUM; i++) - writel_relaxed(context_gic_dist_common.spi_target[i], - context_gic_dist_common.base + - GIC_DIST_SPI_TARGET_SPI32 + i * 4); - - for (i = 0; i < GIC_DIST_PRI_COMMON_NUM; i++) - writel_relaxed(context_gic_dist_common.priority_level[i], - context_gic_dist_common.base + - GIC_DIST_PRI_SPI32 + i * 4); - - for (i = 0; i < GIC_DIST_ENABLE_SET_COMMON_NUM; i++) - writel_relaxed(context_gic_dist_common.enable_set[i], - context_gic_dist_common.base + - GIC_DIST_ENABLE_SET_SPI32 + i * 4); - - writel_relaxed(context_gic_dist_common.ns, - context_gic_dist_common.base + GIC_DIST_ENABLE_NS); -} - - - -/* - * Save GIC Dist CPU registers - * - * This needs to be called by all cpu:s which will not call - * save_gic_dist_common(). Only the registers of the GIC which are - * banked will be saved. - */ -static void save_gic_dist_cpu(struct context_gic_dist_cpu *c_gic) -{ - int i; - - for (i = 0; i < GIC_DIST_ENABLE_SET_CPU_NUM; i++) - c_gic->enable_set[i] = - readl_relaxed(c_gic->base + - GIC_DIST_ENABLE_SET_SPI0 + i * 4); - - for (i = 0; i < GIC_DIST_PRI_CPU_NUM; i++) - c_gic->priority_level[i] = - readl_relaxed(c_gic->base + - GIC_DIST_PRI_SPI0 + i * 4); - - for (i = 0; i < GIC_DIST_SPI_TARGET_CPU_NUM; i++) - c_gic->spi_target[i] = - readl_relaxed(c_gic->base + - GIC_DIST_SPI_TARGET_SPI0 + i * 4); - - for (i = 0; i < GIC_DIST_CONFIG_CPU_NUM; i++) - c_gic->config[i] = - readl_relaxed(c_gic->base + - GIC_DIST_CONFIG_SPI0 + i * 4); -} - -/* - * Restore GIC Dist CPU registers - * - * This needs to be called by all cpu:s which will not call - * restore_gic_dist_common(). Only the registers of the GIC which are - * banked will be saved. - */ -static void restore_gic_dist_cpu(struct context_gic_dist_cpu *c_gic) -{ - - int i; - - for (i = 0; i < GIC_DIST_CONFIG_CPU_NUM; i++) - writel_relaxed(c_gic->config[i], - c_gic->base + - GIC_DIST_CONFIG_SPI0 + i * 4); - - for (i = 0; i < GIC_DIST_SPI_TARGET_CPU_NUM; i++) - writel_relaxed(c_gic->spi_target[i], - c_gic->base + - GIC_DIST_SPI_TARGET_SPI0 + i * 4); - - for (i = 0; i < GIC_DIST_PRI_CPU_NUM; i++) - writel_relaxed(c_gic->priority_level[i], - c_gic->base + - GIC_DIST_PRI_SPI0 + i * 4); - - for (i = 0; i < GIC_DIST_ENABLE_SET_CPU_NUM; i++) - writel_relaxed(c_gic->enable_set[i], - c_gic->base + - GIC_DIST_ENABLE_SET_SPI0 + i * 4); -} - -/* - * Disable interrupts that are not necessary - * to have turned on during ApDeepSleep. - */ -void context_gic_dist_disable_unneeded_irqs(void) -{ - - writel(0xffffffff, - context_gic_dist_common.base + - GIC_DIST_ENABLE_CLEAR_0); - - writel(0xffffffff, - context_gic_dist_common.base + - GIC_DIST_ENABLE_CLEAR_32); - - /* Leave PRCMU IRQ 0 and 1 enabled */ - writel(0xffff3fff, - context_gic_dist_common.base + - GIC_DIST_ENABLE_CLEAR_64); - - writel(0xffffffff, - context_gic_dist_common.base + - GIC_DIST_ENABLE_CLEAR_96); - - writel(0xffffffff, - context_gic_dist_common.base + - GIC_DIST_ENABLE_CLEAR_128); - -} - -static void save_scu(void) -{ - context_scu.ctrl = - readl_relaxed(context_scu.base + SCU_CTRL); - context_scu.cpu_pwrstatus = - readl_relaxed(context_scu.base + SCU_CPU_STATUS); - context_scu.inv_all_nonsecure = - readl_relaxed(context_scu.base + SCU_INVALIDATE); - context_scu.filter_start_addr = - readl_relaxed(context_scu.base + SCU_FILTER_STARTADDR); - context_scu.filter_end_addr = - readl_relaxed(context_scu.base + SCU_FILTER_ENDADDR); - context_scu.access_ctrl_sac = - readl_relaxed(context_scu.base + SCU_ACCESS_CTRL_SAC); -} - -static void restore_scu(void) -{ - writel_relaxed(context_scu.ctrl, - context_scu.base + SCU_CTRL); - writel_relaxed(context_scu.cpu_pwrstatus, - context_scu.base + SCU_CPU_STATUS); - writel_relaxed(context_scu.inv_all_nonsecure, - context_scu.base + SCU_INVALIDATE); - writel_relaxed(context_scu.filter_start_addr, - context_scu.base + SCU_FILTER_STARTADDR); - writel_relaxed(context_scu.filter_end_addr, - context_scu.base + SCU_FILTER_ENDADDR); - writel_relaxed(context_scu.access_ctrl_sac, - context_scu.base + SCU_ACCESS_CTRL_SAC); -} - -/* - * Save VAPE context - */ -void context_vape_save(void) -{ - atomic_notifier_call_chain(&context_ape_notifier_list, - CONTEXT_APE_SAVE, NULL); - - if (cpu_is_u5500()) - u5500_context_save_icn(); - if (cpu_is_u8500()) - u8500_context_save_icn(); - - save_stm_ape(); - - save_tpiu(); - - save_prcc(); - -} - -/* - * Restore VAPE context - */ -void context_vape_restore(void) -{ - restore_prcc(); - - restore_tpiu(); - - restore_stm_ape(); - - if (cpu_is_u5500()) - u5500_context_restore_icn(); - if (cpu_is_u8500()) - u8500_context_restore_icn(); - - atomic_notifier_call_chain(&context_ape_notifier_list, - CONTEXT_APE_RESTORE, NULL); -} - -/* - * Save GPIO registers that might be modified - * for power save reasons. - */ -void context_gpio_save(void) -{ - int i; - - for (i = 0; i < GPIO_NUM_BANKS; i++) { - gpio_save[i][0] = readl(gpio_bankaddr[i] + NMK_GPIO_AFSLA); - gpio_save[i][1] = readl(gpio_bankaddr[i] + NMK_GPIO_AFSLB); - gpio_save[i][2] = readl(gpio_bankaddr[i] + NMK_GPIO_PDIS); - gpio_save[i][3] = readl(gpio_bankaddr[i] + NMK_GPIO_DIR); - gpio_save[i][4] = readl(gpio_bankaddr[i] + NMK_GPIO_DAT); - gpio_save[i][6] = readl(gpio_bankaddr[i] + NMK_GPIO_SLPC); - } -} - -/* - * Restore GPIO registers that might be modified - * for power save reasons. - */ -void context_gpio_restore(void) -{ - int i; - u32 output_state; - u32 pull_up; - u32 pull_down; - u32 pull; - - for (i = 0; i < GPIO_NUM_BANKS; i++) { - writel(gpio_save[i][2], gpio_bankaddr[i] + NMK_GPIO_PDIS); - - writel(gpio_save[i][3], gpio_bankaddr[i] + NMK_GPIO_DIR); - - /* Set the high outputs. outpute_state = GPIO_DIR & GPIO_DAT */ - output_state = gpio_save[i][3] & gpio_save[i][4]; - writel(output_state, gpio_bankaddr[i] + NMK_GPIO_DATS); - - /* - * Set the low outputs. - * outpute_state = ~(GPIO_DIR & GPIO_DAT) & GPIO_DIR - */ - output_state = ~(gpio_save[i][3] & gpio_save[i][4]) & - gpio_save[i][3]; - writel(output_state, gpio_bankaddr[i] + NMK_GPIO_DATC); - - /* - * Restore pull up/down. - * Only write pull up/down settings on inputs where - * PDIS is not set. - * pull = (~GPIO_DIR & ~GPIO_PDIS) - */ - pull = (~gpio_save[i][3] & ~gpio_save[i][2]); - nmk_gpio_read_pull(i, &pull_up); - - pull_down = pull & ~pull_up; - pull_up = pull & pull_up; - /* Set pull ups */ - writel(pull_up, gpio_bankaddr[i] + NMK_GPIO_DATS); - /* Set pull downs */ - writel(pull_down, gpio_bankaddr[i] + NMK_GPIO_DATC); - - writel(gpio_save[i][6], gpio_bankaddr[i] + NMK_GPIO_SLPC); - - } - -} - -/* - * Restore GPIO mux registers that might be modified - * for power save reasons. - */ -void context_gpio_restore_mux(void) -{ - int i; - - /* Change mux settings */ - for (i = 0; i < GPIO_NUM_BANKS; i++) { - writel(gpio_save[i][0], gpio_bankaddr[i] + NMK_GPIO_AFSLA); - writel(gpio_save[i][1], gpio_bankaddr[i] + NMK_GPIO_AFSLB); - } -} - -/* - * Safe sequence used to switch IOs between GPIO and Alternate-C mode: - * - Save SLPM registers (Not done.) - * - Set SLPM=0 for the IOs you want to switch. (We assume that all - * SLPM registers already are 0 except for the ones that wants to - * have the mux connected in sleep (e.g modem STM)). - * - Configure the GPIO registers for the IOs that are being switched - * - Set IOFORCE=1 - * - Modify the AFLSA/B registers for the IOs that are being switched - * - Set IOFORCE=0 - * - Restore SLPM registers (Not done.) - * - Any spurious wake up event during switch sequence to be ignored - * and cleared - */ -void context_gpio_mux_safe_switch(bool begin) -{ - int i; - - static u32 rwimsc[GPIO_NUM_BANKS]; - static u32 fwimsc[GPIO_NUM_BANKS]; - - if (begin) { - for (i = 0; i < GPIO_NUM_BANKS; i++) { - /* Save registers */ - rwimsc[i] = readl(gpio_bankaddr[i] + NMK_GPIO_RWIMSC); - fwimsc[i] = readl(gpio_bankaddr[i] + NMK_GPIO_FWIMSC); - - /* Prevent spurious wakeups */ - writel(0, gpio_bankaddr[i] + NMK_GPIO_RWIMSC); - writel(0, gpio_bankaddr[i] + NMK_GPIO_FWIMSC); - } - - ux500_pm_prcmu_set_ioforce(true); - } else { - ux500_pm_prcmu_set_ioforce(false); - - /* Restore wake up settings */ - for (i = 0; i < GPIO_NUM_BANKS; i++) { - writel(rwimsc[i], gpio_bankaddr[i] + NMK_GPIO_RWIMSC); - writel(fwimsc[i], gpio_bankaddr[i] + NMK_GPIO_FWIMSC); - } - - } - -} - -/* - * Save common - * - * This function must be called once for all cores before going to deep sleep. - */ -void context_varm_save_common(void) -{ - atomic_notifier_call_chain(&context_arm_notifier_list, - CONTEXT_ARM_COMMON_SAVE, NULL); - - /* Save common parts */ - save_gic_dist_common(); - save_scu(); -} - -/* - * Restore common - * - * This function must be called once for all cores when waking up from deep - * sleep. - */ -void context_varm_restore_common(void) -{ - /* Restore common parts */ - restore_scu(); - restore_gic_dist_common(); - - atomic_notifier_call_chain(&context_arm_notifier_list, - CONTEXT_ARM_COMMON_RESTORE, NULL); -} - -/* - * Save core - * - * This function must be called once for each cpu core before going to deep - * sleep. - */ -void context_varm_save_core(void) -{ - - int cpu = smp_processor_id(); - - atomic_notifier_call_chain(&context_arm_notifier_list, - CONTEXT_ARM_CORE_SAVE, NULL); - - per_cpu(varm_cp15_pointer, cpu) = per_cpu(varm_cp15_backup_stack, cpu); - - /* Save core */ - save_gic_if_cpu(&per_cpu(context_gic_cpu, cpu)); - save_gic_dist_cpu(&per_cpu(context_gic_dist_cpu, cpu)); - context_save_cp15_registers(&per_cpu(varm_cp15_pointer, cpu)); -} - -/* - * Restore core - * - * This function must be called once for each cpu core when waking up from - * deep sleep. - */ -void context_varm_restore_core(void) -{ - int cpu = smp_processor_id(); - - /* Restore core */ - context_restore_cp15_registers(&per_cpu(varm_cp15_pointer, cpu)); - restore_gic_dist_cpu(&per_cpu(context_gic_dist_cpu, cpu)); - restore_gic_if_cpu(&per_cpu(context_gic_cpu, cpu)); - - atomic_notifier_call_chain(&context_arm_notifier_list, - CONTEXT_ARM_CORE_RESTORE, NULL); - -} - -/* - * Save CPU registers - * - * This function saves ARM registers. - */ -void context_save_cpu_registers(void) -{ - int cpu = smp_processor_id(); - - per_cpu(varm_registers_pointer, cpu) = - per_cpu(varm_registers_backup_stack, cpu); - context_save_arm_registers(&per_cpu(varm_registers_pointer, cpu)); -} - -/* - * Restore CPU registers - * - * This function restores ARM registers. - */ -void context_restore_cpu_registers(void) -{ - int cpu = smp_processor_id(); - - context_restore_arm_registers(&per_cpu(varm_registers_pointer, cpu)); -} - -/* - * This function stores CP15 registers related to cache and mmu - * in backup SRAM. It also stores stack pointer, CPSR - * and return address for the PC in backup SRAM and - * does wait for interrupt. - */ -void context_save_to_sram_and_wfi(bool cleanL2cache) -{ - int cpu = smp_processor_id(); - - context_save_to_sram_and_wfi_internal(backup_sram_storage[cpu], - cleanL2cache); -} - -static int __init context_init(void) -{ - int i; - void __iomem *ux500_backup_ptr; - - /* allocate backup pointer for RAM data */ - ux500_backup_ptr = (void *)__get_free_pages(GFP_KERNEL, - get_order(U8500_BACKUPRAM_SIZE)); - - if (!ux500_backup_ptr) { - pr_warning("context: could not allocate backup memory\n"); - return -ENOMEM; - } - - /* - * ROM code addresses to store backup contents, - * pass the physical address of back up to ROM code - */ - writel(virt_to_phys(ux500_backup_ptr), - IO_ADDRESS(U8500_EXT_RAM_LOC_BACKUPRAM_ADDR)); - - - if (cpu_is_u5500()) { - writel(IO_ADDRESS(U5500_PUBLIC_BOOT_ROM_BASE), - IO_ADDRESS(U8500_CPU0_BACKUPRAM_ADDR_PUBLIC_BOOT_ROM_LOG_ADDR)); - - writel(IO_ADDRESS(U5500_PUBLIC_BOOT_ROM_BASE), - IO_ADDRESS(U8500_CPU1_BACKUPRAM_ADDR_PUBLIC_BOOT_ROM_LOG_ADDR)); - - context_tpiu.base = ioremap(U5500_TPIU_BASE, SZ_4K); - context_stm_ape.base = ioremap(U5500_STM_REG_BASE, SZ_4K); - context_scu.base = ioremap(U5500_SCU_BASE, SZ_4K); - - context_prcc[0].base = ioremap(U5500_CLKRST1_BASE, SZ_4K); - context_prcc[1].base = ioremap(U5500_CLKRST2_BASE, SZ_4K); - context_prcc[2].base = ioremap(U5500_CLKRST3_BASE, SZ_4K); - context_prcc[3].base = ioremap(U5500_CLKRST5_BASE, SZ_4K); - context_prcc[4].base = ioremap(U5500_CLKRST6_BASE, SZ_4K); - - context_gic_dist_common.base = ioremap(U5500_GIC_DIST_BASE, SZ_4K); - per_cpu(context_gic_cpu, 0).base = ioremap(U5500_GIC_CPU_BASE, SZ_4K); - } else if (cpu_is_u8500()) { - /* Give logical address to backup RAM. For both CPUs */ - writel(IO_ADDRESS(U8500_PUBLIC_BOOT_ROM_BASE), - IO_ADDRESS(U8500_CPU0_BACKUPRAM_ADDR_PUBLIC_BOOT_ROM_LOG_ADDR)); - - writel(IO_ADDRESS(U8500_PUBLIC_BOOT_ROM_BASE), - IO_ADDRESS(U8500_CPU1_BACKUPRAM_ADDR_PUBLIC_BOOT_ROM_LOG_ADDR)); - - context_tpiu.base = ioremap(U8500_TPIU_BASE, SZ_4K); - context_stm_ape.base = ioremap(U8500_STM_REG_BASE, SZ_4K); - context_scu.base = ioremap(U8500_SCU_BASE, SZ_4K); - - /* PERIPH4 is always on, so no need saving prcc */ - context_prcc[0].base = ioremap(U8500_CLKRST1_BASE, SZ_4K); - context_prcc[1].base = ioremap(U8500_CLKRST2_BASE, SZ_4K); - context_prcc[2].base = ioremap(U8500_CLKRST3_BASE, SZ_4K); - context_prcc[3].base = ioremap(U8500_CLKRST5_BASE, SZ_4K); - context_prcc[4].base = ioremap(U8500_CLKRST6_BASE, SZ_4K); - - context_gic_dist_common.base = ioremap(U8500_GIC_DIST_BASE, SZ_4K); - per_cpu(context_gic_cpu, 0).base = ioremap(U8500_GIC_CPU_BASE, SZ_4K); - } - - per_cpu(context_gic_dist_cpu, 0).base = context_gic_dist_common.base; - - for (i = 1; i < num_possible_cpus(); i++) { - per_cpu(context_gic_cpu, i).base - = per_cpu(context_gic_cpu, 0).base; - per_cpu(context_gic_dist_cpu, i).base - = per_cpu(context_gic_dist_cpu, 0).base; - } - - for (i = 0; i < ARRAY_SIZE(context_prcc); i++) { - const int clusters[] = {1, 2, 3, 5, 6}; - char clkname[10]; - - snprintf(clkname, sizeof(clkname), "PERIPH%d", clusters[i]); - - context_prcc[i].clk = clk_get_sys(clkname, NULL); - BUG_ON(IS_ERR(context_prcc[i].clk)); - } - - if (cpu_is_u8500()) { - u8500_context_init(); - } else if (cpu_is_u5500()) { - u5500_context_init(); - } else { - printk(KERN_ERR "context: unknown hardware!\n"); - return -EINVAL; - } - - return 0; -} -subsys_initcall(context_init); diff --git a/arch/arm/mach-ux500/pm/context.h b/arch/arm/mach-ux500/pm/context.h deleted file mode 100644 index 22b56351284..00000000000 --- a/arch/arm/mach-ux500/pm/context.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> - * Rickard Andersson <rickard.andersson@stericsson.com> for - * ST-Ericsson. - * License terms: GNU General Public License (GPL) version 2 - * - */ -#ifndef CONTEXT_H -#define CONTEXT_H - -#include <linux/notifier.h> - -#ifdef CONFIG_UX500_CONTEXT - -/* Defines to be with - * context_ape_notifier_register - */ -#define CONTEXT_APE_SAVE 0 /* APE save */ -#define CONTEXT_APE_RESTORE 1 /* APE restore */ - -/* Defines to be with - * context_arm_notifier_register - */ -#define CONTEXT_ARM_CORE_SAVE 0 /* Called for each ARM core */ -#define CONTEXT_ARM_CORE_RESTORE 1 /* Called for each ARM core */ -#define CONTEXT_ARM_COMMON_SAVE 2 /* Called when ARM common is saved */ -#define CONTEXT_ARM_COMMON_RESTORE 3 /* Called when ARM common is restored */ - -int context_ape_notifier_register(struct notifier_block *nb); -int context_ape_notifier_unregister(struct notifier_block *nb); - -int context_arm_notifier_register(struct notifier_block *nb); -int context_arm_notifier_unregister(struct notifier_block *nb); - -void context_vape_save(void); -void context_vape_restore(void); - -void context_gpio_save(void); -void context_gpio_restore(void); -void context_gpio_restore_mux(void); -void context_gpio_mux_safe_switch(bool begin); - -void context_gic_dist_disable_unneeded_irqs(void); - -void context_varm_save_common(void); -void context_varm_restore_common(void); - -void context_varm_save_core(void); -void context_varm_restore_core(void); - -void context_save_cpu_registers(void); -void context_restore_cpu_registers(void); - -void context_save_to_sram_and_wfi(bool cleanL2cache); - -void context_clean_l1_cache_all(void); -void context_save_arm_registers(u32 **backup_stack); -void context_restore_arm_registers(u32 **backup_stack); - -void context_save_cp15_registers(u32 **backup_stack); -void context_restore_cp15_registers(u32 **backup_stack); - -void context_save_to_sram_and_wfi_internal(u32 backup_sram_storage, - bool cleanL2cache); - -/* DB specific functions in either context-db8500 or context-db5500 */ -void u8500_context_save_icn(void); -void u8500_context_restore_icn(void); -void u8500_context_init(void); - -void u5500_context_save_icn(void); -void u5500_context_restore_icn(void); -void u5500_context_init(void); - -#else - -static inline void context_varm_save_core(void) {} -static inline void context_save_cpu_registers(void) {} -static inline void context_save_to_sram_and_wfi(bool cleanL2cache) {} -static inline void context_restore_cpu_registers(void) {} -static inline void context_varm_restore_core(void) {} - -#endif - -#endif diff --git a/arch/arm/mach-ux500/pm/context_arm.S b/arch/arm/mach-ux500/pm/context_arm.S deleted file mode 100644 index 55e2accc85f..00000000000 --- a/arch/arm/mach-ux500/pm/context_arm.S +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> - * Rickard Andersson <rickard.andersson@stericsson.com> for - * ST-Ericsson. - * License terms: GNU General Public License (GPL) version 2 - * - */ - -#include <linux/linkage.h> -#include <mach/hardware.h> -#include <asm/hardware/cache-l2x0.h> - -/* - * Save and increment macro - */ -.macro SAVE_AND_INCREMENT FROM_REG TO_REG - str \FROM_REG, [\TO_REG], #+4 -.endm - -/* - * Decrement and restore macro - */ -.macro DECREMENT_AND_RESTORE FROM_REG TO_REG - ldr \TO_REG, [\FROM_REG, #-4]! -.endm - -/* - * Save ARM registers - * - * This function must be called in supervisor mode. - * - * r0 = address to backup stack pointer - * - * Backup stack operations: - * + {sp, lr}^ - * + cpsr - * + {r3, r8-r14} (FIQ mode: r3=spsr) - * + {r3, r13, r14} (IRQ mode: r3=spsr) - * + {r3, r13, r14} (abort mode: r3=spsr) - * + {r3, r13, r14} (undef mode: r3=spsr) - */ - .align - .section ".text", "ax" -ENTRY(context_save_arm_registers) - stmfd sp!, {r1, r2, r3, lr} @ Save on stack - ldr r1, [r0] @ Read backup stack pointer - - stmia r1, {sp, lr}^ @ Store user mode sp and lr - @ registers - add r1, r1, #8 @ Update backup pointer (not - @ done in previous instruction) - - mrs r2, cpsr @ Get CPSR - SAVE_AND_INCREMENT r2 r1 @ Save CPSR register - orr r2, r2, #0xc0 @ Disable FIQ and IRQ - bic r2, r2, #0x1f @ Setup r2 to change mode - - @ The suffix to CPSR refers to which field(s) of the CPSR is - @ rereferenced (you can specify one or more). Defined fields are: - @ - @ c - control - @ x - extension - @ s - status - @ f - flags - - orr r3, r2, #0x11 @ Save FIQ mode registers - msr cpsr_cxsf, r3 - mrs r3, spsr - stmia r1!, {r3, r8-r14} - - orr r3, r2, #0x12 @ Save IRQ mode registers - msr cpsr_cxsf, r3 - mrs r3, spsr - stmia r1!, {r3, r13, r14} - - orr r3, r2, #0x17 @ Save abort mode registers + - @ common mode registers - msr cpsr_cxsf, r3 - mrs r3, spsr - stmia r1!, {r3, r13, r14} - - orr r3, r2, #0x1B @ Save undef mode registers - msr cpsr_cxsf, r3 - mrs r3, spsr - stmia r1!, {r3, r13, r14} - - orr r3, r2, #0x13 @ Return to supervisor mode - msr cpsr_cxsf, r3 - - str r1, [r0] @ Write backup stack pointer - ldmfd sp!, {r1, r2, r3, pc} @ Restore registers and return - - - -/* - * Restore ARM registers - * - * This function must be called in supervisor mode. - * - * r0 = address to backup stack pointer - * - * Backup stack operations: - * - {r3, r13, r14} (undef mode: spsr=r3) - * - {r3, r13, r14} (abort mode: spsr=r3) - * - {r3, r13, r14} (IRQ mode: spsr=r3) - * - {r3, r8-r14} (FIQ mode: spsr=r3) - * - cpsr - * - {sp, lr}^ - */ - .align - .section ".text", "ax" -ENTRY(context_restore_arm_registers) - stmfd sp!, {r1, r2, r3, lr} @ Save on stack - ldr r1, [r0] @ Read backup stack pointer - - mrs r2, cpsr @ Get CPSR - orr r2, r2, #0xc0 @ Disable FIQ and IRQ - bic r2, r2, #0x1f @ Setup r2 to change mode - - orr r3, r2, #0x1b @ Restore undef mode registers - msr cpsr_cxsf, r3 - ldmdb r1!, {r3, r13, r14} - msr spsr_cxsf, r3 - - orr r3, r2, #0x17 @ Restore abort mode registers - msr cpsr_cxsf, r3 - ldmdb r1!, {r3, r13, r14} - msr spsr_cxsf, r3 - - orr r3, r2, #0x12 @ Restore IRQ mode registers - msr cpsr_cxsf, r3 - ldmdb r1!, {r3, r13, r14} - msr spsr_cxsf, r3 - - orr r3, r2, #0x11 @ Restore FIQ mode registers - msr cpsr_cxsf, r3 - ldmdb r1!, {r3, r8-r14} - msr spsr_cxsf, r3 - - DECREMENT_AND_RESTORE r1 r3 @ Restore cpsr register - msr cpsr_cxsf, r3 - - ldmdb r1, {sp, lr}^ @ Restore sp and lr registers - sub r1, r1, #8 @ Update backup pointer (not - @ done in previous instruction) - - str r1, [r0] @ Write backup stack pointer - ldmfd sp!, {r1, r2, r3, pc} @ Restore registers and return - - - -/* - * Save CP15 registers - * - * This function must be called in supervisor mode. - * - * r0 = address to backup stack pointer - * - * TTBR0, TTBR1, TTBRC, DACR CP15 registers are restored by boot ROM from SRAM. - */ - .align 4 - .section ".text", "ax" -ENTRY(context_save_cp15_registers) - stmfd sp!, {r1, r2, r3, lr} @ Save on stack (r3 is saved due - @ to 8 byte aligned stack) - ldr r1, [r0] @ Read backup stack pointer - - mrc p15, 0, r2, c12, c0, 0 @ Read Non-secure Vector Base - @ Address Register - SAVE_AND_INCREMENT r2 r1 - - mrc p15, 0, r2, c10, c2, 0 @ Access primary memory region - @ remap register - SAVE_AND_INCREMENT r2 r1 - - mrc p15, 0, r2, c10, c2, 1 @ Access normal memory region - @ remap register - SAVE_AND_INCREMENT r2 r1 - - mrc p15, 0, r2, c13, c0, 1 @ Read Context ID Register - SAVE_AND_INCREMENT r2 r1 - mrc p15, 0, r2, c13, c0, 2 @ Read Thread ID registers, - @ this register is both user - @ and privileged R/W accessible - SAVE_AND_INCREMENT r2 r1 - mrc p15, 0, r2, c13, c0, 3 @ Read Thread ID registers, - @ this register is user - @ read-only and privileged R/W - @ accessible. - SAVE_AND_INCREMENT r2 r1 - mrc p15, 0, r2, c13, c0, 4 @ Read Thread ID registers, - @ this register is privileged - @ R/W accessible only. - SAVE_AND_INCREMENT r2 r1 - - mrc p15, 2, r2, c0, c0, 0 @ Cache Size Selection Register - SAVE_AND_INCREMENT r2 r1 - - mrc p15, 0, r2, c9, c12, 0 @ Read PMNC Register - SAVE_AND_INCREMENT r2 r1 - mrc p15, 0, r2, c9, c12, 1 @ Read PMCNTENSET Register - SAVE_AND_INCREMENT r2 r1 - mrc p15, 0, r2, c9, c12, 5 @ Read PMSELR Register - SAVE_AND_INCREMENT r2 r1 - mrc p15, 0, r2, c9, c13, 0 @ Read PMCCNTR Register - SAVE_AND_INCREMENT r2 r1 - mrc p15, 0, r2, c9, c13, 1 @ Read PMXEVTYPER Register - SAVE_AND_INCREMENT r2 r1 - mrc p15, 0, r2, c9, c14, 0 @ Read PMUSERENR Register - SAVE_AND_INCREMENT r2 r1 - mrc p15, 0, r2, c9, c14, 1 @ Read PMINTENSET Register - SAVE_AND_INCREMENT r2 r1 - mrc p15, 0, r2, c9, c14, 2 @ Read PMINTENCLR Register - SAVE_AND_INCREMENT r2 r1 - - mrc p15, 0, r2, c1, c0, 2 @ Read CPACR Register - SAVE_AND_INCREMENT r2 r1 - - str r1, [r0] @ Write backup stack pointer - ldmfd sp!, {r1, r2, r3, pc} @ Restore registers and return - - - -/* - * Restore CP15 registers - * - * This function must be called in supervisor mode. - * - * r0 = address to backup stack pointer - */ - .align 4 - .section ".text", "ax" -ENTRY(context_restore_cp15_registers) - stmfd sp!, {r1, r2, r3, lr} @ Save on stack (r3 is saved due - @ to 8 byte aligned stack) - ldr r1, [r0] @ Read backup stack pointer - - DECREMENT_AND_RESTORE r1 r2 @ Write CPACR register - mcr p15, 0, r2, c1, c0, 2 - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c9, c14, 2 @ Write PMINTENCLR Register - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c9, c14, 1 @ Write PMINTENSET Register - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c9, c14, 0 @ Write PMUSERENR Register - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c9, c13, 1 @ Write PMXEVTYPER Register - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c9, c13, 0 @ Write PMCCNTR Register - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c9, c12, 5 @ Write PMSELR Register - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c9, c12, 1 @ Write PMCNTENSET Register - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c9, c12, 0 @ Write PMNC Register - - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 2, r2, c0, c0, 0 @ Cache Size Selection Register - - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c13, c0, 4 @ Write Thread ID registers, - @ this register is privileged - @ R/W accessible only - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c13, c0, 3 @ Write Thread ID registers, - @ this register is user - @ read-only and privileged R/W - @ accessible - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c13, c0, 2 @ Write Thread ID registers, - @ this register is both user - @ and privileged R/W accessible - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c13, c0, 1 @ Write Context ID Register - - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c10, c2, 1 @ Access normal memory region - @ remap register - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c10, c2, 0 @ Access primary memory region - @ remap register - - DECREMENT_AND_RESTORE r1 r2 - mcr p15, 0, r2, c12, c0, 0 @ Write Non-secure Vector Base - @ Address Register - - str r1, [r0] @ Write backup stack pointer - ldmfd sp!, {r1, r2, r3, pc} @ Restore registers and return - - -/* - * L1 cache clean function. Commit 'dirty' data from L1 - * to L2 cache. - * - * r0, r1, r2, used locally - * - */ - .align 4 - .section ".text", "ax" -ENTRY(context_clean_l1_cache_all) - - mov r0, #0 @ swith to cache level 0 - @ (L1 cache) - mcr p15, 2, r0, c0, c0, 0 @ select current cache level - @ in cssr - - dmb - mov r1, #0 @ r1 = way index -wayLoopL1clean: - mov r0, #0 @ r0 = line index -lineLoopL1clean: - mov r2, r1, lsl #30 @ TODO: OK to hard-code - @ SoC-specific L1 cache details? - add r2, r0, lsl #5 - mcr p15, 0, r2, c7, c10, 2 @ Clean cache by set/way - add r0, r0, #1 - cmp r0, #256 @ TODO: Ok with hard-coded - @ set/way sizes or do we have to - @ read them from ARM regs? Is it - @ set correctly in silicon? - bne lineLoopL1clean - add r1, r1, #1 - cmp r1, #4 @ TODO: Ditto, sizes... - bne wayLoopL1clean - - dsb - isb - mov pc, lr - -ENDPROC(context_clean_l1_cache_all) - -/* - * Last saves to backup RAM, cache clean and WFI - * - * r0 = address to backup_sram_storage base adress - * r1 = indicate whether also L2 cache should be cleaned - */ - .align 4 - .section ".text", "ax" -ENTRY(context_save_to_sram_and_wfi_internal) - - stmfd sp!, {r2-r12, lr} @ save on stack. - - mrc p15, 0, r2, c1, c0, 0 @ read cp15 system control - @ register - str r2, [r0, #0x00] - mrc p15, 0, r2, c2, c0, 0 @ read cp15 ttb0 register - str r2, [r0, #0x04] - mrc p15, 0, r2, c2, c0, 1 @ read cp15 ttb1 register - str r2, [r0, #0x08] - mrc p15, 0, r2, c2, c0, 2 @ read cp15 ttb control register - str r2, [r0, #0x0C] - mrc p15, 0, r2, c3, c0, 0 @ read domain access control - @ register - str r2, [r0, #0x10] - - ldr r2, =return_here - str r2, [r0, #0x14] @ save program counter restore - @ value to backup_sram_storage - mrs r2, cpsr - str r2, [r0, #0x18] @ save cpsr to - @ backup_sram_storage - str sp, [r0, #0x1c] @ save sp to backup_sram_storage - - mov r4, r1 @ Set r4 = cleanL2cache, r1 - @ will be destroyed by - @ v7_clean_l1_cache_all - - bl context_clean_l1_cache_all @ Commit all dirty data in L1 - @ cache to L2 without - @ invalidating - - dsb @ data synchronization barrier - isb @ instruction synchronization - @ barrier - wfi @ wait for interrupt - -return_here: @ both cores return here - @ now we are out deep sleep - @ with all the context lost - @ except pc, sp and cpsr - - ldmfd sp!, {r2-r12, pc} @ restore from stack - diff --git a/arch/arm/mach-ux500/pm/cpufreq-db5500.c b/arch/arm/mach-ux500/pm/cpufreq-db5500.c deleted file mode 100644 index 2830615f8b4..00000000000 --- a/arch/arm/mach-ux500/pm/cpufreq-db5500.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * License Terms: GNU General Public License v2 - */ - -#include <linux/kernel.h> -#include <linux/cpufreq.h> - -#include <mach/prcmu.h> - -#include "cpufreq.h" - -static struct cpufreq_frequency_table freq_table[] = { - [0] = { - .index = 0, - .frequency = 200000, - }, - [1] = { - .index = 1, - .frequency = 396500, - }, - [2] = { - .index = 2, - .frequency = 793000, - }, - [3] = { - .index = 3, - .frequency = CPUFREQ_TABLE_END, - }, -}; - -static enum arm_opp idx2opp[] = { - ARM_EXTCLK, - ARM_50_OPP, - ARM_100_OPP, -}; - -int u5500_cpufreq_limits(int cpu, int r, unsigned int *min, unsigned int *max) -{ - struct cpufreq_policy p; - int ret; - - ret = cpufreq_get_policy(&p, cpu); - if (ret) { - pr_err("cpufreq-db8500: Failed to get policy.\n"); - return -EINVAL; - } - - (*max) = p.max; - (*min) = p.min; - - return 0; -} - -static int __init u5500_cpufreq_register(void) -{ - int i = 0; - - BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table)); - - if (cpu_is_u5500v1()) - return -ENODEV; - pr_info("u5500-cpufreq : Available frequencies:\n"); - while (freq_table[i].frequency != CPUFREQ_TABLE_END) - pr_info(" %d Mhz\n", freq_table[i++].frequency/1000); - - return ux500_cpufreq_register(freq_table, idx2opp); -} -device_initcall(u5500_cpufreq_register); diff --git a/arch/arm/mach-ux500/pm/cpufreq-db8500.c b/arch/arm/mach-ux500/pm/cpufreq-db8500.c deleted file mode 100644 index 294af62ff37..00000000000 --- a/arch/arm/mach-ux500/pm/cpufreq-db8500.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * License Terms: GNU General Public License v2 - */ - -#include <linux/kernel.h> -#include <linux/cpufreq.h> - -#include <mach/prcmu.h> - -#include "cpufreq.h" - -static struct cpufreq_frequency_table freq_table[] = { - [0] = { - .index = 0, - .frequency = 200000, - }, - [1] = { - .index = 1, - .frequency = 300000, - }, - [2] = { - .index = 2, - .frequency = 600000, - }, - [3] = { - /* Used for MAX_OPP, if available */ - .index = 3, - .frequency = CPUFREQ_TABLE_END, - }, - [4] = { - .index = 4, - .frequency = CPUFREQ_TABLE_END, - }, -}; - -static enum arm_opp idx2opp[] = { - ARM_EXTCLK, - ARM_50_OPP, - ARM_100_OPP, - ARM_MAX_OPP -}; - -/* - * Below is a temporary workaround for wlan performance issues - */ - -#include <linux/kernel_stat.h> -#include <linux/workqueue.h> -#include <linux/cpu.h> - -#include <mach/irqs.h> -#include <mach/prcmu-qos.h> - -#define WLAN_PROBE_DELAY 3000 /* 3 seconds */ -#define WLAN_LIMIT (3000/3) /* If we have more than 1000 irqs per second */ -static struct delayed_work work_wlan_workaround; - -static void wlan_load(struct work_struct *work) -{ - int cpu; - unsigned int num_irqs = 0; - static unsigned int old_num_irqs = UINT_MAX; - - for_each_online_cpu(cpu) - num_irqs += kstat_irqs_cpu(IRQ_DB8500_SDMMC1, cpu); - - if ((num_irqs > old_num_irqs) && - (num_irqs - old_num_irqs) > WLAN_LIMIT) - prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, - "wlan", 125); - else - prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, - "wlan", 25); - - old_num_irqs = num_irqs; - - schedule_delayed_work_on(0, - &work_wlan_workaround, - msecs_to_jiffies(WLAN_PROBE_DELAY)); -} - -int u8500_cpufreq_limits(int cpu, int r, unsigned int *min, unsigned int *max) -{ - int op; - int i; - int ret; - static int old_freq; - struct cpufreq_policy p; - - switch (r) { - case 0: - /* Fall through */ - case 25: - op = ARM_EXTCLK; - break; - case 50: - op = ARM_50_OPP; - break; - case 100: - op = ARM_100_OPP; - break; - case 125: - if (prcmu_has_arm_maxopp()) - op = ARM_MAX_OPP; - else - op = ARM_100_OPP; - break; - default: - pr_err("cpufreq-db8500: Incorrect arm target value (%d).\n", - r); - BUG(); - break; - } - - - for (i = 0; idx2opp[i] != op; i++) - ; - - if (freq_table[i].frequency == CPUFREQ_TABLE_END) { - pr_err("cpufreq-u8500: Minimum frequency does not exist!\n"); - BUG(); - } - - if (freq_table[i].frequency != old_freq) - pr_debug("cpufreq-db8500: set min arm freq to %d\n", - freq_table[i].frequency); - - (*min) = freq_table[i].frequency; - - ret = cpufreq_get_policy(&p, cpu); - if (ret) { - pr_err("cpufreq-db8500: Failed to get policy.\n"); - return -EINVAL; - } - - (*max) = p.max; - return 0; -} - -static int __init u8500_cpufreq_register(void) -{ - int i = 0; - - BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table)); - - if (!prcmu_is_u8400()) { - freq_table[1].frequency = 400000; - freq_table[2].frequency = 800000; - if (prcmu_has_arm_maxopp()) - freq_table[3].frequency = 1000000; - } - - INIT_DELAYED_WORK_DEFERRABLE(&work_wlan_workaround, - wlan_load); - - prcmu_qos_add_requirement(PRCMU_QOS_ARM_OPP, "wlan", 25); - - schedule_delayed_work_on(0, - &work_wlan_workaround, - msecs_to_jiffies(WLAN_PROBE_DELAY)); - - pr_info("u8500-cpufreq : Available frequencies:\n"); - while (freq_table[i].frequency != CPUFREQ_TABLE_END) - pr_info(" %d Mhz\n", freq_table[i++].frequency/1000); - - return ux500_cpufreq_register(freq_table, idx2opp); -} -device_initcall(u8500_cpufreq_register); diff --git a/arch/arm/mach-ux500/pm/cpufreq-dbx500.h b/arch/arm/mach-ux500/pm/cpufreq-dbx500.h deleted file mode 100644 index 2777336ef4e..00000000000 --- a/arch/arm/mach-ux500/pm/cpufreq-dbx500.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * License Terms: GNU General Public License v2 - */ -#ifndef __UX500_PM_CPUFREQ_DBX500_H -#define __UX500_PM_CPUFREQ_DBX500_H - -int u8500_cpufreq_limits(int cpu, int r, unsigned int *min, unsigned int *max); - -int u5500_cpufreq_limits(int cpu, int r, unsigned int *min, unsigned int *max); - -#endif diff --git a/arch/arm/mach-ux500/pm/cpufreq.c b/arch/arm/mach-ux500/pm/cpufreq.c deleted file mode 100644 index fdb3ae8461a..00000000000 --- a/arch/arm/mach-ux500/pm/cpufreq.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) STMicroelectronics 2009 - * Copyright (C) ST-Ericsson SA 2010 - * - * License Terms: GNU General Public License v2 - * Author: Sundar Iyer <sundar.iyer@stericsson.com> - * - */ -#include <linux/kernel.h> -#include <linux/cpufreq.h> -#include <linux/delay.h> -#include <linux/slab.h> - -#include <mach/hardware.h> -#include <mach/prcmu.h> -#include <mach/prcmu-regs.h> - -#include "cpufreq-dbx500.h" - -static struct cpufreq_frequency_table *freq_table; -static enum arm_opp *idx2opp; - -static struct freq_attr *ux500_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static int ux500_cpufreq_verify_speed(struct cpufreq_policy *policy) -{ - return cpufreq_frequency_table_verify(policy, freq_table); -} - -static int ux500_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - struct cpufreq_freqs freqs; - unsigned int idx; - - /* scale the target frequency to one of the extremes supported */ - if (target_freq < policy->cpuinfo.min_freq) - target_freq = policy->cpuinfo.min_freq; - if (target_freq > policy->cpuinfo.max_freq) - target_freq = policy->cpuinfo.max_freq; - - /* Lookup the next frequency */ - if (cpufreq_frequency_table_target - (policy, freq_table, target_freq, relation, &idx)) { - return -EINVAL; - } - - freqs.old = policy->cur; - freqs.new = freq_table[idx].frequency; - freqs.cpu = policy->cpu; - - if (freqs.old == freqs.new) - return 0; - - /* pre-change notification */ - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - /* request the PRCM unit for opp change */ - if (prcmu_set_arm_opp(idx2opp[idx])) { - pr_err("ux500-cpufreq: Failed to set OPP level\n"); - return -EINVAL; - } - - /* post change notification */ - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - - return 0; -} - -static unsigned int ux500_cpufreq_getspeed(unsigned int cpu) -{ - int i; - /* request the prcm to get the current ARM opp */ - for (i = 0; prcmu_get_arm_opp() != idx2opp[i]; i++) - ; - return freq_table[i].frequency; -} - -int ux500_cpufreq_limits(int cpu, int r, unsigned int *min, unsigned int *max) -{ - if (cpu_is_u5500()) - return u5500_cpufreq_limits(cpu, r, min, max); - if (cpu_is_u8500()) - return u8500_cpufreq_limits(cpu, r, min, max); - return -EINVAL; -} - -static int __cpuinit ux500_cpufreq_init(struct cpufreq_policy *policy) -{ - int res; - int i; - - /* get policy fields based on the table */ - res = cpufreq_frequency_table_cpuinfo(policy, freq_table); - if (!res) - cpufreq_frequency_table_get_attr(freq_table, policy->cpu); - else { - pr_err("ux500-cpufreq : Failed to read policy table\n"); - return res; - } - - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; - policy->cur = ux500_cpufreq_getspeed(policy->cpu); - - for (i = 0; freq_table[i].frequency != policy->cur; i++) - ; - - policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - - /* - * FIXME : Need to take time measurement across the target() - * function with no/some/all drivers in the notification - * list. - */ - policy->cpuinfo.transition_latency = 20 * 1000; /* in ns */ - - /* policy sharing between dual CPUs */ - cpumask_copy(policy->cpus, &cpu_present_map); - - policy->shared_type = CPUFREQ_SHARED_TYPE_ALL; - - return 0; -} - -static struct cpufreq_driver ux500_cpufreq_driver = { - .flags = CPUFREQ_STICKY, - .verify = ux500_cpufreq_verify_speed, - .target = ux500_cpufreq_target, - .get = ux500_cpufreq_getspeed, - .init = ux500_cpufreq_init, - .name = "UX500", - .attr = ux500_cpufreq_attr, -}; - -int __init -ux500_cpufreq_register(struct cpufreq_frequency_table *table, - enum arm_opp *idx2opplist) -{ - freq_table = table; - idx2opp = idx2opplist; - - if (ux500_is_svp()) - return -ENODEV; - - pr_info("cpufreq for ux500 started\n"); - return cpufreq_register_driver(&ux500_cpufreq_driver); -} diff --git a/arch/arm/mach-ux500/pm/cpufreq.h b/arch/arm/mach-ux500/pm/cpufreq.h deleted file mode 100644 index eaf5eab3ab3..00000000000 --- a/arch/arm/mach-ux500/pm/cpufreq.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * License Terms: GNU General Public License v2 - */ -#ifndef __UX500_PM_CPUFREQ_H -#define __UX500_PM_CPUFREQ_H - -#include <linux/cpufreq.h> - -extern int ux500_cpufreq_register(struct cpufreq_frequency_table *freq_table, - enum arm_opp *idx2opp); - -/* This function lives in drivers/cpufreq/cpufreq.c */ -int cpufreq_update_freq(int cpu, unsigned int min, unsigned int max); - -int ux500_cpufreq_limits(int cpu, int r, unsigned int *min, unsigned int *max); - -#endif diff --git a/arch/arm/mach-ux500/pm/cpuidle.c b/arch/arm/mach-ux500/pm/cpuidle.c deleted file mode 100644 index eddd2849a16..00000000000 --- a/arch/arm/mach-ux500/pm/cpuidle.c +++ /dev/null @@ -1,710 +0,0 @@ -/* - * Copyright (C) STMicroelectronics 2009 - * Copyright (C) ST-Ericsson SA 2010-2011 - * - * Author: Rickard Andersson <rickard.andersson@stericsson.com>, - * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson. - * - * Loosely based on cpuidle.c by Sundar Iyer. - * - * License terms: GNU General Public License (GPL) version 2 - * - */ -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/sched.h> -#include <linux/tick.h> -#include <linux/clockchips.h> -#include <linux/gpio/nomadik.h> - -#include <mach/prcmu.h> - -#include "cpuidle.h" -#include "cpuidle_dbg.h" -#include "context.h" -#include "pm.h" -#include "timer.h" -#include "../regulator-u8500.h" - -/* - * All measurements are with two cpus online (worst case) and at - * 200 MHz (worst case) - * - * Enter latency depends on cpu frequency, and is only depending on - * code executing on the ARM. - * Exit latency is both depending on "wake latency" which is the - * time between the PRCMU has gotten the interrupt and the ARM starts - * to execute and the time before everything is done on the ARM. - * The wake latency is more or less constant related to cpu frequency, - * but can differ depending on what the modem does. - * Wake latency is not included for plain WFI. - * For states that uses RTC (Sleep & DeepSleep), wake latency is reduced - * from clock programming timeout. - * - */ -#define DEEP_SLEEP_WAKE_UP_LATENCY 8500 -/* Wake latency from ApSleep is measured to be around 1.0 to 1.5 ms */ -#define MIN_SLEEP_WAKE_UP_LATENCY 1000 -#define MAX_SLEEP_WAKE_UP_LATENCY 1500 - -#define UL_PLL_START_UP_LATENCY 8000 /* us */ - -static struct cstate cstates[] = { - { - .enter_latency = 0, - .exit_latency = 0, - .threshold = 0, - .power_usage = 1000, - .APE = APE_ON, - .ARM = ARM_ON, - .UL_PLL = UL_PLL_ON, - .ESRAM = ESRAM_RET, - .pwrst = PRCMU_AP_NO_CHANGE, - .state = CI_RUNNING, - .desc = "Running ", - }, - { - /* These figures are not really true. There is a cost for WFI */ - .enter_latency = 0, - .exit_latency = 0, - .threshold = 0, - .power_usage = 10, - .APE = APE_ON, - .ARM = ARM_ON, - .UL_PLL = UL_PLL_ON, - .ESRAM = ESRAM_RET, - .pwrst = PRCMU_AP_NO_CHANGE, - .flags = CPUIDLE_FLAG_TIME_VALID, - .state = CI_WFI, - .desc = "Wait for interrupt ", - }, - { - .enter_latency = 170, - .exit_latency = 70, - .threshold = 260, - .power_usage = 4, - .APE = APE_ON, - .ARM = ARM_RET, - .UL_PLL = UL_PLL_ON, - .ESRAM = ESRAM_RET, - .pwrst = PRCMU_AP_IDLE, - .flags = CPUIDLE_FLAG_TIME_VALID, - .state = CI_IDLE, - .desc = "ApIdle ", - }, - { - .enter_latency = 350, - .exit_latency = MAX_SLEEP_WAKE_UP_LATENCY + 200, - /* - * Note: Sleep time must be longer than 120 us or else - * there might be issues with the RTC-RTT block. - */ - .threshold = MAX_SLEEP_WAKE_UP_LATENCY + 350 + 200, - .power_usage = 3, - .APE = APE_OFF, - .ARM = ARM_RET, - .UL_PLL = UL_PLL_ON, - .ESRAM = ESRAM_RET, - .pwrst = PRCMU_AP_SLEEP, - .flags = CPUIDLE_FLAG_TIME_VALID, - .state = CI_SLEEP, - .desc = "ApSleep ", - }, - { - .enter_latency = 350, - .exit_latency = (MAX_SLEEP_WAKE_UP_LATENCY + - UL_PLL_START_UP_LATENCY + 200), - .threshold = (MAX_SLEEP_WAKE_UP_LATENCY + - UL_PLL_START_UP_LATENCY + 350 + 200), - .power_usage = 2, - .APE = APE_OFF, - .ARM = ARM_RET, - .UL_PLL = UL_PLL_OFF, - .ESRAM = ESRAM_RET, - .pwrst = PRCMU_AP_SLEEP, - .flags = CPUIDLE_FLAG_TIME_VALID, - .state = CI_SLEEP, - .desc = "ApSleep, UL PLL off ", - }, -#ifdef CONFIG_U8500_CPUIDLE_APDEEPIDLE - { - .enter_latency = 400, - .exit_latency = DEEP_SLEEP_WAKE_UP_LATENCY + 400, - .threshold = DEEP_SLEEP_WAKE_UP_LATENCY + 400 + 400, - .power_usage = 2, - .APE = APE_ON, - .ARM = ARM_OFF, - .UL_PLL = UL_PLL_ON, - .ESRAM = ESRAM_RET, - .pwrst = PRCMU_AP_DEEP_IDLE, - .flags = CPUIDLE_FLAG_TIME_VALID, - .state = CI_DEEP_IDLE, - .desc = "ApDeepIdle, UL PLL off ", - }, -#endif - { - .enter_latency = 410, - .exit_latency = DEEP_SLEEP_WAKE_UP_LATENCY + 420, - .threshold = DEEP_SLEEP_WAKE_UP_LATENCY + 410 + 420, - .power_usage = 1, - .APE = APE_OFF, - .ARM = ARM_OFF, - .UL_PLL = UL_PLL_OFF, - .ESRAM = ESRAM_RET, - .pwrst = PRCMU_AP_DEEP_SLEEP, - .flags = CPUIDLE_FLAG_TIME_VALID, - .state = CI_DEEP_SLEEP, - .desc = "ApDeepsleep, UL PLL off", - }, -}; - -struct cpu_state { - int gov_cstate; - ktime_t sched_wake_up; - struct cpuidle_device dev; - bool restore_arm_core; -}; - -static DEFINE_PER_CPU(struct cpu_state, *cpu_state); - -static DEFINE_SPINLOCK(cpuidle_lock); -static bool restore_ape; /* protected by cpuidle_lock */ -static bool restore_arm; /* protected by cpuidle_lock */ -static ktime_t time_next; /* protected by cpuidle_lock */ - -extern struct clock_event_device u8500_mtu_clkevt; - -static atomic_t idle_cpus_counter = ATOMIC_INIT(0); -static atomic_t master_counter = ATOMIC_INIT(0); - -struct cstate *ux500_ci_get_cstates(int *len) -{ - if (len != NULL) - (*len) = ARRAY_SIZE(cstates); - return cstates; -} - -static void restore_sequence(struct cpu_state *state, ktime_t now) -{ - spin_lock(&cpuidle_lock); - - smp_rmb(); - if (state->restore_arm_core) { - state->restore_arm_core = false; - smp_wmb(); - - context_restore_cpu_registers(); - context_varm_restore_core(); - } - - smp_rmb(); - if (restore_arm) { - - restore_arm = false; - smp_wmb(); - - /* Restore gic settings */ - context_varm_restore_common(); - } - - smp_rmb(); - if (restore_ape) { - restore_ape = false; - smp_wmb(); - - /* - * APE has been turned off. Save GPIO wake up cause before - * clearing ioforce. - */ - context_vape_restore(); - - ux500_pm_gpio_save_wake_up_status(); - - /* Restore IO ring */ - ux500_pm_prcmu_set_ioforce(false); - - ux500_ci_dbg_console_handle_ape_resume(); - - ux500_rtcrtt_off(); - - /* - * If we're returning from ApSleep and the RTC timer - * caused the wake up, program the MTU to trigger. - */ - if ((ktime_to_us(now) >= ktime_to_us(time_next))) - time_next = ktime_add(now, ktime_set(0, 1000)); - - /* Make sure have an MTU interrupt waiting for us */ - WARN_ON(clockevents_program_event(&u8500_mtu_clkevt, - time_next, - now)); - } - - spin_unlock(&cpuidle_lock); - -} - -/** - * get_remaining_sleep_time() - returns remaining sleep time in - * microseconds (us) - */ -static u32 get_remaining_sleep_time(ktime_t *next, int *on_cpu) -{ - ktime_t now, t; - int cpu; - int delta; - u32 remaining_sleep_time = UINT_MAX; - - now = ktime_get(); - - /* Check next schedule to expire considering both cpus */ - - spin_lock(&cpuidle_lock); - for_each_online_cpu(cpu) { - t = per_cpu(cpu_state, cpu)->sched_wake_up; - - delta = ktime_to_us(ktime_sub(t, now)); - if ((delta < remaining_sleep_time) && (delta > 0)) { - remaining_sleep_time = (u32)delta; - if (next) - (*next) = t; - if (on_cpu) - (*on_cpu) = cpu; - } - } - spin_unlock(&cpuidle_lock); - - return remaining_sleep_time; -} - -static bool is_last_cpu_running(void) -{ - smp_rmb(); - return atomic_read(&idle_cpus_counter) == num_online_cpus(); -} - -static int determine_sleep_state(u32 *sleep_time) -{ - int i; - - int cpu; - int max_depth; - bool power_state_req; - - /* If first cpu to sleep, go to most shallow sleep state */ - if (!is_last_cpu_running()) - return CI_WFI; - - /* If other CPU is going to WFI, but not yet there wait. */ - while (1) { - if (ux500_pm_other_cpu_wfi()) - break; - - if (ux500_pm_gic_pending_interrupt()) - return -1; - - if (!is_last_cpu_running()) - return CI_WFI; - } - - power_state_req = power_state_active_is_enabled() || - prcmu_is_ac_wake_requested(); - - (*sleep_time) = get_remaining_sleep_time(NULL, NULL); - - if ((*sleep_time) == UINT_MAX) - return CI_WFI; - /* - * Never go deeper than the governor recommends even though it might be - * possible from a scheduled wake up point of view - */ - max_depth = ux500_ci_dbg_deepest_state(); - - for_each_online_cpu(cpu) { - if (max_depth > per_cpu(cpu_state, cpu)->gov_cstate) - max_depth = per_cpu(cpu_state, cpu)->gov_cstate; - } - - for (i = max_depth; i > 0; i--) { - - if ((*sleep_time) <= cstates[i].threshold) - continue; - - if (cstates[i].APE == APE_OFF) { - /* This state says APE should be off */ - if (power_state_req || - ux500_ci_dbg_force_ape_on()) - continue; - } - - /* OK state */ - break; - } - - ux500_ci_dbg_register_reason(i, power_state_req, - (*sleep_time), - max_depth); - - return max(CI_WFI, i); -} - -static int enter_sleep(struct cpuidle_device *dev, - struct cpuidle_state *ci_state) -{ - ktime_t time_enter, time_exit, time_wake; - ktime_t wake_up; - int sleep_time = 0; - s64 diff; - int ret; - int target; - struct cpu_state *state; - bool slept_well = false; - int this_cpu = smp_processor_id(); - bool migrate_timer; - bool master = false; - - local_irq_disable(); - - time_enter = ktime_get(); /* Time now */ - - state = per_cpu(cpu_state, smp_processor_id()); - - wake_up = ktime_add(time_enter, tick_nohz_get_sleep_length()); - - spin_lock(&cpuidle_lock); - - /* Save scheduled wake up for this cpu */ - state->sched_wake_up = wake_up; - - /* Retrive the cstate that the governor recommends for this CPU */ - state->gov_cstate = (int) cpuidle_get_statedata(ci_state); - - if (state->gov_cstate > ux500_ci_dbg_deepest_state()) - state->gov_cstate = ux500_ci_dbg_deepest_state(); - - if (cstates[state->gov_cstate].ARM != ARM_ON) - migrate_timer = true; - else - migrate_timer = false; - - spin_unlock(&cpuidle_lock); - - atomic_inc(&idle_cpus_counter); - - /* - * Determine sleep state considering both CPUs and - * shared resources like e.g. VAPE - */ - target = determine_sleep_state(&sleep_time); - - if (target < 0) - /* "target" will be last_state in the cpuidle framework */ - goto exit_fast; - - /* Only one CPU should master the sleeping sequence */ - if (cstates[target].ARM != ARM_ON) { - smp_mb(); - if (atomic_inc_return(&master_counter) == 1) - master = true; - else - atomic_dec(&master_counter); - smp_mb(); - } - - if (migrate_timer) - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, - &this_cpu); - - - if (master && (cstates[target].ARM != ARM_ON)) { - - ux500_pm_gic_decouple(); - - /* - * Check if sleep state has changed after GIC has been frozen - */ - if (target != determine_sleep_state(&sleep_time)) { - atomic_dec(&master_counter); - goto exit; - } - - /* Copy GIC interrupt settings to PRCMU interrupt settings */ - ux500_pm_prcmu_copy_gic_settings(); - - if (ux500_pm_gic_pending_interrupt()) { - /* An interrupt found => abort */ - atomic_dec(&master_counter); - goto exit; - } - - if (ux500_pm_prcmu_pending_interrupt()) { - /* An interrupt found => abort */ - atomic_dec(&master_counter); - goto exit; - - } - /* - * No PRCMU interrupt was pending => continue the - * sleeping stages - */ - } - - if (master && (cstates[target].APE == APE_OFF)) { - ktime_t est_wake_time; - int wake_cpu; - - /* We are going to sleep or deep sleep => prepare for it */ - - /* Program the only timer that is available when APE is off */ - - sleep_time = get_remaining_sleep_time(&est_wake_time, - &wake_cpu); - - if (sleep_time == UINT_MAX) { - atomic_dec(&master_counter); - goto exit; - } - - if (cstates[target].UL_PLL == UL_PLL_OFF) - /* Compensate for ULPLL start up time */ - sleep_time -= UL_PLL_START_UP_LATENCY; - - /* - * Not checking for negative sleep time since - * determine_sleep_state has already checked that - * there is enough time. - */ - - /* Adjust for exit latency */ - sleep_time -= MIN_SLEEP_WAKE_UP_LATENCY; - - ux500_rtcrtt_next(sleep_time); - - /* - * Make sure the cpu that is scheduled first gets - * the prcmu interrupt. - */ - irq_set_affinity(IRQ_DB8500_PRCMU1, cpumask_of(wake_cpu)); - - context_vape_save(); - - ux500_ci_dbg_console_handle_ape_suspend(); - ux500_pm_prcmu_set_ioforce(true); - - spin_lock(&cpuidle_lock); - restore_ape = true; - time_next = est_wake_time; - spin_unlock(&cpuidle_lock); - } - - if (master && (cstates[target].ARM == ARM_OFF)) { - int cpu; - - context_varm_save_common(); - - spin_lock(&cpuidle_lock); - restore_arm = true; - for_each_possible_cpu(cpu) { - (per_cpu(cpu_state, cpu))->restore_arm_core = true; - } - spin_unlock(&cpuidle_lock); - } - - if (cstates[state->gov_cstate].ARM == ARM_OFF) { - context_varm_save_core(); - - if (master && (cstates[target].ARM == ARM_OFF)) - context_gic_dist_disable_unneeded_irqs(); - - context_save_cpu_registers(); - - /* - * Due to we have only 100us between requesting a - * powerstate and wfi, we clean the cache before as - * well to assure the final cache clean before wfi - * has as little as possible to do. - */ - context_clean_l1_cache_all(); - } - - ux500_ci_dbg_log(target, time_enter); - - if (master && cstates[target].ARM != ARM_ON) - prcmu_set_power_state(cstates[target].pwrst, - cstates[target].UL_PLL, - /* Is actually the AP PLL */ - cstates[target].UL_PLL); - - if (master) - atomic_dec(&master_counter); - - /* - * If deepsleep/deepidle, Save return address to SRAM and set - * this CPU in WFI. This is last core to enter sleep, so we need to - * clean both L2 and L1 caches - */ - if (cstates[state->gov_cstate].ARM == ARM_OFF) - context_save_to_sram_and_wfi(cstates[target].ARM == ARM_OFF); - else - __asm__ __volatile__ - ("dsb\n\t" "wfi\n\t" : : : "memory"); - - if (is_last_cpu_running()) - ux500_ci_dbg_wake_latency(target, sleep_time); - - time_wake = ktime_get(); - - slept_well = true; - - restore_sequence(state, time_wake); - -exit: - if (!slept_well) - /* Recouple GIC with the interrupt bus */ - ux500_pm_gic_recouple(); - - /* Use the ARM local timer for this cpu */ - if (migrate_timer) - clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, - &this_cpu); -exit_fast: - - atomic_dec(&idle_cpus_counter); - - if (target < 0) - target = CI_RUNNING; - - /* 16 minutes ahead */ - wake_up = ktime_add_us(time_enter, - 1000000000); - - spin_lock(&cpuidle_lock); - /* Remove wake up time i.e. set wake up far ahead */ - state->sched_wake_up = wake_up; - spin_unlock(&cpuidle_lock); - - /* - * We might have chosen another state than what the - * governor recommended - */ - if (target != state->gov_cstate) - /* Update last state pointer used by CPUIDLE subsystem */ - dev->last_state = &(dev->states[target]); - - time_exit = ktime_get(); - diff = ktime_to_us(ktime_sub(time_exit, time_enter)); - if (diff > INT_MAX) - diff = INT_MAX; - - ret = (int)diff; - - ux500_ci_dbg_console_check_uart(); - if (slept_well) - ux500_ci_dbg_exit_latency(target, - time_exit, /* now */ - time_wake, /* exit from wfi */ - time_enter); /* enter cpuidle */ - - ux500_ci_dbg_log(CI_RUNNING, time_exit); - - local_irq_enable(); - - ux500_ci_dbg_console(); - - return ret; -} - -static int init_cstates(int cpu, struct cpu_state *state) -{ - int i; - struct cpuidle_state *ci_state; - struct cpuidle_device *dev; - - dev = &state->dev; - dev->cpu = cpu; - - for (i = 0; i < ARRAY_SIZE(cstates); i++) { - - ci_state = &dev->states[i]; - - cpuidle_set_statedata(ci_state, (void *)i); - - ci_state->exit_latency = cstates[i].exit_latency; - ci_state->target_residency = cstates[i].threshold; - ci_state->flags = cstates[i].flags; - ci_state->enter = enter_sleep; - ci_state->power_usage = cstates[i].power_usage; - snprintf(ci_state->name, CPUIDLE_NAME_LEN, "C%d", i); - strncpy(ci_state->desc, cstates[i].desc, CPUIDLE_DESC_LEN); - } - - dev->state_count = ARRAY_SIZE(cstates); - - dev->safe_state = &dev->states[0]; /* Currently not used */ - - return cpuidle_register_device(dev); -} - -struct cpuidle_driver cpuidle_drv = { - .name = "cpuidle_driver", - .owner = THIS_MODULE, -}; - -static int __init cpuidle_driver_init(void) -{ - int res = -ENODEV; - int cpu; - - if (ux500_is_svp()) - goto out; - - /* Configure wake up reasons */ - prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | - PRCMU_WAKEUP(ABB)); - - ux500_ci_dbg_init(); - - for_each_possible_cpu(cpu) - per_cpu(cpu_state, cpu) = kzalloc(sizeof(struct cpu_state), - GFP_KERNEL); - - res = cpuidle_register_driver(&cpuidle_drv); - if (res) - goto out; - - for_each_possible_cpu(cpu) { - res = init_cstates(cpu, per_cpu(cpu_state, cpu)); - if (res) - goto out; - pr_info("cpuidle: initiated for CPU%d.\n", cpu); - } - return 0; -out: - pr_err("cpuidle: initialization failed.\n"); - return res; -} - -static void __exit cpuidle_driver_exit(void) -{ - int cpu; - struct cpuidle_device *dev; - - ux500_ci_dbg_remove(); - - for_each_possible_cpu(cpu) { - dev = &per_cpu(cpu_state, cpu)->dev; - cpuidle_unregister_device(dev); - } - - for_each_possible_cpu(cpu) - kfree(per_cpu(cpu_state, cpu)); - - cpuidle_unregister_driver(&cpuidle_drv); -} - -late_initcall(cpuidle_driver_init); -module_exit(cpuidle_driver_exit); - -MODULE_DESCRIPTION("U8500 cpuidle driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Rickard Andersson <rickard.andersson@stericsson.com>"); diff --git a/arch/arm/mach-ux500/pm/cpuidle.h b/arch/arm/mach-ux500/pm/cpuidle.h deleted file mode 100644 index 265cce7de59..00000000000 --- a/arch/arm/mach-ux500/pm/cpuidle.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * Author: Rickard Andersson <rickard.andersson@stericsson.com> for - * ST-Ericsson. Loosly based on cpuidle.c by Sundar Iyer. - * License terms: GNU General Public License (GPL) version 2 - * - */ - -#ifndef __CPUIDLE_H -#define __CPUIDLE_H - -#include <linux/cpuidle.h> - -enum ARM { - ARM_OFF, - ARM_RET, - ARM_ON -}; - -enum APE { - APE_OFF, - APE_ON -}; - -enum UL_PLL { - UL_PLL_OFF, - UL_PLL_ON -}; - -enum ESRAM { - ESRAM_OFF, - ESRAM_RET -}; - -enum ci_pwrst { - CI_RUNNING = 0, /* Must be the same number as entry in cstates */ - CI_WFI = 1, /* Must be the same number as entry in cstates */ - CI_IDLE, - CI_SLEEP, - CI_DEEP_IDLE, - CI_DEEP_SLEEP, -}; - -struct cstate { - /* Required state of different hardwares */ - enum ARM ARM; - enum APE APE; - enum UL_PLL UL_PLL; - /* ESRAM = ESRAM_RET means that ESRAM context to be kept */ - enum ESRAM ESRAM; - - u32 enter_latency; - u32 exit_latency; - u32 power_usage; - u32 threshold; - u32 flags; - u8 pwrst; - - /* Only used for debugging purpose */ - enum ci_pwrst state; - char desc[CPUIDLE_DESC_LEN]; -}; - -struct cstate *ux500_ci_get_cstates(int *len); - -#endif diff --git a/arch/arm/mach-ux500/pm/cpuidle_dbg.c b/arch/arm/mach-ux500/pm/cpuidle_dbg.c deleted file mode 100644 index 344d7b8a0ed..00000000000 --- a/arch/arm/mach-ux500/pm/cpuidle_dbg.c +++ /dev/null @@ -1,950 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010-2011 - * - * License Terms: GNU General Public License v2 - * Author: Rickard Andersson <rickard.andersson@stericsson.com>, - * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson - */ - -#include <linux/slab.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/delay.h> -#include <linux/workqueue.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/uaccess.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/gpio/nomadik.h> -#include <linux/amba/serial.h> - -#include <asm/hardware/gic.h> - -#include "cpuidle.h" -#include "pm.h" -#include "timer.h" - -#define APE_ON_TIMER_INTERVAL 5 /* Seconds */ - -#define UART_RX_GPIO_PIN_MASK (1 << (CONFIG_UX500_CONSOLE_UART_GPIO_PIN % 32)) - -#define UART011_MIS_RTIS (1 << 6) /* receive timeout interrupt status */ -#define UART011_MIS_RXIS (1 << 4) /* receive interrupt status */ -#define UART011_MIS 0x40 /* Masked interrupt status register */ - -enum latency_type { - LATENCY_ENTER = 0, - LATENCY_EXIT, - LATENCY_WAKE, - NUM_LATENCY, -}; - -struct state_history_state { - u32 counter; - ktime_t time; - u32 hit_rate; - u32 state_ok; - u32 state_error; - u32 prcmu_int; - u32 pending_int; - - u32 latency_count[NUM_LATENCY]; - ktime_t latency_sum[NUM_LATENCY]; - ktime_t latency_min[NUM_LATENCY]; - ktime_t latency_max[NUM_LATENCY]; -}; - -struct state_history { - ktime_t start; - u32 state; - u32 exit_counter; - ktime_t measure_begin; - int ape_blocked; - int time_blocked; - int both_blocked; - int gov_blocked; - struct state_history_state *states; -}; -static DEFINE_PER_CPU(struct state_history, *state_history); - -static struct delayed_work cpuidle_work; -static u32 dbg_console_enable = 1; -static void __iomem *uart_base; -static struct clk *uart_clk; - -/* Blocks ApSleep and ApDeepSleep */ -static bool force_APE_on; -static bool reset_timer; -static int deepest_allowed_state = CONFIG_U8500_CPUIDLE_DEEPEST_STATE; -static u32 measure_latency; -static bool wake_latency; -static int verbose; - -static bool apidle_both_blocked; -static bool apidle_ape_blocked; -static bool apidle_time_blocked; -static bool apidle_gov_blocked; - -static struct cstate *cstates; -static int cstates_len; -static DEFINE_SPINLOCK(dbg_lock); - -bool ux500_ci_dbg_force_ape_on(void) -{ - clk_enable(uart_clk); - if (readw(uart_base + UART01x_FR) & UART01x_FR_BUSY) { - clk_disable(uart_clk); - return true; - } - clk_disable(uart_clk); - - return force_APE_on; -} - -int ux500_ci_dbg_deepest_state(void) -{ - return deepest_allowed_state; -} - -void ux500_ci_dbg_console_handle_ape_suspend(void) -{ - if (!dbg_console_enable) - return; - - irq_set_irq_wake(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), 1); - irq_set_irq_type(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), - IRQ_TYPE_EDGE_BOTH); -} - -void ux500_ci_dbg_console_handle_ape_resume(void) -{ - unsigned long flags; - u32 WKS_reg_value; - - if (!dbg_console_enable) - return; - - WKS_reg_value = ux500_pm_gpio_read_wake_up_status(0); - - if (WKS_reg_value & UART_RX_GPIO_PIN_MASK) { - spin_lock_irqsave(&dbg_lock, flags); - reset_timer = true; - spin_unlock_irqrestore(&dbg_lock, flags); - } - irq_set_irq_wake(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), 0); - -} - -void ux500_ci_dbg_console_check_uart(void) -{ - unsigned long flags; - u32 status; - - if (!dbg_console_enable) - return; - - clk_enable(uart_clk); - spin_lock_irqsave(&dbg_lock, flags); - status = readw(uart_base + UART011_MIS); - - if (status & (UART011_MIS_RTIS | UART011_MIS_RXIS)) - reset_timer = true; - - spin_unlock_irqrestore(&dbg_lock, flags); - clk_disable(uart_clk); -} - -void ux500_ci_dbg_console(void) -{ - unsigned long flags; - - if (!dbg_console_enable) - return; - - spin_lock_irqsave(&dbg_lock, flags); - if (reset_timer) { - reset_timer = false; - spin_unlock_irqrestore(&dbg_lock, flags); - - cancel_delayed_work(&cpuidle_work); - force_APE_on = true; - schedule_delayed_work(&cpuidle_work, - msecs_to_jiffies(APE_ON_TIMER_INTERVAL * - 1000)); - } else { - spin_unlock_irqrestore(&dbg_lock, flags); - } -} - -static void dbg_cpuidle_work_function(struct work_struct *work) -{ - force_APE_on = false; -} - -static void store_latency(struct state_history *sh, - int ctarget, - enum latency_type type, - ktime_t d, - bool lock) -{ - unsigned long flags = 0; - - if (lock) - spin_lock_irqsave(&dbg_lock, flags); - - sh->states[ctarget].latency_count[type]++; - - sh->states[ctarget].latency_sum[type] = - ktime_add(sh->states[ctarget].latency_sum[type], d); - - if (ktime_to_us(d) > ktime_to_us(sh->states[ctarget].latency_max[type])) - sh->states[ctarget].latency_max[type] = d; - - if (ktime_to_us(d) < ktime_to_us(sh->states[ctarget].latency_min[type])) - sh->states[ctarget].latency_min[type] = d; - - if (lock) - spin_unlock_irqrestore(&dbg_lock, flags); -} - -void ux500_ci_dbg_exit_latency(int ctarget, ktime_t now, ktime_t exit, - ktime_t enter) -{ - struct state_history *sh; - bool hit = true; - enum prcmu_idle_stat prcmu_status; - unsigned int d; - - if (!verbose) - return; - - sh = per_cpu(state_history, smp_processor_id()); - - sh->exit_counter++; - - d = ktime_to_us(ktime_sub(now, enter)); - - if ((ctarget + 1) < deepest_allowed_state) - hit = d < cstates[ctarget + 1].threshold; - if (d < cstates[ctarget].threshold) - hit = false; - - if (hit) - sh->states[ctarget].hit_rate++; - - if (cstates[ctarget].state < CI_IDLE) - return; - - prcmu_status = ux500_pm_prcmu_idle_stat(); - - switch (prcmu_status) { - - case DEEP_SLEEP_OK: - if (cstates[ctarget].state == CI_DEEP_SLEEP) - sh->states[ctarget].state_ok++; - break; - case SLEEP_OK: - if (cstates[ctarget].state == CI_SLEEP) - sh->states[ctarget].state_ok++; - break; - case IDLE_OK: - if (cstates[ctarget].state == CI_IDLE) - sh->states[ctarget].state_ok++; - break; - case DEEPIDLE_OK: - if (cstates[ctarget].state == CI_DEEP_IDLE) - sh->states[ctarget].state_ok++; - break; - case PRCMU2ARMPENDINGIT_ER: - sh->states[ctarget].prcmu_int++; - break; - case ARMPENDINGIT_ER: - sh->states[ctarget].pending_int++; - break; - default: - pr_info("cpuidle: unknown prcmu exit code: 0x%x state: %d\n", - prcmu_status, cstates[ctarget].state); - sh->states[ctarget].state_error++; - break; - } - - if (!measure_latency) - return; - - store_latency(sh, - ctarget, - LATENCY_EXIT, - ktime_sub(now, exit), - true); -} - -void ux500_ci_dbg_wake_latency(int ctarget, int sleep_time) -{ - struct state_history *sh; - ktime_t l; - ktime_t zero_time; - - if (!wake_latency || cstates[ctarget].state < CI_IDLE) - return; - - l = zero_time = ktime_set(0, 0); - sh = per_cpu(state_history, smp_processor_id()); - - if (cstates[ctarget].state >= CI_SLEEP) - l = u8500_rtc_exit_latency_get(); - - if (cstates[ctarget].state == CI_IDLE) { - ktime_t d = ktime_set(0, sleep_time * 1000); - ktime_t now = ktime_get(); - - d = ktime_add(d, sh->start); - if (ktime_to_us(now) > ktime_to_us(d)) - l = ktime_sub(now, d); - else - l = zero_time; - } - - if (!ktime_equal(zero_time, l)) - store_latency(sh, - ctarget, - LATENCY_WAKE, - l, - true); -} - -static void state_record_time(struct state_history *sh, int ctarget, - ktime_t now, ktime_t start, bool latency) -{ - ktime_t dtime; - - dtime = ktime_sub(now, sh->start); - sh->states[sh->state].time = ktime_add(sh->states[sh->state].time, - dtime); - - sh->start = now; - sh->state = ctarget; - - if (latency && cstates[ctarget].state != CI_RUNNING && measure_latency) - store_latency(sh, - ctarget, - LATENCY_ENTER, - ktime_sub(now, start), - false); - - sh->states[sh->state].counter++; -} - -void ux500_ci_dbg_register_reason(int idx, bool power_state_req, - u32 time, u32 max_depth) -{ - if (cstates[idx].state == CI_IDLE && verbose) { - apidle_ape_blocked = power_state_req; - apidle_time_blocked = time < cstates[idx + 1].threshold; - apidle_both_blocked = power_state_req && apidle_time_blocked; - apidle_gov_blocked = cstates[max_depth].state == CI_IDLE; - } -} - -void ux500_ci_dbg_log(int ctarget, ktime_t enter_time) -{ - int i; - ktime_t now; - unsigned long flags; - struct state_history *sh; - struct state_history *sh_other; - int this_cpu; - - this_cpu = smp_processor_id(); - - now = ktime_get(); - - sh = per_cpu(state_history, this_cpu); - - spin_lock_irqsave(&dbg_lock, flags); - - if (cstates[ctarget].state == CI_IDLE && verbose) { - if (apidle_both_blocked) - sh->both_blocked++; - if (apidle_ape_blocked) - sh->ape_blocked++; - if (apidle_time_blocked) - sh->time_blocked++; - if (apidle_gov_blocked) - sh->gov_blocked++; - } - - /* - * Check if current state is just a repeat of - * the state we're already in, then just quit. - */ - if (ctarget == sh->state) - goto done; - - state_record_time(sh, ctarget, now, enter_time, true); - - /* - * Update other cpus, (this_cpu = A, other cpus = B) if: - * - A = running and B != WFI | running: Set B to WFI - * - A = WFI and then B must be running: No changes - * - A = !WFI && !RUNNING and then B must be WFI: B sets to A - */ - - if (sh->state == CI_WFI) - goto done; - - for_each_possible_cpu(i) { - - if (this_cpu == i) - continue; - - sh_other = per_cpu(state_history, i); - - /* Same state, continue */ - if (sh_other->state == sh->state) - continue; - - if (cstates[ctarget].state == CI_RUNNING && - cstates[sh_other->state].state != CI_WFI) { - state_record_time(sh_other, CI_WFI, now, - enter_time, false); - continue; - } - /* - * This cpu is something else than running or wfi, both must be - * in the same state. - */ - state_record_time(sh_other, ctarget, now, enter_time, true); - } -done: - spin_unlock_irqrestore(&dbg_lock, flags); -} - -static void state_history_reset(void) -{ - unsigned long flags; - unsigned int cpu; - int i, j; - struct state_history *sh; - - spin_lock_irqsave(&dbg_lock, flags); - - for_each_possible_cpu(cpu) { - sh = per_cpu(state_history, cpu); - for (i = 0; i < cstates_len; i++) { - sh->states[i].counter = 0; - sh->states[i].hit_rate = 0; - sh->states[i].state_ok = 0; - sh->states[i].state_error = 0; - sh->states[i].prcmu_int = 0; - sh->states[i].pending_int = 0; - - sh->states[i].time = ktime_set(0, 0); - - for (j = 0; j < NUM_LATENCY; j++) { - sh->states[i].latency_count[j] = 0; - sh->states[i].latency_min[j] = ktime_set(0, - 10000000); - sh->states[i].latency_max[j] = ktime_set(0, 0); - sh->states[i].latency_sum[j] = ktime_set(0, 0); - } - } - - sh->start = ktime_get(); - sh->measure_begin = sh->start; - /* Don't touch sh->state, since that is where we are now */ - - sh->exit_counter = 0; - sh->ape_blocked = 0; - sh->time_blocked = 0; - sh->both_blocked = 0; - sh->gov_blocked = 0; - } - spin_unlock_irqrestore(&dbg_lock, flags); -} - -static int get_val(const char __user *user_buf, - size_t count, int min, int max) -{ - long unsigned val; - int err; - - err = kstrtoul_from_user(user_buf, count, 0, &val); - - if (err) - return err; - - if (val > max) - val = max; - if (val < min) - val = min; - - return val; -} - -static ssize_t set_deepest_state(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - int val; - - val = get_val(user_buf, count, CI_WFI, cstates_len - 1); - - if (val < 0) - return val; - - deepest_allowed_state = val; - - pr_debug("cpuidle: changed deepest allowed sleep state to %d.\n", - deepest_allowed_state); - - return count; -} - -static int deepest_state_print(struct seq_file *s, void *p) -{ - seq_printf(s, "Deepest allowed sleep state is %d\n", - deepest_allowed_state); - - return 0; -} - -static ssize_t stats_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - state_history_reset(); - return count; -} - -static int wake_latency_read(struct seq_file *s, void *p) -{ - seq_printf(s, "wake latency measurements is %s\n", - wake_latency ? "on" : "off"); - return 0; -} - -static ssize_t wake_latency_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - int val = get_val(user_buf, count, 0, 1); - if (val < 0) - return val; - - wake_latency = val; - ux500_rtcrtt_measure_latency(wake_latency); - return count; -} - -static int verbose_read(struct seq_file *s, void *p) -{ - seq_printf(s, "verbose debug is %s\n", verbose ? "on" : "off"); - return 0; -} - -static ssize_t verbose_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - int val = get_val(user_buf, count, 0, 1); - if (val < 0) - return val; - - verbose = val; - state_history_reset(); - - return count; -} - -static void stats_disp_one(struct seq_file *s, struct state_history *sh, - s64 total_us, int i) -{ - int j; - s64 avg[NUM_LATENCY]; - s64 t_us; - s64 perc; - ktime_t init_time, zero_time; - - init_time = ktime_set(0, 10000000); - zero_time = ktime_set(0, 0); - - memset(&avg, 0, sizeof(s64) * NUM_LATENCY); - - for (j = 0; j < NUM_LATENCY; j++) - avg[j] = ktime_to_us(sh->states[i].latency_sum[j]); - - t_us = ktime_to_us(sh->states[i].time); - perc = ktime_to_us(sh->states[i].time); - do_div(t_us, 1000); /* to ms */ - do_div(total_us, 100); - if (total_us) - do_div(perc, total_us); - - for (j = 0; j < NUM_LATENCY; j++) { - if (sh->states[i].latency_count[j]) - do_div(avg[j], sh->states[i].latency_count[j]); - } - - seq_printf(s, "\n%d - %s: %u", - i, cstates[i].desc, - sh->states[i].counter); - - if (sh->states[i].counter == 0) - return; - - if (i > CI_WFI && verbose) - seq_printf(s, " (%u prcmu_int:%u int:%u err:%u)", - sh->states[i].state_ok, - sh->states[i].prcmu_int, - sh->states[i].pending_int, - sh->states[i].state_error); - - seq_printf(s, " in %d ms %d%%", - (u32) t_us, (u32)perc); - - if (cstates[i].state == CI_IDLE && verbose) - seq_printf(s, ", reg:%d time:%d both:%d gov:%d", - sh->ape_blocked, sh->time_blocked, - sh->both_blocked, sh->gov_blocked); - - if (sh->states[i].counter && verbose) - seq_printf(s, ", hit rate: %u%% ", - 100 * sh->states[i].hit_rate / - sh->states[i].counter); - - if (i == CI_RUNNING || !(measure_latency || wake_latency)) - return; - - for (j = 0; j < NUM_LATENCY; j++) { - bool show = false; - if (!ktime_equal(sh->states[i].latency_min[j], init_time)) { - seq_printf(s, "\n\t\t\t\t"); - switch (j) { - case LATENCY_ENTER: - if (measure_latency) { - seq_printf(s, "enter: "); - show = true; - } - break; - case LATENCY_EXIT: - if (measure_latency) { - seq_printf(s, "exit: "); - show = true; - } - break; - case LATENCY_WAKE: - if (wake_latency) { - seq_printf(s, "wake: "); - show = true; - } - break; - default: - seq_printf(s, "unknown!: "); - break; - } - - if (!show) - continue; - - if (ktime_equal(sh->states[i].latency_min[j], - zero_time)) - seq_printf(s, "min < 30"); - else - seq_printf(s, "min %lld", - ktime_to_us(sh->states[i].latency_min[j])); - - seq_printf(s, " avg %lld max %lld us, count: %d", - avg[j], - ktime_to_us(sh->states[i].latency_max[j]), - sh->states[i].latency_count[j]); - } - } -} - -static int stats_print(struct seq_file *s, void *p) -{ - int cpu; - int i; - unsigned long flags; - struct state_history *sh; - ktime_t total, wall; - s64 total_us, total_s; - - for_each_online_cpu(cpu) { - sh = per_cpu(state_history, cpu); - spin_lock_irqsave(&dbg_lock, flags); - seq_printf(s, "\nCPU%d\n", cpu); - - total = ktime_set(0, 0); - - for (i = 0; i < cstates_len; i++) - total = ktime_add(total, sh->states[i].time); - - wall = ktime_sub(ktime_get(), sh->measure_begin); - - total_us = ktime_to_us(wall); - total_s = ktime_to_ms(wall); - - do_div(total_s, 1000); - - if (verbose) { - if (total_s) - seq_printf(s, - "wake ups per s: %u.%u \n", - sh->exit_counter / (int) total_s, - (10 * sh->exit_counter / (int) total_s) - - 10 * (sh->exit_counter / (int) total_s)); - - seq_printf(s, - "\ndelta accounted vs wall clock: %lld us\n", - ktime_to_us(ktime_sub(wall, total))); - } - - for (i = 0; i < cstates_len; i++) - stats_disp_one(s, sh, total_us, i); - - seq_printf(s, "\n"); - spin_unlock_irqrestore(&dbg_lock, flags); - } - seq_printf(s, "\n"); - return 0; -} - - -static int ap_family_show(struct seq_file *s, void *iter) -{ - int i; - u32 count = 0; - unsigned long flags; - struct state_history *sh; - - sh = per_cpu(state_history, 0); - spin_lock_irqsave(&dbg_lock, flags); - - for (i = 0 ; i < cstates_len; i++) { - if (cstates[i].state == (enum ci_pwrst)s->private) - count += sh->states[i].counter; - } - - seq_printf(s, "%u\n", count); - spin_unlock_irqrestore(&dbg_lock, flags); - - return 0; -} - -static int deepest_state_open_file(struct inode *inode, struct file *file) -{ - return single_open(file, deepest_state_print, inode->i_private); -} - -static int verbose_open_file(struct inode *inode, struct file *file) -{ - return single_open(file, verbose_read, inode->i_private); -} - -static int stats_open_file(struct inode *inode, struct file *file) -{ - return single_open(file, stats_print, inode->i_private); -} - -static int ap_family_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ap_family_show, inode->i_private); -} - -static int wake_latency_open(struct inode *inode, - struct file *file) -{ - return single_open(file, wake_latency_read, inode->i_private); -} - -static const struct file_operations deepest_state_fops = { - .open = deepest_state_open_file, - .write = set_deepest_state, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations verbose_state_fops = { - .open = verbose_open_file, - .write = verbose_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations stats_fops = { - .open = stats_open_file, - .write = stats_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations ap_family_fops = { - .open = ap_family_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations wake_latency_fops = { - .open = wake_latency_open, - .write = wake_latency_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static struct dentry *cpuidle_dir; - -static void __init setup_debugfs(void) -{ - cpuidle_dir = debugfs_create_dir("cpuidle", NULL); - if (IS_ERR_OR_NULL(cpuidle_dir)) - goto fail; - - if (IS_ERR_OR_NULL(debugfs_create_file("deepest_state", - S_IWUGO | S_IRUGO, cpuidle_dir, - NULL, &deepest_state_fops))) - goto fail; - - if (IS_ERR_OR_NULL(debugfs_create_file("verbose", - S_IWUGO | S_IRUGO, cpuidle_dir, - NULL, &verbose_state_fops))) - goto fail; - - if (IS_ERR_OR_NULL(debugfs_create_file("stats", - S_IRUGO, cpuidle_dir, NULL, - &stats_fops))) - goto fail; - - if (IS_ERR_OR_NULL(debugfs_create_bool("dbg_console_enable", - S_IWUGO | S_IRUGO, cpuidle_dir, - &dbg_console_enable))) - goto fail; - - if (IS_ERR_OR_NULL(debugfs_create_bool("measure_latency", - S_IWUGO | S_IRUGO, cpuidle_dir, - &measure_latency))) - goto fail; - - - if (IS_ERR_OR_NULL(debugfs_create_file("wake_latency", - S_IWUGO | S_IRUGO, cpuidle_dir, - NULL, - &wake_latency_fops))) - goto fail; - - if (IS_ERR_OR_NULL(debugfs_create_file("ap_idle", S_IRUGO, - cpuidle_dir, - (void *)CI_IDLE, - &ap_family_fops))) - goto fail; - - if (IS_ERR_OR_NULL(debugfs_create_file("ap_sleep", S_IRUGO, - cpuidle_dir, - (void *)CI_SLEEP, - &ap_family_fops))) - goto fail; - - if (IS_ERR_OR_NULL(debugfs_create_file("ap_deepidle", S_IRUGO, - cpuidle_dir, - (void *)CI_DEEP_IDLE, - &ap_family_fops))) - goto fail; - - if (IS_ERR_OR_NULL(debugfs_create_file("ap_deepsleep", S_IRUGO, - cpuidle_dir, - (void *)CI_DEEP_SLEEP, - &ap_family_fops))) - goto fail; - - return; -fail: - debugfs_remove_recursive(cpuidle_dir); -} - -#define __UART_BASE(soc, x) soc##_UART##x##_BASE -#define UART_BASE(soc, x) __UART_BASE(soc, x) - -void __init ux500_ci_dbg_init(void) -{ - static const char clkname[] __initconst - = "uart" __stringify(CONFIG_UX500_DEBUG_UART); - unsigned long baseaddr; - int cpu; - - struct state_history *sh; - - cstates = ux500_ci_get_cstates(&cstates_len); - - if (deepest_allowed_state > cstates_len) - deepest_allowed_state = cstates_len; - - for_each_possible_cpu(cpu) { - per_cpu(state_history, cpu) = kzalloc(sizeof(struct state_history), - GFP_KERNEL); - sh = per_cpu(state_history, cpu); - sh->states = kzalloc(sizeof(struct state_history_state) - * cstates_len, - GFP_KERNEL); - } - - state_history_reset(); - - for_each_possible_cpu(cpu) { - sh = per_cpu(state_history, cpu); - /* Only first CPU used during boot */ - if (cpu == 0) - sh->state = CI_RUNNING; - else - sh->state = CI_WFI; - } - - setup_debugfs(); - - /* Uart debug init */ - - if (cpu_is_u8500()) - baseaddr = UART_BASE(U8500, CONFIG_UX500_DEBUG_UART); - else if (cpu_is_u5500()) - baseaddr = UART_BASE(U5500, CONFIG_UX500_DEBUG_UART); - else - ux500_unknown_soc(); - - uart_base = ioremap(baseaddr, SZ_4K); - BUG_ON(!uart_base); - - uart_clk = clk_get_sys(clkname, NULL); - BUG_ON(IS_ERR(uart_clk)); - - INIT_DELAYED_WORK_DEFERRABLE(&cpuidle_work, dbg_cpuidle_work_function); - -} - -void ux500_ci_dbg_remove(void) -{ - int cpu; - struct state_history *sh; - - debugfs_remove_recursive(cpuidle_dir); - - for_each_possible_cpu(cpu) { - sh = per_cpu(state_history, cpu); - kfree(sh->states); - kfree(sh); - } - - iounmap(uart_base); -} diff --git a/arch/arm/mach-ux500/pm/cpuidle_dbg.h b/arch/arm/mach-ux500/pm/cpuidle_dbg.h deleted file mode 100644 index b660b039900..00000000000 --- a/arch/arm/mach-ux500/pm/cpuidle_dbg.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010-2011 - * - * License Terms: GNU General Public License v2 - * Author: Rickard Andersson <rickard.andersson@stericsson.com> for ST-Ericsson - * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson - */ - -#ifndef CPUIDLE_DBG_H -#define CPUIDLE_DBG_H - -#include "cpuidle.h" - -#ifdef CONFIG_U8500_CPUIDLE_DEBUG -void ux500_ci_dbg_init(void); -void ux500_ci_dbg_remove(void); - -void ux500_ci_dbg_log(int ctarget, ktime_t enter_time); -void ux500_ci_dbg_wake_latency(int ctarget, int sleep_time); -void ux500_ci_dbg_exit_latency(int ctarget, ktime_t now, ktime_t exit, - ktime_t enter); - -void ux500_ci_dbg_register_reason(int idx, bool power_state_req, - u32 sleep_time, u32 max_depth); - -bool ux500_ci_dbg_force_ape_on(void); -int ux500_ci_dbg_deepest_state(void); - -void ux500_ci_dbg_console(void); -void ux500_ci_dbg_console_check_uart(void); -void ux500_ci_dbg_console_handle_ape_resume(void); -void ux500_ci_dbg_console_handle_ape_suspend(void); - -#else - -static inline void ux500_ci_dbg_init(void) { } -static inline void ux500_ci_dbg_remove(void) { } - -static inline void ux500_ci_dbg_log(int ctarget, - ktime_t enter_time) { } - -static inline void ux500_ci_dbg_exit_latency(int ctarget, - ktime_t now, ktime_t exit, - ktime_t enter) { } -static inline void ux500_ci_dbg_wake_latency(int ctarget, int sleep_time) { } - - -static inline void ux500_ci_dbg_register_reason(int idx, bool power_state_req, - u32 sleep_time, u32 max_depth) { } - -static inline bool ux500_ci_dbg_force_ape_on(void) -{ - return false; -} - -static inline int ux500_ci_dbg_deepest_state(void) -{ - /* This means no lower sleep state than ApIdle */ - return CONFIG_U8500_CPUIDLE_DEEPEST_STATE; -} - -static inline void ux500_ci_dbg_console(void) { } -static inline void ux500_ci_dbg_console_check_uart(void) { } -static inline void ux500_ci_dbg_console_handle_ape_resume(void) { } -static inline void ux500_ci_dbg_console_handle_ape_suspend(void) { } - -#endif -#endif diff --git a/arch/arm/mach-ux500/pm/performance.c b/arch/arm/mach-ux500/pm/performance.c deleted file mode 100644 index 81d918107b9..00000000000 --- a/arch/arm/mach-ux500/pm/performance.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * License Terms: GNU General Public License v2 - * Author: Johan Rudholm <johan.rudholm@stericsson.com> - */ - -#include <linux/kernel.h> -#include <mach/prcmu-qos.h> -#include <linux/genhd.h> -#include <linux/major.h> -#include <linux/cdev.h> - -/* - * TODO: - * o Develop a more power-aware algorithm - * o Make the parameters visible through debugfs - * o Get the value of CONFIG_MMC_BLOCK_MINORS in runtime instead, since - * it may be altered by drivers/mmc/card/block.c - */ - -/* Sample reads and writes every n ms */ -#define PERF_MMC_PROBE_DELAY 1000 -/* Read threshold, sectors/second */ -#define PERF_MMC_LIMIT_READ 10240 -/* Write threshold, sectors/second */ -#define PERF_MMC_LIMIT_WRITE 8192 -/* Nr of MMC devices */ -#define PERF_MMC_HOSTS 8 - -/* - * Rescan for new MMC devices every - * PERF_MMC_PROBE_DELAY * PERF_MMC_RESCAN_CYCLES ms - */ -#define PERF_MMC_RESCAN_CYCLES 10 - -static struct delayed_work work_mmc; - -/* - * Loop through every CONFIG_MMC_BLOCK_MINORS'th minor device for - * MMC_BLOCK_MAJOR, get the struct gendisk for each device. Returns - * nr of found disks. Populate mmc_disks. - */ -static int scan_mmc_devices(struct gendisk *mmc_disks[]) -{ - dev_t devnr; - int i, j = 0, part; - struct gendisk *mmc_devices[256 / CONFIG_MMC_BLOCK_MINORS]; - - memset(&mmc_devices, 0, sizeof(mmc_devices)); - - for (i = 0; i * CONFIG_MMC_BLOCK_MINORS < 256; i++) { - devnr = MKDEV(MMC_BLOCK_MAJOR, i * CONFIG_MMC_BLOCK_MINORS); - mmc_devices[i] = get_gendisk(devnr, &part); - - /* Invalid capacity of device, do not add to list */ - if (!mmc_devices[i] || !get_capacity(mmc_devices[i])) - continue; - - mmc_disks[j] = mmc_devices[i]; - j++; - - if (j == PERF_MMC_HOSTS) - break; - } - - return j; -} - -/* - * Sample sectors read and written to any MMC devices, update PRCMU - * qos requirement - */ -static void mmc_load(struct work_struct *work) -{ - static unsigned long long old_sectors_read[PERF_MMC_HOSTS]; - static unsigned long long old_sectors_written[PERF_MMC_HOSTS]; - static struct gendisk *mmc_disks[PERF_MMC_HOSTS]; - static int cycle, nrdisk; - static bool old_mode; - unsigned long long sectors; - bool new_mode = false; - int i; - - if (!cycle) { - memset(&mmc_disks, 0, sizeof(mmc_disks)); - nrdisk = scan_mmc_devices(mmc_disks); - cycle = PERF_MMC_RESCAN_CYCLES; - } - cycle--; - - for (i = 0; i < nrdisk; i++) { - sectors = part_stat_read(&(mmc_disks[i]->part0), - sectors[READ]); - - if (old_sectors_read[i] && - sectors > old_sectors_read[i] && - (sectors - old_sectors_read[i]) > - PERF_MMC_LIMIT_READ) - new_mode = true; - - old_sectors_read[i] = sectors; - sectors = part_stat_read(&(mmc_disks[i]->part0), - sectors[WRITE]); - - if (old_sectors_written[i] && - sectors > old_sectors_written[i] && - (sectors - old_sectors_written[i]) > - PERF_MMC_LIMIT_WRITE) - new_mode = true; - - old_sectors_written[i] = sectors; - } - - if (!old_mode && new_mode) - prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, - "mmc", 125); - - if (old_mode && !new_mode) - prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, - "mmc", 25); - - old_mode = new_mode; - - schedule_delayed_work(&work_mmc, - msecs_to_jiffies(PERF_MMC_PROBE_DELAY)); - -} - - -static int __init performance_register(void) -{ - int ret; - - prcmu_qos_add_requirement(PRCMU_QOS_ARM_OPP, "mmc", 25); - - INIT_DELAYED_WORK_DEFERRABLE(&work_mmc, mmc_load); - ret = schedule_delayed_work(&work_mmc, - msecs_to_jiffies(PERF_MMC_PROBE_DELAY)); - - return ret; -} -late_initcall(performance_register); diff --git a/arch/arm/mach-ux500/pm/pm.c b/arch/arm/mach-ux500/pm/pm.c deleted file mode 100644 index ae6951ede45..00000000000 --- a/arch/arm/mach-ux500/pm/pm.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * Author: Rickard Andersson <rickard.andersson@stericsson.com> for - * ST-Ericsson. - * License terms: GNU General Public License (GPL) version 2 - * - */ - -#include <linux/io.h> -#include <linux/percpu.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/gpio.h> -#include <linux/gpio/nomadik.h> - -#include <asm/hardware/gic.h> -#include <asm/processor.h> - -#include <mach/hardware.h> -#include <mach/prcmu-regs.h> - -#include "pm.h" - -#define STABILIZATION_TIME 30 /* us */ -#define GIC_FREEZE_DELAY 1 /* us */ - -#define PRCM_ARM_WFI_STANDBY_CPU0_WFI 0x8 -#define PRCM_ARM_WFI_STANDBY_CPU1_WFI 0x10 - -static u32 u8500_gpio_banks[] = {U8500_GPIOBANK0_BASE, - U8500_GPIOBANK1_BASE, - U8500_GPIOBANK2_BASE, - U8500_GPIOBANK3_BASE, - U8500_GPIOBANK4_BASE, - U8500_GPIOBANK5_BASE, - U8500_GPIOBANK6_BASE, - U8500_GPIOBANK7_BASE, - U8500_GPIOBANK8_BASE}; - -static u32 u5500_gpio_banks[] = {U5500_GPIOBANK0_BASE, - U5500_GPIOBANK1_BASE, - U5500_GPIOBANK2_BASE, - U5500_GPIOBANK3_BASE, - U5500_GPIOBANK4_BASE, - U5500_GPIOBANK5_BASE, - U5500_GPIOBANK6_BASE, - U5500_GPIOBANK7_BASE}; - -static u32 ux500_gpio_wks[ARRAY_SIZE(u8500_gpio_banks)]; - -inline int ux500_pm_arm_on_ext_clk(bool leave_arm_pll_on) -{ - return 0; -} - -/* Decouple GIC from the interrupt bus */ -void ux500_pm_gic_decouple(void) -{ - writel(readl(PRCM_A9_MASK_REQ) | PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ, - PRCM_A9_MASK_REQ); - - while (!readl(PRCM_A9_MASK_REQ)) - cpu_relax(); - - /* TODO: Use the ack bit when possible */ - udelay(GIC_FREEZE_DELAY); /* Wait for the GIC to freeze */ -} - -/* Recouple GIC with the interrupt bus */ -void ux500_pm_gic_recouple(void) -{ - writel((readl(PRCM_A9_MASK_REQ) & ~PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ), - PRCM_A9_MASK_REQ); - - /* TODO: Use the ack bit when possible */ -} - -#define GIC_NUMBER_REGS 5 -bool ux500_pm_gic_pending_interrupt(void) -{ - u32 pr; /* Pending register */ - u32 er; /* Enable register */ - int i; - - /* 5 registers. STI & PPI not skipped */ - for (i = 0; i < GIC_NUMBER_REGS; i++) { - - pr = readl_relaxed(__io_address(U8500_GIC_DIST_BASE) + - GIC_DIST_PENDING_SET + i * 4); - er = readl_relaxed(__io_address(U8500_GIC_DIST_BASE) + - GIC_DIST_ENABLE_SET + i * 4); - - if (pr & er) - return true; /* There is a pending interrupt */ - } - return false; -} - -#define GIC_NUMBER_SPI_REGS 4 -bool ux500_pm_prcmu_pending_interrupt(void) -{ - u32 it; - u32 im; - int i; - - for (i = 0; i < GIC_NUMBER_SPI_REGS; i++) { /* There are 4 registers */ - - it = readl(PRCM_ARMITVAL31TO0 + i * 4); - im = readl(PRCM_ARMITMSK31TO0 + i * 4); - - if (it & im) - return true; /* There is a pending interrupt */ - } - - return false; -} - -void ux500_pm_prcmu_set_ioforce(bool enable) -{ - if (enable) - writel(readl(PRCM_IOCR) | PRCM_IOCR_IOFORCE, PRCM_IOCR); - else - writel(readl(PRCM_IOCR) & ~PRCM_IOCR_IOFORCE, PRCM_IOCR); -} - -void ux500_pm_prcmu_copy_gic_settings(void) -{ - u32 er; /* Enable register */ - int i; - - for (i = 0; i < GIC_NUMBER_SPI_REGS; i++) { /* 4*32 SPI interrupts */ - /* +1 due to skip STI and PPI */ - er = readl_relaxed(__io_address(U8500_GIC_DIST_BASE) + - GIC_DIST_ENABLE_SET + (i + 1) * 4); - writel(er, PRCM_ARMITMSK31TO0 + i * 4); - } -} - -void ux500_pm_gpio_save_wake_up_status(void) -{ - int num_banks; - u32 *banks; - int i; - - if (cpu_is_u5500()) { - num_banks = ARRAY_SIZE(u5500_gpio_banks); - banks = u5500_gpio_banks; - } else { - num_banks = ARRAY_SIZE(u8500_gpio_banks); - banks = u8500_gpio_banks; - } - - nmk_gpio_clocks_enable(); - - for (i = 0; i < num_banks; i++) - ux500_gpio_wks[i] = readl(__io_address(banks[i]) + NMK_GPIO_WKS); - - nmk_gpio_clocks_disable(); -} - -u32 ux500_pm_gpio_read_wake_up_status(unsigned int bank_num) -{ - if (WARN_ON(cpu_is_u5500() && bank_num >= - ARRAY_SIZE(u5500_gpio_banks))) - return 0; - - if (WARN_ON(cpu_is_u8500() && bank_num >= - ARRAY_SIZE(u8500_gpio_banks))) - return 0; - - return ux500_gpio_wks[bank_num]; -} - -/* Check if the other CPU is in WFI */ -bool ux500_pm_other_cpu_wfi(void) -{ - if (smp_processor_id()) { - /* We are CPU 1 => check if CPU0 is in WFI */ - if (readl(PRCM_ARM_WFI_STANDBY) & - PRCM_ARM_WFI_STANDBY_CPU0_WFI) - return true; - } else { - /* We are CPU 0 => check if CPU1 is in WFI */ - if (readl(PRCM_ARM_WFI_STANDBY) & - PRCM_ARM_WFI_STANDBY_CPU1_WFI) - return true; - } - - return false; -} - -/* PRCM_ACK_MB0_AP_PWRSTTR_STATUS */ -#define DB8500_PRCMU_STATUS_REGISTER 0x801b8e08 -#define DB5500_PRCMU_STATUS_REGISTER 0x80168f38 - -enum prcmu_idle_stat ux500_pm_prcmu_idle_stat(void) -{ - u32 val; - void __iomem *prcmu_status_reg; - - if (cpu_is_u8500()) - prcmu_status_reg = __io_address(DB8500_PRCMU_STATUS_REGISTER); - else if (cpu_is_u5500()) - prcmu_status_reg = __io_address(DB5500_PRCMU_STATUS_REGISTER); - else - ux500_unknown_soc(); - - val = readl(prcmu_status_reg) & 0xff; - - return (enum prcmu_idle_stat)val; -} diff --git a/arch/arm/mach-ux500/pm/pm.h b/arch/arm/mach-ux500/pm/pm.h index 8b58bd52e18..af95d7b2325 100644 --- a/arch/arm/mach-ux500/pm/pm.h +++ b/arch/arm/mach-ux500/pm/pm.h @@ -10,113 +10,9 @@ #define PM_COMMON_H #ifdef CONFIG_PM - -enum prcmu_idle_stat { - SLEEP_OK = 0xf3, - DEEP_SLEEP_OK = 0xf6, - IDLE_OK = 0xf0, - DEEPIDLE_OK = 0xe3, - PRCMU2ARMPENDINGIT_ER = 0x91, - ARMPENDINGIT_ER = 0x93, -}; - -/** - * ux500_pm_gic_decouple() - * - * Decouple GIC from the interrupt bus. - */ -void ux500_pm_gic_decouple(void); - -/** - * ux500_pm_gic_recouple() - * - * Recouple GIC with the interrupt bus. - */ -void ux500_pm_gic_recouple(void); - -/** - * ux500_pm_gic_pending_interrupt() - * - * returns true, if there are pending interrupts. - */ -bool ux500_pm_gic_pending_interrupt(void); - -/** - * ux500_pm_prcmu_pending_interrupt() - * - * returns true, if there are pending interrupts. - */ -bool ux500_pm_prcmu_pending_interrupt(void); - -/** - * ux500_pm_prcmu_set_ioforce() - * - * @enable: Enable/disable - * - * Enable/disable the gpio-ring - */ -void ux500_pm_prcmu_set_ioforce(bool enable); - -/** - * ux500_pm_prcmu_copy_gic_settings() - * - * This function copies all the gic interrupt settings to the prcmu. - * This is needed for the system to catch interrupts in ApIdle - */ -void ux500_pm_prcmu_copy_gic_settings(void); - -/** - * ux500_pm_gpio_save_wake_up_status() - * - * This function is called when the prcmu has woken the ARM - * but before ioforce is disabled. - */ -void ux500_pm_gpio_save_wake_up_status(void); - -/** - * ux500_pm_gpio_read_wake_up_status() - * - * @bank_number: The gpio bank. - * - * Returns the WKS register settings for given bank number. - * The WKS register is cleared when ioforce is released therefore - * this function is needed. - */ -u32 ux500_pm_gpio_read_wake_up_status(unsigned int bank_number); - -/** - * ux500_pm_other_cpu_wfi() - * - * Returns true if the other CPU is in WFI. - */ -bool ux500_pm_other_cpu_wfi(void); - -/** - * ux500_pm_prcmu_idle_stat() - * - * Returns the status of the last prcmu idle/sleep - */ -enum prcmu_idle_stat ux500_pm_prcmu_idle_stat(void); - struct dev_power_domain; extern struct dev_power_domain ux500_dev_power_domain; extern struct dev_power_domain ux500_amba_dev_power_domain; - -#else -u32 ux500_pm_gpio_read_wake_up_status(unsigned int bank_number) -{ - return 0; -} - -/** - * ux500_pm_prcmu_set_ioforce() - * - * @enable: Enable/disable - * - * Enable/disable the gpio-ring - */ -static inline void ux500_pm_prcmu_set_ioforce(bool enable) { } - #endif #endif diff --git a/arch/arm/mach-ux500/pm/suspend.c b/arch/arm/mach-ux500/pm/suspend.c deleted file mode 100644 index f0a9433b9fb..00000000000 --- a/arch/arm/mach-ux500/pm/suspend.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (C) STMicroelectronics 2009 - * Copyright (C) ST-Ericsson SA 2010-2011 - * - * License Terms: GNU General Public License v2 - * - * Authors: Rickard Andersson <rickard.andersson@stericsson.com>, - * Jonas Aaberg <jonas.aberg@stericsson.com>, - * Sundar Iyer for ST-Ericsson. - * - */ - -#include <linux/suspend.h> -#include <linux/gpio.h> -#include <linux/delay.h> -#include <linux/regulator/ab8500-debug.h> -#include <linux/gpio/nomadik.h> - -#include <mach/prcmu.h> -#include <mach/prcmu-regs.h> -#include <mach/prcmu-qos.h> -#include <mach/regulator.h> - -#include "context.h" -#include "pm.h" -#include "suspend_dbg.h" - -static void (*pins_suspend_force)(void); -static void (*pins_suspend_force_mux)(void); - -void suspend_set_pins_force_fn(void (*force)(void), void (*force_mux)(void)) -{ - pins_suspend_force = force; - pins_suspend_force_mux = force_mux; -} - -static atomic_t block_sleep = ATOMIC_INIT(0); - -void suspend_block_sleep(void) -{ - atomic_inc(&block_sleep); -} - -void suspend_unblock_sleep(void) -{ - atomic_dec(&block_sleep); -} - -static bool sleep_is_blocked(void) -{ - return (atomic_read(&block_sleep) != 0); -} - -static int suspend(bool do_deepsleep) -{ - bool pins_force = pins_suspend_force_mux && pins_suspend_force; - int ret = 0; - - if (sleep_is_blocked()) { - pr_info("suspend/resume: interrupted by modem.\n"); - return -EBUSY; - } - - nmk_gpio_clocks_enable(); - - ux500_suspend_dbg_add_wake_on_uart(); - nmk_gpio_wakeups_suspend(); - - /* configure the prcm for a sleep wakeup */ - prcmu_enable_wakeups(PRCMU_WAKEUP(ABB)); - - context_vape_save(); - - if (pins_force) { - /* - * Save GPIO settings before applying power save - * settings - */ - context_gpio_save(); - - /* Apply GPIO power save mux settings */ - context_gpio_mux_safe_switch(true); - pins_suspend_force_mux(); - context_gpio_mux_safe_switch(false); - - /* Apply GPIO power save settings */ - pins_suspend_force(); - } - - ux500_pm_gic_decouple(); - - if (ux500_pm_gic_pending_interrupt()) { - pr_info("suspend/resume: pending interrupt\n"); - - /* Recouple GIC with the interrupt bus */ - ux500_pm_gic_recouple(); - ret = -EBUSY; - - goto exit; - } - ux500_pm_prcmu_set_ioforce(true); - - if (do_deepsleep) { - context_varm_save_common(); - context_varm_save_core(); - context_gic_dist_disable_unneeded_irqs(); - context_save_cpu_registers(); - - /* - * Due to we have only 100us between requesting a powerstate - * and wfi, we clean the cache before as well to assure the - * final cache clean before wfi has as little as possible to - * do. - */ - context_clean_l1_cache_all(); - - (void) prcmu_set_power_state(PRCMU_AP_DEEP_SLEEP, - false, false); - context_save_to_sram_and_wfi(true); - - context_restore_cpu_registers(); - context_varm_restore_core(); - context_varm_restore_common(); - - } else { - - context_clean_l1_cache_all(); - (void) prcmu_set_power_state(APEXECUTE_TO_APSLEEP, - false, false); - dsb(); - __asm__ __volatile__("wfi\n\t" : : : "memory"); - } - - context_vape_restore(); - - /* If GPIO woke us up then save the pins that caused the wake up */ - ux500_pm_gpio_save_wake_up_status(); - - ux500_suspend_dbg_sleep_status(do_deepsleep); - - /* APE was turned off, restore IO ring */ - ux500_pm_prcmu_set_ioforce(false); - -exit: - if (pins_force) { - /* Restore gpio settings */ - context_gpio_mux_safe_switch(true); - context_gpio_restore_mux(); - context_gpio_mux_safe_switch(false); - context_gpio_restore(); - } - - /* This is what cpuidle wants */ - prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) | - PRCMU_WAKEUP(ABB)); - - nmk_gpio_wakeups_resume(); - ux500_suspend_dbg_remove_wake_on_uart(); - - nmk_gpio_clocks_disable(); - - return ret; -} - -static int ux500_suspend_enter(suspend_state_t state) -{ - - if (ux500_suspend_enabled()) { - if (ux500_suspend_deepsleep_enabled() && - state == PM_SUSPEND_MEM) - return suspend(true); - if (ux500_suspend_sleep_enabled()) - return suspend(false); - } - - ux500_suspend_dbg_add_wake_on_uart(); - /* - * Set IOFORCE in order to wake on GPIO the same way - * as in deeper sleep. - * (U5500 is not ready for IOFORCE) - */ - if (!cpu_is_u5500()) - ux500_pm_prcmu_set_ioforce(true); - - dsb(); - __asm__ __volatile__("wfi\n\t" : : : "memory"); - - if (!cpu_is_u5500()) - ux500_pm_prcmu_set_ioforce(false); - ux500_suspend_dbg_remove_wake_on_uart(); - - return 0; -} - -static int ux500_suspend_valid(suspend_state_t state) -{ - return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY; -} - -static int ux500_suspend_prepare_late(void) -{ - /* ESRAM to retention instead of OFF until ROM is fixed */ - (void)prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); - ab8500_regulator_debug_force(); - ux500_regulator_suspend_debug(); - - return 0; -} - -static void ux500_suspend_wake(void) -{ - ux500_regulator_resume_debug(); - ab8500_regulator_debug_restore(); - (void)prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); -} - -static int ux500_suspend_begin(suspend_state_t state) -{ - prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, - "suspend", 100); - return ux500_suspend_dbg_begin(state); -} - -static void ux500_suspend_end(void) -{ - prcmu_qos_update_requirement(PRCMU_QOS_ARM_OPP, - "suspend", 25); -} - -static struct platform_suspend_ops ux500_suspend_ops = { - .enter = ux500_suspend_enter, - .valid = ux500_suspend_valid, - .prepare_late = ux500_suspend_prepare_late, - .wake = ux500_suspend_wake, - .begin = ux500_suspend_begin, - .end = ux500_suspend_end, -}; - -static __init int ux500_suspend_init(void) -{ - ux500_suspend_dbg_init(); - - prcmu_qos_add_requirement(PRCMU_QOS_ARM_OPP, "suspend", 25); - - suspend_set_ops(&ux500_suspend_ops); - return 0; -} - -device_initcall(ux500_suspend_init); diff --git a/arch/arm/mach-ux500/pm/suspend_dbg.c b/arch/arm/mach-ux500/pm/suspend_dbg.c deleted file mode 100644 index d89e280c9dd..00000000000 --- a/arch/arm/mach-ux500/pm/suspend_dbg.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * License Terms: GNU General Public License v2 - * - * Author: Rickard Andersson <rickard.andersson@stericsson.com>, - * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson - * - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/suspend.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/uaccess.h> - -#include "pm.h" - -#ifdef CONFIG_UX500_SUSPEND_STANDBY -static u32 sleep_enabled = 1; -#else -static u32 sleep_enabled; -#endif - -#ifdef CONFIG_UX500_SUSPEND_MEM -static u32 deepsleep_enabled = 1; -#else -static u32 deepsleep_enabled; -#endif - -static u32 suspend_enabled = 1; - -static u32 deepsleeps_done; -static u32 deepsleeps_failed; -static u32 sleeps_done; -static u32 sleeps_failed; -static u32 suspend_count; - -#ifdef CONFIG_UX500_SUSPEND_DBG_WAKE_ON_UART -void ux500_suspend_dbg_add_wake_on_uart(void) -{ - irq_set_irq_wake(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), 1); - irq_set_irq_type(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), - IRQ_TYPE_EDGE_BOTH); -} - -void ux500_suspend_dbg_remove_wake_on_uart(void) -{ - irq_set_irq_wake(GPIO_TO_IRQ(CONFIG_UX500_CONSOLE_UART_GPIO_PIN), 0); -} -#endif - -bool ux500_suspend_enabled(void) -{ - return suspend_enabled != 0; -} - -bool ux500_suspend_sleep_enabled(void) -{ - return sleep_enabled != 0; -} - -bool ux500_suspend_deepsleep_enabled(void) -{ - return deepsleep_enabled != 0; -} - -void ux500_suspend_dbg_sleep_status(bool is_deepsleep) -{ - enum prcmu_idle_stat prcmu_status; - - prcmu_status = ux500_pm_prcmu_idle_stat(); - - if (is_deepsleep) { - pr_info("Returning from ApDeepSleep. PRCMU ret: 0x%x - %s\n", - prcmu_status, - prcmu_status == DEEP_SLEEP_OK ? "Success" : "Fail!"); - if (prcmu_status == DEEP_SLEEP_OK) - deepsleeps_done++; - else - deepsleeps_failed++; - } else { - pr_info("Returning from ApSleep. PRCMU ret: 0x%x - %s\n", - prcmu_status, - prcmu_status == SLEEP_OK ? "Success" : "Fail!"); - if (prcmu_status == SLEEP_OK) - sleeps_done++; - else - sleeps_failed++; - } -} - -int ux500_suspend_dbg_begin(suspend_state_t state) -{ - suspend_count++; - return 0; -} - -void ux500_suspend_dbg_init(void) -{ - struct dentry *suspend_dir = NULL; - struct dentry *sleep_file = NULL; - struct dentry *deepsleep_file = NULL; - struct dentry *enable_file = NULL; - struct dentry *suspend_count_file = NULL; - struct dentry *sleeps_done_file = NULL; - struct dentry *deepsleeps_done_file = NULL; - struct dentry *sleeps_failed_file = NULL; - struct dentry *deepsleeps_failed_file = NULL; - - suspend_dir = debugfs_create_dir("suspend", NULL); - if (IS_ERR_OR_NULL(suspend_dir)) - return; - - sleep_file = debugfs_create_bool("sleep", S_IWUGO | S_IRUGO, - suspend_dir, - &sleep_enabled); - if (IS_ERR_OR_NULL(sleep_file)) - goto error; - - deepsleep_file = debugfs_create_bool("deepsleep", S_IWUGO | S_IRUGO, - suspend_dir, - &deepsleep_enabled); - if (IS_ERR_OR_NULL(deepsleep_file)) - goto error; - - enable_file = debugfs_create_bool("enable", S_IWUGO | S_IRUGO, - suspend_dir, - &suspend_enabled); - if (IS_ERR_OR_NULL(enable_file)) - goto error; - - suspend_count_file = debugfs_create_u32("count", S_IRUGO, - suspend_dir, - &suspend_count); - if (IS_ERR_OR_NULL(suspend_count_file)) - goto error; - - sleeps_done_file = debugfs_create_u32("sleep_count", S_IRUGO, - suspend_dir, - &sleeps_done); - if (IS_ERR_OR_NULL(sleeps_done_file)) - goto error; - - deepsleeps_done_file = debugfs_create_u32("deepsleep_count", S_IRUGO, - suspend_dir, - &deepsleeps_done); - if (IS_ERR_OR_NULL(deepsleeps_done_file)) - goto error; - - - sleeps_failed_file = debugfs_create_u32("sleep_failed", S_IRUGO, - suspend_dir, - &sleeps_failed); - if (IS_ERR_OR_NULL(sleeps_failed_file)) - goto error; - - deepsleeps_failed_file = debugfs_create_u32("deepsleep_failed", S_IRUGO, - suspend_dir, - &deepsleeps_failed); - if (IS_ERR_OR_NULL(deepsleeps_failed_file)) - goto error; - - return; -error: - if (!IS_ERR_OR_NULL(deepsleeps_failed_file)) - debugfs_remove(deepsleeps_failed_file); - if (!IS_ERR_OR_NULL(sleeps_failed_file)) - debugfs_remove(sleeps_failed_file); - if (!IS_ERR_OR_NULL(deepsleeps_done_file)) - debugfs_remove(deepsleeps_done_file); - if (!IS_ERR_OR_NULL(sleeps_done_file)) - debugfs_remove(sleeps_done_file); - if (!IS_ERR_OR_NULL(suspend_count_file)) - debugfs_remove(suspend_count_file); - if (!IS_ERR_OR_NULL(enable_file)) - debugfs_remove(enable_file); - if (!IS_ERR_OR_NULL(deepsleep_file)) - debugfs_remove(deepsleep_file); - if (!IS_ERR_OR_NULL(sleep_file)) - debugfs_remove(sleep_file); - - debugfs_remove(suspend_dir); -} diff --git a/arch/arm/mach-ux500/pm/suspend_dbg.h b/arch/arm/mach-ux500/pm/suspend_dbg.h deleted file mode 100644 index bd2afb93472..00000000000 --- a/arch/arm/mach-ux500/pm/suspend_dbg.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * License Terms: GNU General Public License v2 - * - * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson - * - */ - -#ifndef UX500_SUSPEND_DBG_H -#define UX500_SUSPEND_DBG_H - -#include <linux/kernel.h> -#include <linux/suspend.h> - -#ifdef CONFIG_UX500_SUSPEND_DBG_WAKE_ON_UART -void ux500_suspend_dbg_add_wake_on_uart(void); -void ux500_suspend_dbg_remove_wake_on_uart(void); -#else -static inline void ux500_suspend_dbg_add_wake_on_uart(void) { } -static inline void ux500_suspend_dbg_remove_wake_on_uart(void) { } -#endif - -#ifdef CONFIG_UX500_SUSPEND_DBG -bool ux500_suspend_enabled(void); -bool ux500_suspend_sleep_enabled(void); -bool ux500_suspend_deepsleep_enabled(void); -void ux500_suspend_dbg_sleep_status(bool is_deepsleep); -void ux500_suspend_dbg_init(void); -int ux500_suspend_dbg_begin(suspend_state_t state); - -#else -static inline bool ux500_suspend_enabled(void) -{ - return true; -} -static inline bool ux500_suspend_sleep_enabled(void) -{ -#ifdef CONFIG_UX500_SUSPEND_STANDBY - return true; -#else - return false; -#endif -} -static inline bool ux500_suspend_deepsleep_enabled(void) -{ -#ifdef CONFIG_UX500_SUSPEND_MEM - return true; -#else - return false; -#endif -} -static inline void ux500_suspend_dbg_sleep_status(bool is_deepsleep) { } -static inline void ux500_suspend_dbg_init(void) { } - -static inline int ux500_suspend_dbg_begin(suspend_state_t state) -{ - return 0; -} - -#endif - -#endif diff --git a/arch/arm/mach-ux500/pm/timer.c b/arch/arm/mach-ux500/pm/timer.c deleted file mode 100644 index 12553a3351b..00000000000 --- a/arch/arm/mach-ux500/pm/timer.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010-2011 - * - * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson - * - * License Terms: GNU General Public License v2 - * - * The RTC timer block is a ST Microelectronics variant of ARM PL031. - * Clockwatch part is the same as PL031, while the timer part is only - * present on the ST Microelectronics variant. - * Here only the timer part is used. - * - * The timer part is quite troublesome to program correctly. Lots - * of long delays must be there in order to secure that you actually get what - * you wrote. - * - * In other words, this timer is and should only used from cpuidle during - * special conditions when the surroundings are know in order to be able - * to remove the number of delays. - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/ktime.h> -#include <linux/delay.h> - -#include <asm/errno.h> - -#include <mach/hardware.h> - -#include "cpuidle_dbg.h" - -#define RTC_IMSC 0x10 -#define RTC_MIS 0x18 -#define RTC_ICR 0x1C -#define RTC_TDR 0x20 -#define RTC_TLR1 0x24 -#define RTC_TCR 0x28 - -#define RTC_TLR2 0x2C -#define RTC_TPR1 0x3C - -#define RTC_TCR_RTTOS (1 << 0) -#define RTC_TCR_RTTEN (1 << 1) -#define RTC_TCR_RTTSS (1 << 2) - -#define RTC_IMSC_TIMSC (1 << 1) -#define RTC_ICR_TIC (1 << 1) -#define RTC_MIS_RTCTMIS (1 << 1) - -#define RTC_TCR_RTTPS_2 (1 << 4) -#define RTC_TCR_RTTPS_3 (2 << 4) -#define RTC_TCR_RTTPS_4 (3 << 4) -#define RTC_TCR_RTTPS_5 (4 << 4) -#define RTC_TCR_RTTPS_6 (5 << 4) -#define RTC_TCR_RTTPS_7 (6 << 4) -#define RTC_TCR_RTTPS_8 (7 << 4) - -#define WRITE_DELAY 130 /* 4 cycles plus margin */ - -/* - * Count down measure point. It just have to be high to differ - * from scheduled values. - */ -#define MEASURE_VAL 0xffffffff - -/* Just a value bigger than any reason able scheduled timeout. */ -#define MEASURE_VAL_LIMIT 0xf0000000 - - -#define TICKS_TO_NS(x) ((s64)x * 30512) -#define US_TO_TICKS(x) ((u32)((1000 * x) / 30512)) - -static void __iomem *rtc_base; -static bool measure_latency; - -#ifdef CONFIG_U8500_CPUIDLE_DEBUG - -/* - * The plan here is to be able to measure the ApSleep/ApDeepSleep exit latency - * by having a know timer pattern. - * The first entry in the pattern, LR1, is the value that the scheduler - * wants us to sleep. The second pattern in a high value, too large to be - * scheduled, so we can differ between a running scheduled value and a - * time measure value. - * When a RTT interrupt has occured, the block will automatically start - * to execute the measure value in LR2 and when the ARM is awake, it reads - * how far the RTT has decreased the value loaded from LR2 and from that - * calculate how long time it took to wake up. - */ -ktime_t u8500_rtc_exit_latency_get(void) -{ - u32 ticks; - - if (measure_latency) { - ticks = MEASURE_VAL - readl(rtc_base + RTC_TDR); - - /* - * Check if we are actually counting on a LR2 value. - * If not we have woken on another interrupt. - */ - if (ticks < MEASURE_VAL_LIMIT) { - /* convert 32 kHz ticks to ns */ - return ktime_set(0, TICKS_TO_NS(ticks)); - } - } - return ktime_set(0, 0); -} - -static void measure_latency_start(void) -{ - udelay(WRITE_DELAY); - /* - * Disable RTT and clean self-start due to we want to restart, - * not continue from current pattern. (See below) - */ - writel(0, rtc_base + RTC_TCR); - udelay(WRITE_DELAY); - - /* - * Program LR2 (load register two) to maximum value to ease - * identification of timer interrupt vs other. - */ - writel(MEASURE_VAL, rtc_base + RTC_TLR2); - /* - * Set Load Register execution pattern, bit clear - * means pick LR1, bit set means LR2 - * 0xfe, binary 11111110 means first do LR1 then do - * LR2 seven times - */ - writel(0xfe, rtc_base + RTC_TPR1); - - udelay(WRITE_DELAY); - - /* - * Enable self-start, plus a pattern of eight. - */ - writel(RTC_TCR_RTTSS | RTC_TCR_RTTPS_8, - rtc_base + RTC_TCR); - udelay(WRITE_DELAY); -} - -void ux500_rtcrtt_measure_latency(bool enable) -{ - if (enable) { - measure_latency_start(); - } else { - writel(RTC_TCR_RTTSS | RTC_TCR_RTTOS, rtc_base + RTC_TCR); - writel(RTC_ICR_TIC, rtc_base + RTC_ICR); - writel(RTC_IMSC_TIMSC, rtc_base + RTC_IMSC); - } - measure_latency = enable; -} -#else -static inline void measure_latency_start(void) { } -static inline void ux500_rtcrtt_measure_latency(bool enable) { } -#endif - -void ux500_rtcrtt_off(void) -{ - if (measure_latency) { - measure_latency_start(); - } else { - /* Clear eventual interrupts */ - if (readl(rtc_base + RTC_MIS) & RTC_MIS_RTCTMIS) - writel(RTC_ICR_TIC, rtc_base + RTC_ICR); - - /* Disable, self start and oneshot mode */ - writel(RTC_TCR_RTTSS | RTC_TCR_RTTOS, rtc_base + RTC_TCR); - } -} - -void ux500_rtcrtt_next(u32 time_us) -{ - writel(US_TO_TICKS(time_us), rtc_base + RTC_TLR1); -} - -static int __init ux500_rtcrtt_init(void) -{ - if (cpu_is_u8500()) { - rtc_base = __io_address(U8500_RTC_BASE); - } else if (cpu_is_u5500()) { - rtc_base = __io_address(U5500_RTC_BASE); - } else { - pr_err("timer-rtt: Unknown DB Asic!\n"); - return -EINVAL; - } - ux500_rtcrtt_measure_latency(false); - return 0; -} -subsys_initcall(ux500_rtcrtt_init); diff --git a/arch/arm/mach-ux500/pm/timer.h b/arch/arm/mach-ux500/pm/timer.h deleted file mode 100644 index ec9e919e70d..00000000000 --- a/arch/arm/mach-ux500/pm/timer.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * Author: Jonas Aaberg <jonas.aberg@stericsson.com> - * - * License Terms: GNU General Public License v2 - * - */ - -#ifndef PM_TIMER_H -#define PM_TIMER_H - -#include <linux/ktime.h> - -#ifdef CONFIG_U8500_CPUIDLE_DEBUG -ktime_t u8500_rtc_exit_latency_get(void); -void ux500_rtcrtt_measure_latency(bool enable); -#else -static inline ktime_t u8500_rtc_exit_latency_get(void) -{ - return ktime_set(0, 0); -} -static inline void ux500_rtcrtt_measure_latency(bool enable) { } - -#endif - -void ux500_rtcrtt_off(void); -void ux500_rtcrtt_next(u32 time_us); - -#endif diff --git a/arch/arm/mach-ux500/pm/usecase_gov.c b/arch/arm/mach-ux500/pm/usecase_gov.c deleted file mode 100644 index 2a6b36cfaef..00000000000 --- a/arch/arm/mach-ux500/pm/usecase_gov.c +++ /dev/null @@ -1,942 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2011 - * - * Author: Alexandre Torgue <alexandre.torgue@stericsson.com> for ST-Ericsson - * Author: Vincent Guittot <vincent.guittot@stericsson.com> for ST-Ericsson - * License terms: GNU General Public License (GPL) version 2 - */ - -#include <linux/io.h> -#include <linux/earlysuspend.h> -#include <linux/cpu.h> -#include <linux/sched.h> -#include <linux/tick.h> -#include <linux/workqueue.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/uaccess.h> -#include <linux/kernel_stat.h> -#include <linux/ktime.h> -#include <linux/cpufreq.h> -#include <mach/prcmu.h> - -#define CPULOAD_MEAS_DELAY 3000 /* 3 secondes of delta */ - -/* debug */ -static unsigned long debug; - -#define hp_printk \ - if (debug) \ - printk \ - -enum ux500_uc { - UX500_UC_NORMAL = 0, - UX500_UC_AUTO, /* Add use case below this. */ - UX500_UC_VC, - UX500_UC_LPA, - UX500_UC_USER, /* Add use case above this. */ - UX500_UC_MAX, -}; - -/* cpu load monitor struct */ -#define LOAD_MONITOR 4 -struct hotplug_cpu_info { - cputime64_t prev_cpu_wall; - cputime64_t prev_cpu_idle; - cputime64_t prev_cpu_io; - unsigned int load[LOAD_MONITOR]; - unsigned int io[LOAD_MONITOR]; - unsigned int idx; -}; - -static DEFINE_PER_CPU(struct hotplug_cpu_info, hotplug_info); - -/* Auto trigger criteria */ -/* loadavg threshold */ -static unsigned long lower_threshold = 175; -static unsigned long upper_threshold = 450; -/* load balancing */ -static unsigned long max_unbalance = 210; -/* trend load */ -static unsigned long trend_unbalance = 40; -static unsigned long min_trend = 5; -/* instant load */ -static unsigned long max_instant = 85; - -/* Number of interrupts per second before exiting auto mode */ -static u32 exit_irq_per_s = 1000; -static u64 old_num_irqs; - -static DEFINE_MUTEX(usecase_mutex); -static bool user_config_updated; -static enum ux500_uc current_uc = UX500_UC_MAX; -static bool is_work_scheduled; -static bool is_early_suspend; -static bool uc_master_enable = true; - -static unsigned int cpuidle_deepest_state; - -struct usecase_config { - char *name; - unsigned long max_freq; - unsigned long min_freq; /* if no requirement set 0 */ - unsigned long cpuidle_multiplier; - bool second_cpu_online; - bool l2_prefetch_en; - bool enable; - unsigned int forced_state; /* Forced cpu idle state. */ - bool vc_override; /* QOS override for voice-call. */ -}; - -static struct usecase_config usecase_conf[UX500_UC_MAX] = { - [UX500_UC_NORMAL] = { - .name = "normal", - .max_freq = 1000000, - .min_freq = 200000, - .cpuidle_multiplier = 1024, - .second_cpu_online = true, - .l2_prefetch_en = true, - .enable = true, - .forced_state = 0, - .vc_override = false, - }, - [UX500_UC_AUTO] = { - .name = "auto", - .max_freq = 400000, - .min_freq = 200000, - .cpuidle_multiplier = 0, - .second_cpu_online = false, - .l2_prefetch_en = true, - .enable = false, - .forced_state = 0, - .vc_override = false, - }, - [UX500_UC_VC] = { - .name = "voice-call", - .max_freq = 400000, - .min_freq = 400000, - .cpuidle_multiplier = 0, - .second_cpu_online = false, - .l2_prefetch_en = false, - .enable = false, - .forced_state = 0, - .vc_override = true, - }, - [UX500_UC_LPA] = { - .name = "low-power-audio", - .max_freq = 400000, - .min_freq = 400000, - .cpuidle_multiplier = 0, - .second_cpu_online = false, - .l2_prefetch_en = false, - .enable = false, - .forced_state = 0, /* Updated dynamically */ - .vc_override = false, - }, -}; - -/* daemon */ -static struct delayed_work work_usecase; -static struct early_suspend usecase_early_suspend; - -/* calculate loadavg */ -#define LOAD_INT(x) ((x) >> FSHIFT) -#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) - -extern int cpufreq_update_freq(int cpu, unsigned int min, unsigned int max); -extern int cpuidle_set_multiplier(unsigned int value); -extern int cpuidle_force_state(unsigned int state); - -static unsigned long determine_loadavg(void) -{ - unsigned long avg = 0; - unsigned long avnrun[3]; - - get_avenrun(avnrun, FIXED_1 / 200, 0); - avg += (LOAD_INT(avnrun[0]) * 100) + (LOAD_FRAC(avnrun[0]) % 100); - - return avg; -} - -static unsigned long determine_cpu_load(void) -{ - int i; - unsigned long total_load = 0; - - /* get cpu load of each cpu */ - for_each_online_cpu(i) { - unsigned int load, iowait; - unsigned int idle_time, iowait_time, wall_time; - cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; - struct hotplug_cpu_info *info; - - info = &per_cpu(hotplug_info, i); - - /* update both cur_idle_time and cur_wall_time */ - cur_idle_time = get_cpu_idle_time_us(i, &cur_wall_time); - cur_iowait_time = get_cpu_iowait_time_us(i, &cur_wall_time); - - /* how much wall time has passed since last iteration? */ - wall_time = (unsigned int) cputime64_sub(cur_wall_time, - info->prev_cpu_wall); - info->prev_cpu_wall = cur_wall_time; - - /* how much idle time has passed since last iteration? */ - idle_time = (unsigned int) cputime64_sub(cur_idle_time, - info->prev_cpu_idle); - info->prev_cpu_idle = cur_idle_time; - - /* how much io wait time has passed since last iteration? */ - iowait_time = (unsigned int) cputime64_sub(cur_iowait_time, - info->prev_cpu_io); - info->prev_cpu_io = cur_iowait_time; - - if (unlikely(!wall_time || wall_time < idle_time)) - continue; - - /* load is the percentage of time not spent in idle */ - load = 100 * (wall_time - idle_time) / wall_time; - info->load[info->idx] = load; - hp_printk("cpu %d load %u ", i, load); - - /* iowait is the percentage of time not spent in io wait */ - iowait = 100 * (iowait_time) / wall_time; - info->io[info->idx++] = load; - hp_printk("iowait %u\n", iowait); - - if (info->idx >= LOAD_MONITOR) - info->idx = 0; - - total_load += load; - } - - return total_load; -} - -static unsigned long determine_cpu_load_trend(void) -{ - int i, j, k; - unsigned long total_load = 0; - - /* Get cpu load of each cpu */ - for_each_online_cpu(i) { - unsigned int load = 0; - struct hotplug_cpu_info *info; - - info = &per_cpu(hotplug_info, i); - - for (k = 0, j = info->idx; k < LOAD_MONITOR; k++, j++) - load += info->load[j]; - - load /= LOAD_MONITOR; - - hp_printk("cpu %d load trend %u\n", i, load); - - total_load += load; - } - - return total_load; -} - -static unsigned long determine_cpu_balance_trend(void) -{ - int i, j, k; - unsigned long total_load = 0; - unsigned long min_load = (unsigned long) (-1); - - /* Get cpu load of each cpu */ - for_each_online_cpu(i) { - unsigned int load = 0; - struct hotplug_cpu_info *info; - - info = &per_cpu(hotplug_info, i); - - for (k = 0, j = info->idx; k < LOAD_MONITOR; k++, j++) - load += info->load[j]; - - load /= LOAD_MONITOR; - - if (min_load > load) - min_load = load; - total_load += load; - } - - if (min_load > min_trend) - total_load = (100 * total_load) / min_load; - else - total_load = 50 << num_online_cpus(); - - return total_load; -} - -static void init_cpu_load_trend(void) -{ - int i; - - for_each_possible_cpu(i) { - struct hotplug_cpu_info *info; - int j; - - info = &per_cpu(hotplug_info, i); - - info->prev_cpu_idle = get_cpu_idle_time_us(i, - &(info->prev_cpu_wall)); - info->prev_cpu_io = get_cpu_iowait_time_us(i, - &(info->prev_cpu_wall)); - - for (j = 0; j < LOAD_MONITOR; j++) { - info->load[j] = 100; - info->io[j] = 100; - } - info->idx = 0; - } -} - -static u32 get_num_interrupts_per_s(void) -{ - int cpu; - int i; - u64 num_irqs = 0; - ktime_t now; - static ktime_t last; - unsigned int delta; - u32 irqs = 0; - - now = ktime_get(); - - for_each_possible_cpu(cpu) { - for (i = 0; i < NR_IRQS; i++) - num_irqs += kstat_irqs_cpu(i, cpu); - } - pr_debug("%s: total num irqs: %lld, previous %lld\n", - __func__, num_irqs, old_num_irqs); - - if (old_num_irqs > 0) { - delta = (u32)ktime_to_ms(ktime_sub(now, last)) / 1000; - irqs = ((u32)(num_irqs - old_num_irqs)) / delta; - } - - old_num_irqs = num_irqs; - last = now; - - pr_debug("delta irqs per sec:%d\n", irqs); - - return irqs; -} - -static void set_cpu_config(enum ux500_uc new_uc) -{ - struct cpufreq_policy policy; - int err; - bool update = false; - u32 min_freq, max_freq; - - if (new_uc != current_uc) - update = true; - else if ((user_config_updated) && (new_uc == UX500_UC_USER)) - update = true; - - pr_debug("%s: new_usecase=%d, current_usecase=%d, update=%d\n", - __func__, new_uc, current_uc, update); - - if (!update) - goto exit; - - /* Cpu hotplug */ - if (!(usecase_conf[new_uc].second_cpu_online) && - (num_online_cpus() > 1)) - cpu_down(1); - else if ((usecase_conf[new_uc].second_cpu_online) && - (num_online_cpus() < 2)) - cpu_up(1); - - /* Cpu freq */ - err = cpufreq_get_policy(&policy, 0); - if (err) - pr_err("usecase-gov: get cpufreq policy failed\n"); - - /* If requirement is 0, use current policy value */ - min_freq = usecase_conf[new_uc].min_freq ? - usecase_conf[new_uc].min_freq : policy.min; - - max_freq = usecase_conf[new_uc].max_freq ? - usecase_conf[new_uc].max_freq : policy.max; - - /* - * cpufreq fw does not allow frequency change if - * "current min freq" > "new max freq" or - * "current max freq" < "new min freq". - * Thus the intermediate steps below. - */ - if (policy.min > max_freq) { - err = cpufreq_update_freq(0, min_freq, policy.max); - if (err) - pr_err("usecase-gov: update min cpufreq failed\n"); - } - if (policy.max < min_freq) { - err = cpufreq_update_freq(0, policy.min, max_freq); - if (err) - pr_err("usecase-gov: update max cpufreq failed\n"); - } - - err = cpufreq_update_freq(0, min_freq, max_freq); - if (err) - pr_err("usecase-gov: update min/max cpufreq failed\n"); - - /* Cpu idle */ - cpuidle_set_multiplier(usecase_conf[new_uc].cpuidle_multiplier); - - /* L2 prefetch */ - if (usecase_conf[new_uc].l2_prefetch_en) - outer_prefetch_enable(); - else - outer_prefetch_disable(); - - /* Force cpuidle state */ - cpuidle_force_state(usecase_conf[new_uc].forced_state); - - /* QOS override */ - prcmu_qos_voice_call_override(usecase_conf[new_uc].vc_override); - - current_uc = new_uc; - -exit: - /* Its ok to clear even if new_uc != UX500_UC_USER */ - user_config_updated = false; -} - -void usecase_update_governor_state(void) -{ - bool cancel_work = false; - - mutex_lock(&usecase_mutex); - - if (uc_master_enable && (usecase_conf[UX500_UC_AUTO].enable || - usecase_conf[UX500_UC_USER].enable)) { - /* - * Usecases are enabled. If we are in early suspend put - * governor to work. - */ - if (is_early_suspend && !is_work_scheduled) { - schedule_delayed_work_on(0, &work_usecase, - msecs_to_jiffies(CPULOAD_MEAS_DELAY)); - is_work_scheduled = true; - } else if (!is_early_suspend && is_work_scheduled) { - /* Exiting from early suspend. */ - cancel_work = true; - } - - } else if (is_work_scheduled) { - /* No usecase enabled or governor is not enabled. */ - cancel_work = true; - } - - if (cancel_work) { - cancel_delayed_work_sync(&work_usecase); - is_work_scheduled = false; - - /* Set the default settings before exiting. */ - set_cpu_config(UX500_UC_NORMAL); - } - - mutex_unlock(&usecase_mutex); - -} - -/* - * Start load measurment every 6 s in order detrmine if can unplug one CPU. - * In order to not corrupt measurment, the first load average is not done - * here call in early suspend. - */ -static void usecase_earlysuspend_callback(struct early_suspend *h) -{ - init_cpu_load_trend(); - - is_early_suspend = true; - - usecase_update_governor_state(); -} - -/* Stop measurement, call LCD early resume */ -static void usecase_lateresume_callback(struct early_suspend *h) -{ - is_early_suspend = false; - - usecase_update_governor_state(); -} - -static void delayed_usecase_work(struct work_struct *work) -{ - unsigned long avg, load, trend, balance; - bool inc_perf = false; - bool dec_perf = false; - u32 irqs_per_s; - - /* determine loadavg */ - avg = determine_loadavg(); - hp_printk("loadavg = %lu lower th %lu upper th %lu\n", - avg, lower_threshold, upper_threshold); - - /* determine instant load */ - load = determine_cpu_load(); - hp_printk("cpu instant load = %lu max %lu\n", load, max_instant); - - /* determine load trend */ - trend = determine_cpu_load_trend(); - hp_printk("cpu load trend = %lu min %lu unbal %lu\n", - trend, min_trend, trend_unbalance); - - /* determine load balancing */ - balance = determine_cpu_balance_trend(); - hp_printk("load balancing trend = %lu min %lu\n", - balance, max_unbalance); - - irqs_per_s = get_num_interrupts_per_s(); - - /* Dont let configuration change in the middle of our calculations. */ - mutex_lock(&usecase_mutex); - - /* detect "instant" load increase */ - if (load > max_instant || irqs_per_s > exit_irq_per_s) { - inc_perf = true; - } else if (!usecase_conf[UX500_UC_USER].enable && - usecase_conf[UX500_UC_AUTO].enable) { - /* detect high loadavg use case */ - if (avg > upper_threshold) - inc_perf = true; - /* detect idle use case */ - else if (trend < min_trend) - dec_perf = true; - /* detect unbalanced low cpu load use case */ - else if ((balance > max_unbalance) && (trend < trend_unbalance)) - dec_perf = true; - /* detect low loadavg use case */ - else if (avg < lower_threshold) - dec_perf = true; - /* All user use cases disabled, current load not triggering - * any change. - */ - else if (user_config_updated) - dec_perf = true; - } else { - dec_perf = true; - } - - /* - * set_cpu_config() will not update the config unless it has been - * changed. - */ - if (dec_perf) { - if (usecase_conf[UX500_UC_USER].enable) - set_cpu_config(UX500_UC_USER); - else if (usecase_conf[UX500_UC_AUTO].enable) - set_cpu_config(UX500_UC_AUTO); - } else if (inc_perf) { - set_cpu_config(UX500_UC_NORMAL); - } - - mutex_unlock(&usecase_mutex); - - /* reprogramm scheduled work */ - schedule_delayed_work_on(0, &work_usecase, - msecs_to_jiffies(CPULOAD_MEAS_DELAY)); - -} - -static struct dentry *usecase_dir; - -#ifdef CONFIG_DEBUG_FS -#define define_set(_name) \ -static ssize_t set_##_name(struct file *file, \ - const char __user *user_buf, \ - size_t count, loff_t *ppos) \ -{ \ - int err; \ - long unsigned i; \ - \ - err = kstrtoul_from_user(user_buf, count, 0, &i); \ - \ - if (err) \ - return err; \ - \ - _name = i; \ - hp_printk("New value : %lu\n", _name); \ - \ - return count; \ -} - -define_set(upper_threshold); -define_set(lower_threshold); -define_set(max_unbalance); -define_set(trend_unbalance); -define_set(min_trend); -define_set(max_instant); -define_set(debug); - -#define define_print(_name) \ -static ssize_t print_##_name(struct seq_file *s, void *p) \ -{ \ - return seq_printf(s, "%lu\n", _name); \ -} - -define_print(upper_threshold); -define_print(lower_threshold); -define_print(max_unbalance); -define_print(trend_unbalance); -define_print(min_trend); -define_print(max_instant); -define_print(debug); - -#define define_open(_name) \ -static ssize_t open_##_name(struct inode *inode, struct file *file) \ -{ \ - return single_open(file, print_##_name, inode->i_private); \ -} - -define_open(upper_threshold); -define_open(lower_threshold); -define_open(max_unbalance); -define_open(trend_unbalance); -define_open(min_trend); -define_open(max_instant); -define_open(debug); - -#define define_dbg_file(_name) \ -static const struct file_operations fops_##_name = { \ - .open = open_##_name, \ - .write = set_##_name, \ - .read = seq_read, \ - .llseek = seq_lseek, \ - .release = single_release, \ - .owner = THIS_MODULE, \ -}; \ -static struct dentry *file_##_name; - -define_dbg_file(upper_threshold); -define_dbg_file(lower_threshold); -define_dbg_file(max_unbalance); -define_dbg_file(trend_unbalance); -define_dbg_file(min_trend); -define_dbg_file(max_instant); -define_dbg_file(debug); - -struct dbg_file { - struct dentry **file; - const struct file_operations *fops; - const char *name; -}; - -#define define_dbg_entry(_name) \ -{ \ - .file = &file_##_name, \ - .fops = &fops_##_name, \ - .name = #_name \ -} - -static struct dbg_file debug_entry[] = { - define_dbg_entry(upper_threshold), - define_dbg_entry(lower_threshold), - define_dbg_entry(max_unbalance), - define_dbg_entry(trend_unbalance), - define_dbg_entry(min_trend), - define_dbg_entry(max_instant), - define_dbg_entry(debug), -}; - -static int setup_debugfs(void) -{ - int i; - usecase_dir = debugfs_create_dir("usecase", NULL); - - if (IS_ERR_OR_NULL(usecase_dir)) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(debug_entry); i++) { - if (IS_ERR_OR_NULL(debugfs_create_file(debug_entry[i].name, - S_IWUGO | S_IRUGO, - usecase_dir, - NULL, - debug_entry[i].fops))) - goto fail; - } - - if (IS_ERR_OR_NULL(debugfs_create_u32("exit_irq_per_s", - S_IWUGO | S_IRUGO, usecase_dir, - &exit_irq_per_s))) - goto fail; - return 0; -fail: - debugfs_remove_recursive(usecase_dir); - return -EINVAL; -} -#else -static int setup_debugfs(void) -{ - return 0; -} -#endif - -static void usecase_update_user_config(void) -{ - int i; - bool config_enable = false; - struct usecase_config *user_conf = &usecase_conf[UX500_UC_USER]; - - mutex_lock(&usecase_mutex); - - user_conf->max_freq = 0; - user_conf->min_freq = 0; - user_conf->cpuidle_multiplier = 0; - user_conf->second_cpu_online = false; - user_conf->l2_prefetch_en = false; - user_conf->forced_state = cpuidle_deepest_state; - user_conf->vc_override = true; /* A single false will clear it. */ - - /* Dont include Auto and Normal modes in this */ - for (i = (UX500_UC_AUTO + 1); i < UX500_UC_USER; i++) { - if (!usecase_conf[i].enable) - continue; - - config_enable = true; - - if (usecase_conf[i].max_freq > user_conf->max_freq) - user_conf->max_freq = usecase_conf[i].max_freq; - /* It's the highest min freq requirement that should be used */ - if (usecase_conf[i].min_freq > user_conf->min_freq) - user_conf->min_freq = usecase_conf[i].min_freq; - - if (usecase_conf[i].cpuidle_multiplier > - user_conf->cpuidle_multiplier) - user_conf->cpuidle_multiplier = - usecase_conf[i].cpuidle_multiplier; - - user_conf->second_cpu_online |= - usecase_conf[i].second_cpu_online; - - user_conf->l2_prefetch_en |= - usecase_conf[i].l2_prefetch_en; - - /* Take the shallowest state. */ - if (usecase_conf[i].forced_state < user_conf->forced_state) - user_conf->forced_state = usecase_conf[i].forced_state; - - /* Only override QOS if all enabled configurations are - * requesting it. - */ - if (!usecase_conf[i].vc_override) - user_conf->vc_override = false; - } - - user_conf->enable = config_enable; - user_config_updated = true; - - mutex_unlock(&usecase_mutex); -} - -struct usecase_devclass_attr { - struct sysdev_class_attribute class_attr; - u32 index; -}; - -/* One for each usecase except "user" + current + enable */ -#define UX500_NUM_SYSFS_NODES (UX500_UC_USER + 2) -#define UX500_CURRENT_NODE_INDEX (UX500_NUM_SYSFS_NODES - 1) -#define UX500_ENABLE_NODE_INDEX (UX500_NUM_SYSFS_NODES - 2) - -static struct usecase_devclass_attr usecase_dc_attr[UX500_NUM_SYSFS_NODES]; - -static struct attribute *dbs_attributes[UX500_NUM_SYSFS_NODES + 1] = {NULL}; - -static struct attribute_group dbs_attr_group = { - .attrs = dbs_attributes, - .name = "usecase", -}; - -static ssize_t show_current(struct sysdev_class *class, - struct sysdev_class_attribute *attr, char *buf) -{ - enum ux500_uc display_uc = (current_uc == UX500_UC_MAX) ? - UX500_UC_NORMAL : current_uc; - - return sprintf(buf, "max_freq: %ld\n" - "min_freq: %ld\n" - "cpuidle_multiplier: %ld\n" - "second_cpu_online: %s\n" - "l2_prefetch_en: %s\n" - "forced_state: %d\n" - "vc_override: %s\n", - usecase_conf[display_uc].max_freq, - usecase_conf[display_uc].min_freq, - usecase_conf[display_uc].cpuidle_multiplier, - usecase_conf[display_uc].second_cpu_online ? "true" : "false", - usecase_conf[display_uc].l2_prefetch_en ? "true" : "false", - usecase_conf[display_uc].forced_state, - usecase_conf[display_uc].vc_override ? "true" : "false"); -} - -static ssize_t show_enable(struct sysdev_class *class, - struct sysdev_class_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", uc_master_enable); -} - -static ssize_t store_enable(struct sysdev_class *class, - struct sysdev_class_attribute *attr, - const char *buf, size_t count) -{ - unsigned int input; - int ret; - - ret = sscanf(buf, "%u", &input); - if (ret != 1) - return -EINVAL; - - uc_master_enable = (bool) input; - - usecase_update_governor_state(); - - return count; -} - -static ssize_t show_dc_attr(struct sysdev_class *class, - struct sysdev_class_attribute *attr, char *buf) -{ - struct usecase_devclass_attr *uattr = - container_of(attr, struct usecase_devclass_attr, class_attr); - - return sprintf(buf, "%u\n", - usecase_conf[uattr->index].enable); -} - -static ssize_t store_dc_attr(struct sysdev_class *class, - struct sysdev_class_attribute *attr, - const char *buf, size_t count) -{ - unsigned int input; - int ret; - - struct usecase_devclass_attr *uattr = - container_of(attr, struct usecase_devclass_attr, class_attr); - - ret = sscanf(buf, "%u", &input); - - /* Normal mode cant be changed. */ - if ((ret != 1) || (uattr->index == 0)) - return -EINVAL; - - usecase_conf[uattr->index].enable = (bool)input; - - usecase_update_user_config(); - - usecase_update_governor_state(); - - return count; -} - -static int usecase_sysfs_init(void) -{ - int err; - int i; - - /* Last two nodes are not based on usecase configurations */ - for (i = 0; i < (UX500_NUM_SYSFS_NODES - 2); i++) { - usecase_dc_attr[i].class_attr.attr.name = usecase_conf[i].name; - usecase_dc_attr[i].class_attr.attr.mode = 0644; - usecase_dc_attr[i].class_attr.show = show_dc_attr; - usecase_dc_attr[i].class_attr.store = store_dc_attr; - usecase_dc_attr[i].index = i; - - dbs_attributes[i] = &(usecase_dc_attr[i].class_attr.attr); - } - - /* sysfs current */ - usecase_dc_attr[UX500_CURRENT_NODE_INDEX].class_attr.attr.name = - "current"; - usecase_dc_attr[UX500_CURRENT_NODE_INDEX].class_attr.attr.mode = - 0644; - usecase_dc_attr[UX500_CURRENT_NODE_INDEX].class_attr.show = - show_current; - usecase_dc_attr[UX500_CURRENT_NODE_INDEX].class_attr.store = - NULL; - usecase_dc_attr[UX500_CURRENT_NODE_INDEX].index = - 0; - dbs_attributes[UX500_CURRENT_NODE_INDEX] = - &(usecase_dc_attr[UX500_CURRENT_NODE_INDEX].class_attr.attr); - - /* sysfs enable */ - usecase_dc_attr[UX500_ENABLE_NODE_INDEX].class_attr.attr.name = - "enable"; - usecase_dc_attr[UX500_ENABLE_NODE_INDEX].class_attr.attr.mode = - 0644; - usecase_dc_attr[UX500_ENABLE_NODE_INDEX].class_attr.show = - show_enable; - usecase_dc_attr[UX500_ENABLE_NODE_INDEX].class_attr.store = - store_enable; - usecase_dc_attr[UX500_ENABLE_NODE_INDEX].index = - 0; - dbs_attributes[UX500_ENABLE_NODE_INDEX] = - &(usecase_dc_attr[UX500_ENABLE_NODE_INDEX].class_attr.attr); - - err = sysfs_create_group(&(cpu_sysdev_class.kset.kobj), - &dbs_attr_group); - if (err) - pr_err("usecase-gov: sysfs_create_group" - " failed with error = %d\n", err); - - return err; -} - -#include "cpuidle.h" - -static void usecase_cpuidle_init(void) -{ - int max_states; - int i; - struct cstate *state = ux500_ci_get_cstates(&max_states); - - for (i = 0; i < max_states; i++) - if ((state[i].APE == APE_OFF) && (state[i].ARM == ARM_RET)) - break; - - usecase_conf[UX500_UC_LPA].forced_state = i; - - cpuidle_deepest_state = max_states - 1; -} - -/* initialize devices */ -static int __init init_usecase_devices(void) -{ - int err; - - pr_info("Use-case governor initialized\n"); - - /* add early_suspend callback */ - usecase_early_suspend.level = 200; - usecase_early_suspend.suspend = usecase_earlysuspend_callback; - usecase_early_suspend.resume = usecase_lateresume_callback; - register_early_suspend(&usecase_early_suspend); - - /* register delayed queuework */ - INIT_DELAYED_WORK_DEFERRABLE(&work_usecase, - delayed_usecase_work); - - init_cpu_load_trend(); - - err = setup_debugfs(); - if (err) - goto error; - err = usecase_sysfs_init(); - if (err) - goto error2; - - usecase_cpuidle_init(); - - return 0; -error2: - debugfs_remove_recursive(usecase_dir); -error: - unregister_early_suspend(&usecase_early_suspend); - return err; -} - -device_initcall(init_usecase_devices); |