aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ux500/prcmu.c
diff options
context:
space:
mode:
authorMartin Persson <martin.persson@stericsson.com>2010-12-08 09:13:28 -0500
committerLinus Walleij <linus.walleij@stericsson.com>2010-12-09 04:06:01 -0500
commite0befb23dfed4d4d0de9d97dac936ccc0bbec093 (patch)
tree269484cb63d3449de74f18a21a1b72bcb182c431 /arch/arm/mach-ux500/prcmu.c
parent20e218a77fc0b0576817b6b204fe5b9391a5b209 (diff)
ux500: Add prcmu support for operating points
Adds support in PRCMU driver to handle CPU and APE operating points. Signed-off-by: Martin Persson <martin.persson@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Diffstat (limited to 'arch/arm/mach-ux500/prcmu.c')
-rw-r--r--arch/arm/mach-ux500/prcmu.c151
1 files changed, 149 insertions, 2 deletions
diff --git a/arch/arm/mach-ux500/prcmu.c b/arch/arm/mach-ux500/prcmu.c
index 07d5f13d2a4e..c522d26ef348 100644
--- a/arch/arm/mach-ux500/prcmu.c
+++ b/arch/arm/mach-ux500/prcmu.c
@@ -1,10 +1,14 @@
1/* 1/*
2 * Copyright (C) ST Ericsson SA 2010 2 * Copyright (C) STMicroelectronics 2009
3 * Copyright (C) ST-Ericsson SA 2010
3 * 4 *
4 * License Terms: GNU General Public License v2 5 * License Terms: GNU General Public License v2
6 * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
7 * Author: Sundar Iyer <sundar.iyer@stericsson.com>
5 * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> 8 * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
6 * 9 *
7 * U8500 PRCMU driver. 10 * U8500 PRCM Unit interface driver
11 *
8 */ 12 */
9#include <linux/kernel.h> 13#include <linux/kernel.h>
10#include <linux/module.h> 14#include <linux/module.h>
@@ -19,13 +23,27 @@
19 23
20#include <mach/hardware.h> 24#include <mach/hardware.h>
21#include <mach/prcmu-regs.h> 25#include <mach/prcmu-regs.h>
26#include <mach/prcmu-defs.h>
22 27
23/* Global var to runtime determine TCDM base for v2 or v1 */ 28/* Global var to runtime determine TCDM base for v2 or v1 */
24static __iomem void *tcdm_base; 29static __iomem void *tcdm_base;
25 30
31#define _MBOX_HEADER (tcdm_base + 0xFE8)
32#define MBOX_HEADER_REQ_MB0 (_MBOX_HEADER + 0x0)
33
34#define REQ_MB1 (tcdm_base + 0xFD0)
26#define REQ_MB5 (tcdm_base + 0xE44) 35#define REQ_MB5 (tcdm_base + 0xE44)
36
37#define REQ_MB1_ARMOPP (REQ_MB1 + 0x0)
38#define REQ_MB1_APEOPP (REQ_MB1 + 0x1)
39#define REQ_MB1_BOOSTOPP (REQ_MB1 + 0x2)
40
41#define ACK_MB1 (tcdm_base + 0xE04)
27#define ACK_MB5 (tcdm_base + 0xDF4) 42#define ACK_MB5 (tcdm_base + 0xDF4)
28 43
44#define ACK_MB1_CURR_ARMOPP (ACK_MB1 + 0x0)
45#define ACK_MB1_CURR_APEOPP (ACK_MB1 + 0x1)
46
29#define REQ_MB5_I2C_SLAVE_OP (REQ_MB5) 47#define REQ_MB5_I2C_SLAVE_OP (REQ_MB5)
30#define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1) 48#define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1)
31#define REQ_MB5_I2C_REG (REQ_MB5 + 2) 49#define REQ_MB5_I2C_REG (REQ_MB5 + 2)
@@ -34,12 +52,33 @@ static __iomem void *tcdm_base;
34#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1) 52#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1)
35#define ACK_MB5_I2C_VAL (ACK_MB5 + 3) 53#define ACK_MB5_I2C_VAL (ACK_MB5 + 3)
36 54
55#define PRCM_AVS_VARM_MAX_OPP (tcdm_base + 0x2E4)
56#define PRCM_AVS_ISMODEENABLE 7
57#define PRCM_AVS_ISMODEENABLE_MASK (1 << PRCM_AVS_ISMODEENABLE)
58
37#define I2C_WRITE(slave) \ 59#define I2C_WRITE(slave) \
38 (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0)) 60 (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0))
39#define I2C_READ(slave) \ 61#define I2C_READ(slave) \
40 (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0) | BIT(0)) 62 (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0) | BIT(0))
41#define I2C_STOP_EN BIT(3) 63#define I2C_STOP_EN BIT(3)
42 64
65enum mb1_h {
66 MB1H_ARM_OPP = 1,
67 MB1H_APE_OPP,
68 MB1H_ARM_APE_OPP,
69};
70
71static struct {
72 struct mutex lock;
73 struct completion work;
74 struct {
75 u8 arm_opp;
76 u8 ape_opp;
77 u8 arm_status;
78 u8 ape_status;
79 } ack;
80} mb1_transfer;
81
43enum ack_mb5_status { 82enum ack_mb5_status {
44 I2C_WR_OK = 0x01, 83 I2C_WR_OK = 0x01,
45 I2C_RD_OK = 0x02, 84 I2C_RD_OK = 0x02,
@@ -148,6 +187,104 @@ unlock_and_return:
148} 187}
149EXPORT_SYMBOL(prcmu_abb_write); 188EXPORT_SYMBOL(prcmu_abb_write);
150 189
190static int set_ape_cpu_opps(u8 header, enum prcmu_ape_opp ape_opp,
191 enum prcmu_cpu_opp cpu_opp)
192{
193 bool do_ape;
194 bool do_arm;
195 int err = 0;
196
197 do_ape = ((header == MB1H_APE_OPP) || (header == MB1H_ARM_APE_OPP));
198 do_arm = ((header == MB1H_ARM_OPP) || (header == MB1H_ARM_APE_OPP));
199
200 mutex_lock(&mb1_transfer.lock);
201
202 while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
203 cpu_relax();
204
205 writeb(0, MBOX_HEADER_REQ_MB0);
206 writeb(cpu_opp, REQ_MB1_ARMOPP);
207 writeb(ape_opp, REQ_MB1_APEOPP);
208 writeb(0, REQ_MB1_BOOSTOPP);
209 writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
210 wait_for_completion(&mb1_transfer.work);
211 if ((do_ape) && (mb1_transfer.ack.ape_status != 0))
212 err = -EIO;
213 if ((do_arm) && (mb1_transfer.ack.arm_status != 0))
214 err = -EIO;
215
216 mutex_unlock(&mb1_transfer.lock);
217
218 return err;
219}
220
221/**
222 * prcmu_set_ape_opp() - Set the OPP of the APE.
223 * @opp: The OPP to set.
224 *
225 * This function sets the OPP of the APE.
226 */
227int prcmu_set_ape_opp(enum prcmu_ape_opp opp)
228{
229 return set_ape_cpu_opps(MB1H_APE_OPP, opp, APE_OPP_NO_CHANGE);
230}
231EXPORT_SYMBOL(prcmu_set_ape_opp);
232
233/**
234 * prcmu_set_cpu_opp() - Set the OPP of the CPU.
235 * @opp: The OPP to set.
236 *
237 * This function sets the OPP of the CPU.
238 */
239int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp)
240{
241 return set_ape_cpu_opps(MB1H_ARM_OPP, CPU_OPP_NO_CHANGE, opp);
242}
243EXPORT_SYMBOL(prcmu_set_cpu_opp);
244
245/**
246 * prcmu_set_ape_cpu_opps() - Set the OPPs of the APE and the CPU.
247 * @ape_opp: The APE OPP to set.
248 * @cpu_opp: The CPU OPP to set.
249 *
250 * This function sets the OPPs of the APE and the CPU.
251 */
252int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
253 enum prcmu_cpu_opp cpu_opp)
254{
255 return set_ape_cpu_opps(MB1H_ARM_APE_OPP, ape_opp, cpu_opp);
256}
257EXPORT_SYMBOL(prcmu_set_ape_cpu_opps);
258
259/**
260 * prcmu_get_ape_opp() - Get the OPP of the APE.
261 *
262 * This function gets the OPP of the APE.
263 */
264enum prcmu_ape_opp prcmu_get_ape_opp(void)
265{
266 return readb(ACK_MB1_CURR_APEOPP);
267}
268EXPORT_SYMBOL(prcmu_get_ape_opp);
269
270/**
271 * prcmu_get_cpu_opp() - Get the OPP of the CPU.
272 *
273 * This function gets the OPP of the CPU. The OPP is specified in %%.
274 * PRCMU_OPP_EXT is a special OPP value, not specified in %%.
275 */
276int prcmu_get_cpu_opp(void)
277{
278 return readb(ACK_MB1_CURR_ARMOPP);
279}
280EXPORT_SYMBOL(prcmu_get_cpu_opp);
281
282bool prcmu_has_arm_maxopp(void)
283{
284 return (readb(PRCM_AVS_VARM_MAX_OPP) & PRCM_AVS_ISMODEENABLE_MASK)
285 == PRCM_AVS_ISMODEENABLE_MASK;
286}
287
151static void read_mailbox_0(void) 288static void read_mailbox_0(void)
152{ 289{
153 writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR); 290 writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
@@ -155,6 +292,9 @@ static void read_mailbox_0(void)
155 292
156static void read_mailbox_1(void) 293static void read_mailbox_1(void)
157{ 294{
295 mb1_transfer.ack.arm_opp = readb(ACK_MB1_CURR_ARMOPP);
296 mb1_transfer.ack.ape_opp = readb(ACK_MB1_CURR_APEOPP);
297 complete(&mb1_transfer.work);
158 writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR); 298 writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
159} 299}
160 300
@@ -234,6 +374,13 @@ void __init prcmu_early_init(void)
234 374
235static int __init prcmu_init(void) 375static int __init prcmu_init(void)
236{ 376{
377 if (cpu_is_u8500ed()) {
378 pr_err("prcmu: Unsupported chip version\n");
379 return 0;
380 }
381
382 mutex_init(&mb1_transfer.lock);
383 init_completion(&mb1_transfer.work);
237 mutex_init(&mb5_transfer.lock); 384 mutex_init(&mb5_transfer.lock);
238 init_completion(&mb5_transfer.work); 385 init_completion(&mb5_transfer.work);
239 386