diff options
28 files changed, 1458 insertions, 469 deletions
diff --git a/arch/arm/mach-ux500/board-u5500-regulators.c b/arch/arm/mach-ux500/board-u5500-regulators.c index b345a72038b..f890ebebf10 100644 --- a/arch/arm/mach-ux500/board-u5500-regulators.c +++ b/arch/arm/mach-ux500/board-u5500-regulators.c @@ -9,7 +9,6 @@ #include <linux/platform_device.h> #include <linux/regulator/machine.h> #include <linux/regulator/ab5500.h> -#include <linux/regulator/db5500-prcmu.h> #include "board-u5500.h" @@ -146,83 +145,6 @@ struct ab5500_regulator_platform_data u5500_ab5500_regulator_data = { .num_regulator = ARRAY_SIZE(ab5500_regulator_init_data), }; -/* - * Power state, ePOD, etc. - */ - -static struct regulator_consumer_supply u5500_vape_consumers[] = { - REGULATOR_SUPPLY("v-ape", NULL), - REGULATOR_SUPPLY("v-i2c", "nmk-i2c.0"), - REGULATOR_SUPPLY("v-i2c", "nmk-i2c.1"), - REGULATOR_SUPPLY("v-i2c", "nmk-i2c.2"), - REGULATOR_SUPPLY("v-i2c", "nmk-i2c.3"), - REGULATOR_SUPPLY("v-mmc", "sdi0"), - REGULATOR_SUPPLY("v-mmc", "sdi1"), - REGULATOR_SUPPLY("v-mmc", "sdi2"), - REGULATOR_SUPPLY("v-mmc", "sdi3"), - REGULATOR_SUPPLY("v-mmc", "sdi4"), - REGULATOR_SUPPLY("v-uart", "uart0"), - REGULATOR_SUPPLY("v-uart", "uart1"), - REGULATOR_SUPPLY("v-uart", "uart2"), - REGULATOR_SUPPLY("v-uart", "uart3"), -}; - -static struct regulator_consumer_supply u5500_sga_consumers[] = { - REGULATOR_SUPPLY("debug", "reg-virt-consumer.0"), - REGULATOR_SUPPLY("v-mali", NULL), -}; - -static struct regulator_consumer_supply u5500_hva_consumers[] = { - REGULATOR_SUPPLY("debug", "reg-virt-consumer.1"), - REGULATOR_SUPPLY("v-hva", NULL), -}; - -static struct regulator_consumer_supply u5500_sia_consumers[] = { - REGULATOR_SUPPLY("debug", "reg-virt-consumer.2"), - REGULATOR_SUPPLY("v-sia", "mmio_camera"), -}; - -static struct regulator_consumer_supply u5500_disp_consumers[] = { - REGULATOR_SUPPLY("debug", "reg-virt-consumer.3"), - REGULATOR_SUPPLY("vsupply", "b2r2_bus"), - REGULATOR_SUPPLY("vsupply", "mcde"), -}; - -static struct regulator_consumer_supply u5500_esram12_consumers[] = { - REGULATOR_SUPPLY("debug", "reg-virt-consumer.4"), - REGULATOR_SUPPLY("v-esram12", "mcde"), - REGULATOR_SUPPLY("esram12", "cm_control"), -}; - -#define U5500_REGULATOR_SWITCH(lower, upper) \ -[U5500_REGULATOR_SWITCH_##upper] = (struct regulator_init_data []) { \ -{ \ - .constraints = { \ - .valid_ops_mask = REGULATOR_CHANGE_STATUS, \ - }, \ - .consumer_supplies = u5500_##lower##_consumers, \ - .num_consumer_supplies = ARRAY_SIZE(u5500_##lower##_consumers),\ -} \ -} - -static struct regulator_init_data * -u5500_regulator_init_data[U5500_NUM_REGULATORS] __initdata = { - [U5500_REGULATOR_VAPE] = (struct regulator_init_data []) { - { - .constraints = { - .valid_ops_mask = REGULATOR_CHANGE_STATUS, - }, - .consumer_supplies = u5500_vape_consumers, - .num_consumer_supplies = ARRAY_SIZE(u5500_vape_consumers), - } - }, - U5500_REGULATOR_SWITCH(sga, SGA), - U5500_REGULATOR_SWITCH(hva, HVA), - U5500_REGULATOR_SWITCH(sia, SIA), - U5500_REGULATOR_SWITCH(disp, DISP), - U5500_REGULATOR_SWITCH(esram12, ESRAM12), -}; - static void __init u5500_regulators_init_debug(void) { const char data[] = "debug"; @@ -236,8 +158,4 @@ static void __init u5500_regulators_init_debug(void) void __init u5500_regulators_init(void) { u5500_regulators_init_debug(); - - platform_device_register_data(NULL, "u5500-regulators", -1, - u5500_regulator_init_data, - sizeof(u5500_regulator_init_data)); } diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c index 3759a815261..65fca58b364 100644 --- a/arch/arm/mach-ux500/board-u5500.c +++ b/arch/arm/mach-ux500/board-u5500.c @@ -303,9 +303,8 @@ static void __init u5500_spi_init(void) static struct resource ab5500_resources[] = { [0] = { - /*TODO Change this when prcmu driver arrives */ - .start = IRQ_DB5500_AB5500, - .end = IRQ_DB5500_AB5500, + .start = IRQ_DB5500_PRCMU_ABB, + .end = IRQ_DB5500_PRCMU_ABB, .flags = IORESOURCE_IRQ } }; diff --git a/arch/arm/mach-ux500/clock-db5500.c b/arch/arm/mach-ux500/clock-db5500.c index ee2ea8033bd..18583a52334 100644 --- a/arch/arm/mach-ux500/clock-db5500.c +++ b/arch/arm/mach-ux500/clock-db5500.c @@ -36,59 +36,16 @@ static DEFINE_MUTEX(ab_ulpclk_mutex); static DEFINE_MUTEX(audioclk_mutex); /* SysClk operations. */ - -static int request_sysclk(bool enable) -{ - static int requests; - - if ((enable && (requests++ == 0)) || (!enable && (--requests == 0))) - return prcmu_request_clock(PRCMU_SYSCLK, enable); - return 0; -} - static int sysclk_enable(struct clk *clk) { - static bool swat_enable; - int r; - - if (!swat_enable) { - r = ab8500_sysctrl_set(AB8500_SWATCTRL, - AB8500_SWATCTRL_SWATENABLE); - if (r) - return r; - - swat_enable = true; - } - - r = request_sysclk(true); - if (r) - return r; - - if (clk->cg_sel) { - r = ab8500_sysctrl_set(AB8500_SYSULPCLKCTRL1, (u8)clk->cg_sel); - if (r) - (void)request_sysclk(false); - } - return r; + return prcmu_request_clock(PRCMU_SYSCLK, true); } static void sysclk_disable(struct clk *clk) { - int r; - if (clk->cg_sel) { - r = ab8500_sysctrl_clear(AB8500_SYSULPCLKCTRL1, - (u8)clk->cg_sel); - if (r) - goto disable_failed; - } - r = request_sysclk(false); - if (r) - goto disable_failed; + prcmu_request_clock(PRCMU_SYSCLK, false); return; - -disable_failed: - pr_err("clock: failed to disable %s.\n", clk->name); } static struct clkops sysclk_ops = { @@ -324,27 +281,6 @@ static struct clk sysclk = { .mutex = &sysclk_mutex, }; -static struct clk sysclk2 = { - .name = "sysclk2", - .ops = &sysclk_ops, - .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, - .mutex = &sysclk_mutex, -}; - -static struct clk sysclk3 = { - .name = "sysclk3", - .ops = &sysclk_ops, - .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, - .mutex = &sysclk_mutex, -}; - -static struct clk sysclk4 = { - .name = "sysclk4", - .ops = &sysclk_ops, - .cg_sel = AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, - .mutex = &sysclk_mutex, -}; - static struct clk rtc32k = { .name = "rtc32k", .rate = 32768, @@ -633,7 +569,6 @@ static struct clk *db5500_dbg_clks[] __initdata = { &p6_pclk7, /* Clock sources */ - &sysclk2, &clkout0, &clkout1, &rtc_clk1, @@ -655,12 +590,6 @@ static struct clk_lookup u8500_common_clock_sources[] = { CLK_LOOKUP(audioclk, "ab8500-codec.0", "audioclk"), }; -static struct clk_lookup u8500_v2_sysclks[] = { - CLK_LOOKUP(sysclk2, NULL, "sysclk2"), - CLK_LOOKUP(sysclk3, NULL, "sysclk3"), - CLK_LOOKUP(sysclk4, NULL, "sysclk4"), -}; - static struct clk_lookup db5500_prcmu_clocks[] = { CLK_LOOKUP(sgaclk, "mali", NULL), CLK_LOOKUP(siaclk, "mmio_camera", "sia"), @@ -793,9 +722,6 @@ static void __init db5500_boot_clk_enable(void) int __init db5500_clk_init(void) { - sysclk_ops.enable = NULL; - sysclk_ops.disable = NULL; - if (ux500_is_svp()) { prcmu_clk_ops.enable = NULL; prcmu_clk_ops.disable = NULL; @@ -813,11 +739,6 @@ int __init db5500_clk_init(void) clks_register(db5500_clkouts, ARRAY_SIZE(db5500_clkouts)); clks_register(u5500_clocks, ARRAY_SIZE(u5500_clocks)); - if (cpu_is_u8500v2()) { - clks_register(u8500_v2_sysclks, - ARRAY_SIZE(u8500_v2_sysclks)); - } - db5500_boot_clk_enable(); /* diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c index 3b0fd471d80..8e20bc69efa 100644 --- a/arch/arm/mach-ux500/cpu-db5500.c +++ b/arch/arm/mach-ux500/cpu-db5500.c @@ -158,11 +158,16 @@ static struct platform_device mbox2_device = { .num_resources = ARRAY_SIZE(mbox2_resources), }; +static struct platform_device db5500_prcmu_device = { + .name = "db5500-prcmu", +}; + static struct platform_device *db5500_platform_devs[] __initdata = { &db5500_pmu_device, &mbox0_device, &mbox1_device, &mbox2_device, + &db5500_prcmu_device, }; static resource_size_t __initdata db5500_gpio_base[] = { diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index a9b01188dc4..f28f7858040 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -64,13 +64,8 @@ void __init ux500_init_irq(void) * Init clocks here so that they are available for system timer * initialization. */ - if (cpu_is_u5500()) - db5500_prcmu_early_init(); - if (cpu_is_u8500()) { - prcmu_early_init(); - arm_pm_restart = ux500_restart; - } - + prcmu_early_init(); + arm_pm_restart = ux500_restart; clk_init(); } diff --git a/arch/arm/mach-ux500/devices-db5500.c b/arch/arm/mach-ux500/devices-db5500.c index aa6389a2c20..75ecfd7a881 100644 --- a/arch/arm/mach-ux500/devices-db5500.c +++ b/arch/arm/mach-ux500/devices-db5500.c @@ -40,6 +40,11 @@ .start = IRQ_DB5500_GPIO##block, \ .end = IRQ_DB5500_GPIO##block, \ .flags = IORESOURCE_IRQ, \ + }, \ + { \ + .start = IRQ_DB5500_PRCMU_GPIO##block, \ + .end = IRQ_DB5500_PRCMU_GPIO##block, \ + .flags = IORESOURCE_IRQ, \ } #define GPIO_DEVICE(block) \ diff --git a/arch/arm/mach-ux500/include/mach/irqs-db5500.h b/arch/arm/mach-ux500/include/mach/irqs-db5500.h index 77239776a6f..d8d00b6c2ba 100644 --- a/arch/arm/mach-ux500/include/mach/irqs-db5500.h +++ b/arch/arm/mach-ux500/include/mach/irqs-db5500.h @@ -85,6 +85,35 @@ #ifdef CONFIG_UX500_SOC_DB5500 +/* Virtual interrupts corresponding to the PRCMU wakeups. */ +#define IRQ_DB5500_PRCMU_BASE IRQ_SOC_START + +#define IRQ_DB5500_PRCMU_RTC (IRQ_DB5500_PRCMU_BASE) +#define IRQ_DB5500_PRCMU_RTT0 (IRQ_DB5500_PRCMU_BASE + 1) +#define IRQ_DB5500_PRCMU_RTT1 (IRQ_DB5500_PRCMU_BASE + 2) +#define IRQ_DB5500_PRCMU_CD_IRQ (IRQ_DB5500_PRCMU_BASE + 3) +#define IRQ_DB5500_PRCMU_SRP_TIM (IRQ_DB5500_PRCMU_BASE + 4) +#define IRQ_DB5500_PRCMU_APE_REQ (IRQ_DB5500_PRCMU_BASE + 5) +#define IRQ_DB5500_PRCMU_USB (IRQ_DB5500_PRCMU_BASE + 6) +#define IRQ_DB5500_PRCMU_ABB (IRQ_DB5500_PRCMU_BASE + 7) +#define IRQ_DB5500_PRCMU_ARM (IRQ_DB5500_PRCMU_BASE + 8) +#define IRQ_DB5500_PRCMU_MODEM_SW_RESET_REQ (IRQ_DB5500_PRCMU_BASE + 9) +#define IRQ_DB5500_PRCMU_AC_WAKE_ACK (IRQ_DB5500_PRCMU_BASE + 10) +#define IRQ_DB5500_PRCMU_GPIO0 (IRQ_DB5500_PRCMU_BASE + 11) +#define IRQ_DB5500_PRCMU_GPIO1 (IRQ_DB5500_PRCMU_BASE + 12) +#define IRQ_DB5500_PRCMU_GPIO2 (IRQ_DB5500_PRCMU_BASE + 13) +#define IRQ_DB5500_PRCMU_GPIO3 (IRQ_DB5500_PRCMU_BASE + 14) +#define IRQ_DB5500_PRCMU_GPIO4 (IRQ_DB5500_PRCMU_BASE + 15) +#define IRQ_DB5500_PRCMU_GPIO5 (IRQ_DB5500_PRCMU_BASE + 16) +#define IRQ_DB5500_PRCMU_GPIO6 (IRQ_DB5500_PRCMU_BASE + 17) +#define IRQ_DB5500_PRCMU_GPIO7 (IRQ_DB5500_PRCMU_BASE + 18) +#define IRQ_DB5500_PRCMU_AC_REL_ACK (IRQ_DB5500_PRCMU_BASE + 19) +#define IRQ_DB5500_PRCMU_LOW_POWER_AUDIO (IRQ_DB5500_PRCMU_BASE + 20) +#define IRQ_DB5500_PRCMU_TEMP_SENSOR (IRQ_DB5500_PRCMU_BASE + 21) +#define IRQ_DB5500_PRCMU_END (IRQ_DB5500_PRCMU_BASE + 22) + +#define NUM_DB5500_PRCMU_WAKEUPS (IRQ_DB5500_PRCMU_END - IRQ_DB5500_PRCMU_BASE) + /* * After the GPIO ones we reserve a range of IRQ:s in which virtual * IRQ:s representing modem IRQ:s can be allocated diff --git a/arch/arm/mach-ux500/include/mach/prcmu-regs.h b/arch/arm/mach-ux500/include/mach/prcmu-regs.h index ec4663046e3..50c51b5605e 100644 --- a/arch/arm/mach-ux500/include/mach/prcmu-regs.h +++ b/arch/arm/mach-ux500/include/mach/prcmu-regs.h @@ -110,6 +110,11 @@ #define PRCM_ARM_IT1_VAL (_PRCMU_BASE + 0x494) #define PRCM_HOLD_EVT (_PRCMU_BASE + 0x174) +#define PRCM_MOD_AWAKE_STATUS (_PRCMU_BASE + 0x4A0) +#define PRCM_MOD_AWAKE_STATUS_PRCM_MOD_COREPD_AWAKE BIT(0) +#define PRCM_MOD_AWAKE_STATUS_PRCM_MOD_AAPD_AWAKE BIT(1) +#define PRCM_MOD_AWAKE_STATUS_PRCM_MOD_VMODEM_OFF_ISO BIT(2) + #define PRCM_ITSTATUS0 (_PRCMU_BASE + 0x148) #define PRCM_ITSTATUS1 (_PRCMU_BASE + 0x150) #define PRCM_ITSTATUS2 (_PRCMU_BASE + 0x158) @@ -193,4 +198,7 @@ #define PRCM_RESOUTN_SET (_PRCMU_BASE + 0x214) #define PRCM_RESOUTN_CLR (_PRCMU_BASE + 0x218) +/* System reset register */ +#define PRCM_APE_SOFTRST (_PRCMU_BASE + 0x228) + #endif /* __MACH_PRCMU__REGS_H */ diff --git a/arch/arm/mach-ux500/include/mach/prcmu.h b/arch/arm/mach-ux500/include/mach/prcmu.h index 41f68f0f087..6c7584d69d8 100644 --- a/arch/arm/mach-ux500/include/mach/prcmu.h +++ b/arch/arm/mach-ux500/include/mach/prcmu.h @@ -23,6 +23,7 @@ enum prcmu_wakeup_index { PRCMU_WAKEUP_INDEX_ABB, PRCMU_WAKEUP_INDEX_ABB_FIFO, PRCMU_WAKEUP_INDEX_ARM, + PRCMU_WAKEUP_INDEX_CD_IRQ, NUM_PRCMU_WAKEUP_INDICES }; #define PRCMU_WAKEUP(_name) (BIT(PRCMU_WAKEUP_INDEX_##_name)) @@ -192,12 +193,38 @@ enum ddr_opp { DDR_25_OPP = 0x02, }; +/* + * Definitions for controlling ESRAM0 in deep sleep. + */ +#define ESRAM0_DEEP_SLEEP_STATE_OFF 1 +#define ESRAM0_DEEP_SLEEP_STATE_RET 2 + +/** + * enum ddr_pwrst - DDR power states definition + * @DDR_PWR_STATE_UNCHANGED: SDRAM and DDR controller state is unchanged + * @DDR_PWR_STATE_ON: + * @DDR_PWR_STATE_OFFLOWLAT: + * @DDR_PWR_STATE_OFFHIGHLAT: + */ +enum ddr_pwrst { + DDR_PWR_STATE_UNCHANGED = 0x00, + DDR_PWR_STATE_ON = 0x01, + DDR_PWR_STATE_OFFLOWLAT = 0x02, + DDR_PWR_STATE_OFFHIGHLAT = 0x03 +}; + #include <linux/mfd/db8500-prcmu.h> #include <linux/mfd/db5500-prcmu.h> #if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500) -void __init prcmu_early_init(void); +static inline void __init prcmu_early_init(void) +{ + if (machine_is_u5500()) + return db5500_prcmu_early_init(); + else + return db8500_prcmu_early_init(); +} static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll) @@ -231,6 +258,22 @@ static inline void prcmu_disable_wakeups(void) prcmu_enable_wakeups(0); } +static inline void prcmu_config_abb_event_readout(u32 abb_events) +{ + if (machine_is_u5500()) + db5500_prcmu_config_abb_event_readout(abb_events); + else + db8500_prcmu_config_abb_event_readout(abb_events); +} + +static inline void prcmu_get_abb_event_buffer(void __iomem **buf) +{ + if (machine_is_u5500()) + db5500_prcmu_get_abb_event_buffer(buf); + else + db8500_prcmu_get_abb_event_buffer(buf); +} + int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size); int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size); @@ -246,11 +289,25 @@ static inline int prcmu_request_clock(u8 clock, bool enable) int prcmu_set_ape_opp(u8 opp); int prcmu_get_ape_opp(void); -int prcmu_set_arm_opp(u8 opp); -int prcmu_get_arm_opp(void); int prcmu_set_ddr_opp(u8 opp); int prcmu_get_ddr_opp(void); +static inline int prcmu_set_arm_opp(u8 opp) +{ + if (machine_is_u5500()) + return db5500_prcmu_set_arm_opp(opp); + else + return db8500_prcmu_set_arm_opp(opp); +} + +static inline int prcmu_get_arm_opp(void) +{ + if (machine_is_u5500()) + return db5500_prcmu_get_arm_opp(); + else + return db8500_prcmu_get_arm_opp(); +} + static inline void prcmu_system_reset(u16 reset_code) { if (machine_is_u5500()) @@ -259,17 +316,56 @@ static inline void prcmu_system_reset(u16 reset_code) return db8500_prcmu_system_reset(reset_code); } -u16 prcmu_get_reset_code(void); +static inline u16 prcmu_get_reset_code(void) +{ + if (machine_is_u5500()) + return db5500_prcmu_get_reset_code(); + else + return db8500_prcmu_get_reset_code(); +} void prcmu_ac_wake_req(void); void prcmu_ac_sleep_req(void); void prcmu_modem_reset(void); -bool prcmu_is_ac_wake_requested(void); +static inline bool prcmu_is_ac_wake_requested(void) +{ + if (machine_is_u5500()) + return db5500_prcmu_is_ac_wake_requested(); + else + return db8500_prcmu_is_ac_wake_requested(); +} + +static inline int prcmu_set_display_clocks(void) +{ + if (machine_is_u5500()) + return db5500_prcmu_set_display_clocks(); + else + return db8500_prcmu_set_display_clocks(); +} + +static inline int prcmu_disable_dsipll(void) +{ + if (machine_is_u5500()) + return db5500_prcmu_disable_dsipll(); + else + return db8500_prcmu_disable_dsipll(); +} -int prcmu_set_display_clocks(void); -int prcmu_disable_dsipll(void); -int prcmu_enable_dsipll(void); +static inline int prcmu_enable_dsipll(void) +{ + if (machine_is_u5500()) + return db5500_prcmu_enable_dsipll(); + else + return db8500_prcmu_enable_dsipll(); +} +static inline int prcmu_config_esram0_deep_sleep(u8 state) +{ + if (machine_is_u5500()) + return db5500_prcmu_config_esram0_deep_sleep(state); + else + return db8500_prcmu_config_esram0_deep_sleep(state); +} #else static inline void __init prcmu_early_init(void) {} @@ -372,6 +468,18 @@ static inline int prcmu_enable_dsipll(void) return 0; } +static inline int prcmu_config_esram0_deep_sleep(u8 state) +{ + return 0; +} + +static inline void prcmu_config_abb_event_readout(u32 abb_events) {} + +static inline void prcmu_get_abb_event_buffer(void __iomem **buf) +{ + *buf = NULL; +} + #endif /* PRCMU QoS APE OPP class */ diff --git a/arch/arm/mach-ux500/include/mach/regulator.h b/arch/arm/mach-ux500/include/mach/regulator.h deleted file mode 100644 index cacb6bf5277..00000000000 --- a/arch/arm/mach-ux500/include/mach/regulator.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * Author: Bengt Jonsson <bengt.jonsson@stericsson.com> for ST-Ericsson, - * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson - * - * License Terms: GNU General Public License v2 - * - */ - -#ifndef MACH_UX500_REGULATOR_H -#define MACH_UX500_REGULATOR_H - -#include <linux/regulator/dbx500-prcmu.h> - -#endif diff --git a/arch/arm/mach-ux500/pm/Kconfig b/arch/arm/mach-ux500/pm/Kconfig index d6454eab2a5..03aeaea57a5 100644 --- a/arch/arm/mach-ux500/pm/Kconfig +++ b/arch/arm/mach-ux500/pm/Kconfig @@ -1,10 +1,3 @@ -config U8500_CPUFREQ - tristate "CPUFreq support" - depends on UX500_SOC_DB8500 && CPU_FREQ && PM - default y - help - Add support for CPU Frequency scaling for U8500. - config U8500_CPUIDLE tristate "CPUIdle support" depends on UX500_SOC_DB8500 && CPU_IDLE && !RTC_DRV_PL031 && PM diff --git a/arch/arm/mach-ux500/pm/pm.c b/arch/arm/mach-ux500/pm/pm.c index 5324d715274..b6442212324 100644 --- a/arch/arm/mach-ux500/pm/pm.c +++ b/arch/arm/mach-ux500/pm/pm.c @@ -185,18 +185,21 @@ bool ux500_pm_other_cpu_wfi(void) return false; } -#define PRCMU_STATUS_REGISTER_V1 0x8015fe08 -#define PRCMU_STATUS_REGISTER_V2 0x801b8e08 +/* 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_u8500v20_or_later()) - prcmu_status_reg = (void *)IO_ADDRESS(PRCMU_STATUS_REGISTER_V2); + 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 - prcmu_status_reg = (void *)IO_ADDRESS(PRCMU_STATUS_REGISTER_V1); + ux500_unknown_soc(); val = readl(prcmu_status_reg) & 0xff; diff --git a/arch/arm/mach-ux500/pm/runtime.c b/arch/arm/mach-ux500/pm/runtime.c index 40b360b684b..265faf3085d 100644 --- a/arch/arm/mach-ux500/pm/runtime.c +++ b/arch/arm/mach-ux500/pm/runtime.c @@ -19,7 +19,7 @@ #include <linux/amba/bus.h> #include <linux/clk.h> #include <plat/pincfg.h> -#include <mach/regulator.h> +#include <linux/regulator/dbx500-prcmu.h> #include "../pins.h" diff --git a/arch/arm/mach-ux500/pm/suspend.c b/arch/arm/mach-ux500/pm/suspend.c index 44cd2373cc4..021ee8f53b5 100644 --- a/arch/arm/mach-ux500/pm/suspend.c +++ b/arch/arm/mach-ux500/pm/suspend.c @@ -155,7 +155,7 @@ exit: nmk_gpio_wakeups_resume(); ux500_suspend_dbg_remove_wake_on_uart(); - return 0; + return ret; } static int ux500_suspend_enter(suspend_state_t state) @@ -168,7 +168,8 @@ static int ux500_suspend_enter(suspend_state_t state) if (ux500_suspend_sleep_enabled()) return suspend(false); /* For debugging, if Sleep and DeepSleep disabled, do Idle */ - prcmu_set_power_state(PRCMU_AP_IDLE, true, true); + if (!cpu_is_u5500()) + prcmu_set_power_state(PRCMU_AP_IDLE, true, true); } dsb(); diff --git a/arch/arm/mach-ux500/prcmu-debug.c b/arch/arm/mach-ux500/prcmu-debug.c index 44e7c15bbcf..8344ff36ffb 100644 --- a/arch/arm/mach-ux500/prcmu-debug.c +++ b/arch/arm/mach-ux500/prcmu-debug.c @@ -285,24 +285,19 @@ static ssize_t opp_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos, int prcmu_qos_class) { - char buf[32]; - ssize_t buf_size; - long unsigned int i; + long unsigned i; + int err; - /* Get userspace string and assure termination */ - buf_size = min(count, (sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; + err = kstrtoul_from_user(user_buf, count, 0, &i); - if (strict_strtoul(buf, 0, &i) != 0) - return buf_size; + if (err) + return err; prcmu_qos_force_opp(prcmu_qos_class, i); pr_info("prcmu debug: forced OPP for %d to %d\n", prcmu_qos_class, (int)i); - return buf_size; + return count; } static ssize_t ddr_opp_write(struct file *file, @@ -335,20 +330,13 @@ static ssize_t ape_voltage_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - - char buf[32]; - ssize_t buf_size; - long unsigned int i; + long unsigned i; int err; - /* Get userspace string and assure termination */ - buf_size = min(count, (sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; + err = kstrtoul_from_user(user_buf, count, 0, &i); - if (strict_strtoul(buf, 0, &i) != 0) - return buf_size; + if (err) + return err; switch (i) { case 0: @@ -372,33 +360,27 @@ static ssize_t ape_voltage_write(struct file *file, default: pr_info("prcmu debug: value not equal to 0 or 1\n"); } - return buf_size; + return count; } static ssize_t cpufreq_delay_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { + int err; + long unsigned i; - char buf[32]; - ssize_t buf_size; - long unsigned int i; - - /* Get userspace string and assure termination */ - buf_size = min(count, (sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; + err = kstrtoul_from_user(user_buf, count, 0, &i); - if (strict_strtoul(buf, 0, &i) != 0) - return buf_size; + if (err) + return err; prcmu_qos_set_cpufreq_opp_delay(i); pr_info("prcmu debug: changed delay between cpufreq change and QoS " "requirement to %lu.\n", i); - return buf_size; + return count; } static int arm_opp_open_file(struct inode *inode, struct file *file) diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index e2fc2d21fa6..a01791e7566 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -41,3 +41,4 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o # ARM SoC drivers obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o +obj-$(CONFIG_UX500_SOC_DB5500) += db5500-cpufreq.o diff --git a/drivers/cpufreq/db5500-cpufreq.c b/drivers/cpufreq/db5500-cpufreq.c new file mode 100644 index 00000000000..7c78bcb4761 --- /dev/null +++ b/drivers/cpufreq/db5500-cpufreq.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) STMicroelectronics 2009 + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Sundar Iyer <sundar.iyer@stericsson.com> + * Author: Martin Persson <martin.persson@stericsson.com> + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> + * + */ +#include <linux/kernel.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <mach/prcmu.h> +#include <mach/id.h> + +static struct cpufreq_frequency_table freq_table[] = { + [0] = { + .index = 0, + .frequency = 200000, + }, + [1] = { + .index = 1, + .frequency = 300000, + }, + [2] = { + .index = 2, + .frequency = 600000, + }, + [3] = { + .index = 3, + .frequency = CPUFREQ_TABLE_END, + }, +}; + +static enum arm_opp idx2opp[] = { + ARM_EXTCLK, + ARM_50_OPP, + ARM_100_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> + +static struct freq_attr *db5500_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static int db5500_cpufreq_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, freq_table); +} + +static int db5500_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("db5500-cpufreq: Failed to set OPP level\n"); + return -EINVAL; + } + + /* post change notification */ + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +static unsigned int db5500_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; +} + +static int __cpuinit db5500_cpufreq_init(struct cpufreq_policy *policy) +{ + int res; + int i = 0; + + BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table)); + + pr_info("db5500-cpufreq : Available frequencies:\n"); + while (freq_table[i].frequency != CPUFREQ_TABLE_END) + pr_info(" %d Mhz\n", freq_table[i++].frequency/1000); + + /* 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("db5500-cpufreq : Failed to read policy table\n"); + return res; + } + + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; + policy->cur = db5500_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 db5500_cpufreq_driver = { + .flags = CPUFREQ_STICKY, + .verify = db5500_cpufreq_verify_speed, + .target = db5500_cpufreq_target, + .get = db5500_cpufreq_getspeed, + .init = db5500_cpufreq_init, + .name = "DB5500", + .attr = db5500_cpufreq_attr, +}; + +static int __init db5500_cpufreq_register(void) +{ + pr_info("cpufreq for DB5500 started\n"); + return cpufreq_register_driver(&db5500_cpufreq_driver); +} +device_initcall(db5500_cpufreq_register); diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c index 4943578f452..4b863110bd8 100644 --- a/drivers/cpufreq/db8500-cpufreq.c +++ b/drivers/cpufreq/db8500-cpufreq.c @@ -151,7 +151,7 @@ static unsigned int db8500_cpufreq_getspeed(unsigned int cpu) static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy) { int res; - int i; + int i = 0; BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table)); @@ -169,6 +169,10 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy) &work_wlan_workaround, msecs_to_jiffies(WLAN_PROBE_DELAY)); + pr_info("db8500-cpufreq : Available frequencies:\n"); + while (freq_table[i].frequency != CPUFREQ_TABLE_END) + pr_info(" %d Mhz\n", freq_table[i++].frequency/1000); + /* get policy fields based on the table */ res = cpufreq_frequency_table_cpuinfo(policy, freq_table); if (!res) diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c index da168cb57f6..f0aed67f29a 100644 --- a/drivers/crypto/ux500/cryp/cryp_core.c +++ b/drivers/crypto/ux500/cryp/cryp_core.c @@ -20,7 +20,7 @@ #include <linux/klist.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <mach/regulator.h> +#include <linux/regulator/dbx500-prcmu.h> #include <linux/semaphore.h> #include <crypto/aes.h> diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c index 3b472d0bfaa..aec6bcf5e1d 100644 --- a/drivers/crypto/ux500/hash/hash_core.c +++ b/drivers/crypto/ux500/hash/hash_core.c @@ -21,7 +21,7 @@ #include <linux/platform_device.h> #include <linux/crypto.h> -#include <mach/regulator.h> +#include <linux/regulator/dbx500-prcmu.h> #include <linux/bitops.h> #include <crypto/internal/hash.h> diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c index 75c773b232f..df0ce72e585 100755 --- a/drivers/mfd/ab5500-core.c +++ b/drivers/mfd/ab5500-core.c @@ -28,7 +28,8 @@ #include <linux/spinlock.h> #include <linux/mfd/core.h> #include <linux/version.h> -#include <linux/mfd/db5500-prcmu.h> +#include <linux/io.h> +#include <mach/prcmu.h> #define AB5500_NAME_STRING "ab5500" #define AB5500_ID_FORMAT_STRING "AB5500 %s" @@ -48,7 +49,7 @@ #define AB5500_MASK_BASE (0x60) #define AB5500_MASK_END (0x79) #define AB5500_CHIP_ID (0x20) - +#define AB5500_INTERRUPTS 0x007FFFFF /** * struct ab5500_bank * @slave_addr: I2C slave_addr found in AB5500 specification @@ -1072,17 +1073,6 @@ static struct mfd_cell ab5500_devs[AB5500_NUM_DEVICES] = { }; /* - * This stubbed prcmu functionality should be removed when the prcmu driver - * implements it. - */ -static u8 prcmu_event_buf[AB5500_NUM_EVENT_REG]; - -void prcmu_get_abb_event_buf(u8 **buf) -{ - *buf = prcmu_event_buf; -} - -/* * Functionality for getting/setting register values. */ static int get_register_interruptible(struct ab5500 *ab, u8 bank, u8 reg, @@ -1355,19 +1345,20 @@ static irqreturn_t ab5500_irq(int irq, void *data) { struct ab5500 *ab = data; u8 i; + u8 *pvalue; + u8 value; - /* - * TODO: use the ITMASTER registers to reduce the number of i2c reads. - */ - + prcmu_get_abb_event_buffer((void **)&pvalue); + if (unlikely(pvalue == NULL)) { + dev_err(ab->dev, "PRCMU not enabled!!!\n"); + goto error_irq; + } for (i = 0; i < AB5500_NUM_EVENT_REG; i++) { - int status; - u8 value; - - status = get_register_interruptible(ab, AB5500_BANK_IT, - AB5500_IT_LATCH0_REG + i, &value); - if (status < 0 || value == 0) + value = readb(pvalue); + if (value == 0) { + pvalue++; continue; + } do { int bit = __ffs(value); @@ -1376,9 +1367,12 @@ static irqreturn_t ab5500_irq(int irq, void *data) handle_nested_irq(ab->irq_base + line); value &= ~(1 << bit); } while (value); + pvalue++; } return IRQ_HANDLED; +error_irq: + return IRQ_NONE; } #ifdef CONFIG_DEBUG_FS @@ -2416,7 +2410,7 @@ static int __init ab5500_probe(struct platform_device *pdev) goto exit_remove_irq; } - + prcmu_config_abb_event_readout(AB5500_INTERRUPTS); /* This real unpredictable IRQ is of course sampled for entropy */ rand_initialize_irq(res->start); diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c index 7bbd34c04ad..f5774493e7e 100644 --- a/drivers/mfd/db5500-prcmu.c +++ b/drivers/mfd/db5500-prcmu.c @@ -19,6 +19,11 @@ #include <linux/irq.h> #include <linux/jiffies.h> #include <linux/bitops.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <linux/mfd/core.h> +#include <linux/regulator/db5500-prcmu.h> +#include <linux/regulator/machine.h> #include <linux/interrupt.h> #include <mach/hardware.h> #include <mach/irqs.h> @@ -26,6 +31,8 @@ #include <mach/db5500-regs.h> #include <mach/prcmu-regs.h> +#define PRCM_SW_RST_REASON (tcdm_base + 0xFF8) /* 2 bytes */ + #define _PRCM_MB_HEADER (tcdm_base + 0xFE8) #define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0) #define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1) @@ -64,6 +71,34 @@ #define PRCM_ACK_MB6 (tcdm_base + 0xF0C) #define PRCM_ACK_MB7 (tcdm_base + 0xF08) +/* Mailbox 0 REQs */ +#define PRCM_REQ_MB0_AP_POWER_STATE (PRCM_REQ_MB0 + 0x0) +#define PRCM_REQ_MB0_ULP_CLOCK_STATE (PRCM_REQ_MB0 + 0x1) +#define PRCM_REQ_MB0_AP_PLL_STATE (PRCM_REQ_MB0 + 0x2) +#define PRCM_REQ_MB0_DDR_STATE (PRCM_REQ_MB0 + 0x3) +#define PRCM_REQ_MB0_ESRAM0_STATE (PRCM_REQ_MB0 + 0x4) +#define PRCM_REQ_MB0_WAKEUP_DBB (PRCM_REQ_MB0 + 0x8) +#define PRCM_REQ_MB0_WAKEUP_ABB (PRCM_REQ_MB0 + 0xC) + +/* Mailbox 0 ACKs */ +#define PRCM_ACK_MB0_AP_PWRSTTR_STATUS (PRCM_ACK_MB0 + 0x0) +#define PRCM_ACK_MB0_READ_POINTER (PRCM_ACK_MB0 + 0x1) +#define PRCM_ACK_MB0_WAKEUP_0_DBB (PRCM_ACK_MB0 + 0x4) +#define PRCM_ACK_MB0_WAKEUP_0_ABB (PRCM_ACK_MB0 + 0x8) +#define PRCM_ACK_MB0_WAKEUP_1_DBB (PRCM_ACK_MB0 + 0x28) +#define PRCM_ACK_MB0_WAKEUP_1_ABB (PRCM_ACK_MB0 + 0x2C) +#define PRCM_ACK_MB0_EVENT_ABB_NUMBERS 20 + +/* Request mailbox 1 fields. */ +#define PRCM_REQ_MB1_ARM_OPP (PRCM_REQ_MB1 + 0x0) +#define PRCM_REQ_MB1_APE_OPP (PRCM_REQ_MB1 + 0x1) + +/* Mailbox 1 ACKs */ +#define PRCM_ACK_MB1_CURRENT_ARM_OPP (PRCM_ACK_MB1 + 0x0) +#define PRCM_ACK_MB1_CURRENT_APE_OPP (PRCM_ACK_MB1 + 0x1) +#define PRCM_ACK_MB1_ARM_VOLT_STATUS (PRCM_ACK_MB1 + 0x2) +#define PRCM_ACK_MB1_APE_VOLT_STATUS (PRCM_ACK_MB1 + 0x3) + /* Mailbox 2 REQs */ #define PRCM_REQ_MB2_EPOD_CLIENT (PRCM_REQ_MB2 + 0x0) #define PRCM_REQ_MB2_EPOD_STATE (PRCM_REQ_MB2 + 0x1) @@ -84,31 +119,59 @@ enum mb_return_code { /* Mailbox 0 headers. */ enum mb0_header { - /* request */ - RMB0H_PWR_STATE_TRANS = 1, - RMB0H_WAKE_UP_CFG, - RMB0H_RD_WAKE_UP_ACK, /* acknowledge */ - AMB0H_WAKE_UP = 1, + MB0H_WAKE_UP = 0, + /* request */ + MB0H_PWR_STATE_TRANS, + MB0H_WAKE_UP_CFG, + MB0H_RD_WAKE_UP_ACK, }; -/* Mailbox 5 headers. */ +/* Mailbox 1 headers.*/ +enum mb1_header { + MB1H_ARM_OPP = 1, + MB1H_APE_OPP, + MB1H_ARM_APE_OPP, +}; + +/* Mailbox 2 headers. */ enum mb2_header { MB2H_EPOD_REQUEST = 1, MB2H_CLK_REQUEST, MB2H_PLL_REQUEST, }; +/* Mailbox 3 headers. */ +enum mb3_header { + MB3H_REFCLK_REQUEST = 1, +}; + +enum sysclk_state { + SYSCLK_OFF, + SYSCLK_ON, +}; + /* Mailbox 5 headers. */ enum mb5_header { MB5H_I2C_WRITE = 1, MB5H_I2C_READ, }; +enum db5500_arm_opp { + DB5500_ARM_100_OPP = 1, + DB5500_ARM_50_OPP, + DB5500_ARM_EXT_OPP, +}; + enum epod_state { EPOD_OFF, EPOD_ON, }; +enum epod_onoffret_state { + EPOD_OOR_OFF, + EPOD_OOR_RET, + EPOD_OOR_ON, +}; enum db5500_prcmu_pll { DB5500_PLL_SOC0, DB5500_PLL_SOC1, @@ -116,6 +179,24 @@ enum db5500_prcmu_pll { DB5500_NUM_PLL_ID, }; +enum on_off_ret { + OFF_ST, + RET_ST, + ON_ST, +}; + +enum db5500_ap_pwr_state { + DB5500_AP_SLEEP = 2, + DB5500_AP_DEEP_SLEEP, + DB5500_AP_IDLE, +}; + +/* Request mailbox 3 fields */ +#define PRCM_REQ_MB3_REFCLK_MGT (PRCM_REQ_MB3 + 0x0) + +/* Ack. mailbox 3 fields */ +#define PRCM_ACK_MB3_REFCLK_REQ (PRCM_ACK_MB3 + 0x0) + /* Request mailbox 5 fields. */ #define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0) #define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1) @@ -156,13 +237,120 @@ enum db5500_prcmu_pll { #define PRCMU_PLLDSI_LOCKP_LOCKED 0x3 /* + * Wakeups/IRQs + */ + +#define WAKEUP_BIT_RTC BIT(0) +#define WAKEUP_BIT_RTT0 BIT(1) +#define WAKEUP_BIT_RTT1 BIT(2) +#define WAKEUP_BIT_CD_IRQ BIT(3) +#define WAKEUP_BIT_SRP_TIM BIT(4) +#define WAKEUP_BIT_APE_REQ BIT(5) +#define WAKEUP_BIT_USB BIT(6) +#define WAKEUP_BIT_ABB BIT(7) +#define WAKEUP_BIT_LOW_POWER_AUDIO BIT(8) +#define WAKEUP_BIT_TEMP_SENSOR BIT(9) +#define WAKEUP_BIT_ARM BIT(10) +#define WAKEUP_BIT_AC_WAKE_ACK BIT(11) +#define WAKEUP_BIT_MODEM_SW_RESET_REQ BIT(20) +#define WAKEUP_BIT_GPIO0 BIT(23) +#define WAKEUP_BIT_GPIO1 BIT(24) +#define WAKEUP_BIT_GPIO2 BIT(25) +#define WAKEUP_BIT_GPIO3 BIT(26) +#define WAKEUP_BIT_GPIO4 BIT(27) +#define WAKEUP_BIT_GPIO5 BIT(28) +#define WAKEUP_BIT_GPIO6 BIT(29) +#define WAKEUP_BIT_GPIO7 BIT(30) +#define WAKEUP_BIT_AC_REL_ACK BIT(30) + +/* + * This vector maps irq numbers to the bits in the bit field used in + * communication with the PRCMU firmware. + * + * The reason for having this is to keep the irq numbers contiguous even though + * the bits in the bit field are not. (The bits also have a tendency to move + * around, to further complicate matters.) + */ +#define IRQ_INDEX(_name) ((IRQ_DB5500_PRCMU_##_name) - IRQ_DB5500_PRCMU_BASE) +#define IRQ_ENTRY(_name)[IRQ_INDEX(_name)] = (WAKEUP_BIT_##_name) +static u32 prcmu_irq_bit[NUM_DB5500_PRCMU_WAKEUPS] = { + IRQ_ENTRY(RTC), + IRQ_ENTRY(RTT0), + IRQ_ENTRY(RTT1), + IRQ_ENTRY(CD_IRQ), + IRQ_ENTRY(SRP_TIM), + IRQ_ENTRY(APE_REQ), + IRQ_ENTRY(USB), + IRQ_ENTRY(ABB), + IRQ_ENTRY(LOW_POWER_AUDIO), + IRQ_ENTRY(TEMP_SENSOR), + IRQ_ENTRY(ARM), + IRQ_ENTRY(AC_WAKE_ACK), + IRQ_ENTRY(MODEM_SW_RESET_REQ), + IRQ_ENTRY(GPIO0), + IRQ_ENTRY(GPIO1), + IRQ_ENTRY(GPIO2), + IRQ_ENTRY(GPIO3), + IRQ_ENTRY(GPIO4), + IRQ_ENTRY(GPIO5), + IRQ_ENTRY(GPIO6), + IRQ_ENTRY(GPIO7), + IRQ_ENTRY(AC_REL_ACK), +}; + +#define VALID_WAKEUPS (BIT(NUM_PRCMU_WAKEUP_INDICES) - 1) +#define WAKEUP_ENTRY(_name)[PRCMU_WAKEUP_INDEX_##_name] = (WAKEUP_BIT_##_name) +static u32 prcmu_wakeup_bit[NUM_PRCMU_WAKEUP_INDICES] = { + WAKEUP_ENTRY(RTC), + WAKEUP_ENTRY(RTT0), + WAKEUP_ENTRY(RTT1), + WAKEUP_ENTRY(CD_IRQ), + WAKEUP_ENTRY(USB), + WAKEUP_ENTRY(ABB), + WAKEUP_ENTRY(ARM) +}; + +/* * mb0_transfer - state needed for mailbox 0 communication. - * @lock: The transaction lock. + * @lock The transaction lock. + * @dbb_irqs_lock lock used for (un)masking DBB wakeup interrupts + * @mask_work: Work structure used for (un)masking wakeup interrupts. + * @req: Request data that need to persist between requests. */ static struct { spinlock_t lock; + spinlock_t dbb_irqs_lock; + struct work_struct mask_work; + struct { + u32 dbb_irqs; + u32 dbb_wakeups; + u32 abb_events; + } req; } mb0_transfer; + +/* + * mb1_transfer - state needed for mailbox 1 communication. + * @lock: The transaction lock. + * @work: The transaction completion structure. + * @req_arm_opp Requested arm opp + * @req_ape_opp Requested ape opp + * @ack: Reply ("acknowledge") data. + */ +static struct { + struct mutex lock; + struct completion work; + u8 req_arm_opp; + u8 req_ape_opp; + struct { + u8 header; + u8 arm_opp; + u8 ape_opp; + u8 arm_voltage_st; + u8 ape_voltage_st; + } ack; +} mb1_transfer; + /* * mb2_transfer - state needed for mailbox 2 communication. * @lock: The transaction lock. @@ -174,8 +362,8 @@ static struct { struct mutex lock; struct completion work; struct { - u8 epod_states[DB5500_NUM_EPOD_ID]; - u8 pll_states[DB5500_NUM_PLL_ID]; + u8 epod_st[DB5500_NUM_EPOD_ID]; + u8 pll_st[DB5500_NUM_PLL_ID]; } req; struct { u8 header; @@ -184,6 +372,23 @@ static struct { } mb2_transfer; /* + * mb3_transfer - state needed for mailbox 3 communication. + * @sysclk_lock: A lock used to handle concurrent sysclk requests. + * @sysclk_work: Work structure used for sysclk requests. + * @req_st: Requested clock state. + * @ack: Acknowledgement data + */ +static struct { + struct mutex sysclk_lock; + struct completion sysclk_work; + enum sysclk_state req_st; + struct { + u8 header; + u8 status; + } ack; +} mb3_transfer; + +/* * mb5_transfer - state needed for mailbox 5 communication. * @lock: The transaction lock. * @work: The transaction completion structure. @@ -239,6 +444,55 @@ static struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = { CLK_MGT_ENTRY(SVACLK), }; +bool db5500_prcmu_is_ac_wake_requested(void) +{ + return false; +} + +static int request_sysclk(bool enable) +{ + int r; + + r = 0; + mutex_lock(&mb3_transfer.sysclk_lock); + + while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(3)) + cpu_relax(); + + if (enable) + mb3_transfer.req_st = SYSCLK_ON; + else + mb3_transfer.req_st = SYSCLK_OFF; + + writeb(mb3_transfer.req_st, (PRCM_REQ_MB3_REFCLK_MGT)); + + writeb(MB3H_REFCLK_REQUEST, (PRCM_REQ_MB3_HEADER)); + writel(MBOX_BIT(3), PRCM_MBOX_CPU_SET); + + /* + * The firmware only sends an ACK if we want to enable the + * SysClk, and it succeeds. + */ + if (!wait_for_completion_timeout(&mb3_transfer.sysclk_work, + msecs_to_jiffies(20000))) { + pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", + __func__); + r = -EIO; + WARN(1, "Failed to set sysclk"); + goto unlock_and_return; + } + + if ((mb3_transfer.ack.header != MB3H_REFCLK_REQUEST) || + (mb3_transfer.ack.status != mb3_transfer.req_st)) { + r = -EIO; + } + +unlock_and_return: + mutex_unlock(&mb3_transfer.sysclk_lock); + + return r; +} + static int request_timclk(bool enable) { u32 val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK); @@ -298,11 +552,11 @@ static int request_pll(u8 pll, bool enable) while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(2)) cpu_relax(); - mb2_transfer.req.pll_states[pll] = enable; + mb2_transfer.req.pll_st[pll] = enable; /* fill in mailbox */ writeb(pll, PRCM_REQ_MB2_PLL_CLIENT); - writeb(mb2_transfer.req.pll_states[pll], PRCM_REQ_MB2_PLL_STATE); + writeb(mb2_transfer.req.pll_st[pll], PRCM_REQ_MB2_PLL_STATE); writeb(MB2H_PLL_REQUEST, PRCM_REQ_MB2_HEADER); @@ -325,12 +579,8 @@ unlock_and_return: return r; } -void db5500_prcmu_enable_wakeups(u32 wakeups) -{ -} - /** - * prcmu_request_clock() - Request for a clock to be enabled or disabled. + * db5500_prcmu_request_clock() - Request for a clock to be enabled or disabled. * @clock: The clock for which the request is made. * @enable: Whether the clock should be enabled (true) or disabled (false). * @@ -350,11 +600,144 @@ int db5500_prcmu_request_clock(u8 clock, bool enable) else if (clock == PRCMU_PLLDDR) return request_pll(DB5500_PLL_DDR, enable); else if (clock == PRCMU_SYSCLK) - return -EINVAL; + return request_sysclk(enable); else return -EINVAL; } +/* This function should only be called while mb0_transfer.lock is held. */ +static void config_wakeups(void) +{ + static u32 last_dbb_events; + static u32 last_abb_events; + u32 dbb_events; + u32 abb_events; + + dbb_events = mb0_transfer.req.dbb_irqs | mb0_transfer.req.dbb_wakeups; + + abb_events = mb0_transfer.req.abb_events; + + if ((dbb_events == last_dbb_events) && (abb_events == last_abb_events)) + return; + + while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) + cpu_relax(); + + writel(dbb_events, PRCM_REQ_MB0_WAKEUP_DBB); + writel(abb_events, PRCM_REQ_MB0_WAKEUP_ABB); + writeb(MB0H_WAKE_UP_CFG, PRCM_REQ_MB0_HEADER); + writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET); + + last_dbb_events = dbb_events; + last_abb_events = abb_events; +} + +int db5500_prcmu_config_esram0_deep_sleep(u8 state) +{ + unsigned long flags; + + if ((state > ESRAM0_DEEP_SLEEP_STATE_RET) || + (state < ESRAM0_DEEP_SLEEP_STATE_OFF)) + return -EINVAL; + + spin_lock_irqsave(&mb0_transfer.lock, flags); + + if (state == ESRAM0_DEEP_SLEEP_STATE_RET) + writeb(RET_ST, PRCM_REQ_MB0_ESRAM0_STATE); + else + writeb(OFF_ST, PRCM_REQ_MB0_ESRAM0_STATE); + + spin_unlock_irqrestore(&mb0_transfer.lock, flags); + + return 0; +} + +int db5500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll) +{ + int r = 0; + unsigned long flags; + + /* Deep Idle is not supported in DB5500 */ + BUG_ON((state < PRCMU_AP_SLEEP) || (state >= PRCMU_AP_DEEP_IDLE)); + + spin_lock_irqsave(&mb0_transfer.lock, flags); + + while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) + cpu_relax(); + + switch (state) { + case PRCMU_AP_IDLE: + writeb(DB5500_AP_IDLE, PRCM_REQ_MB0_AP_POWER_STATE); + /* TODO: Can be high latency */ + writeb(DDR_PWR_STATE_UNCHANGED, PRCM_REQ_MB0_DDR_STATE); + break; + case PRCMU_AP_SLEEP: + writeb(DB5500_AP_SLEEP, PRCM_REQ_MB0_AP_POWER_STATE); + break; + case PRCMU_AP_DEEP_SLEEP: + writeb(DB5500_AP_DEEP_SLEEP, PRCM_REQ_MB0_AP_POWER_STATE); + break; + default: + r = -EINVAL; + goto unlock_return; + } + writeb((keep_ap_pll ? 1 : 0), PRCM_REQ_MB0_AP_PLL_STATE); + writeb((keep_ulp_clk ? 1 : 0), PRCM_REQ_MB0_ULP_CLOCK_STATE); + + writeb(MB0H_PWR_STATE_TRANS, PRCM_REQ_MB0_HEADER); + writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET); + +unlock_return: + spin_unlock_irqrestore(&mb0_transfer.lock, flags); + + return r; +} + +void db5500_prcmu_enable_wakeups(u32 wakeups) +{ + unsigned long flags; + u32 bits; + int i; + + BUG_ON(wakeups != (wakeups & VALID_WAKEUPS)); + + for (i = 0, bits = 0; i < NUM_PRCMU_WAKEUP_INDICES; i++) { + if (wakeups & BIT(i)) { + if (prcmu_wakeup_bit[i] == 0) + WARN(1, "WAKEUP NOT SUPPORTED"); + else + bits |= prcmu_wakeup_bit[i]; + } + } + + spin_lock_irqsave(&mb0_transfer.lock, flags); + + mb0_transfer.req.dbb_wakeups = bits; + config_wakeups(); + + spin_unlock_irqrestore(&mb0_transfer.lock, flags); +} + +void db5500_prcmu_config_abb_event_readout(u32 abb_events) +{ + unsigned long flags; + + spin_lock_irqsave(&mb0_transfer.lock, flags); + + mb0_transfer.req.abb_events = abb_events; + config_wakeups(); + + spin_unlock_irqrestore(&mb0_transfer.lock, flags); +} + +void db5500_prcmu_get_abb_event_buffer(void __iomem **buf) +{ + if (readb(PRCM_ACK_MB0_READ_POINTER) & 1) + *buf = (PRCM_ACK_MB0_WAKEUP_1_ABB); + else + *buf = (PRCM_ACK_MB0_WAKEUP_0_ABB); +} + /** * db5500_prcmu_abb_read() - Read register value(s) from the ABB. * @slave: The I2C slave address. @@ -437,6 +820,75 @@ int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size) return r; } +/** + * db5500_prcmu_set_arm_opp - set the appropriate ARM OPP + * @opp: The new ARM operating point to which transition is to be made + * Returns: 0 on success, non-zero on failure + * + * This function sets the the operating point of the ARM. + */ +int db5500_prcmu_set_arm_opp(u8 opp) +{ + int r; + u8 db5500_opp; + + r = 0; + + switch (opp) { + case ARM_EXTCLK: + db5500_opp = DB5500_ARM_EXT_OPP; + break; + case ARM_50_OPP: + db5500_opp = DB5500_ARM_50_OPP; + break; + case ARM_100_OPP: + db5500_opp = DB5500_ARM_100_OPP; + break; + default: + pr_err("prcmu: %s() received wrong opp value: %d\n", + __func__, opp); + r = -EINVAL; + goto bailout; + } + + mutex_lock(&mb1_transfer.lock); + + while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) + cpu_relax(); + + writeb(MB1H_ARM_OPP, PRCM_REQ_MB1_HEADER); + + writeb(db5500_opp, PRCM_REQ_MB1_ARM_OPP); + writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET); + + if (!wait_for_completion_timeout(&mb1_transfer.work, + msecs_to_jiffies(500))) { + r = -EIO; + WARN(1, "prcmu: failed to set arm opp"); + goto unlock_and_return; + } + + if (mb1_transfer.ack.header != MB1H_ARM_OPP || + (mb1_transfer.ack.arm_opp != db5500_opp) || + (mb1_transfer.ack.arm_voltage_st != RC_SUCCESS)) + r = -EIO; + +unlock_and_return: + mutex_unlock(&mb1_transfer.lock); +bailout: + return r; +} + +/** + * db5500_prcmu_get_arm_opp - get the current ARM OPP + * + * Returns: the current ARM OPP + */ +int db5500_prcmu_get_arm_opp(void) +{ + return readb(PRCM_ACK_MB1_CURRENT_ARM_OPP); +} + int prcmu_resetout(u8 resoutn, u8 state) { int pin = -1; @@ -511,6 +963,29 @@ int db5500_prcmu_set_display_clocks(void) return 0; } +/** + * db5500_prcmu_system_reset - System reset + * + * Saves the reset reason code and then sets the APE_SOFTRST register which + * fires an interrupt to fw + */ +void db5500_prcmu_system_reset(u16 reset_code) +{ + writew(reset_code, PRCM_SW_RST_REASON); + writel(1, PRCM_APE_SOFTRST); +} + +/** + * db5500_prcmu_get_reset_code - Retrieve SW reset reason code + * + * Retrieves the reset reason code stored by prcmu_system_reset() before + * last restart. + */ +u16 db5500_prcmu_get_reset_code(void) +{ + return readw(PRCM_SW_RST_REASON); +} + static void ack_dbb_wakeup(void) { unsigned long flags; @@ -520,34 +995,27 @@ static void ack_dbb_wakeup(void) while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) cpu_relax(); - writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER); + writeb(MB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER); writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET); spin_unlock_irqrestore(&mb0_transfer.lock, flags); } -int db5500_prcmu_set_epod(u16 epod_id, u8 epod_state) +int db5500_prcmu_set_epod(u16 epod, u8 epod_state) { int r = 0; bool ram_retention = false; /* check argument */ - BUG_ON(epod_id < DB5500_EPOD_ID_BASE); + BUG_ON(epod < DB5500_EPOD_ID_BASE); BUG_ON(epod_state > EPOD_STATE_ON); + BUG_ON((epod - DB5500_EPOD_ID_BASE) >= DB5500_NUM_EPOD_ID); - epod_id &= 0xFF; - BUG_ON(epod_id > DB5500_NUM_EPOD_ID); - - /* TODO: FW does not take retention for ESRAM12? - set flag if retention is possible */ - switch (epod_id) { - case DB5500_EPOD_ID_ESRAM12: + if (epod == DB5500_EPOD_ID_ESRAM12) ram_retention = true; - break; - } /* check argument */ - /* BUG_ON(epod_state == EPOD_STATE_RAMRET && !ram_retention); */ + BUG_ON(epod_state == EPOD_STATE_RAMRET && !ram_retention); /* get lock */ mutex_lock(&mb2_transfer.lock); @@ -556,19 +1024,42 @@ int db5500_prcmu_set_epod(u16 epod_id, u8 epod_state) while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(2)) cpu_relax(); - /* PRCMU FW can only handle on or off */ - if (epod_state == EPOD_STATE_ON) - mb2_transfer.req.epod_states[epod_id] = EPOD_ON; - else if (epod_state == EPOD_STATE_OFF) - mb2_transfer.req.epod_states[epod_id] = EPOD_OFF; - else { - r = -EINVAL; - goto unlock_and_return; + /* Retention is allowed only for ESRAM12 */ + if (epod == DB5500_EPOD_ID_ESRAM12) { + switch (epod_state) { + case EPOD_STATE_ON: + mb2_transfer.req.epod_st[epod - DB5500_EPOD_ID_BASE] = + EPOD_OOR_ON; + break; + case EPOD_STATE_OFF: + mb2_transfer.req.epod_st[epod - DB5500_EPOD_ID_BASE] = + EPOD_OOR_OFF; + break; + case EPOD_STATE_RAMRET: + mb2_transfer.req.epod_st[epod - DB5500_EPOD_ID_BASE] = + EPOD_OOR_RET; + break; + default: + r = -EINVAL; + goto unlock_and_return; + break; + } + } else { + if (epod_state == EPOD_STATE_ON) + mb2_transfer.req.epod_st[epod - DB5500_EPOD_ID_BASE] = + EPOD_ON; + else if (epod_state == EPOD_STATE_OFF) + mb2_transfer.req.epod_st[epod - DB5500_EPOD_ID_BASE] = + EPOD_OFF; + else { + r = -EINVAL; + goto unlock_and_return; + } } - /* fill in mailbox */ - writeb(epod_id, PRCM_REQ_MB2_EPOD_CLIENT); - writeb(mb2_transfer.req.epod_states[epod_id], PRCM_REQ_MB2_EPOD_STATE); + writeb((epod - DB5500_EPOD_ID_BASE), PRCM_REQ_MB2_EPOD_CLIENT); + writeb(mb2_transfer.req.epod_st[epod - DB5500_EPOD_ID_BASE], + PRCM_REQ_MB2_EPOD_STATE); writeb(MB2H_EPOD_REQUEST, PRCM_REQ_MB2_HEADER); @@ -601,11 +1092,25 @@ static inline void print_unknown_header_warning(u8 n, u8 header) static bool read_mailbox_0(void) { bool r; + u32 ev; + unsigned int n; + u8 header; header = readb(PRCM_ACK_MB0_HEADER); switch (header) { - case AMB0H_WAKE_UP: + case MB0H_WAKE_UP: + if (readb(PRCM_ACK_MB0_READ_POINTER) & 1) + ev = readl(PRCM_ACK_MB0_WAKEUP_1_DBB); + else + ev = readl(PRCM_ACK_MB0_WAKEUP_0_DBB); + + ev &= mb0_transfer.req.dbb_irqs; + + for (n = 0; n < NUM_DB5500_PRCMU_WAKEUPS; n++) { + if (ev & prcmu_irq_bit[n]) + generic_handle_irq(IRQ_DB5500_PRCMU_BASE + n); + } r = true; break; default: @@ -619,7 +1124,33 @@ static bool read_mailbox_0(void) static bool read_mailbox_1(void) { + u8 header; + bool do_complete = true; + + header = mb1_transfer.ack.header = readb(PRCM_ACK_MB1_HEADER); + + switch (header) { + case MB1H_ARM_OPP: + mb1_transfer.ack.arm_opp = readb(PRCM_ACK_MB1_CURRENT_ARM_OPP); + mb1_transfer.ack.arm_voltage_st = + readb(PRCM_ACK_MB1_ARM_VOLT_STATUS); + break; + case MB1H_ARM_APE_OPP: + mb1_transfer.ack.ape_opp = readb(PRCM_ACK_MB1_CURRENT_APE_OPP); + mb1_transfer.ack.ape_voltage_st = + readb(PRCM_ACK_MB1_APE_VOLT_STATUS); + break; + default: + print_unknown_header_warning(1, header); + do_complete = false; + break; + } + writel(MBOX_BIT(1), PRCM_ARM_IT1_CLR); + + if (do_complete) + complete(&mb1_transfer.work); + return false; } @@ -652,7 +1183,22 @@ static bool read_mailbox_2(void) static bool read_mailbox_3(void) { - writel(MBOX_BIT(3), PRCM_ARM_IT1_CLR); + u8 header; + + header = readb(PRCM_ACK_MB3_HEADER); + mb3_transfer.ack.header = header; + switch (header) { + case MB3H_REFCLK_REQUEST: + mb3_transfer.ack.status = readb(PRCM_ACK_MB3_REFCLK_REQ); + writel(MBOX_BIT(3), PRCM_ARM_IT1_CLR); + complete(&mb3_transfer.sysclk_work); + break; + default: + writel(MBOX_BIT(3), PRCM_ARM_IT1_CLR); + pr_err("prcmu: wrong MB3 header\n"); + break; + } + return false; } @@ -733,23 +1279,171 @@ static irqreturn_t prcmu_irq_thread_fn(int irq, void *data) return IRQ_HANDLED; } +static void prcmu_mask_work(struct work_struct *work) +{ + unsigned long flags; + + spin_lock_irqsave(&mb0_transfer.lock, flags); + + config_wakeups(); + + spin_unlock_irqrestore(&mb0_transfer.lock, flags); +} + +static void prcmu_irq_mask(struct irq_data *d) +{ + unsigned long flags; + + spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); + + mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->irq - IRQ_DB5500_PRCMU_BASE]; + + spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); + schedule_work(&mb0_transfer.mask_work); +} + +static void prcmu_irq_unmask(struct irq_data *d) +{ + unsigned long flags; + + spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); + + mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->irq - IRQ_DB5500_PRCMU_BASE]; + + spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); + schedule_work(&mb0_transfer.mask_work); +} + +static void noop(struct irq_data *d) +{ +} + +static struct irq_chip prcmu_irq_chip = { + .name = "prcmu", + .irq_disable = prcmu_irq_mask, + .irq_ack = noop, + .irq_mask = prcmu_irq_mask, + .irq_unmask = prcmu_irq_unmask, +}; + void __init db5500_prcmu_early_init(void) { + unsigned int i; + tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE); spin_lock_init(&mb0_transfer.lock); + spin_lock_init(&mb0_transfer.dbb_irqs_lock); + mutex_init(&mb1_transfer.lock); + init_completion(&mb1_transfer.work); mutex_init(&mb2_transfer.lock); - mutex_init(&mb5_transfer.lock); init_completion(&mb2_transfer.work); + mutex_init(&mb3_transfer.sysclk_lock); + init_completion(&mb3_transfer.sysclk_work); + mutex_init(&mb5_transfer.lock); init_completion(&mb5_transfer.work); + + INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work); + + /* Initalize irqs. */ + for (i = 0; i < NUM_DB5500_PRCMU_WAKEUPS; i++) { + unsigned int irq; + + irq = IRQ_DB5500_PRCMU_BASE + i; + irq_set_chip_and_handler(irq, &prcmu_irq_chip, + handle_simple_irq); + set_irq_flags(irq, IRQF_VALID); + } } +/* + * Power domain switches (ePODs) modeled as regulators for the DB5500 SoC + */ +static struct regulator_consumer_supply db5500_vape_consumers[] = { + REGULATOR_SUPPLY("v-ape", NULL), + REGULATOR_SUPPLY("v-i2c", "nmk-i2c.0"), + REGULATOR_SUPPLY("v-i2c", "nmk-i2c.1"), + REGULATOR_SUPPLY("v-i2c", "nmk-i2c.2"), + REGULATOR_SUPPLY("v-i2c", "nmk-i2c.3"), + REGULATOR_SUPPLY("v-mmc", "sdi0"), + REGULATOR_SUPPLY("v-mmc", "sdi1"), + REGULATOR_SUPPLY("v-mmc", "sdi2"), + REGULATOR_SUPPLY("v-mmc", "sdi3"), + REGULATOR_SUPPLY("v-mmc", "sdi4"), + REGULATOR_SUPPLY("v-uart", "uart0"), + REGULATOR_SUPPLY("v-uart", "uart1"), + REGULATOR_SUPPLY("v-uart", "uart2"), + REGULATOR_SUPPLY("v-uart", "uart3"), +}; + +static struct regulator_consumer_supply db5500_sga_consumers[] = { + REGULATOR_SUPPLY("debug", "reg-virt-consumer.0"), + REGULATOR_SUPPLY("v-mali", NULL), +}; + +static struct regulator_consumer_supply db5500_hva_consumers[] = { + REGULATOR_SUPPLY("debug", "reg-virt-consumer.1"), + REGULATOR_SUPPLY("v-hva", NULL), +}; + +static struct regulator_consumer_supply db5500_sia_consumers[] = { + REGULATOR_SUPPLY("debug", "reg-virt-consumer.2"), + REGULATOR_SUPPLY("v-sia", "mmio_camera"), +}; + +static struct regulator_consumer_supply db5500_disp_consumers[] = { + REGULATOR_SUPPLY("debug", "reg-virt-consumer.3"), + REGULATOR_SUPPLY("vsupply", "b2r2_bus"), + REGULATOR_SUPPLY("vsupply", "mcde"), +}; + +static struct regulator_consumer_supply db5500_esram12_consumers[] = { + REGULATOR_SUPPLY("debug", "reg-virt-consumer.4"), + REGULATOR_SUPPLY("v-esram12", "mcde"), + REGULATOR_SUPPLY("esram12", "cm_control"), +}; + +#define DB5500_REGULATOR_SWITCH(lower, upper) \ +[DB5500_REGULATOR_SWITCH_##upper] = { \ + .constraints = { \ + .valid_ops_mask = REGULATOR_CHANGE_STATUS, \ + }, \ + .consumer_supplies = db5500_##lower##_consumers, \ + .num_consumer_supplies = ARRAY_SIZE(db5500_##lower##_consumers),\ +} + +static struct regulator_init_data db5500_regulators[DB5500_NUM_REGULATORS] = { + [DB5500_REGULATOR_VAPE] = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = db5500_vape_consumers, + .num_consumer_supplies = ARRAY_SIZE(db5500_vape_consumers), + }, + DB5500_REGULATOR_SWITCH(sga, SGA), + DB5500_REGULATOR_SWITCH(hva, HVA), + DB5500_REGULATOR_SWITCH(sia, SIA), + DB5500_REGULATOR_SWITCH(disp, DISP), + DB5500_REGULATOR_SWITCH(esram12, ESRAM12), +}; + +static struct mfd_cell db5500_prcmu_devs[] = { + { + .name = "db5500-prcmu-regulators", + .platform_data = &db5500_regulators, + .pdata_size = sizeof(db5500_regulators), + }, + { + .name = "cpufreq-u5500", + }, +}; + /** * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic * */ -int __init db5500_prcmu_init(void) +static int __init db5500_prcmu_probe(struct platform_device *pdev) { - int r = 0; + int err = 0; if (ux500_is_svp() || !cpu_is_u5500()) return -ENODEV; @@ -757,13 +1451,38 @@ int __init db5500_prcmu_init(void) /* Clean up the mailbox interrupts after pre-kernel code. */ writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR); - r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler, - prcmu_irq_thread_fn, 0, "prcmu", NULL); - if (r < 0) { + err = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler, + prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL); + if (err < 0) { pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n"); - return -EBUSY; + err = -EBUSY; + goto no_irq_return; } - return 0; + + err = mfd_add_devices(&pdev->dev, 0, db5500_prcmu_devs, + ARRAY_SIZE(db5500_prcmu_devs), NULL, + 0); + + if (err) + pr_err("prcmu: Failed to add subdevices\n"); + else + pr_info("DB5500 PRCMU initialized\n"); + +no_irq_return: + return err; + +} + +static struct platform_driver db5500_prcmu_driver = { + .driver = { + .name = "db5500-prcmu", + .owner = THIS_MODULE, + }, +}; + +static int __init db5500_prcmu_init(void) +{ + return platform_driver_probe(&db5500_prcmu_driver, db5500_prcmu_probe); } arch_initcall(db5500_prcmu_init); diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 5a1283d1a83..a2926a9cc05 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -185,6 +185,11 @@ #define MB4H_HOTDOG 0x12 #define MB4H_HOTMON 0x13 #define MB4H_HOT_PERIOD 0x14 +#define MB4H_A9WDOG_CONF 0x16 +#define MB4H_A9WDOG_EN 0x17 +#define MB4H_A9WDOG_DIS 0x18 +#define MB4H_A9WDOG_LOAD 0x19 +#define MB4H_A9WDOG_KICK 0x20 /* Mailbox 4 Requests */ #define PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE (PRCM_REQ_MB4 + 0x0) @@ -197,6 +202,13 @@ #define PRCM_REQ_MB4_HOT_PERIOD (PRCM_REQ_MB4 + 0x0) #define HOTMON_CONFIG_LOW BIT(0) #define HOTMON_CONFIG_HIGH BIT(1) +#define PRCM_REQ_MB4_A9WDOG_0 (PRCM_REQ_MB4 + 0x0) +#define PRCM_REQ_MB4_A9WDOG_1 (PRCM_REQ_MB4 + 0x1) +#define PRCM_REQ_MB4_A9WDOG_2 (PRCM_REQ_MB4 + 0x2) +#define PRCM_REQ_MB4_A9WDOG_3 (PRCM_REQ_MB4 + 0x3) +#define A9WDOG_AUTO_OFF_EN BIT(7) +#define A9WDOG_AUTO_OFF_DIS 0 +#define A9WDOG_ID_MASK 0xf /* Mailbox 5 Requests */ #define PRCM_REQ_MB5_I2C_SLAVE_OP (PRCM_REQ_MB5 + 0x0) @@ -527,7 +539,7 @@ static struct { } prcmu_version; -int prcmu_enable_dsipll(void) +int db8500_prcmu_enable_dsipll(void) { int i; unsigned int plldsifreq; @@ -562,7 +574,7 @@ int prcmu_enable_dsipll(void) return 0; } -int prcmu_disable_dsipll(void) +int db8500_prcmu_disable_dsipll(void) { /* Disable dsi pll */ writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE); @@ -571,7 +583,7 @@ int prcmu_disable_dsipll(void) return 0; } -int prcmu_set_display_clocks(void) +int db8500_prcmu_set_display_clocks(void) { unsigned long flags; unsigned int dsiclk; @@ -832,7 +844,7 @@ void db8500_prcmu_enable_wakeups(u32 wakeups) spin_unlock_irqrestore(&mb0_transfer.lock, flags); } -void prcmu_config_abb_event_readout(u32 abb_events) +void db8500_prcmu_config_abb_event_readout(u32 abb_events) { unsigned long flags; @@ -844,7 +856,7 @@ void prcmu_config_abb_event_readout(u32 abb_events) spin_unlock_irqrestore(&mb0_transfer.lock, flags); } -void prcmu_get_abb_event_buffer(void __iomem **buf) +void db8500_prcmu_get_abb_event_buffer(void __iomem **buf) { if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1) *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_1_4500); @@ -853,13 +865,13 @@ void prcmu_get_abb_event_buffer(void __iomem **buf) } /** - * prcmu_set_arm_opp - set the appropriate ARM OPP + * db8500_prcmu_set_arm_opp - set the appropriate ARM OPP * @opp: The new ARM operating point to which transition is to be made * Returns: 0 on success, non-zero on failure * * This function sets the the operating point of the ARM. */ -int prcmu_set_arm_opp(u8 opp) +int db8500_prcmu_set_arm_opp(u8 opp) { int r; @@ -890,11 +902,11 @@ int prcmu_set_arm_opp(u8 opp) } /** - * prcmu_get_arm_opp - get the current ARM OPP + * db8500_prcmu_get_arm_opp - get the current ARM OPP * * Returns: the current ARM OPP */ -int prcmu_get_arm_opp(void) +int db8500_prcmu_get_arm_opp(void) { return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_ARM_OPP); } @@ -1438,7 +1450,7 @@ int db8500_prcmu_request_clock(u8 clock, bool enable) return -EINVAL; } -int prcmu_config_esram0_deep_sleep(u8 state) +int db8500_prcmu_config_esram0_deep_sleep(u8 state) { if ((state > ESRAM0_DEEP_SLEEP_STATE_RET) || (state < ESRAM0_DEEP_SLEEP_STATE_OFF)) @@ -1534,6 +1546,78 @@ int prcmu_stop_temp_sense(void) return config_hot_period(0xFFFF); } +static int prcmu_a9wdog(u8 cmd, u8 d0, u8 d1, u8 d2, u8 d3) +{ + + mutex_lock(&mb4_transfer.lock); + + while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) + cpu_relax(); + + writeb(d0, (tcdm_base + PRCM_REQ_MB4_A9WDOG_0)); + writeb(d1, (tcdm_base + PRCM_REQ_MB4_A9WDOG_1)); + writeb(d2, (tcdm_base + PRCM_REQ_MB4_A9WDOG_2)); + writeb(d3, (tcdm_base + PRCM_REQ_MB4_A9WDOG_3)); + + writeb(cmd, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); + + writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET); + wait_for_completion(&mb4_transfer.work); + + mutex_unlock(&mb4_transfer.lock); + + return 0; + +} + +int prcmu_config_a9wdog(u8 num, bool sleep_auto_off) +{ + BUG_ON(num == 0 || num > 0xf); + return prcmu_a9wdog(MB4H_A9WDOG_CONF, num, 0, 0, + sleep_auto_off ? A9WDOG_AUTO_OFF_EN : + A9WDOG_AUTO_OFF_DIS); +} + +int prcmu_enable_a9wdog(u8 id) +{ + return prcmu_a9wdog(MB4H_A9WDOG_EN, id, 0, 0, 0); +} + +int prcmu_disable_a9wdog(u8 id) +{ + return prcmu_a9wdog(MB4H_A9WDOG_DIS, id, 0, 0, 0); +} + +int prcmu_kick_a9wdog(u8 id) +{ + return prcmu_a9wdog(MB4H_A9WDOG_KICK, id, 0, 0, 0); +} + +/* + * timeout is 28 bit, in ms. + */ +#define MAX_WATCHDOG_TIMEOUT 131000 +int prcmu_load_a9wdog(u8 id, u32 timeout) +{ + if (timeout > MAX_WATCHDOG_TIMEOUT) + /* + * Due to calculation bug in prcmu fw, timeouts + * can't be bigger than 131 seconds. + */ + return -EINVAL; + + return prcmu_a9wdog(MB4H_A9WDOG_LOAD, + (id & A9WDOG_ID_MASK) | + /* + * Put the lowest 28 bits of timeout at + * offset 4. Four first bits are used for id. + */ + (u8)((timeout << 4) & 0xf0), + (u8)((timeout >> 4) & 0xff), + (u8)((timeout >> 12) & 0xff), + (u8)((timeout >> 20) & 0xff)); +} + /** * prcmu_set_clock_divider() - Configure the clock divider. * @clock: The clock for which the request is made. @@ -1664,6 +1748,7 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size) void prcmu_ac_wake_req(void) { u32 val; + u32 status; mutex_lock(&mb0_transfer.ac_wake_lock); @@ -1673,11 +1758,34 @@ void prcmu_ac_wake_req(void) atomic_set(&ac_wake_req_state, 1); +retry: writel((val | PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ), PRCM_HOSTACCESS_REQ); if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, - msecs_to_jiffies(20000))) { - pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", + msecs_to_jiffies(5000))) { + panic("prcmu: %s timed out (5 s) waiting for a reply.\n", + __func__); + goto unlock_and_return; + } + + /* + * The modem can generate an AC_WAKE_ACK, and then still go to sleep. + * As a workaround, we wait, and then check that the modem is indeed + * awake (in terms of the value of the PRCM_MOD_AWAKE_STATUS + * register, which may not be the whole truth). + */ + udelay(400); + status = (readl(PRCM_MOD_AWAKE_STATUS) & BITS(0, 2)); + if (status != (PRCM_MOD_AWAKE_STATUS_PRCM_MOD_AAPD_AWAKE | + PRCM_MOD_AWAKE_STATUS_PRCM_MOD_COREPD_AWAKE)) { + pr_err("prcmu: %s received ack, but modem not awake (0x%X).\n", + __func__, status); + udelay(1200); + writel(val, PRCM_HOSTACCESS_REQ); + if (wait_for_completion_timeout(&mb0_transfer.ac_wake_work, + msecs_to_jiffies(5000))) + goto retry; + panic("prcmu: %s timed out (5 s) waiting for AC_SLEEP_ACK.\n", __func__); } @@ -1702,8 +1810,8 @@ void prcmu_ac_sleep_req() PRCM_HOSTACCESS_REQ); if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, - msecs_to_jiffies(20000))) { - pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", + msecs_to_jiffies(5000))) { + panic("prcmu: %s timed out (5 s) waiting for a reply.\n", __func__); } @@ -1713,7 +1821,7 @@ unlock_and_return: mutex_unlock(&mb0_transfer.ac_wake_lock); } -bool prcmu_is_ac_wake_requested(void) +bool db8500_prcmu_is_ac_wake_requested(void) { return (atomic_read(&ac_wake_req_state) != 0); } @@ -1731,12 +1839,12 @@ void db8500_prcmu_system_reset(u16 reset_code) } /** - * prcmu_get_reset_code - Retrieve SW reset reason code + * db8500_prcmu_get_reset_code - Retrieve SW reset reason code * * Retrieves the reset reason code stored by prcmu_system_reset() before * last restart. */ -u16 prcmu_get_reset_code(void) +u16 db8500_prcmu_get_reset_code(void) { return readw(tcdm_base + PRCM_SW_RST_REASON); } @@ -1861,6 +1969,11 @@ static bool read_mailbox_4(void) case MB4H_HOTDOG: case MB4H_HOTMON: case MB4H_HOT_PERIOD: + case MB4H_A9WDOG_CONF: + case MB4H_A9WDOG_EN: + case MB4H_A9WDOG_DIS: + case MB4H_A9WDOG_LOAD: + case MB4H_A9WDOG_KICK: break; default: print_unknown_header_warning(4, header); @@ -1986,7 +2099,7 @@ static struct irq_chip prcmu_irq_chip = { .irq_unmask = prcmu_irq_unmask, }; -void __init prcmu_early_init(void) +void __init db8500_prcmu_early_init(void) { unsigned int i; diff --git a/drivers/regulator/db5500-prcmu.c b/drivers/regulator/db5500-prcmu.c index a6884ca8942..d52f459fc3c 100644 --- a/drivers/regulator/db5500-prcmu.c +++ b/drivers/regulator/db5500-prcmu.c @@ -102,22 +102,28 @@ static struct regulator_ops db5500_regulator_ops = { static bool epod_on[NUM_EPOD_ID]; static bool epod_ramret[NUM_EPOD_ID]; +static inline int epod_id_to_index(u16 epod_id) +{ + return epod_id - DB5500_EPOD_ID_BASE; +} + static int enable_epod(u16 epod_id, bool ramret) { + int idx = epod_id_to_index(epod_id); int ret; if (ramret) { - if (!epod_on[epod_id]) { + if (!epod_on[idx]) { ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET); if (ret < 0) return ret; } - epod_ramret[epod_id] = true; + epod_ramret[idx] = true; } else { ret = prcmu_set_epod(epod_id, EPOD_STATE_ON); if (ret < 0) return ret; - epod_on[epod_id] = true; + epod_on[idx] = true; } return 0; @@ -125,17 +131,18 @@ static int enable_epod(u16 epod_id, bool ramret) static int disable_epod(u16 epod_id, bool ramret) { + int idx = epod_id_to_index(epod_id); int ret; if (ramret) { - if (!epod_on[epod_id]) { + if (!epod_on[idx]) { ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF); if (ret < 0) return ret; } - epod_ramret[epod_id] = false; + epod_ramret[idx] = false; } else { - if (epod_ramret[epod_id]) { + if (epod_ramret[idx]) { ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET); if (ret < 0) return ret; @@ -144,7 +151,7 @@ static int disable_epod(u16 epod_id, bool ramret) if (ret < 0) return ret; } - epod_on[epod_id] = false; + epod_on[idx] = false; } return 0; @@ -224,11 +231,11 @@ static struct regulator_ops db5500_regulator_switch_ops = { /* * Regulator information */ -#define U5500_REGULATOR_SWITCH(_name, reg) \ - [U5500_REGULATOR_SWITCH_##reg] = { \ +#define DB5500_REGULATOR_SWITCH(_name, reg) \ + [DB5500_REGULATOR_SWITCH_##reg] = { \ .desc = { \ .name = _name, \ - .id = U5500_REGULATOR_SWITCH_##reg, \ + .id = DB5500_REGULATOR_SWITCH_##reg, \ .ops = &db5500_regulator_switch_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -237,21 +244,21 @@ static struct regulator_ops db5500_regulator_switch_ops = { } static struct db5500_regulator_info - db5500_regulator_info[U5500_NUM_REGULATORS] = { - [U5500_REGULATOR_VAPE] = { + db5500_regulator_info[DB5500_NUM_REGULATORS] = { + [DB5500_REGULATOR_VAPE] = { .desc = { .name = "db5500-vape", - .id = U5500_REGULATOR_VAPE, + .id = DB5500_REGULATOR_VAPE, .ops = &db5500_regulator_ops, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, }, - U5500_REGULATOR_SWITCH("u5500-sga", SGA), - U5500_REGULATOR_SWITCH("u5500-hva", HVA), - U5500_REGULATOR_SWITCH("u5500-sia", SIA), - U5500_REGULATOR_SWITCH("u5500-disp", DISP), - U5500_REGULATOR_SWITCH("u5500-esram12", ESRAM12), + DB5500_REGULATOR_SWITCH("db5500-sga", SGA), + DB5500_REGULATOR_SWITCH("db5500-hva", HVA), + DB5500_REGULATOR_SWITCH("db5500-sia", SIA), + DB5500_REGULATOR_SWITCH("db5500-disp", DISP), + DB5500_REGULATOR_SWITCH("db5500-esram12", ESRAM12), }; static int __devinit db5500_regulator_probe(struct platform_device *pdev) diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index 3df5fcd454a..1ee6f6a7c4a 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/err.h> #include <linux/regulator/driver.h> +#include <linux/regulator/dbx500-prcmu.h> /* * power state reference count diff --git a/include/linux/mfd/db5500-prcmu.h b/include/linux/mfd/db5500-prcmu.h index 5be46a7157b..9890687f582 100644 --- a/include/linux/mfd/db5500-prcmu.h +++ b/include/linux/mfd/db5500-prcmu.h @@ -5,35 +5,36 @@ * * U5500 PRCMU API. */ -#ifndef __MACH_PRCMU_U5500_H -#define __MACH_PRCMU_U5500_H +#ifndef __MFD_DB5500_PRCMU_H +#define __MFD_DB5500_PRCMU_H -#ifdef CONFIG_UX500_SOC_DB5500 +#ifdef CONFIG_MFD_DB5500_PRCMU void db5500_prcmu_early_init(void); int db5500_prcmu_set_epod(u16 epod_id, u8 epod_state); +int db5500_prcmu_set_display_clocks(void); +int db5500_prcmu_disable_dsipll(void); +int db5500_prcmu_enable_dsipll(void); int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size); int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size); void db5500_prcmu_enable_wakeups(u32 wakeups); - int db5500_prcmu_request_clock(u8 clock, bool enable); - +void db5500_prcmu_config_abb_event_readout(u32 abb_events); +void db5500_prcmu_get_abb_event_buffer(void __iomem **buf); int prcmu_resetout(u8 resoutn, u8 state); - -static inline int db5500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, - bool keep_ap_pll) -{ - return 0; -} - -static inline void db5500_prcmu_system_reset(u16 reset_code) {} +int db5500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, + bool keep_ap_pll); +int db5500_prcmu_config_esram0_deep_sleep(u8 state); +void db5500_prcmu_system_reset(u16 reset_code); +u16 db5500_prcmu_get_reset_code(void); +bool db5500_prcmu_is_ac_wake_requested(void); +int db5500_prcmu_set_arm_opp(u8 opp); +int db5500_prcmu_get_arm_opp(void); #else /* !CONFIG_UX500_SOC_DB5500 */ static inline void db5500_prcmu_early_init(void) {} -static inline void db5500_prcmu_system_reset(u16 reset_code) {} - static inline int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size) { return -ENOSYS; @@ -49,7 +50,13 @@ static inline int db5500_prcmu_request_clock(u8 clock, bool enable) return 0; } +static inline int db5500_prcmu_set_display_clocks(void) +{ + return 0; +} +static inline int db5500_prcmu_disable_dsipll(void) +{ return 0; } @@ -65,31 +72,48 @@ static inline int db5500_prcmu_config_esram0_deep_sleep(u8 state) static inline void db5500_prcmu_enable_wakeups(u32 wakeups) {} +static inline int prcmu_resetout(u8 resoutn, u8 state) +{ + return 0; +} + static inline int db5500_prcmu_set_epod(u16 epod_id, u8 epod_state) { return 0; } +static inline void db5500_prcmu_get_abb_event_buffer(void __iomem **buf) {} +static inline void db5500_prcmu_config_abb_event_readout(u32 abb_events) {} + static inline int db5500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll) { return 0; } -static inline int prcmu_resetout(u8 resoutn, u8 state) +static inline void db5500_prcmu_system_reset(u16 reset_code) {} + +static inline u16 db5500_prcmu_get_reset_code(void) { return 0; } -#endif /* CONFIG_UX500_SOC_DB5500 */ +static inline bool db5500_prcmu_is_ac_wake_requested(void) +{ + return 0; +} + +static inline int db5500_prcmu_set_arm_opp(u8 opp) +{ + return 0; +} -static inline int db5500_prcmu_config_abb_event_readout(u32 abb_events) +static inline int db5500_prcmu_get_arm_opp(void) { -#ifdef CONFIG_MACH_U5500_SIMULATOR return 0; -#else - return -1; -#endif } -#endif /* __MACH_PRCMU_U5500_H */ + +#endif /* CONFIG_MFD_DB5500_PRCMU */ + +#endif /* __MFD_DB5500_PRCMU_H */ diff --git a/include/linux/mfd/db8500-prcmu.h b/include/linux/mfd/db8500-prcmu.h index a03b51e991a..60d27f7bfc1 100644 --- a/include/linux/mfd/db8500-prcmu.h +++ b/include/linux/mfd/db8500-prcmu.h @@ -145,20 +145,6 @@ enum ap_pwrst_trans { }; /** - * enum ddr_pwrst - DDR power states definition - * @DDR_PWR_STATE_UNCHANGED: SDRAM and DDR controller state is unchanged - * @DDR_PWR_STATE_ON: - * @DDR_PWR_STATE_OFFLOWLAT: - * @DDR_PWR_STATE_OFFHIGHLAT: - */ -enum ddr_pwrst { - DDR_PWR_STATE_UNCHANGED = 0x00, - DDR_PWR_STATE_ON = 0x01, - DDR_PWR_STATE_OFFLOWLAT = 0x02, - DDR_PWR_STATE_OFFHIGHLAT = 0x03 -}; - -/** * enum hw_acc_state - State definition for hardware accelerator * @HW_NO_CHANGE: The hardware accelerator state must remain unchanged * @HW_OFF: The hardware accelerator must be switched off @@ -507,30 +493,12 @@ struct prcmu_auto_pm_config { u8 sva_policy; }; -/* - * Definitions for controlling ESRAM0 in deep sleep. - */ -#define ESRAM0_DEEP_SLEEP_STATE_OFF 1 -#define ESRAM0_DEEP_SLEEP_STATE_RET 2 - -#ifdef CONFIG_MFD_DB8500_PRCMU -void __init prcmu_early_init(void); -int prcmu_set_display_clocks(void); -int prcmu_disable_dsipll(void); -int prcmu_enable_dsipll(void); -#else -static inline void __init prcmu_early_init(void) {} -#endif - #ifdef CONFIG_MFD_DB8500_PRCMU +void db8500_prcmu_early_init(void); int prcmu_set_rc_a2p(enum romcode_write); enum romcode_read prcmu_get_rc_p2a(void); enum ap_pwrst prcmu_get_xp70_current_state(void); -void prcmu_config_abb_event_readout(u32 abb_events); -void prcmu_get_abb_event_buffer(void __iomem **buf); -int prcmu_set_arm_opp(u8 opp); -int prcmu_get_arm_opp(void); bool prcmu_has_arm_maxopp(void); bool prcmu_is_u8400(void); int prcmu_set_ape_opp(u8 opp); @@ -539,8 +507,6 @@ int prcmu_request_ape_opp_100_voltage(bool enable); int prcmu_release_usb_wakeup_state(void); int prcmu_set_ddr_opp(u8 opp); int prcmu_get_ddr_opp(void); -unsigned long prcmu_qos_get_cpufreq_opp_delay(void); -void prcmu_qos_set_cpufreq_opp_delay(unsigned long); /* NOTE! Use regulator framework instead */ int prcmu_set_hwacc(u16 hw_acc_dev, u8 state); void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep, @@ -549,7 +515,6 @@ bool prcmu_is_auto_pm_enabled(void); int prcmu_config_clkout(u8 clkout, u8 source, u8 div); int prcmu_set_clock_divider(u8 clock, u8 divider); -int prcmu_config_esram0_deep_sleep(u8 state); int prcmu_config_hotdog(u8 threshold); int prcmu_config_hotmon(u8 low, u8 high); int prcmu_start_temp_sense(u16 cycles32k); @@ -560,18 +525,35 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size); void prcmu_ac_wake_req(void); void prcmu_ac_sleep_req(void); void prcmu_modem_reset(void); -bool prcmu_is_ac_wake_requested(void); void prcmu_enable_spi2(void); void prcmu_disable_spi2(void); +int prcmu_config_a9wdog(u8 num, bool sleep_auto_off); +int prcmu_enable_a9wdog(u8 id); +int prcmu_disable_a9wdog(u8 id); +int prcmu_kick_a9wdog(u8 id); +int prcmu_load_a9wdog(u8 id, u32 val); + void db8500_prcmu_system_reset(u16 reset_code); int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll); void db8500_prcmu_enable_wakeups(u32 wakeups); int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state); int db8500_prcmu_request_clock(u8 clock, bool enable); +int db8500_prcmu_set_display_clocks(void); +int db8500_prcmu_disable_dsipll(void); +int db8500_prcmu_enable_dsipll(void); +void db8500_prcmu_config_abb_event_readout(u32 abb_events); +void db8500_prcmu_get_abb_event_buffer(void __iomem **buf); +int db8500_prcmu_config_esram0_deep_sleep(u8 state); +u16 db8500_prcmu_get_reset_code(void); +bool db8500_prcmu_is_ac_wake_requested(void); +int db8500_prcmu_set_arm_opp(u8 opp); +int db8500_prcmu_get_arm_opp(void); #else /* !CONFIG_MFD_DB8500_PRCMU */ +static inline void db8500_prcmu_early_init(void) {} + static inline int prcmu_set_rc_a2p(enum romcode_write code) { return 0; @@ -587,20 +569,6 @@ static inline enum ap_pwrst prcmu_get_xp70_current_state(void) return AP_EXECUTE; } -static inline void prcmu_disable_wakeups(void) {} - -static inline void prcmu_config_abb_event_readout(u32 abb_events) {} - -static inline int prcmu_set_arm_opp(u8 opp) -{ - return 0; -} - -static inline int prcmu_get_arm_opp(void) -{ - return ARM_100_OPP; -} - static inline bool prcmu_has_arm_maxopp(void) { return false; @@ -641,13 +609,6 @@ static inline int prcmu_get_ddr_opp(void) return DDR_100_OPP; } -static inline unsigned long prcmu_qos_get_cpufreq_opp_delay(void) -{ - return 0; -} - -static inline void prcmu_qos_set_cpufreq_opp_delay(unsigned long n) {} - static inline int prcmu_set_hwacc(u16 hw_acc_dev, u8 state) { return 0; @@ -673,11 +634,6 @@ static inline int prcmu_set_clock_divider(u8 clock, u8 divider) return 0; } -int prcmu_config_esram0_deep_sleep(u8 state) -{ - return 0; -} - static inline int prcmu_config_hotdog(u8 threshold) { return 0; @@ -714,54 +670,101 @@ static inline void prcmu_ac_sleep_req(void) {} static inline void prcmu_modem_reset(void) {} -static inline bool prcmu_is_ac_wake_requested(void) +static inline int prcmu_enable_spi2(void) { - return false; + return 0; } -#ifndef CONFIG_UX500_SOC_DB5500 -static inline int prcmu_set_display_clocks(void) +static inline int prcmu_disable_spi2(void) { return 0; } -static inline int prcmu_disable_dsipll(void) +static inline void db8500_prcmu_system_reset(u16 reset_code) {} + +static inline int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, + bool keep_ap_pll) { return 0; } -static inline int prcmu_enable_dsipll(void) +static inline void db8500_prcmu_enable_wakeups(u32 wakeups) {} + +static inline int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state) { return 0; } -#endif -static inline int prcmu_enable_spi2(void) +static inline int db8500_prcmu_request_clock(u8 clock, bool enable) { return 0; } -static inline int prcmu_disable_spi2(void) +static inline int db8500_prcmu_set_display_clocks(void) { return 0; } -static inline void db8500_prcmu_system_reset(u16 reset_code) {} +static inline int db8500_prcmu_disable_dsipll(void) +{ + return 0; +} -static inline int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, - bool keep_ap_pll) +static inline int db8500_prcmu_enable_dsipll(void) { return 0; } -static inline void db8500_prcmu_enable_wakeups(u32 wakeups) {} +static inline int db8500_prcmu_config_esram0_deep_sleep(u8 state) +{ + return 0; +} -static inline int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state) +static inline void db8500_prcmu_config_abb_event_readout(u32 abb_events) {} + +static inline void db8500_prcmu_get_abb_event_buffer(void __iomem **buf) {} + +static inline u16 db8500_prcmu_get_reset_code(void) { return 0; } -static inline int db8500_prcmu_request_clock(u8 clock, bool enable) +static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off) +{ + return 0; +} + +static inline int prcmu_enable_a9wdog(u8 id) +{ + return 0; +} + +static inline int prcmu_disable_a9wdog(u8 id) +{ + return 0; +} + +static inline int prcmu_kick_a9wdog(u8 id) +{ + return 0; +} + +static inline int prcmu_load_a9wdog(u8 id, u32 val) +{ + return 0; +} + +static inline bool db8500_prcmu_is_ac_wake_requested(void) +{ + return 0; +} + +static inline int db8500_prcmu_set_arm_opp(u8 opp) +{ + return 0; +} + +static inline int db8500_prcmu_get_arm_opp(void) { return 0; } diff --git a/include/linux/regulator/db5500-prcmu.h b/include/linux/regulator/db5500-prcmu.h index 52950287c09..fee68795867 100644 --- a/include/linux/regulator/db5500-prcmu.h +++ b/include/linux/regulator/db5500-prcmu.h @@ -15,13 +15,13 @@ /* Number of DB5500 regulators and regulator enumeration */ enum db5500_regulator_id { - U5500_REGULATOR_VAPE, - U5500_REGULATOR_SWITCH_SGA, - U5500_REGULATOR_SWITCH_HVA, - U5500_REGULATOR_SWITCH_SIA, - U5500_REGULATOR_SWITCH_DISP, - U5500_REGULATOR_SWITCH_ESRAM12, - U5500_NUM_REGULATORS + DB5500_REGULATOR_VAPE, + DB5500_REGULATOR_SWITCH_SGA, + DB5500_REGULATOR_SWITCH_HVA, + DB5500_REGULATOR_SWITCH_SIA, + DB5500_REGULATOR_SWITCH_DISP, + DB5500_REGULATOR_SWITCH_ESRAM12, + DB5500_NUM_REGULATORS }; #endif |
