diff options
author | Shreshtha Kumar Sahu <shreshthakumar.sahu@stericsson.com> | 2011-05-30 18:33:58 +0530 |
---|---|---|
committer | said m bagheri <ebgheri@steludxu2848.(none)> | 2011-06-29 10:30:24 +0200 |
commit | 175979f8e4d64e7e9d1d4c933659150d048381ef (patch) | |
tree | 0dfc75b48e3b95d2657a688ddf09a3d908187c19 | |
parent | 0cca37a41d36e36bd69ea0f095ac6b1493b6167a (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.c | 83 | ||||
-rw-r--r-- | arch/arm/mach-ux500/prcmu-db5500.c | 100 |
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); } |