summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-ux500/board-u5500-regulators.c82
-rw-r--r--arch/arm/mach-ux500/board-u5500.c5
-rw-r--r--arch/arm/mach-ux500/clock-db5500.c83
-rw-r--r--arch/arm/mach-ux500/cpu-db5500.c5
-rw-r--r--arch/arm/mach-ux500/cpu.c9
-rw-r--r--arch/arm/mach-ux500/devices-db5500.c5
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-db5500.h29
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu-regs.h8
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu.h124
-rw-r--r--arch/arm/mach-ux500/include/mach/regulator.h16
-rw-r--r--arch/arm/mach-ux500/pm/Kconfig7
-rw-r--r--arch/arm/mach-ux500/pm/pm.c13
-rw-r--r--arch/arm/mach-ux500/pm/runtime.c2
-rw-r--r--arch/arm/mach-ux500/pm/suspend.c5
-rw-r--r--arch/arm/mach-ux500/prcmu-debug.c52
-rw-r--r--drivers/cpufreq/Makefile1
-rw-r--r--drivers/cpufreq/db5500-cpufreq.c172
-rw-r--r--drivers/cpufreq/db8500-cpufreq.c6
-rw-r--r--drivers/crypto/ux500/cryp/cryp_core.c2
-rw-r--r--drivers/crypto/ux500/hash/hash_core.c2
-rwxr-xr-xdrivers/mfd/ab5500-core.c42
-rw-r--r--drivers/mfd/db5500-prcmu.c821
-rw-r--r--drivers/mfd/db8500-prcmu.c149
-rw-r--r--drivers/regulator/db5500-prcmu.c43
-rw-r--r--drivers/regulator/dbx500-prcmu.c1
-rw-r--r--include/linux/mfd/db5500-prcmu.h70
-rw-r--r--include/linux/mfd/db8500-prcmu.h159
-rw-r--r--include/linux/regulator/db5500-prcmu.h14
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