aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShreshtha Kumar Sahu <shreshthakumar.sahu@stericsson.com>2011-05-30 18:33:58 +0530
committersaid m bagheri <ebgheri@steludxu2848.(none)>2011-06-29 10:30:24 +0200
commit175979f8e4d64e7e9d1d4c933659150d048381ef (patch)
tree0dfc75b48e3b95d2657a688ddf09a3d908187c19
parent0cca37a41d36e36bd69ea0f095ac6b1493b6167a (diff)
u5500: add support for sysclk
basic sysclk support added in PRCMU driver and clock framework driver updated. ST-Ericsson Linux next: - ST-Ericsson ID: WP334774 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I0d29ed9459cdfdd4f1d5bc3f4e3054722110178c Signed-off-by: Shreshtha Kumar Sahu <shreshthakumar.sahu@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/24164 Reviewed-by: QATEST Reviewed-by: Vijaya Kumar K-1 <vijay.kilari@stericsson.com> Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
-rw-r--r--arch/arm/mach-ux500/clock-db5500.c83
-rw-r--r--arch/arm/mach-ux500/prcmu-db5500.c100
2 files changed, 99 insertions, 84 deletions
diff --git a/arch/arm/mach-ux500/clock-db5500.c b/arch/arm/mach-ux500/clock-db5500.c
index 93f65e5cc79..53c25605317 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/prcmu-db5500.c b/arch/arm/mach-ux500/prcmu-db5500.c
index 63aa600c04b..c549de7a4b9 100644
--- a/arch/arm/mach-ux500/prcmu-db5500.c
+++ b/arch/arm/mach-ux500/prcmu-db5500.c
@@ -101,6 +101,16 @@ enum mb2_header {
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,
@@ -118,6 +128,12 @@ enum db5500_prcmu_pll {
DB5500_NUM_PLL_ID,
};
+/* 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)
@@ -186,6 +202,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.
@@ -241,6 +274,50 @@ static struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
CLK_MGT_ENTRY(SVACLK),
};
+static int request_sysclk(bool enable)
+{
+ int r;
+
+ r = 0;
+ mutex_lock(&mb3_transfer.sysclk_lock);
+
+ while (readl(_PRCMU_BASE + 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), (_PRCMU_BASE + 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);
@@ -352,7 +429,7 @@ 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;
}
@@ -655,7 +732,22 @@ static bool read_mailbox_2(void)
static bool read_mailbox_3(void)
{
- writel(MBOX_BIT(3), _PRCMU_BASE + PRCM_ARM_IT1_CLEAR);
+ 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), _PRCMU_BASE + PRCM_ARM_IT1_CLEAR);
+ complete(&mb3_transfer.sysclk_work);
+ break;
+ default:
+ writel(MBOX_BIT(3), _PRCMU_BASE + PRCM_ARM_IT1_CLEAR);
+ pr_err("prcmu: wrong MB3 header\n");
+ break;
+ }
+
return false;
}
@@ -742,8 +834,10 @@ void __init db5500_prcmu_early_init(void)
tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
spin_lock_init(&mb0_transfer.lock);
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);
}