[PATCH 2/3] ux500: Add basic PRCM TCDM support

Sundar Iyer sundar.iyer at stericsson.com
Tue May 18 04:36:25 EDT 2010


From: Kumar Sanghvi <kumar.sanghvi at stericsson.com>

Acked-by: Linus Walleij <linus.walleij at stericsson.com>
Signed-off-by: Kumar A Sanghvi <kumar.sanghvi at stericsson.com>
Signed-off-by: Sundar R Iyer <sundar.iyer at stericsson.com>
---
 arch/arm/mach-ux500/Makefile                       |    2 +-
 arch/arm/mach-ux500/cpu-db8500.c                   |    1 +
 arch/arm/mach-ux500/include/mach/hardware.h        |    1 +
 arch/arm/mach-ux500/include/mach/irqs.h            |    1 +
 arch/arm/mach-ux500/include/mach/u8500-prcm-api.h  |   21 +++
 arch/arm/mach-ux500/include/mach/u8500-prcm-regs.h |   28 ++++
 arch/arm/mach-ux500/include/mach/u8500-prcm.h      |   57 +++++++
 arch/arm/mach-ux500/u8500-prcm.c                   |  169 ++++++++++++++++++++
 8 files changed, 279 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-ux500/include/mach/u8500-prcm-api.h
 create mode 100644 arch/arm/mach-ux500/include/mach/u8500-prcm-regs.h
 create mode 100644 arch/arm/mach-ux500/include/mach/u8500-prcm.h
 create mode 100644 arch/arm/mach-ux500/u8500-prcm.c

diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index 3c1ac87..d3613ca 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -4,7 +4,7 @@
 
 obj-y				:= clock.o cpu.o devices.o
 obj-$(CONFIG_UX500_SOC_DB5500)	+= cpu-db5500.o devices-db5500.o
-obj-$(CONFIG_UX500_SOC_DB8500)	+= cpu-db8500.o devices-db8500.o
+obj-$(CONFIG_UX500_SOC_DB8500)	+= cpu-db8500.o devices-db8500.o u8500-prcm.o
 obj-$(CONFIG_MACH_U8500_MOP)	+= board-mop500.o
 obj-$(CONFIG_MACH_U5500)	+= board-u5500.o
 obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o localtimer.o
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 2e28d6f..5e5e749 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -38,6 +38,7 @@ static struct platform_device *platform_devs[] __initdata = {
 /* minimum static i/o mapping required to boot U8500 platforms */
 static struct map_desc u8500_io_desc[] __initdata = {
 	__IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
+	__IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h
index 8656379..f640415 100644
--- a/arch/arm/mach-ux500/include/mach/hardware.h
+++ b/arch/arm/mach-ux500/include/mach/hardware.h
@@ -60,6 +60,7 @@
 #define UX500_MTU0_BASE		UX500(MTU0)
 #define UX500_MTU1_BASE		UX500(MTU1)
 #define UX500_PRCMU_BASE	UX500(PRCMU)
+#define UX500_PRCMU_TCDM_BASE	UX500(PRCMU_TCDM)
 
 #define UX500_RNG_BASE		UX500(RNG)
 #define UX500_RTC_BASE		UX500(RTC)
diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h
index 910149e..a0a49a5 100644
--- a/arch/arm/mach-ux500/include/mach/irqs.h
+++ b/arch/arm/mach-ux500/include/mach/irqs.h
@@ -41,6 +41,7 @@
 #define IRQ_HSIR_CH2_OVRRUN	(IRQ_SHPI_START + 34)
 #define IRQ_HSIR_CH3_OVRRUN	(IRQ_SHPI_START + 35)
 #define IRQ_AB4500		(IRQ_SHPI_START + 40)
+#define IRQ_PRCMU		(IRQ_SHPI_START + 47)
 #define IRQ_DISP		(IRQ_SHPI_START + 48)
 #define IRQ_SiPI3		(IRQ_SHPI_START + 49)
 #define IRQ_I2C4		(IRQ_SHPI_START + 51)
diff --git a/arch/arm/mach-ux500/include/mach/u8500-prcm-api.h b/arch/arm/mach-ux500/include/mach/u8500-prcm-api.h
new file mode 100644
index 0000000..5f113c1
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/u8500-prcm-api.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Kumar Sanghvi <kumar.sanghvi at stericsson.com>
+ *
+ * U8500 PRCMU APIs
+ */
+
+/* ux500 subsystem */
+enum ux500_subsys {
+	SUBSYS_ARM,
+	SUBSYS_APE,
+};
+
+int prcm_set_subsys_opp(unsigned int subsys_opp_idx,
+		unsigned int subsys);
+int prcm_get_subsys_opp(unsigned int subsys);
+
diff --git a/arch/arm/mach-ux500/include/mach/u8500-prcm-regs.h b/arch/arm/mach-ux500/include/mach/u8500-prcm-regs.h
new file mode 100644
index 0000000..fd16755
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/u8500-prcm-regs.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Kumar Sanghvi <kumar.sanghvi at stericsson.com>
+ *
+ * U8500 PRCM Memory Map
+ */
+
+#ifndef __U8500_PRCM_REGS_H
+#define __U8500_PRCM_REGS_H
+
+#include <mach/hardware.h>
+
+#define _PRCMU_BASE             IO_ADDRESS(U8500_PRCMU_BASE)
+
+/* CPU mailbox registers */
+#define PRCM_MBOX_CPU_VAL       (_PRCMU_BASE + 0x0fc)
+#define PRCM_MBOX_CPU_SET       (_PRCMU_BASE + 0x100)
+#define PRCM_MBOX_CPU_CLR       (_PRCMU_BASE + 0x104)
+
+/* register for Ack mailbox interrupts */
+#define PRCM_ARM_IT1_CLEAR      (_PRCMU_BASE + 0x48C)
+#define PRCM_ARM_IT1_VAL        (_PRCMU_BASE + 0x494)
+
+#endif /* __U8500_PRCMU_REGS_H */
diff --git a/arch/arm/mach-ux500/include/mach/u8500-prcm.h b/arch/arm/mach-ux500/include/mach/u8500-prcm.h
new file mode 100644
index 0000000..5131649
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/u8500-prcm.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Kumar Sanghvi <kumar.sanghvi at stericsson.com>
+ *
+ * PRCM Mailbox definitions
+ */
+#ifndef __U8500_PRCM_H
+#define __U8500_PRCM_H
+
+#include <mach/hardware.h>
+
+#define _PRCMU_TCDM_BASE		IO_ADDRESS(U8500_PRCMU_TCDM_BASE)
+
+#define PRCM_CUR_PWRSTATE		(_PRCMU_TCDM_BASE + 0xffc)
+
+/* PRCM Mbox header */
+#define _PRCM_MBOX_HEADER		(_PRCMU_TCDM_BASE + 0xfe8)
+#define PRCM_MBOX_HEADER_REQ		(_PRCM_MBOX_HEADER + 0x0)
+#define PRCM_MBOX_HEADER_ACK		(_PRCM_MBOX_HEADER + 0x8)
+
+/* PRCM MailBox 1
+ *
+ * requests for controlling :
+ * - ARM OPP
+ * - APE OPP
+ * - Boost mode OPP
+ *
+ * replies for querying :
+ * - ARM/APE/Boost mode OPP
+ * - current DVFS transitions
+ */
+/* maiboxes */
+#define PRCM_REQ_MBOX1			(_PRCMU_TCDM_BASE + 0xfd0)
+#define PRCM_ACK_MBOX1			(_PRCMU_TCDM_BASE + 0xe04)
+
+/* headers */
+#define PRCM_MBOX_HEADER_REQ_MBOX1	(PRCM_MBOX_HEADER_REQ + 0x1)
+#define PRCM_MBOX_HEADER_ACK_MBOX1	(PRCM_MBOX_HEADER_ACK + 0x1)
+
+/* Mailbox 1 Requests */
+#define PRCM_MBOX1_REQ_ARMOPP		(PRCM_REQ_MBOX1 + 0x0)
+#define PRCM_MBOX1_REQ_APEOPP		(PRCM_REQ_MBOX1 + 0x1)
+#define PRCM_MBOX1_REQ_BOOSTOPP		(PRCM_REQ_MBOX1 + 0x2)
+
+/* Mailbox 1 ACKs */
+#define PRCM_MBOX1_ACK_ARMOPP		(PRCM_ACK_MBOX1 + 0x0)
+#define PRCM_MBOX1_ACK_APEOPP		(PRCM_ACK_MBOX1 + 0x1)
+#define PRCM_MBOX1_ACK_BOOSTOPP		(PRCM_ACK_MBOX1 + 0x2)
+#define PRCM_MBOX1_ACK_DVFS_STATUS	(PRCM_ACK_MBOX1 + 0x3)
+
+/* Mailbox Interrupts */
+#define PRCM_IRQ_ACK_MBOX1		(1 << 0x1)
+#endif /* __U8500_PRCM_H */
diff --git a/arch/arm/mach-ux500/u8500-prcm.c b/arch/arm/mach-ux500/u8500-prcm.c
new file mode 100644
index 0000000..2703768
--- /dev/null
+++ b/arch/arm/mach-ux500/u8500-prcm.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Kumar Sanghvi <kumar.sanghvi at stericsson.com>
+ * Author: Sundar Iyer <sundar.iyer at stericsson.com>
+ *
+ * U8500 PRCM Unit driver
+ */
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+
+#include <mach/u8500-prcm.h>
+#include <mach/u8500-prcm-regs.h>
+#include <mach/u8500-prcm-api.h>
+
+/* PRCM enums, definitions */
+#define U8500_PRCM_PWRSTATE_EXECUTE	(0x2)
+#define U8500_PRCM_MBOX1_ERROR		(0xB)
+
+/* supported mailboxes */
+enum ux500_prcm_mbox {
+	MBOX0,
+	MBOX1,
+};
+
+/* sync-helpers for req mbox 1 */
+DECLARE_COMPLETION(prcm_rqmbox1_completion);
+DEFINE_MUTEX(prcm_rqmbox1_lock);
+
+/**
+ * prcm_get_pwr_state() - get the PRCM current power state
+ */
+static inline int prcm_get_pwr_state(void)
+{
+	return readb(PRCM_CUR_PWRSTATE);
+}
+
+/**
+ * prcm_set_subsys_opp() - set the subsyste,(ARM/APE) frequency
+ * @freq: new frequency to be set
+ * @core: target core as ARM/APE
+ *
+ * this function recieves the new OPP index as requested
+ * and requests the PRCM for the desired core
+ */
+int prcm_set_subsys_opp(unsigned int subsys_opp_idx,
+		unsigned int subsys)
+{
+	int ret = 0;
+	int updated_sys_opp, dvfs_status;
+
+	mutex_lock(&prcm_rqmbox1_lock);
+
+	/* request opp mgmt for mbox  */
+	writel(0x0, PRCM_MBOX_HEADER_REQ_MBOX1);
+
+	/* later on, we handle the APE sub sys */
+	if (subsys == SUBSYS_ARM) {
+		writel(subsys_opp_idx, PRCM_MBOX1_REQ_ARMOPP);
+		writel(0x0, PRCM_MBOX1_REQ_APEOPP);
+	} else {
+		ret = -EINVAL;
+		goto error_ret;
+	}
+
+	/* trigger the prcm */
+	writel((1 << MBOX1), PRCM_MBOX_CPU_SET);
+
+	/* request and wait for reply */
+	wait_for_completion(&prcm_rqmbox1_completion);
+
+	dvfs_status = readb(PRCM_MBOX1_ACK_DVFS_STATUS);
+	/* confirm if dvfs status is not an error */
+	if ((dvfs_status & 0x0f) ==
+			U8500_PRCM_MBOX1_ERROR) {
+		ret = -EINVAL;
+		goto error_ret;
+	}
+
+	updated_sys_opp = readb(PRCM_MBOX1_ACK_ARMOPP);
+
+	mutex_unlock(&prcm_rqmbox1_lock);
+
+	if (subsys_opp_idx != updated_sys_opp)
+		ret = -EINVAL;
+
+error_ret:
+	mutex_unlock(&prcm_rqmbox1_lock);
+	return ret;
+}
+
+/**
+ * prcm_get_subsys_opp() - get the subsys(ARM/APE) frequency
+ * @core: target core as ARM/APE
+ *
+ * this function gets the OPP for the desired core
+ */
+int prcm_get_subsys_opp(unsigned int subsys)
+{
+	if (subsys == SUBSYS_ARM)
+		return readb(PRCM_MBOX1_ACK_ARMOPP);
+	else if (subsys == SUBSYS_APE)
+		return readb(PRCM_MBOX1_ACK_APEOPP);
+	else
+		return -EINVAL;
+}
+
+/**
+ * prcm_irq_handler() - IRQ handler
+ * @irq:        the irq number
+ * @ctrlr:      control
+ */
+static irqreturn_t prcm_irq_handler (int irq, void *ctrlr)
+{
+	/* clear interrupts */
+	if (readl(PRCM_ARM_IT1_VAL) & PRCM_IRQ_ACK_MBOX1) {
+		complete(&prcm_rqmbox1_completion);
+		writeb(PRCM_IRQ_ACK_MBOX1, PRCM_ARM_IT1_CLEAR);
+	} else
+		return IRQ_NONE;
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * u8500_prcm_init() - U8500 PRCM driver init
+ */
+static int u8500_prcm_init(void)
+{
+	int err;
+
+	if (cpu_is_u8500ed()) {
+		printk(KERN_INFO "ux500-prcm: Not supported on ED versions\n");
+		return 0;
+	}
+
+	/* check if the PRCM is active or not */
+	if (prcm_get_pwr_state() != U8500_PRCM_PWRSTATE_EXECUTE) {
+		printk(KERN_INFO "ux500-prcm: no prcm available\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * clear all prcm interrupts.
+	 * possibly some transaction can happen (from u-boot)
+	 * even before the driver starts
+	 */
+	writeb(0xFF, PRCM_ARM_IT1_CLEAR);
+
+	err = request_irq(IRQ_PRCMU, prcm_irq_handler, IRQF_TRIGGER_HIGH,
+			"prcm_irq", NULL);
+	if (err < 0) {
+		printk(KERN_ERR
+			"ux500-prcm: Failed to request irq\n");
+		return err;
+	}
+
+	printk(KERN_INFO "ux500-prcm: prcm init done\n");
+
+	return 0;
+}
+
+arch_initcall(u8500_prcm_init);
-- 
1.6.3.3




More information about the linux-arm-kernel mailing list