[PATCH 13/17] mfd: prcmu: make legacy mailbox services configurable
Loic Pallardy
loic.pallardy-ext at stericsson.com
Wed Sep 5 05:59:09 EDT 2012
8500 and x540 are using same services based on prcmu legacy
mailbox but with different base address and different arguments.
Signed-off-by: Loic Pallardy <loic.pallardy at stericsson.com>
Acked-by: Linus Walleij <linus.walleij at linaro.org>
---
drivers/mfd/db8500-prcmu.c | 371 +++++++++++++++++++++++++++------------------
drivers/mfd/dbx500-prcmu.h | 16 ++
2 files changed, 243 insertions(+), 144 deletions(-)
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 327e9f6..73c98e5 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -137,13 +137,21 @@ static DEFINE_SPINLOCK(clkout_lock);
static __iomem void *tcdm_legacy_base;
static __iomem void *tcdm_base;
+/* mailbox pointers */
+static struct mb0_transfer *mb0;
+static struct mb1_transfer *mb1;
+static struct mb2_transfer *mb2;
+static struct mb3_transfer *mb3;
+static struct mb4_transfer *mb4;
+static struct mb5_transfer *mb5;
+
/* mailbox definition */
-static struct mb0_transfer mb0;
-static struct mb1_transfer mb1;
-static struct mb2_transfer mb2;
-static struct mb3_transfer mb3;
-static struct mb4_transfer mb4;
-static struct mb5_transfer mb5;
+static struct mb0_transfer db8500_mb0;
+static struct mb1_transfer db8500_mb1;
+static struct mb2_transfer db8500_mb2;
+static struct mb3_transfer db8500_mb3;
+static struct mb4_transfer db8500_mb4;
+static struct mb5_transfer db8500_mb5;
static DEFINE_SPINLOCK(clk_mgt_lock);
@@ -472,20 +480,31 @@ unlock_and_return:
return r;
}
+static u8 db8500_fw_trans[] = {
+ 0x00,/* PRCMU_AP_NO_CHANGE */
+ 0x01,/* PRCMU_AP_SLEEP */
+ 0x04,/* PRCMU_AP_DEEP_SLEEP */
+ 0x05,/* PRCMU_AP_IDLE */
+ 0x07,/* PRCMU_AP_DEEP_IDLE*/
+};
+
+static u8 *fw_trans;
+static u32 fw_trans_nb;
+
int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
{
unsigned long flags;
- BUG_ON((state < PRCMU_AP_SLEEP) || (PRCMU_AP_DEEP_IDLE < state));
-
- spin_lock_irqsave(&mb0.lock, flags);
+ BUG_ON((state == PRCMU_AP_NO_CHANGE) ||
+ (state >= fw_trans_nb));
+ spin_lock_irqsave(&mb0->lock, flags);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
cpu_relax();
writeb(MB0H_POWER_STATE_TRANS,
tcdm_legacy_base + PRCM_MBOX_HEADER_REQ_MB0);
- writeb(state, (tcdm_legacy_base + PRCM_REQ_MB0_AP_POWER_STATE));
+ writeb(fw_trans[state], tcdm_legacy_base + PRCM_REQ_MB0_AP_POWER_STATE);
writeb((keep_ap_pll ? 1 : 0),
tcdm_legacy_base + PRCM_REQ_MB0_AP_PLL_STATE);
writeb((keep_ulp_clk ? 1 : 0),
@@ -493,7 +512,7 @@ int db8500_prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
writeb(0, (tcdm_legacy_base + PRCM_REQ_MB0_DO_NOT_WFI));
writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
- spin_unlock_irqrestore(&mb0.lock, flags);
+ spin_unlock_irqrestore(&mb0->lock, flags);
return 0;
}
@@ -616,7 +635,7 @@ int db8500_prcmu_copy_gic_settings(void)
return 0;
}
-/* This function should only be called while mb0.lock is held. */
+/* This function should only be called while mb0->lock is held. */
static void config_wakeups(void)
{
const u8 header[2] = {
@@ -629,10 +648,10 @@ static void config_wakeups(void)
u32 abb_events;
unsigned int i;
- dbb_events = mb0.req.dbb_irqs | mb0.req.dbb_wakeups;
+ dbb_events = mb0->req.dbb_irqs | mb0->req.dbb_wakeups;
dbb_events |= (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK);
- abb_events = mb0.req.abb_events;
+ abb_events = mb0->req.abb_events;
if ((dbb_events == last_dbb_events) && (abb_events == last_abb_events))
return;
@@ -662,24 +681,24 @@ static void db8500_prcmu_enable_wakeups(u32 wakeups)
bits |= prcmu_wakeup_bit[i];
}
- spin_lock_irqsave(&mb0.lock, flags);
+ spin_lock_irqsave(&mb0->lock, flags);
- mb0.req.dbb_wakeups = bits;
+ mb0->req.dbb_wakeups = bits;
config_wakeups();
- spin_unlock_irqrestore(&mb0.lock, flags);
+ spin_unlock_irqrestore(&mb0->lock, flags);
}
static void db8500_prcmu_config_abb_event_readout(u32 abb_events)
{
unsigned long flags;
- spin_lock_irqsave(&mb0.lock, flags);
+ spin_lock_irqsave(&mb0->lock, flags);
- mb0.req.abb_events = abb_events;
+ mb0->req.abb_events = abb_events;
config_wakeups();
- spin_unlock_irqrestore(&mb0.lock, flags);
+ spin_unlock_irqrestore(&mb0->lock, flags);
}
static void db8500_prcmu_get_abb_event_buffer(void __iomem **buf)
@@ -706,7 +725,7 @@ static int db8500_prcmu_set_arm_opp(u8 opp)
r = 0;
- mutex_lock(&mb1.lock);
+ mutex_lock(&mb1->lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
cpu_relax();
@@ -716,13 +735,13 @@ static int db8500_prcmu_set_arm_opp(u8 opp)
writeb(APE_NO_CHANGE, (tcdm_legacy_base + PRCM_REQ_MB1_APE_OPP));
writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb1.work);
+ wait_for_completion(&mb1->work);
- if ((mb1.ack.header != MB1H_ARM_APE_OPP) ||
- (mb1.ack.arm_opp != opp))
+ if ((mb1->ack.header != MB1H_ARM_APE_OPP) ||
+ (mb1->ack.arm_opp != opp))
r = -EIO;
- mutex_unlock(&mb1.lock);
+ mutex_unlock(&mb1->lock);
return r;
}
@@ -822,15 +841,15 @@ static int db8500_prcmu_set_ape_opp(u8 opp)
{
int r = 0;
- if (opp == mb1.ape_opp)
+ if (opp == mb1->ape_opp)
return 0;
- mutex_lock(&mb1.lock);
+ mutex_lock(&mb1->lock);
- if (mb1.ape_opp == APE_50_PARTLY_25_OPP)
+ if (mb1->ape_opp == APE_50_PARTLY_25_OPP)
request_even_slower_clocks(false);
- if ((opp != APE_100_OPP) && (mb1.ape_opp != APE_100_OPP))
+ if ((opp != APE_100_OPP) && (mb1->ape_opp != APE_100_OPP))
goto skip_message;
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
@@ -842,20 +861,20 @@ static int db8500_prcmu_set_ape_opp(u8 opp)
(tcdm_legacy_base + PRCM_REQ_MB1_APE_OPP));
writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb1.work);
+ wait_for_completion(&mb1->work);
- if ((mb1.ack.header != MB1H_ARM_APE_OPP) ||
- (mb1.ack.ape_opp != opp))
+ if ((mb1->ack.header != MB1H_ARM_APE_OPP) ||
+ (mb1->ack.ape_opp != opp))
r = -EIO;
skip_message:
if ((!r && (opp == APE_50_PARTLY_25_OPP)) ||
- (r && (mb1.ape_opp == APE_50_PARTLY_25_OPP)))
+ (r && (mb1->ape_opp == APE_50_PARTLY_25_OPP)))
request_even_slower_clocks(true);
if (!r)
- mb1.ape_opp = opp;
+ mb1->ape_opp = opp;
- mutex_unlock(&mb1.lock);
+ mutex_unlock(&mb1->lock);
return r;
}
@@ -882,7 +901,7 @@ static int db8500_prcmu_request_ape_opp_100_voltage(bool enable)
u8 header;
static unsigned int requests;
- mutex_lock(&mb1.lock);
+ mutex_lock(&mb1->lock);
if (enable) {
if (0 != requests++)
@@ -904,14 +923,14 @@ static int db8500_prcmu_request_ape_opp_100_voltage(bool enable)
writeb(header, (tcdm_legacy_base + PRCM_MBOX_HEADER_REQ_MB1));
writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb1.work);
+ wait_for_completion(&mb1->work);
- if ((mb1.ack.header != header) ||
- ((mb1.ack.ape_voltage_status & BIT(0)) != 0))
+ if ((mb1->ack.header != header) ||
+ ((mb1->ack.ape_voltage_status & BIT(0)) != 0))
r = -EIO;
unlock_and_return:
- mutex_unlock(&mb1.lock);
+ mutex_unlock(&mb1->lock);
return r;
}
@@ -925,7 +944,7 @@ int prcmu_release_usb_wakeup_state(void)
{
int r = 0;
- mutex_lock(&mb1.lock);
+ mutex_lock(&mb1->lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
cpu_relax();
@@ -934,13 +953,13 @@ int prcmu_release_usb_wakeup_state(void)
(tcdm_legacy_base + PRCM_MBOX_HEADER_REQ_MB1));
writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb1.work);
+ wait_for_completion(&mb1->work);
- if ((mb1.ack.header != MB1H_RELEASE_USB_WAKEUP) ||
- ((mb1.ack.ape_voltage_status & BIT(0)) != 0))
+ if ((mb1->ack.header != MB1H_RELEASE_USB_WAKEUP) ||
+ ((mb1->ack.ape_voltage_status & BIT(0)) != 0))
r = -EIO;
- mutex_unlock(&mb1.lock);
+ mutex_unlock(&mb1->lock);
return r;
}
@@ -956,7 +975,7 @@ static int request_pll(u8 clock, bool enable)
else
return -EINVAL;
- mutex_lock(&mb1.lock);
+ mutex_lock(&mb1->lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
cpu_relax();
@@ -965,12 +984,12 @@ static int request_pll(u8 clock, bool enable)
writeb(clock, (tcdm_legacy_base + PRCM_REQ_MB1_PLL_ON_OFF));
writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb1.work);
+ wait_for_completion(&mb1->work);
- if (mb1.ack.header != MB1H_PLL_ON_OFF)
+ if (mb1->ack.header != MB1H_PLL_ON_OFF)
r = -EIO;
- mutex_unlock(&mb1.lock);
+ mutex_unlock(&mb1->lock);
return r;
}
@@ -1007,7 +1026,7 @@ static int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state)
BUG_ON(epod_state == EPOD_STATE_RAMRET && !ram_retention);
/* get lock */
- mutex_lock(&mb2.lock);
+ mutex_lock(&mb2->lock);
/* wait for mailbox */
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(2))
@@ -1028,7 +1047,7 @@ static int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state)
* and we cannot recover if there is an error.
* This is expected to change when the firmware is updated.
*/
- if (!wait_for_completion_timeout(&mb2.work,
+ if (!wait_for_completion_timeout(&mb2->work,
msecs_to_jiffies(20000))) {
pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
__func__);
@@ -1036,11 +1055,11 @@ static int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state)
goto unlock_and_return;
}
- if (mb2.ack.status != HWACC_PWR_ST_OK)
+ if (mb2->ack.status != HWACC_PWR_ST_OK)
r = -EIO;
unlock_and_return:
- mutex_unlock(&mb2.lock);
+ mutex_unlock(&mb2->lock);
return r;
}
@@ -1072,7 +1091,7 @@ static void db8500_prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
idle_cfg = ((idle_cfg << 4) | (idle->sva_policy & 0xF));
idle_cfg = ((idle_cfg << 4) | (idle->sia_policy & 0xF));
- spin_lock_irqsave(&mb2.auto_pm_lock, flags);
+ spin_lock_irqsave(&mb2->auto_pm_lock, flags);
/*
* The autonomous power management configuration is done through
@@ -1082,18 +1101,18 @@ static void db8500_prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
writel(sleep_cfg, (tcdm_legacy_base + PRCM_REQ_MB2_AUTO_PM_SLEEP));
writel(idle_cfg, (tcdm_legacy_base + PRCM_REQ_MB2_AUTO_PM_IDLE));
- mb2.auto_pm_enabled =
+ mb2->auto_pm_enabled =
((sleep->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
(sleep->sia_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
(idle->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
(idle->sia_auto_pm_enable == PRCMU_AUTO_PM_ON));
- spin_unlock_irqrestore(&mb2.auto_pm_lock, flags);
+ spin_unlock_irqrestore(&mb2->auto_pm_lock, flags);
}
bool prcmu_is_auto_pm_enabled(void)
{
- return mb2.auto_pm_enabled;
+ return mb2->auto_pm_enabled;
}
static int request_sysclk(bool enable)
@@ -1103,9 +1122,9 @@ static int request_sysclk(bool enable)
r = 0;
- mutex_lock(&mb3.sysclk_lock);
+ mutex_lock(&mb3->sysclk_lock);
- spin_lock_irqsave(&mb3.lock, flags);
+ spin_lock_irqsave(&mb3->lock, flags);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(3))
cpu_relax();
@@ -1115,20 +1134,20 @@ static int request_sysclk(bool enable)
writeb(MB3H_SYSCLK, (tcdm_legacy_base + PRCM_MBOX_HEADER_REQ_MB3));
writel(MBOX_BIT(3), PRCM_MBOX_CPU_SET);
- spin_unlock_irqrestore(&mb3.lock, flags);
+ spin_unlock_irqrestore(&mb3->lock, flags);
/*
* The firmware only sends an ACK if we want to enable the
* SysClk, and it succeeds.
*/
- if (enable && !wait_for_completion_timeout(&mb3.sysclk_work,
+ if (enable && !wait_for_completion_timeout(&mb3->sysclk_work,
msecs_to_jiffies(20000))) {
pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
__func__);
r = -EIO;
}
- mutex_unlock(&mb3.sysclk_lock);
+ mutex_unlock(&mb3->sysclk_lock);
return r;
}
@@ -1711,7 +1730,7 @@ static int db8500_prcmu_config_esram0_deep_sleep(u8 state)
(state < ESRAM0_DEEP_SLEEP_STATE_OFF))
return -EINVAL;
- mutex_lock(&mb4.lock);
+ mutex_lock(&mb4->lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
cpu_relax();
@@ -1724,16 +1743,16 @@ static int db8500_prcmu_config_esram0_deep_sleep(u8 state)
writeb(state, (tcdm_legacy_base + PRCM_REQ_MB4_ESRAM0_ST));
writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb4.work);
+ wait_for_completion(&mb4->work);
- mutex_unlock(&mb4.lock);
+ mutex_unlock(&mb4->lock);
return 0;
}
int db8500_prcmu_config_hotdog(u8 threshold)
{
- mutex_lock(&mb4.lock);
+ mutex_lock(&mb4->lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
cpu_relax();
@@ -1742,16 +1761,16 @@ int db8500_prcmu_config_hotdog(u8 threshold)
writeb(MB4H_HOTDOG, (tcdm_legacy_base + PRCM_MBOX_HEADER_REQ_MB4));
writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb4.work);
+ wait_for_completion(&mb4->work);
- mutex_unlock(&mb4.lock);
+ mutex_unlock(&mb4->lock);
return 0;
}
int db8500_prcmu_config_hotmon(u8 low, u8 high)
{
- mutex_lock(&mb4.lock);
+ mutex_lock(&mb4->lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
cpu_relax();
@@ -1763,16 +1782,16 @@ int db8500_prcmu_config_hotmon(u8 low, u8 high)
writeb(MB4H_HOTMON, (tcdm_legacy_base + PRCM_MBOX_HEADER_REQ_MB4));
writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb4.work);
+ wait_for_completion(&mb4->work);
- mutex_unlock(&mb4.lock);
+ mutex_unlock(&mb4->lock);
return 0;
}
static int config_hot_period(u16 val)
{
- mutex_lock(&mb4.lock);
+ mutex_lock(&mb4->lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
cpu_relax();
@@ -1781,9 +1800,9 @@ static int config_hot_period(u16 val)
writeb(MB4H_HOT_PERIOD, (tcdm_legacy_base + PRCM_MBOX_HEADER_REQ_MB4));
writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb4.work);
+ wait_for_completion(&mb4->work);
- mutex_unlock(&mb4.lock);
+ mutex_unlock(&mb4->lock);
return 0;
}
@@ -1804,7 +1823,7 @@ int db8500_prcmu_stop_temp_sense(void)
static int prcmu_a9wdog(u8 cmd, u8 d0, u8 d1, u8 d2, u8 d3)
{
- mutex_lock(&mb4.lock);
+ mutex_lock(&mb4->lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
cpu_relax();
@@ -1817,9 +1836,9 @@ static int prcmu_a9wdog(u8 cmd, u8 d0, u8 d1, u8 d2, u8 d3)
writeb(cmd, (tcdm_legacy_base + PRCM_MBOX_HEADER_REQ_MB4));
writel(MBOX_BIT(4), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb4.work);
+ wait_for_completion(&mb4->work);
- mutex_unlock(&mb4.lock);
+ mutex_unlock(&mb4->lock);
return 0;
@@ -1882,7 +1901,7 @@ static int db8500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
if (size != 1)
return -EINVAL;
- mutex_lock(&mb5.lock);
+ mutex_lock(&mb5->lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
cpu_relax();
@@ -1896,19 +1915,19 @@ static int db8500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
- if (!wait_for_completion_timeout(&mb5.work,
+ if (!wait_for_completion_timeout(&mb5->work,
msecs_to_jiffies(20000))) {
pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
__func__);
r = -EIO;
} else {
- r = ((mb5.ack.status == I2C_RD_OK) ? 0 : -EIO);
+ r = ((mb5->ack.status == I2C_RD_OK) ? 0 : -EIO);
}
if (!r)
- *value = mb5.ack.value;
+ *value = mb5->ack.value;
- mutex_unlock(&mb5.lock);
+ mutex_unlock(&mb5->lock);
return r;
}
@@ -1934,7 +1953,7 @@ static int db8500_prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask,
if (size != 1)
return -EINVAL;
- mutex_lock(&mb5.lock);
+ mutex_lock(&mb5->lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
cpu_relax();
@@ -1948,16 +1967,16 @@ static int db8500_prcmu_abb_write_masked(u8 slave, u8 reg, u8 *value, u8 *mask,
writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
- if (!wait_for_completion_timeout(&mb5.work,
+ if (!wait_for_completion_timeout(&mb5->work,
msecs_to_jiffies(20000))) {
pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
__func__);
r = -EIO;
} else {
- r = ((mb5.ack.status == I2C_WR_OK) ? 0 : -EIO);
+ r = ((mb5->ack.status == I2C_WR_OK) ? 0 : -EIO);
}
- mutex_unlock(&mb5.lock);
+ mutex_unlock(&mb5->lock);
return r;
}
@@ -1987,7 +2006,7 @@ int prcmu_ac_wake_req(void)
u32 val;
int ret = 0;
- mutex_lock(&mb0.ac_wake_lock);
+ mutex_lock(&mb0->ac_wake_lock);
val = readl(PRCM_HOSTACCESS_REQ);
if (val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ)
@@ -2008,7 +2027,7 @@ int prcmu_ac_wake_req(void)
val |= PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ;
writel(val, PRCM_HOSTACCESS_REQ);
- if (!wait_for_completion_timeout(&mb0.ac_wake_work,
+ if (!wait_for_completion_timeout(&mb0->ac_wake_work,
msecs_to_jiffies(5000))) {
#if defined(CONFIG_DBX500_PRCMU_DEBUG)
db8500_prcmu_debug_dump(__func__, true, true);
@@ -2019,7 +2038,7 @@ int prcmu_ac_wake_req(void)
}
unlock_and_return:
- mutex_unlock(&mb0.ac_wake_lock);
+ mutex_unlock(&mb0->ac_wake_lock);
return ret;
}
@@ -2030,7 +2049,7 @@ void prcmu_ac_sleep_req()
{
u32 val;
- mutex_lock(&mb0.ac_wake_lock);
+ mutex_lock(&mb0->ac_wake_lock);
val = readl(PRCM_HOSTACCESS_REQ);
if (!(val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ))
@@ -2039,7 +2058,7 @@ void prcmu_ac_sleep_req()
writel((val & ~PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ),
PRCM_HOSTACCESS_REQ);
- if (!wait_for_completion_timeout(&mb0.ac_wake_work,
+ if (!wait_for_completion_timeout(&mb0->ac_wake_work,
msecs_to_jiffies(5000))) {
pr_crit("prcmu: %s timed out (5 s) waiting for a reply.\n",
__func__);
@@ -2048,7 +2067,7 @@ void prcmu_ac_sleep_req()
atomic_set(&ac_wake_req_state, 0);
unlock_and_return:
- mutex_unlock(&mb0.ac_wake_lock);
+ mutex_unlock(&mb0->ac_wake_lock);
}
static bool db8500_prcmu_is_ac_wake_requested(void)
@@ -2084,28 +2103,28 @@ static u16 db8500_prcmu_get_reset_code(void)
*/
static void db8500_prcmu_modem_reset(void)
{
- mutex_lock(&mb1.lock);
+ mutex_lock(&mb1->lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
cpu_relax();
writeb(MB1H_RESET_MODEM, (tcdm_legacy_base + PRCM_MBOX_HEADER_REQ_MB1));
writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb1.work);
+ wait_for_completion(&mb1->work);
/*
* No need to check return from PRCMU as modem should go in reset state
* This state is already managed by upper layer
*/
- mutex_unlock(&mb1.lock);
+ mutex_unlock(&mb1->lock);
}
static void ack_dbb_wakeup(void)
{
unsigned long flags;
- spin_lock_irqsave(&mb0.lock, flags);
+ spin_lock_irqsave(&mb0->lock, flags);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
cpu_relax();
@@ -2114,7 +2133,7 @@ static void ack_dbb_wakeup(void)
tcdm_legacy_base + PRCM_MBOX_HEADER_REQ_MB0);
writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
- spin_unlock_irqrestore(&mb0.lock, flags);
+ spin_unlock_irqrestore(&mb0->lock, flags);
}
static inline void print_unknown_header_warning(u8 n, u8 header)
@@ -2142,11 +2161,11 @@ static bool read_mailbox_0(void)
PRCM_ACK_MB0_WAKEUP_0_8500);
if (ev & (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK))
- complete(&mb0.ac_wake_work);
+ complete(&mb0->ac_wake_work);
if (ev & WAKEUP_BIT_SYSCLK_OK)
- complete(&mb3.sysclk_work);
+ complete(&mb3->sysclk_work);
- ev &= mb0.req.dbb_irqs;
+ ev &= mb0->req.dbb_irqs;
for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) {
if (ev & prcmu_irq_bit[n])
@@ -2165,25 +2184,25 @@ static bool read_mailbox_0(void)
static bool read_mailbox_1(void)
{
- mb1.ack.header = readb(tcdm_legacy_base +
+ mb1->ack.header = readb(tcdm_legacy_base +
PRCM_MBOX_HEADER_REQ_MB1);
- mb1.ack.arm_opp = readb(tcdm_legacy_base +
+ mb1->ack.arm_opp = readb(tcdm_legacy_base +
PRCM_ACK_MB1_CURRENT_ARM_OPP);
- mb1.ack.ape_opp = readb(tcdm_legacy_base +
+ mb1->ack.ape_opp = readb(tcdm_legacy_base +
PRCM_ACK_MB1_CURRENT_APE_OPP);
- mb1.ack.ape_voltage_status = readb(tcdm_legacy_base +
+ mb1->ack.ape_voltage_status = readb(tcdm_legacy_base +
PRCM_ACK_MB1_APE_VOLTAGE_STATUS);
writel(MBOX_BIT(1), PRCM_ARM_IT1_CLR);
- complete(&mb1.work);
+ complete(&mb1->work);
return false;
}
static bool read_mailbox_2(void)
{
- mb2.ack.status = readb(tcdm_legacy_base
+ mb2->ack.status = readb(tcdm_legacy_base
+ PRCM_ACK_MB2_DPS_STATUS);
writel(MBOX_BIT(2), PRCM_ARM_IT1_CLR);
- complete(&mb2.work);
+ complete(&mb2->work);
return false;
}
@@ -2219,18 +2238,18 @@ static bool read_mailbox_4(void)
writel(MBOX_BIT(4), PRCM_ARM_IT1_CLR);
if (do_complete)
- complete(&mb4.work);
+ complete(&mb4->work);
return false;
}
static bool read_mailbox_5(void)
{
- mb5.ack.status = readb(tcdm_legacy_base
+ mb5->ack.status = readb(tcdm_legacy_base
+ PRCM_ACK_MB5_I2C_STATUS);
- mb5.ack.value = readb(tcdm_legacy_base + PRCM_ACK_MB5_I2C_VAL);
+ mb5->ack.value = readb(tcdm_legacy_base + PRCM_ACK_MB5_I2C_VAL);
writel(MBOX_BIT(5), PRCM_ARM_IT1_CLR);
- complete(&mb5.work);
+ complete(&mb5->work);
return false;
}
@@ -2246,7 +2265,7 @@ static bool read_mailbox_7(void)
return false;
}
-static bool (* const read_mailbox[NUM_MB])(void) = {
+static bool (*db8500_read_mailbox[NUM_MB])(void) = {
read_mailbox_0,
read_mailbox_1,
read_mailbox_2,
@@ -2257,6 +2276,8 @@ static bool (* const read_mailbox[NUM_MB])(void) = {
read_mailbox_7
};
+static bool (**read_mailbox)(void);
+
static irqreturn_t prcmu_irq_handler(int irq, void *data)
{
u32 bits;
@@ -2288,39 +2309,39 @@ static void prcmu_mask_work(struct work_struct *work)
{
unsigned long flags;
- spin_lock_irqsave(&mb0.lock, flags);
+ spin_lock_irqsave(&mb0->lock, flags);
config_wakeups();
- spin_unlock_irqrestore(&mb0.lock, flags);
+ spin_unlock_irqrestore(&mb0->lock, flags);
}
static void prcmu_irq_mask(struct irq_data *d)
{
unsigned long flags;
- spin_lock_irqsave(&mb0.dbb_irqs_lock, flags);
+ spin_lock_irqsave(&mb0->dbb_irqs_lock, flags);
- mb0.req.dbb_irqs &= ~prcmu_irq_bit[d->hwirq];
+ mb0->req.dbb_irqs &= ~prcmu_irq_bit[d->hwirq];
- spin_unlock_irqrestore(&mb0.dbb_irqs_lock, flags);
+ spin_unlock_irqrestore(&mb0->dbb_irqs_lock, flags);
if (d->irq != IRQ_PRCMU_CA_SLEEP)
- schedule_work(&mb0.mask_work);
+ schedule_work(&mb0->mask_work);
}
static void prcmu_irq_unmask(struct irq_data *d)
{
unsigned long flags;
- spin_lock_irqsave(&mb0.dbb_irqs_lock, flags);
+ spin_lock_irqsave(&mb0->dbb_irqs_lock, flags);
- mb0.req.dbb_irqs |= prcmu_irq_bit[d->hwirq];
+ mb0->req.dbb_irqs |= prcmu_irq_bit[d->hwirq];
- spin_unlock_irqrestore(&mb0.dbb_irqs_lock, flags);
+ spin_unlock_irqrestore(&mb0->dbb_irqs_lock, flags);
if (d->irq != IRQ_PRCMU_CA_SLEEP)
- schedule_work(&mb0.mask_work);
+ schedule_work(&mb0->mask_work);
}
static void noop(struct irq_data *d)
@@ -2553,6 +2574,62 @@ struct prcmu_fops_register_data db8500_probe_data = {
.tab = db8500_probe_tab,
};
+int __init db8500_prcmu_init_mb0(struct mb0_transfer *mb)
+{
+ mb0 = mb;
+ spin_lock_init(&mb0->lock);
+ spin_lock_init(&mb0->dbb_irqs_lock);
+ mutex_init(&mb0->ac_wake_lock);
+ init_completion(&mb0->ac_wake_work);
+ INIT_WORK(&mb0->mask_work, prcmu_mask_work);
+
+ return 0;
+}
+
+int __init db8500_prcmu_init_mb1(struct mb1_transfer *mb)
+{
+ mb1 = mb;
+ mutex_init(&mb1->lock);
+ init_completion(&mb1->work);
+ mb1->ape_opp = APE_NO_CHANGE;
+ return 0;
+}
+
+int __init db8500_prcmu_init_mb2(struct mb2_transfer *mb)
+{
+ mb2 = mb;
+ mutex_init(&mb2->lock);
+ init_completion(&mb2->work);
+ spin_lock_init(&mb2->auto_pm_lock);
+ return 0;
+}
+
+int __init db8500_prcmu_init_mb3(struct mb3_transfer *mb)
+{
+ mb3 = mb;
+ spin_lock_init(&mb3->lock);
+ mutex_init(&mb3->sysclk_lock);
+ init_completion(&mb3->sysclk_work);
+ spin_lock_init(&mb3->fw_log_lock);
+ return 0;
+}
+
+int __init db8500_prcmu_init_mb4(struct mb4_transfer *mb)
+{
+ mb4 = mb;
+ mutex_init(&mb4->lock);
+ init_completion(&mb4->work);
+ return 0;
+}
+
+int __init db8500_prcmu_init_mb5(struct mb5_transfer *mb)
+{
+ mb5 = mb;
+ mutex_init(&mb5->lock);
+ init_completion(&mb5->work);
+ return 0;
+}
+
static int db8500_irq_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hwirq)
{
@@ -2582,10 +2659,23 @@ static int db8500_irq_init(struct device_node *np)
return 0;
}
+int __init db8500_prcmu_context_init(struct prcmu_context *context)
+{
+ /* initialize PRCMU driver context */
+ tcdm_base = context->tcdm_base;
+ tcdm_legacy_base = context->tcdm_legacy_base;
+ fw_trans = context->fw_trans;
+ fw_trans_nb = context->fw_trans_nb;
+ read_mailbox = context->read_mbox;
+
+ return 0;
+}
+
struct prcmu_fops_register_data *__init
db8500_prcmu_early_init(struct prcmu_tcdm_map *map)
{
void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K);
+ struct prcmu_context context;
if (tcpm_base != NULL) {
u32 version;
@@ -2601,28 +2691,21 @@ struct prcmu_fops_register_data *__init
(version >> 24) & 0xFF);
iounmap(tcpm_base);
}
- tcdm_base = ioremap_nocache(U8500_PRCMU_TCDM_BASE, map->tcdm_size);
- tcdm_legacy_base = tcdm_base + map->legacy_offset;
-
- spin_lock_init(&mb0.lock);
- spin_lock_init(&mb0.dbb_irqs_lock);
- mutex_init(&mb0.ac_wake_lock);
- init_completion(&mb0.ac_wake_work);
- mutex_init(&mb1.lock);
- init_completion(&mb1.work);
- mb1.ape_opp = APE_NO_CHANGE;
- mutex_init(&mb2.lock);
- init_completion(&mb2.work);
- spin_lock_init(&mb2.auto_pm_lock);
- spin_lock_init(&mb3.lock);
- mutex_init(&mb3.sysclk_lock);
- init_completion(&mb3.sysclk_work);
- mutex_init(&mb4.lock);
- init_completion(&mb4.work);
- mutex_init(&mb5.lock);
- init_completion(&mb5.work);
-
- INIT_WORK(&mb0.mask_work, prcmu_mask_work);
+
+ context.tcdm_base = ioremap_nocache(U8500_PRCMU_TCDM_BASE,
+ map->tcdm_size);
+ context.tcdm_legacy_base = context.tcdm_base + map->legacy_offset;
+ context.fw_trans = db8500_fw_trans;
+ context.fw_trans_nb = ARRAY_SIZE(db8500_fw_trans);
+ context.read_mbox = db8500_read_mailbox;
+ db8500_prcmu_context_init(&context);
+
+ db8500_prcmu_init_mb0(&db8500_mb0);
+ db8500_prcmu_init_mb1(&db8500_mb1);
+ db8500_prcmu_init_mb2(&db8500_mb2);
+ db8500_prcmu_init_mb3(&db8500_mb3);
+ db8500_prcmu_init_mb4(&db8500_mb4);
+ db8500_prcmu_init_mb5(&db8500_mb5);
/* early init of dbx500-prcmu */
return &db8500_early_data;
diff --git a/drivers/mfd/dbx500-prcmu.h b/drivers/mfd/dbx500-prcmu.h
index 79cba24..ce0e519 100644
--- a/drivers/mfd/dbx500-prcmu.h
+++ b/drivers/mfd/dbx500-prcmu.h
@@ -376,3 +376,19 @@ struct mb5_transfer {
} ack;
};
+/*
+ * prcmu_context - PRCMU common layer need to be configured
+ * @tcdm_base: PRCMU TCDM base address
+ * @tcdm_legacy_base: Base address for legacy mailbox
+ * @fw_trans: Firmware power transition list
+ * @fw_trans_nb: Nb of firmware power transitions
+ * @read_mbox: Pointer on mailbox interrupt management
+ */
+struct prcmu_context {
+ void *tcdm_base;
+ void *tcdm_legacy_base;
+ u8 *fw_trans;
+ u32 fw_trans_nb;
+ bool (**read_mbox)(void);
+};
+
--
1.7.11.1
More information about the linux-arm-kernel
mailing list