linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank)
@ 2012-10-30 21:04 Mark Langsdorf
  2012-10-30 21:04 ` [PATCH 1/6] arm: use devicetree to get smp_twd clock Mark Langsdorf
                   ` (17 more replies)
  0 siblings, 18 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-10-30 21:04 UTC (permalink / raw)
  To: linux-kernel

This patch series adds cpufreq support for the Calxeda ECX-1000 (highbank)
SoCs. The driver is based on the cpufreq-cpu0 driver. Because of the 
unique way that highbank uses the EnergyCore Management Engine to manage
voltages, it was not possible to use the cpufreq-cpu0 driver.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/6] arm: use devicetree to get smp_twd clock
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
@ 2012-10-30 21:04 ` Mark Langsdorf
  2012-10-30 21:04 ` [PATCH 2/6] clk, highbank: remove non-bypass reset mode Mark Langsdorf
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-10-30 21:04 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mark Langsdorf, Rob Herring, Russell King, linux-arm-kernel

From: Rob Herring <rob.herring@calxeda.com>

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: linux-arm-kernel@lists.infradead.org
---
 arch/arm/kernel/smp_twd.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index b22d700..600fbcc 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -237,12 +237,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static struct clk *twd_get_clock(struct device_node *np)
 {
-	struct clk *clk;
+	struct clk *clk = NULL;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
+	if (np)
+		clk = of_clk_get(np, 0);
+	if (!clk)
+		clk = clk_get_sys("smp_twd", NULL);
 	if (IS_ERR(clk)) {
 		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
 		return clk;
@@ -263,6 +266,7 @@ static struct clk *twd_get_clock(void)
 		return ERR_PTR(err);
 	}
 
+	twd_timer_rate = clk_get_rate(clk);
 	return clk;
 }
 
@@ -273,12 +277,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
 	struct clock_event_device **this_cpu_clk;
 
-	if (!twd_clk)
-		twd_clk = twd_get_clock();
-
-	if (!IS_ERR_OR_NULL(twd_clk))
-		twd_timer_rate = clk_get_rate(twd_clk);
-	else
+	if (IS_ERR_OR_NULL(twd_clk))
 		twd_calibrate_rate();
 
 	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
@@ -349,6 +348,10 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
+	twd_clk = twd_get_clock(NULL);
+
+	twd_clk = twd_get_clock(NULL);
+
 	return twd_local_timer_common_register();
 }
 
@@ -383,6 +386,8 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
+	twd_clk = twd_get_clock(np);
+
 	err = twd_local_timer_common_register();
 
 out:
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/6] clk, highbank: remove non-bypass reset mode
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2012-10-30 21:04 ` [PATCH 1/6] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2012-10-30 21:04 ` Mark Langsdorf
  2012-10-30 21:04 ` [PATCH 3/6] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-10-30 21:04 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mark Langsdorf, Rob Herring

The highbank clock will glitch if the clock rate is reset without
relocking the PLL. Remove the option to attempt reseting without
relocking.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
---
 drivers/clk/clk-highbank.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..4f50c42 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -171,7 +171,8 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 
 		writel(reg | HB_PLL_RESET, hbclk->reg);
 		reg &= ~(HB_PLL_DIVF_MASK | HB_PLL_DIVQ_MASK);
-		reg |= (divf << HB_PLL_DIVF_SHIFT) | (divq << HB_PLL_DIVQ_SHIFT);
+		reg |= (divf << HB_PLL_DIVF_SHIFT) |
+			(divq << HB_PLL_DIVQ_SHIFT);
 		writel(reg | HB_PLL_RESET, hbclk->reg);
 		writel(reg, hbclk->reg);
 
@@ -182,8 +183,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/6] cpufreq: tolerate inexact values when collecting stats
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2012-10-30 21:04 ` [PATCH 1/6] arm: use devicetree to get smp_twd clock Mark Langsdorf
  2012-10-30 21:04 ` [PATCH 2/6] clk, highbank: remove non-bypass reset mode Mark Langsdorf
@ 2012-10-30 21:04 ` Mark Langsdorf
  2012-10-30 21:04 ` [PATCH 4/6] arm highbank: add support for pl320 IPC Mark Langsdorf
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-10-30 21:04 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mark Langsdorf, cpufreq, Rafael J. Wysocki

Allow frequency values to vary by +/-5000 Hz when collecting stats.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: cpufreq@vger.kernel.org
Cc: Rafael J. Wysocki <rjw@sisk.pl>

---
 drivers/cpufreq/cpufreq_stats.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 3998316..4e2ea7e 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -158,9 +158,11 @@ static struct attribute_group stats_attr_group = {
 static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
 {
 	int index;
-	for (index = 0; index < stat->max_state; index++)
-		if (stat->freq_table[index] == freq)
+	for (index = 0; index < stat->max_state; index++) {
+		if ((stat->freq_table[index] < (freq + 5000)) &&
+		    (stat->freq_table[index] > (freq - 5000)))
 			return index;
+	}
 	return -1;
 }
 
@@ -251,6 +253,8 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
 	spin_lock(&cpufreq_stats_lock);
 	stat->last_time = get_jiffies_64();
 	stat->last_index = freq_table_get_index(stat, policy->cur);
+	if (stat->last_index > stat->max_state)
+		stat->last_index = stat->max_state - 1;
 	spin_unlock(&cpufreq_stats_lock);
 	cpufreq_cpu_put(data);
 	return 0;
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 4/6] arm highbank: add support for pl320 IPC
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (2 preceding siblings ...)
  2012-10-30 21:04 ` [PATCH 3/6] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
@ 2012-10-30 21:04 ` Mark Langsdorf
  2012-10-30 21:04 ` [PATCH 5/6] power: export opp cpufreq functions Mark Langsdorf
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-10-30 21:04 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the highbank A9
and the EnergyCore Management Engine. The pl320 implements a straightforward
mailbox protocol.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>

---
 arch/arm/include/asm/pl320-ipc.h                |  20 ++
 arch/arm/mach-highbank/Kconfig                  |   2 +
 arch/arm/mach-highbank/Makefile                 |   2 +
 arch/arm/mach-highbank/include/mach/pl320-ipc.h |  20 ++
 arch/arm/mach-highbank/pl320-ipc.c              | 232 ++++++++++++++++++++++++
 5 files changed, 276 insertions(+)
 create mode 100644 arch/arm/include/asm/pl320-ipc.h
 create mode 100644 arch/arm/mach-highbank/include/mach/pl320-ipc.h
 create mode 100644 arch/arm/mach-highbank/pl320-ipc.c

diff --git a/arch/arm/include/asm/pl320-ipc.h b/arch/arm/include/asm/pl320-ipc.h
new file mode 100644
index 0000000..a0e58ee
--- /dev/null
+++ b/arch/arm/include/asm/pl320-ipc.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+int ipc_call_fast(u32 *data);
+int ipc_call_slow(u32 *data);
+
+extern int pl320_ipc_register_notifier(struct notifier_block *nb);
+extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 0e1d0a4..ee83af6 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -13,3 +13,5 @@ config ARCH_HIGHBANK
 	select HAVE_SMP
 	select SPARSE_IRQ
 	select USE_OF
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile
index 3ec8bdd..b894708 100644
--- a/arch/arm/mach-highbank/Makefile
+++ b/arch/arm/mach-highbank/Makefile
@@ -7,3 +7,5 @@ obj-$(CONFIG_DEBUG_HIGHBANK_UART)	+= lluart.o
 obj-$(CONFIG_SMP)			+= platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
 obj-$(CONFIG_PM_SLEEP)			+= pm.o
+
+obj-y					+= pl320-ipc.o
diff --git a/arch/arm/mach-highbank/include/mach/pl320-ipc.h b/arch/arm/mach-highbank/include/mach/pl320-ipc.h
new file mode 100644
index 0000000..a0e58ee
--- /dev/null
+++ b/arch/arm/mach-highbank/include/mach/pl320-ipc.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+int ipc_call_fast(u32 *data);
+int ipc_call_slow(u32 *data);
+
+extern int pl320_ipc_register_notifier(struct notifier_block *nb);
+extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);
diff --git a/arch/arm/mach-highbank/pl320-ipc.c b/arch/arm/mach-highbank/pl320-ipc.c
new file mode 100644
index 0000000..0eb92e4
--- /dev/null
+++ b/arch/arm/mach-highbank/pl320-ipc.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <asm/pl320-ipc.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_FAST_MBOX		0
+#define IPC_SLOW_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_SPINLOCK(ipc_m0_lock);
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* non-blocking implementation from the A9 side, interrupt safe in theory */
+int ipc_call_fast(u32 *data)
+{
+	int timeout, ret;
+
+	spin_lock(&ipc_m0_lock);
+
+	__ipc_send(IPC_FAST_MBOX, data);
+
+	for (timeout = 500; timeout > 0; timeout--) {
+		if (__raw_readl(ipc_base + IPCMxSEND(IPC_FAST_MBOX)) == 0x2)
+			break;
+		udelay(100);
+	}
+	if (timeout == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_FAST_MBOX, data);
+out:
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_FAST_MBOX));
+	spin_unlock(&ipc_m0_lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipc_call_fast);
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int ipc_call_slow(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_SLOW_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_SLOW_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipc_call_slow);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_SLOW_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_SLOW_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+
+static int __devinit pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_FAST_MBOX));
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_SLOW_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init fast mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_FAST_MBOX));
+	set_destination(M3_SOURCE, IPC_FAST_MBOX);
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_SLOW_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_SLOW_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_SLOW_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 5/6] power: export opp cpufreq functions
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (3 preceding siblings ...)
  2012-10-30 21:04 ` [PATCH 4/6] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2012-10-30 21:04 ` Mark Langsdorf
  2012-10-31  1:17   ` Nishanth Menon
  2012-10-30 21:04 ` [PATCH 6/6] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
                   ` (12 subsequent siblings)
  17 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-10-30 21:04 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mark Langsdorf, linux-pm

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: linux-pm@vger.kernel.org

---
 drivers/base/power/opp.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index d946864..37dc5f4 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -23,6 +23,7 @@
 #include <linux/rcupdate.h>
 #include <linux/opp.h>
 #include <linux/of.h>
+#include <linux/module.h>
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -643,6 +644,7 @@ int opp_init_cpufreq_table(struct device *dev,
 
 	return 0;
 }
+EXPORT_SYMBOL(opp_init_cpufreq_table);
 
 /**
  * opp_free_cpufreq_table() - free the cpufreq table
@@ -660,6 +662,7 @@ void opp_free_cpufreq_table(struct device *dev,
 	kfree(*table);
 	*table = NULL;
 }
+EXPORT_SYMBOL(opp_free_cpufreq_table);
 #endif		/* CONFIG_CPU_FREQ */
 
 /**
@@ -720,4 +723,5 @@ int of_init_opp_table(struct device *dev)
 
 	return 0;
 }
+EXPORT_SYMBOL(of_init_opp_table);
 #endif
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 6/6] cpufreq, highbank: add support for highbank cpufreq
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (4 preceding siblings ...)
  2012-10-30 21:04 ` [PATCH 5/6] power: export opp cpufreq functions Mark Langsdorf
@ 2012-10-30 21:04 ` Mark Langsdorf
  2012-10-31  0:21 ` [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-10-30 21:04 UTC (permalink / raw)
  To: linux-kernel; +Cc: Mark Langsdorf, cpufreq, Rafael J. Wysocki

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
highbank and ECME cores happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: cpufreq@vger.kernel.org
Cc: Rafael J. Wysocki <rjw@sisk.pl>

---
 .../bindings/cpufreq/highbank-cpufreq.txt          |  53 +++++
 arch/arm/Kconfig                                   |   2 +
 arch/arm/boot/dts/highbank.dts                     |  10 +
 drivers/cpufreq/Kconfig.arm                        |  15 ++
 drivers/cpufreq/Makefile                           |   1 +
 drivers/cpufreq/highbank-cpufreq.c                 | 229 +++++++++++++++++++++
 6 files changed, 310 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
new file mode 100644
index 0000000..3ec2cec
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
@@ -0,0 +1,53 @@
+Highbank cpufreq driver
+
+This is cpufreq driver for Calxeda ECX-1000 (highbank) processor. It is based
+on the generic cpu0 driver and uses a similar format for bindings. Since
+the EnergyCore Management Engine maintains the voltage based on the
+frequency, the voltage component of the operating points can be set to any
+arbitrary values.
+
+Both required properties listed below must be defined under node /cpus/cpu@0.
+
+Required properties:
+- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+  for details
+- clock-latency: Specify the possible maximum transition latency for clock,
+  in unit of nanoseconds.
+
+Examples:
+
+cpus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cpu@0 {
+		compatible = "arm,cortex-a9";
+		reg = <0>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz  ignored */
+			790000  1000000
+			396000  1000000
+			198000  1000000
+		>;
+		transition-latency = <200000>;
+	};
+
+	cpu@1 {
+		compatible = "arm,cortex-a9";
+		reg = <1>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@2 {
+		compatible = "arm,cortex-a9";
+		reg = <2>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@3 {
+		compatible = "arm,cortex-a9";
+		reg = <3>;
+		next-level-cache = <&L2>;
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ade7e92..4ed0b7b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -391,6 +391,8 @@ config ARCH_SIRF
 	select PINCTRL
 	select PINCTRL_SIRF
 	select USE_OF
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	help
 	  Support for CSR SiRFprimaII/Marco/Polo platforms
 
diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 0c6fc34..7c4c27d 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -36,6 +36,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			clock-latency = <100000>;
 		};
 
 		cpu@1 {
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 5961e64..bc3ef55 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -76,3 +76,18 @@ config ARM_EXYNOS5250_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
+
+config ARM_HIGHBANK_CPUFREQ
+       tristate "Calxeda Highbank-based"
+       depends on ARCH_HIGHBANK
+       select CPU_FREQ_TABLE
+       select HAVE_CLK
+       select PM_OPP
+       select OF
+       default m
+       help
+         This adds the CPUFreq driver for Calxeda Highbank SoC
+         based boards.
+
+         If in doubt, say N.
+
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 1bc90e1..9e8f12a 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..005213b
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * derived from cpufreq-cpu0 by Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <asm/pl320-ipc.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE 0x80000001
+
+static unsigned int transition_latency;
+
+static struct device *cpu_dev;
+static struct clk *cpu_clk;
+static struct cpufreq_frequency_table *freq_table;
+
+static int hb_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int hb_get_speed(unsigned int cpu)
+{
+	return clk_get_rate(cpu_clk) / 1000;
+}
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[7];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000;
+	for (i = 2; i < 7; i++)
+		msg[i] = 0;
+
+	return ipc_call_slow(msg);
+}
+
+static int hb_set_target(struct cpufreq_policy *policy,
+			   unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned long freq_Hz;
+	unsigned int index, cpu;
+	int ret;
+
+	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+					     relation, &index);
+	if (ret) {
+		pr_err("failed to match target freqency %d: %d\n",
+		       target_freq, ret);
+		return ret;
+	}
+
+	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
+	if (freq_Hz < 0)
+		freq_Hz = freq_table[index].frequency * 1000;
+	freqs.new = freq_Hz / 1000;
+	freqs.old = clk_get_rate(cpu_clk) / 1000;
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	pr_debug("%u MHz --> %u MHz\n", freqs.old / 1000, freqs.new / 1000);
+
+	/* scaling up?  scale voltage before frequency */
+	if (freqs.new > freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+	if (ret) {
+		pr_err("failed to set clock rate: %d\n", ret);
+		hb_voltage_change(freqs.old);
+		return ret;
+	}
+
+	/* scaling down?  scale voltage after frequency */
+	if (freqs.new < freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			if (clk_set_rate(cpu_clk, freqs.old * 1000))
+				pr_err("also failed to reset freq\n");
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	return 0;
+}
+
+static int hb_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	if (ret) {
+		pr_err("invalid frequency table: %d\n", ret);
+		return ret;
+	}
+
+	policy->cpuinfo.transition_latency = transition_latency;
+	policy->cur = clk_get_rate(cpu_clk) / 1000;
+
+	policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+	cpumask_setall(policy->cpus);
+
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int hb_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	return 0;
+}
+
+static struct freq_attr *hb_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver hb_cpufreq_driver = {
+	.flags = CPUFREQ_STICKY,
+	.verify = hb_verify_speed,
+	.target = hb_set_target,
+	.get = hb_get_speed,
+	.init = hb_cpufreq_init,
+	.exit = hb_cpufreq_exit,
+	.name = "highbank-cpufreq",
+	.attr = hb_cpufreq_attr,
+};
+
+static int __devinit hb_cpufreq_driver_init(void)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = of_init_opp_table(cpu_dev);
+	if (ret) {
+		pr_err("failed to init OPP table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
+	if (ret) {
+		pr_err("failed to init cpufreq table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	if (of_property_read_u32(np, "clock-latency", &transition_latency))
+		transition_latency = CPUFREQ_ETERNAL;
+
+	ret = cpufreq_register_driver(&hb_cpufreq_driver);
+	if (ret) {
+		pr_err("failed register driver: %d\n", ret);
+		goto out_free_table;
+	}
+
+	of_node_put(np);
+	return 0;
+
+out_free_table:
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (5 preceding siblings ...)
  2012-10-30 21:04 ` [PATCH 6/6] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2012-10-31  0:21 ` Rafael J. Wysocki
  2012-11-02 18:51 ` [PATCH 0/6 v2] " Mark Langsdorf
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 142+ messages in thread
From: Rafael J. Wysocki @ 2012-10-31  0:21 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, Linux PM list

On Tuesday, October 30, 2012 04:04:10 PM Mark Langsdorf wrote:
> This patch series adds cpufreq support for the Calxeda ECX-1000 (highbank)
> SoCs. The driver is based on the cpufreq-cpu0 driver. Because of the 
> unique way that highbank uses the EnergyCore Management Engine to manage
> voltages, it was not possible to use the cpufreq-cpu0 driver.

I've got patches [3-6/6] only for some reason.  Care to resend the other three
with direct CCs to me?

Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 5/6] power: export opp cpufreq functions
  2012-10-30 21:04 ` [PATCH 5/6] power: export opp cpufreq functions Mark Langsdorf
@ 2012-10-31  1:17   ` Nishanth Menon
  0 siblings, 0 replies; 142+ messages in thread
From: Nishanth Menon @ 2012-10-31  1:17 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, linux-pm

On 16:04-20121030, Mark Langsdorf wrote:
$subject
PM / OPP:
Also adding info that this allows cpufreq drivers to be used as module
might be helpful.
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> Cc: linux-pm@vger.kernel.org
Side note:
Applies on v3.7-rc3
on rafael's linux-next branch:
linux-next      2b7f449 Merge branch 'pm-opp-next' into linux-next
on git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
needs a rebase as it probably conflicts with
https://patchwork.kernel.org/patch/1582091/

Otherwise, approach:
Acked-by: Nishanth Menon <nm@ti.com>

-- 
Regards,
Nishanth Menon

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 0/6 v2] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (6 preceding siblings ...)
  2012-10-31  0:21 ` [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
@ 2012-11-02 18:51 ` Mark Langsdorf
  2012-11-02 18:51   ` [PATCH 1/6 v2] arm: use devicetree to get smp_twd clock Mark Langsdorf
                     ` (6 more replies)
  2012-11-06 20:18 ` [PATCH 0/6 v3] " Mark Langsdorf
                   ` (9 subsequent siblings)
  17 siblings, 7 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-02 18:51 UTC (permalink / raw)
  To: linux-kernel; +Cc: cpufreq

This patch series adds cpufreq support for the Calxeda ECX-1000 (highbank)
SoCs. The driver is based on the cpufreq-cpu0 driver. Because of the 
unique way that highbank uses the EnergyCore Management Engine to manage
voltages, it was not possible to use the cpufreq-cpu0 driver.

--Mark Langsdorf


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/6 v2] arm: use devicetree to get smp_twd clock
  2012-11-02 18:51 ` [PATCH 0/6 v2] " Mark Langsdorf
@ 2012-11-02 18:51   ` Mark Langsdorf
  2012-11-04 10:08     ` Russell King - ARM Linux
  2012-11-02 18:51   ` [PATCH 2/6 v2] clk, highbank: remove non-bypass reset mode Mark Langsdorf
                     ` (5 subsequent siblings)
  6 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-02 18:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: cpufreq, Mark Langsdorf, Rob Herring, Russell King, linux-arm-kernel

From: Rob Herring <rob.herring@calxeda.com>

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: linux-arm-kernel@lists.infradead.org

Changes from v1
	None.
---
 arch/arm/kernel/smp_twd.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index b22d700..600fbcc 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -237,12 +237,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static struct clk *twd_get_clock(struct device_node *np)
 {
-	struct clk *clk;
+	struct clk *clk = NULL;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
+	if (np)
+		clk = of_clk_get(np, 0);
+	if (!clk)
+		clk = clk_get_sys("smp_twd", NULL);
 	if (IS_ERR(clk)) {
 		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
 		return clk;
@@ -263,6 +266,7 @@ static struct clk *twd_get_clock(void)
 		return ERR_PTR(err);
 	}
 
+	twd_timer_rate = clk_get_rate(clk);
 	return clk;
 }
 
@@ -273,12 +277,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
 	struct clock_event_device **this_cpu_clk;
 
-	if (!twd_clk)
-		twd_clk = twd_get_clock();
-
-	if (!IS_ERR_OR_NULL(twd_clk))
-		twd_timer_rate = clk_get_rate(twd_clk);
-	else
+	if (IS_ERR_OR_NULL(twd_clk))
 		twd_calibrate_rate();
 
 	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
@@ -349,6 +348,10 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
+	twd_clk = twd_get_clock(NULL);
+
+	twd_clk = twd_get_clock(NULL);
+
 	return twd_local_timer_common_register();
 }
 
@@ -383,6 +386,8 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
+	twd_clk = twd_get_clock(np);
+
 	err = twd_local_timer_common_register();
 
 out:
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/6 v2] clk, highbank: remove non-bypass reset mode
  2012-11-02 18:51 ` [PATCH 0/6 v2] " Mark Langsdorf
  2012-11-02 18:51   ` [PATCH 1/6 v2] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2012-11-02 18:51   ` Mark Langsdorf
  2012-11-02 18:51   ` [PATCH 3/6 v2] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-02 18:51 UTC (permalink / raw)
  To: linux-kernel; +Cc: cpufreq, Mark Langsdorf, Rob Herring, mturquette

The highbank clock will glitch if the clock rate is reset without
relocking the PLL. Remove the option to attempt reseting without
relocking.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: mturquette@linaro.org

Changes from v2:
	Removed erroneous reformating.

---
 drivers/clk/clk-highbank.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..3a0b723 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/6 v2] cpufreq: tolerate inexact values when collecting stats
  2012-11-02 18:51 ` [PATCH 0/6 v2] " Mark Langsdorf
  2012-11-02 18:51   ` [PATCH 1/6 v2] arm: use devicetree to get smp_twd clock Mark Langsdorf
  2012-11-02 18:51   ` [PATCH 2/6 v2] clk, highbank: remove non-bypass reset mode Mark Langsdorf
@ 2012-11-02 18:51   ` Mark Langsdorf
  2012-11-02 18:51   ` [PATCH 4/6 v2] arm highbank: add support for pl320 IPC Mark Langsdorf
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-02 18:51 UTC (permalink / raw)
  To: linux-kernel; +Cc: cpufreq, Mark Langsdorf, MyungJoo Ham

When collecting stats, if a frequency doesn't match the table, go through
the table again with both the search frequency and table values shifted
left by 10 bits.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: MyungJoo Ham <myungjoo.ham@gmail.com>

Changes from v1:
	Implemented a simple round-up algorithm instead of the over/under
method that could cause errors on Intel processors with boost mode.
---
 drivers/cpufreq/cpufreq_stats.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 3998316..ab583e7 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -158,8 +158,12 @@ static struct attribute_group stats_attr_group = {
 static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
 {
 	int index;
+	for (index = 0; index < stat->max_state; index++) 
+		 if (stat->freq_table[index] == freq)
+			return index;
+	/* no exact match, round up */
 	for (index = 0; index < stat->max_state; index++)
-		if (stat->freq_table[index] == freq)
+		if ((stat->freq_table[index] >> 10) == (freq >> 10))
 			return index;
 	return -1;
 }
@@ -251,6 +255,8 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
 	spin_lock(&cpufreq_stats_lock);
 	stat->last_time = get_jiffies_64();
 	stat->last_index = freq_table_get_index(stat, policy->cur);
+	if (stat->last_index > stat->max_state)
+		stat->last_index = stat->max_state - 1;
 	spin_unlock(&cpufreq_stats_lock);
 	cpufreq_cpu_put(data);
 	return 0;
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 4/6 v2] arm highbank: add support for pl320 IPC
  2012-11-02 18:51 ` [PATCH 0/6 v2] " Mark Langsdorf
                     ` (2 preceding siblings ...)
  2012-11-02 18:51   ` [PATCH 3/6 v2] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
@ 2012-11-02 18:51   ` Mark Langsdorf
  2012-11-02 18:51   ` [PATCH 5/6 v2] power: export opp cpufreq functions Mark Langsdorf
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-02 18:51 UTC (permalink / raw)
  To: linux-kernel; +Cc: cpufreq, Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the highbank A9
and the EnergyCore Management Engine. The pl320 implements a straightforward
mailbox protocol.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>

Changes from v1:
	Removed erroneous changes for cpufreq Kconfig
---
 arch/arm/mach-highbank/Makefile                 |   2 +
 arch/arm/mach-highbank/include/mach/pl320-ipc.h |  20 ++
 arch/arm/mach-highbank/pl320-ipc.c              | 232 ++++++++++++++++++++++++
 3 files changed, 254 insertions(+)
 create mode 100644 arch/arm/mach-highbank/include/mach/pl320-ipc.h
 create mode 100644 arch/arm/mach-highbank/pl320-ipc.c

diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile
index 3ec8bdd..b894708 100644
--- a/arch/arm/mach-highbank/Makefile
+++ b/arch/arm/mach-highbank/Makefile
@@ -7,3 +7,5 @@ obj-$(CONFIG_DEBUG_HIGHBANK_UART)	+= lluart.o
 obj-$(CONFIG_SMP)			+= platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
 obj-$(CONFIG_PM_SLEEP)			+= pm.o
+
+obj-y					+= pl320-ipc.o
diff --git a/arch/arm/mach-highbank/include/mach/pl320-ipc.h b/arch/arm/mach-highbank/include/mach/pl320-ipc.h
new file mode 100644
index 0000000..a0e58ee
--- /dev/null
+++ b/arch/arm/mach-highbank/include/mach/pl320-ipc.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+int ipc_call_fast(u32 *data);
+int ipc_call_slow(u32 *data);
+
+extern int pl320_ipc_register_notifier(struct notifier_block *nb);
+extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);
diff --git a/arch/arm/mach-highbank/pl320-ipc.c b/arch/arm/mach-highbank/pl320-ipc.c
new file mode 100644
index 0000000..0eb92e4
--- /dev/null
+++ b/arch/arm/mach-highbank/pl320-ipc.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <asm/pl320-ipc.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_FAST_MBOX		0
+#define IPC_SLOW_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_SPINLOCK(ipc_m0_lock);
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* non-blocking implementation from the A9 side, interrupt safe in theory */
+int ipc_call_fast(u32 *data)
+{
+	int timeout, ret;
+
+	spin_lock(&ipc_m0_lock);
+
+	__ipc_send(IPC_FAST_MBOX, data);
+
+	for (timeout = 500; timeout > 0; timeout--) {
+		if (__raw_readl(ipc_base + IPCMxSEND(IPC_FAST_MBOX)) == 0x2)
+			break;
+		udelay(100);
+	}
+	if (timeout == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_FAST_MBOX, data);
+out:
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_FAST_MBOX));
+	spin_unlock(&ipc_m0_lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipc_call_fast);
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int ipc_call_slow(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_SLOW_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_SLOW_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipc_call_slow);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_SLOW_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_SLOW_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+
+static int __devinit pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_FAST_MBOX));
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_SLOW_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init fast mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_FAST_MBOX));
+	set_destination(M3_SOURCE, IPC_FAST_MBOX);
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_SLOW_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_SLOW_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_SLOW_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 5/6 v2] power: export opp cpufreq functions
  2012-11-02 18:51 ` [PATCH 0/6 v2] " Mark Langsdorf
                     ` (3 preceding siblings ...)
  2012-11-02 18:51   ` [PATCH 4/6 v2] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2012-11-02 18:51   ` Mark Langsdorf
  2012-11-02 18:51   ` [PATCH 6/6 v2] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  2012-11-02 21:45   ` [PATCH 0/6 v2] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-02 18:51 UTC (permalink / raw)
  To: linux-kernel; +Cc: cpufreq, Mark Langsdorf, linux-pm

These functions are needed to make the cpufreq-core0 and highbank-cpufreq
drivers loadable as modules.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Acked-by: Nishanth Menon <nm@ti.com>
Cc: linux-pm@vger.kernel.org

Changes from v1:
	Added Nishanth Menon's ack.
	Clarified the purpose of the change in the commit message.
---
 drivers/base/power/opp.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index d946864..37dc5f4 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -23,6 +23,7 @@
 #include <linux/rcupdate.h>
 #include <linux/opp.h>
 #include <linux/of.h>
+#include <linux/module.h>
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -643,6 +644,7 @@ int opp_init_cpufreq_table(struct device *dev,
 
 	return 0;
 }
+EXPORT_SYMBOL(opp_init_cpufreq_table);
 
 /**
  * opp_free_cpufreq_table() - free the cpufreq table
@@ -660,6 +662,7 @@ void opp_free_cpufreq_table(struct device *dev,
 	kfree(*table);
 	*table = NULL;
 }
+EXPORT_SYMBOL(opp_free_cpufreq_table);
 #endif		/* CONFIG_CPU_FREQ */
 
 /**
@@ -720,4 +723,5 @@ int of_init_opp_table(struct device *dev)
 
 	return 0;
 }
+EXPORT_SYMBOL(of_init_opp_table);
 #endif
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 6/6 v2] cpufreq, highbank: add support for highbank cpufreq
  2012-11-02 18:51 ` [PATCH 0/6 v2] " Mark Langsdorf
                     ` (4 preceding siblings ...)
  2012-11-02 18:51   ` [PATCH 5/6 v2] power: export opp cpufreq functions Mark Langsdorf
@ 2012-11-02 18:51   ` Mark Langsdorf
  2012-11-02 21:45   ` [PATCH 0/6 v2] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-02 18:51 UTC (permalink / raw)
  To: linux-kernel
  Cc: cpufreq, Mark Langsdorf, devicetree-discuss, Rafael J. Wysocki

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
highbank and ECME cores happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: Rafael J. Wysocki <rjw@sisk.pl>

Changes from v1:
	Added highbank specific Kconfig changes
---
 .../bindings/cpufreq/highbank-cpufreq.txt          |  53 +++++
 arch/arm/Kconfig                                   |   2 +
 arch/arm/boot/dts/highbank.dts                     |  10 +
 arch/arm/mach-highbank/Kconfig                     |   2 +
 drivers/cpufreq/Kconfig.arm                        |  15 ++
 drivers/cpufreq/Makefile                           |   1 +
 drivers/cpufreq/highbank-cpufreq.c                 | 229 +++++++++++++++++++++
 7 files changed, 312 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
new file mode 100644
index 0000000..3ec2cec
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
@@ -0,0 +1,53 @@
+Highbank cpufreq driver
+
+This is cpufreq driver for Calxeda ECX-1000 (highbank) processor. It is based
+on the generic cpu0 driver and uses a similar format for bindings. Since
+the EnergyCore Management Engine maintains the voltage based on the
+frequency, the voltage component of the operating points can be set to any
+arbitrary values.
+
+Both required properties listed below must be defined under node /cpus/cpu@0.
+
+Required properties:
+- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+  for details
+- clock-latency: Specify the possible maximum transition latency for clock,
+  in unit of nanoseconds.
+
+Examples:
+
+cpus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cpu@0 {
+		compatible = "arm,cortex-a9";
+		reg = <0>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz  ignored */
+			790000  1000000
+			396000  1000000
+			198000  1000000
+		>;
+		transition-latency = <200000>;
+	};
+
+	cpu@1 {
+		compatible = "arm,cortex-a9";
+		reg = <1>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@2 {
+		compatible = "arm,cortex-a9";
+		reg = <2>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@3 {
+		compatible = "arm,cortex-a9";
+		reg = <3>;
+		next-level-cache = <&L2>;
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ade7e92..4ed0b7b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -391,6 +391,8 @@ config ARCH_SIRF
 	select PINCTRL
 	select PINCTRL_SIRF
 	select USE_OF
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	help
 	  Support for CSR SiRFprimaII/Marco/Polo platforms
 
diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 0c6fc34..7c4c27d 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -36,6 +36,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			clock-latency = <100000>;
 		};
 
 		cpu@1 {
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 0e1d0a4..ee83af6 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -13,3 +13,5 @@ config ARCH_HIGHBANK
 	select HAVE_SMP
 	select SPARSE_IRQ
 	select USE_OF
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 5961e64..bc3ef55 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -76,3 +76,18 @@ config ARM_EXYNOS5250_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
+
+config ARM_HIGHBANK_CPUFREQ
+       tristate "Calxeda Highbank-based"
+       depends on ARCH_HIGHBANK
+       select CPU_FREQ_TABLE
+       select HAVE_CLK
+       select PM_OPP
+       select OF
+       default m
+       help
+         This adds the CPUFreq driver for Calxeda Highbank SoC
+         based boards.
+
+         If in doubt, say N.
+
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 1bc90e1..9e8f12a 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..005213b
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * derived from cpufreq-cpu0 by Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <asm/pl320-ipc.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE 0x80000001
+
+static unsigned int transition_latency;
+
+static struct device *cpu_dev;
+static struct clk *cpu_clk;
+static struct cpufreq_frequency_table *freq_table;
+
+static int hb_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int hb_get_speed(unsigned int cpu)
+{
+	return clk_get_rate(cpu_clk) / 1000;
+}
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[7];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000;
+	for (i = 2; i < 7; i++)
+		msg[i] = 0;
+
+	return ipc_call_slow(msg);
+}
+
+static int hb_set_target(struct cpufreq_policy *policy,
+			   unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned long freq_Hz;
+	unsigned int index, cpu;
+	int ret;
+
+	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+					     relation, &index);
+	if (ret) {
+		pr_err("failed to match target freqency %d: %d\n",
+		       target_freq, ret);
+		return ret;
+	}
+
+	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
+	if (freq_Hz < 0)
+		freq_Hz = freq_table[index].frequency * 1000;
+	freqs.new = freq_Hz / 1000;
+	freqs.old = clk_get_rate(cpu_clk) / 1000;
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	pr_debug("%u MHz --> %u MHz\n", freqs.old / 1000, freqs.new / 1000);
+
+	/* scaling up?  scale voltage before frequency */
+	if (freqs.new > freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+	if (ret) {
+		pr_err("failed to set clock rate: %d\n", ret);
+		hb_voltage_change(freqs.old);
+		return ret;
+	}
+
+	/* scaling down?  scale voltage after frequency */
+	if (freqs.new < freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			if (clk_set_rate(cpu_clk, freqs.old * 1000))
+				pr_err("also failed to reset freq\n");
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	return 0;
+}
+
+static int hb_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	if (ret) {
+		pr_err("invalid frequency table: %d\n", ret);
+		return ret;
+	}
+
+	policy->cpuinfo.transition_latency = transition_latency;
+	policy->cur = clk_get_rate(cpu_clk) / 1000;
+
+	policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+	cpumask_setall(policy->cpus);
+
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int hb_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	return 0;
+}
+
+static struct freq_attr *hb_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver hb_cpufreq_driver = {
+	.flags = CPUFREQ_STICKY,
+	.verify = hb_verify_speed,
+	.target = hb_set_target,
+	.get = hb_get_speed,
+	.init = hb_cpufreq_init,
+	.exit = hb_cpufreq_exit,
+	.name = "highbank-cpufreq",
+	.attr = hb_cpufreq_attr,
+};
+
+static int __devinit hb_cpufreq_driver_init(void)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = of_init_opp_table(cpu_dev);
+	if (ret) {
+		pr_err("failed to init OPP table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
+	if (ret) {
+		pr_err("failed to init cpufreq table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	if (of_property_read_u32(np, "clock-latency", &transition_latency))
+		transition_latency = CPUFREQ_ETERNAL;
+
+	ret = cpufreq_register_driver(&hb_cpufreq_driver);
+	if (ret) {
+		pr_err("failed register driver: %d\n", ret);
+		goto out_free_table;
+	}
+
+	of_node_put(np);
+	return 0;
+
+out_free_table:
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 0/6 v2] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-11-02 18:51 ` [PATCH 0/6 v2] " Mark Langsdorf
                     ` (5 preceding siblings ...)
  2012-11-02 18:51   ` [PATCH 6/6 v2] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2012-11-02 21:45   ` Rafael J. Wysocki
  6 siblings, 0 replies; 142+ messages in thread
From: Rafael J. Wysocki @ 2012-11-02 21:45 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq

Hi,

On Friday, November 02, 2012 01:51:43 PM Mark Langsdorf wrote:
> This patch series adds cpufreq support for the Calxeda ECX-1000 (highbank)
> SoCs. The driver is based on the cpufreq-cpu0 driver. Because of the 
> unique way that highbank uses the EnergyCore Management Engine to manage
> voltages, it was not possible to use the cpufreq-cpu0 driver.

Can you please resend the whole series with CCs to linux-pm@vger.kernel.org,
so that the patches are accessible to me through Patchwork?

Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/6 v2] arm: use devicetree to get smp_twd clock
  2012-11-02 18:51   ` [PATCH 1/6 v2] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2012-11-04 10:08     ` Russell King - ARM Linux
  2012-11-05 22:28       ` Mark Langsdorf
  0 siblings, 1 reply; 142+ messages in thread
From: Russell King - ARM Linux @ 2012-11-04 10:08 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq, Rob Herring, linux-arm-kernel

On Fri, Nov 02, 2012 at 01:51:44PM -0500, Mark Langsdorf wrote:
> -static struct clk *twd_get_clock(void)
> +static struct clk *twd_get_clock(struct device_node *np)
>  {
> -	struct clk *clk;
> +	struct clk *clk = NULL;
>  	int err;
>  
> -	clk = clk_get_sys("smp_twd", NULL);
> +	if (np)
> +		clk = of_clk_get(np, 0);
> +	if (!clk)

What does a NULL return from of_clk_get() mean?  Where is this defined?

> @@ -349,6 +348,10 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
>  	if (!twd_base)
>  		return -ENOMEM;
>  
> +	twd_clk = twd_get_clock(NULL);
> +
> +	twd_clk = twd_get_clock(NULL);
> +

Why twice?

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/6 v2] arm: use devicetree to get smp_twd clock
  2012-11-04 10:08     ` Russell King - ARM Linux
@ 2012-11-05 22:28       ` Mark Langsdorf
  2012-11-05 22:31         ` Russell King - ARM Linux
  0 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-05 22:28 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-kernel, cpufreq, Rob Herring, linux-arm-kernel

On 11/04/2012 04:08 AM, Russell King - ARM Linux wrote:
> On Fri, Nov 02, 2012 at 01:51:44PM -0500, Mark Langsdorf wrote:
>> -static struct clk *twd_get_clock(void)
>> +static struct clk *twd_get_clock(struct device_node *np)
>>  {
>> -	struct clk *clk;
>> +	struct clk *clk = NULL;
>>  	int err;
>>  
>> -	clk = clk_get_sys("smp_twd", NULL);
>> +	if (np)
>> +		clk = of_clk_get(np, 0);
>> +	if (!clk)
> 
> What does a NULL return from of_clk_get() mean?  Where is this defined?

Well, it's a valid path if (np) is NULL. I'll add an IS_ERR(clk) and
resubmit.

>> @@ -349,6 +348,10 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
>>  	if (!twd_base)
>>  		return -ENOMEM;
>>  
>> +	twd_clk = twd_get_clock(NULL);
>> +
>> +	twd_clk = twd_get_clock(NULL);
>> +
> 
> Why twice?

No good reason. I'll resubmit with it cleaned up. Thanks for the review.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/6 v2] arm: use devicetree to get smp_twd clock
  2012-11-05 22:28       ` Mark Langsdorf
@ 2012-11-05 22:31         ` Russell King - ARM Linux
  2012-11-05 22:49           ` Mark Langsdorf
  0 siblings, 1 reply; 142+ messages in thread
From: Russell King - ARM Linux @ 2012-11-05 22:31 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq, Rob Herring, linux-arm-kernel

On Mon, Nov 05, 2012 at 04:28:05PM -0600, Mark Langsdorf wrote:
> On 11/04/2012 04:08 AM, Russell King - ARM Linux wrote:
> > On Fri, Nov 02, 2012 at 01:51:44PM -0500, Mark Langsdorf wrote:
> >> -static struct clk *twd_get_clock(void)
> >> +static struct clk *twd_get_clock(struct device_node *np)
> >>  {
> >> -	struct clk *clk;
> >> +	struct clk *clk = NULL;
> >>  	int err;
> >>  
> >> -	clk = clk_get_sys("smp_twd", NULL);
> >> +	if (np)
> >> +		clk = of_clk_get(np, 0);
> >> +	if (!clk)
> > 
> > What does a NULL return from of_clk_get() mean?  Where is this defined?
> 
> Well, it's a valid path if (np) is NULL. I'll add an IS_ERR(clk) and
> resubmit.

Hang on - what logic are you trying to achieve here?  Wouldn't:

	if (np)
		clk = of_clk_get(np, 0);
	else
		clk = clk_get_sys("smp_twd", NULL);

be sufficient?  If we have DT, why would we ever want to fall back to
"smp_twd" ?

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/6 v2] arm: use devicetree to get smp_twd clock
  2012-11-05 22:31         ` Russell King - ARM Linux
@ 2012-11-05 22:49           ` Mark Langsdorf
  0 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-05 22:49 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-kernel, cpufreq, Rob Herring, linux-arm-kernel

On 11/05/2012 04:31 PM, Russell King - ARM Linux wrote:
> On Mon, Nov 05, 2012 at 04:28:05PM -0600, Mark Langsdorf wrote:
>> On 11/04/2012 04:08 AM, Russell King - ARM Linux wrote:
>>> On Fri, Nov 02, 2012 at 01:51:44PM -0500, Mark Langsdorf wrote:
>>>> -static struct clk *twd_get_clock(void)
>>>> +static struct clk *twd_get_clock(struct device_node *np)
>>>>  {
>>>> -	struct clk *clk;
>>>> +	struct clk *clk = NULL;
>>>>  	int err;
>>>>  
>>>> -	clk = clk_get_sys("smp_twd", NULL);
>>>> +	if (np)
>>>> +		clk = of_clk_get(np, 0);
>>>> +	if (!clk)
>>>
>>> What does a NULL return from of_clk_get() mean?  Where is this defined?
>>
>> Well, it's a valid path if (np) is NULL. I'll add an IS_ERR(clk) and
>> resubmit.
> 
> Hang on - what logic are you trying to achieve here?  Wouldn't:
> 
> 	if (np)
> 		clk = of_clk_get(np, 0);
> 	else
> 		clk = clk_get_sys("smp_twd", NULL);
> 
> be sufficient?  If we have DT, why would we ever want to fall back to
> "smp_twd" ?

I'm just trying to make sure I have a clock so I can do cpufreq operations.

Your solution works and is sufficient. Thanks.

--Mark Langsdorf
Calxeda, Inc.



^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 0/6 v3] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (7 preceding siblings ...)
  2012-11-02 18:51 ` [PATCH 0/6 v2] " Mark Langsdorf
@ 2012-11-06 20:18 ` Mark Langsdorf
  2012-11-06 20:18   ` [PATCH 1/6 v3] arm: use devicetree to get smp_twd clock Mark Langsdorf
                     ` (6 more replies)
  2012-11-07 18:32 ` [PATCH 0/6 v4] " Mark Langsdorf
                   ` (8 subsequent siblings)
  17 siblings, 7 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-06 20:18 UTC (permalink / raw)
  To: linux-kernel, linux-pm, cpufreq, mark.langsdorf

This patch series adds cpufreq support for the Calxeda
ECX-1000 (highbank) SoCs. The driver is based on the 
cpufreq-cpu0 driver. Because of the unique way that 
highbank uses the EnergyCore Management Engine to manage
voltages, it was not possible to use the cpufreq-cpu0 driver.

--Mark Langsdorf



^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/6 v3] arm: use devicetree to get smp_twd clock
  2012-11-06 20:18 ` [PATCH 0/6 v3] " Mark Langsdorf
@ 2012-11-06 20:18   ` Mark Langsdorf
  2012-11-06 20:18   ` [PATCH 2/6 v3] clk, highbank: remove non-bypass reset mode Mark Langsdorf
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-06 20:18 UTC (permalink / raw)
  To: linux-kernel, linux-pm, cpufreq, mark.langsdorf; +Cc: Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>

---
Changes from v2
	Turned the check for the node pointer into an if-then-else statement.
	Removed the second, redundant clk_get_rate
Changes from v1
        None.

 arch/arm/kernel/smp_twd.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index b22d700..b1fb6e1 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -237,12 +237,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static struct clk *twd_get_clock(struct device_node *np)
 {
-	struct clk *clk;
+	struct clk *clk = NULL;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
+	if (np)
+		clk = of_clk_get(np, 0);
+	else
+		clk = clk_get_sys("smp_twd", NULL);
 	if (IS_ERR(clk)) {
 		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
 		return clk;
@@ -263,6 +266,7 @@ static struct clk *twd_get_clock(void)
 		return ERR_PTR(err);
 	}
 
+	twd_timer_rate = clk_get_rate(clk);
 	return clk;
 }
 
@@ -273,12 +277,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
 	struct clock_event_device **this_cpu_clk;
 
-	if (!twd_clk)
-		twd_clk = twd_get_clock();
-
-	if (!IS_ERR_OR_NULL(twd_clk))
-		twd_timer_rate = clk_get_rate(twd_clk);
-	else
+	if (IS_ERR_OR_NULL(twd_clk))
 		twd_calibrate_rate();
 
 	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
@@ -349,6 +348,8 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
+	twd_clk = twd_get_clock(NULL);
+
 	return twd_local_timer_common_register();
 }
 
@@ -383,6 +384,8 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
+	twd_clk = twd_get_clock(np);
+
 	err = twd_local_timer_common_register();
 
 out:
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/6 v3] clk, highbank: remove non-bypass reset mode
  2012-11-06 20:18 ` [PATCH 0/6 v3] " Mark Langsdorf
  2012-11-06 20:18   ` [PATCH 1/6 v3] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2012-11-06 20:18   ` Mark Langsdorf
  2012-11-06 20:18   ` [PATCH 3/6 v3] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-06 20:18 UTC (permalink / raw)
  To: linux-kernel, linux-pm, cpufreq, mark.langsdorf

The highbank clock will glitch if the clock rate is reset without
relocking the PLL. Remove the option to attempt reseting without
relocking.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v2:
	None
Changes from v1:
        Removed erroneous reformating.

 drivers/clk/clk-highbank.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..4f50c42 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -171,7 +171,8 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 
 		writel(reg | HB_PLL_RESET, hbclk->reg);
 		reg &= ~(HB_PLL_DIVF_MASK | HB_PLL_DIVQ_MASK);
-		reg |= (divf << HB_PLL_DIVF_SHIFT) | (divq << HB_PLL_DIVQ_SHIFT);
+		reg |= (divf << HB_PLL_DIVF_SHIFT) |
+			(divq << HB_PLL_DIVQ_SHIFT);
 		writel(reg | HB_PLL_RESET, hbclk->reg);
 		writel(reg, hbclk->reg);
 
@@ -182,8 +183,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/6 v3] cpufreq: tolerate inexact values when collecting stats
  2012-11-06 20:18 ` [PATCH 0/6 v3] " Mark Langsdorf
  2012-11-06 20:18   ` [PATCH 1/6 v3] arm: use devicetree to get smp_twd clock Mark Langsdorf
  2012-11-06 20:18   ` [PATCH 2/6 v3] clk, highbank: remove non-bypass reset mode Mark Langsdorf
@ 2012-11-06 20:18   ` Mark Langsdorf
  2012-11-06 20:18   ` [PATCH 4/6 v3] arm highbank: add support for pl320 IPC Mark Langsdorf
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-06 20:18 UTC (permalink / raw)
  To: linux-kernel, linux-pm, cpufreq, mark.langsdorf

Allow frequency values to vary by +/-5000 Hz when collecting stats.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v2:
	None
Changes from v1:
        Implemented a simple round-up algorithm instead of the over/under
method that could cause errors on Intel processors with boost mode.

 drivers/cpufreq/cpufreq_stats.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 3998316..4e2ea7e 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -158,9 +158,11 @@ static struct attribute_group stats_attr_group = {
 static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
 {
 	int index;
-	for (index = 0; index < stat->max_state; index++)
-		if (stat->freq_table[index] == freq)
+	for (index = 0; index < stat->max_state; index++) {
+		if ((stat->freq_table[index] < (freq + 5000)) &&
+		    (stat->freq_table[index] > (freq - 5000)))
 			return index;
+	}
 	return -1;
 }
 
@@ -251,6 +253,8 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
 	spin_lock(&cpufreq_stats_lock);
 	stat->last_time = get_jiffies_64();
 	stat->last_index = freq_table_get_index(stat, policy->cur);
+	if (stat->last_index > stat->max_state)
+		stat->last_index = stat->max_state - 1;
 	spin_unlock(&cpufreq_stats_lock);
 	cpufreq_cpu_put(data);
 	return 0;
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 4/6 v3] arm highbank: add support for pl320 IPC
  2012-11-06 20:18 ` [PATCH 0/6 v3] " Mark Langsdorf
                     ` (2 preceding siblings ...)
  2012-11-06 20:18   ` [PATCH 3/6 v3] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
@ 2012-11-06 20:18   ` Mark Langsdorf
  2012-11-06 20:18   ` [PATCH 5/6 v3] power: export opp cpufreq functions Mark Langsdorf
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-06 20:18 UTC (permalink / raw)
  To: linux-kernel, linux-pm, cpufreq, mark.langsdorf; +Cc: Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the highbank A9
and the EnergyCore Management Engine. The pl320 implements a straightforward
mailbox protocol.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
---
Changes from v2:
	None
Changes from v1:
        Removed erroneous changes for cpufreq Kconfig

 arch/arm/include/asm/pl320-ipc.h                |  20 ++
 arch/arm/mach-highbank/Kconfig                  |   2 +
 arch/arm/mach-highbank/Makefile                 |   2 +
 arch/arm/mach-highbank/include/mach/pl320-ipc.h |  20 ++
 arch/arm/mach-highbank/pl320-ipc.c              | 232 ++++++++++++++++++++++++
 5 files changed, 276 insertions(+)
 create mode 100644 arch/arm/include/asm/pl320-ipc.h
 create mode 100644 arch/arm/mach-highbank/include/mach/pl320-ipc.h
 create mode 100644 arch/arm/mach-highbank/pl320-ipc.c

diff --git a/arch/arm/include/asm/pl320-ipc.h b/arch/arm/include/asm/pl320-ipc.h
new file mode 100644
index 0000000..a0e58ee
--- /dev/null
+++ b/arch/arm/include/asm/pl320-ipc.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+int ipc_call_fast(u32 *data);
+int ipc_call_slow(u32 *data);
+
+extern int pl320_ipc_register_notifier(struct notifier_block *nb);
+extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 0e1d0a4..ee83af6 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -13,3 +13,5 @@ config ARCH_HIGHBANK
 	select HAVE_SMP
 	select SPARSE_IRQ
 	select USE_OF
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile
index 3ec8bdd..b894708 100644
--- a/arch/arm/mach-highbank/Makefile
+++ b/arch/arm/mach-highbank/Makefile
@@ -7,3 +7,5 @@ obj-$(CONFIG_DEBUG_HIGHBANK_UART)	+= lluart.o
 obj-$(CONFIG_SMP)			+= platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
 obj-$(CONFIG_PM_SLEEP)			+= pm.o
+
+obj-y					+= pl320-ipc.o
diff --git a/arch/arm/mach-highbank/include/mach/pl320-ipc.h b/arch/arm/mach-highbank/include/mach/pl320-ipc.h
new file mode 100644
index 0000000..a0e58ee
--- /dev/null
+++ b/arch/arm/mach-highbank/include/mach/pl320-ipc.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+int ipc_call_fast(u32 *data);
+int ipc_call_slow(u32 *data);
+
+extern int pl320_ipc_register_notifier(struct notifier_block *nb);
+extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);
diff --git a/arch/arm/mach-highbank/pl320-ipc.c b/arch/arm/mach-highbank/pl320-ipc.c
new file mode 100644
index 0000000..0eb92e4
--- /dev/null
+++ b/arch/arm/mach-highbank/pl320-ipc.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <asm/pl320-ipc.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_FAST_MBOX		0
+#define IPC_SLOW_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_SPINLOCK(ipc_m0_lock);
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* non-blocking implementation from the A9 side, interrupt safe in theory */
+int ipc_call_fast(u32 *data)
+{
+	int timeout, ret;
+
+	spin_lock(&ipc_m0_lock);
+
+	__ipc_send(IPC_FAST_MBOX, data);
+
+	for (timeout = 500; timeout > 0; timeout--) {
+		if (__raw_readl(ipc_base + IPCMxSEND(IPC_FAST_MBOX)) == 0x2)
+			break;
+		udelay(100);
+	}
+	if (timeout == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_FAST_MBOX, data);
+out:
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_FAST_MBOX));
+	spin_unlock(&ipc_m0_lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipc_call_fast);
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int ipc_call_slow(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_SLOW_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_SLOW_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipc_call_slow);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_SLOW_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_SLOW_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+
+static int __devinit pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_FAST_MBOX));
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_SLOW_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init fast mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_FAST_MBOX));
+	set_destination(M3_SOURCE, IPC_FAST_MBOX);
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_SLOW_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_SLOW_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_SLOW_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 5/6 v3] power: export opp cpufreq functions
  2012-11-06 20:18 ` [PATCH 0/6 v3] " Mark Langsdorf
                     ` (3 preceding siblings ...)
  2012-11-06 20:18   ` [PATCH 4/6 v3] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2012-11-06 20:18   ` Mark Langsdorf
  2012-11-06 20:18   ` [PATCH 6/6 v3] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  2012-11-07 18:11   ` [PATCH 0/6 v3] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-06 20:18 UTC (permalink / raw)
  To: linux-kernel, linux-pm, cpufreq, mark.langsdorf

These functions are needed to make the cpufreq-core0 and highbank-cpufreq
drivers loadable as modules.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Acked-by: Nishanth Menon <nm@ti.com>

---
Changes from v2:
	None.
Changes from v1:
        Added Nishanth Menon's ack.
        Clarified the purpose of the change in the commit message.

 drivers/base/power/opp.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index d946864..37dc5f4 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -23,6 +23,7 @@
 #include <linux/rcupdate.h>
 #include <linux/opp.h>
 #include <linux/of.h>
+#include <linux/module.h>
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -643,6 +644,7 @@ int opp_init_cpufreq_table(struct device *dev,
 
 	return 0;
 }
+EXPORT_SYMBOL(opp_init_cpufreq_table);
 
 /**
  * opp_free_cpufreq_table() - free the cpufreq table
@@ -660,6 +662,7 @@ void opp_free_cpufreq_table(struct device *dev,
 	kfree(*table);
 	*table = NULL;
 }
+EXPORT_SYMBOL(opp_free_cpufreq_table);
 #endif		/* CONFIG_CPU_FREQ */
 
 /**
@@ -720,4 +723,5 @@ int of_init_opp_table(struct device *dev)
 
 	return 0;
 }
+EXPORT_SYMBOL(of_init_opp_table);
 #endif
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 6/6 v3] cpufreq, highbank: add support for highbank cpufreq
  2012-11-06 20:18 ` [PATCH 0/6 v3] " Mark Langsdorf
                     ` (4 preceding siblings ...)
  2012-11-06 20:18   ` [PATCH 5/6 v3] power: export opp cpufreq functions Mark Langsdorf
@ 2012-11-06 20:18   ` Mark Langsdorf
  2012-11-07 18:11   ` [PATCH 0/6 v3] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-06 20:18 UTC (permalink / raw)
  To: linux-kernel, linux-pm, cpufreq, mark.langsdorf
  Cc: devicetree-discuss, Rafael J. Wysocki

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
highbank and ECME cores happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: Rafael J. Wysocki <rjw@sisk.pl>

---
Changes from v2:
	Changed transition latency binding in code to match documentation
Changes from v1:
        Added highbank specific Kconfig changes

 .../bindings/cpufreq/highbank-cpufreq.txt          |  53 +++++
 arch/arm/Kconfig                                   |   2 +
 arch/arm/boot/dts/highbank.dts                     |  10 +
 drivers/cpufreq/Kconfig.arm                        |  15 ++
 drivers/cpufreq/Makefile                           |   1 +
 drivers/cpufreq/highbank-cpufreq.c                 | 229 +++++++++++++++++++++
 6 files changed, 310 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
new file mode 100644
index 0000000..3ec2cec
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
@@ -0,0 +1,53 @@
+Highbank cpufreq driver
+
+This is cpufreq driver for Calxeda ECX-1000 (highbank) processor. It is based
+on the generic cpu0 driver and uses a similar format for bindings. Since
+the EnergyCore Management Engine maintains the voltage based on the
+frequency, the voltage component of the operating points can be set to any
+arbitrary values.
+
+Both required properties listed below must be defined under node /cpus/cpu@0.
+
+Required properties:
+- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+  for details
+- clock-latency: Specify the possible maximum transition latency for clock,
+  in unit of nanoseconds.
+
+Examples:
+
+cpus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cpu@0 {
+		compatible = "arm,cortex-a9";
+		reg = <0>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz  ignored */
+			790000  1000000
+			396000  1000000
+			198000  1000000
+		>;
+		transition-latency = <200000>;
+	};
+
+	cpu@1 {
+		compatible = "arm,cortex-a9";
+		reg = <1>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@2 {
+		compatible = "arm,cortex-a9";
+		reg = <2>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@3 {
+		compatible = "arm,cortex-a9";
+		reg = <3>;
+		next-level-cache = <&L2>;
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ade7e92..4ed0b7b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -391,6 +391,8 @@ config ARCH_SIRF
 	select PINCTRL
 	select PINCTRL_SIRF
 	select USE_OF
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	help
 	  Support for CSR SiRFprimaII/Marco/Polo platforms
 
diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 0c6fc34..7c4c27d 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -36,6 +36,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			clock-latency = <100000>;
 		};
 
 		cpu@1 {
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 5961e64..bc3ef55 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -76,3 +76,18 @@ config ARM_EXYNOS5250_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
+
+config ARM_HIGHBANK_CPUFREQ
+       tristate "Calxeda Highbank-based"
+       depends on ARCH_HIGHBANK
+       select CPU_FREQ_TABLE
+       select HAVE_CLK
+       select PM_OPP
+       select OF
+       default m
+       help
+         This adds the CPUFreq driver for Calxeda Highbank SoC
+         based boards.
+
+         If in doubt, say N.
+
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 1bc90e1..9e8f12a 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..a167073
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * derived from cpufreq-cpu0 by Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <asm/pl320-ipc.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE 0x80000001
+
+static unsigned int transition_latency;
+
+static struct device *cpu_dev;
+static struct clk *cpu_clk;
+static struct cpufreq_frequency_table *freq_table;
+
+static int hb_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int hb_get_speed(unsigned int cpu)
+{
+	return clk_get_rate(cpu_clk) / 1000;
+}
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[7];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000;
+	for (i = 2; i < 7; i++)
+		msg[i] = 0;
+
+	return ipc_call_slow(msg);
+}
+
+static int hb_set_target(struct cpufreq_policy *policy,
+			   unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned long freq_Hz;
+	unsigned int index, cpu;
+	int ret;
+
+	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+					     relation, &index);
+	if (ret) {
+		pr_err("failed to match target freqency %d: %d\n",
+		       target_freq, ret);
+		return ret;
+	}
+
+	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
+	if (freq_Hz < 0)
+		freq_Hz = freq_table[index].frequency * 1000;
+	freqs.new = freq_Hz / 1000;
+	freqs.old = clk_get_rate(cpu_clk) / 1000;
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	pr_debug("%u MHz --> %u MHz\n", freqs.old / 1000, freqs.new / 1000);
+
+	/* scaling up?  scale voltage before frequency */
+	if (freqs.new > freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+	if (ret) {
+		pr_err("failed to set clock rate: %d\n", ret);
+		hb_voltage_change(freqs.old);
+		return ret;
+	}
+
+	/* scaling down?  scale voltage after frequency */
+	if (freqs.new < freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			if (clk_set_rate(cpu_clk, freqs.old * 1000))
+				pr_err("also failed to reset freq\n");
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	return 0;
+}
+
+static int hb_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	if (ret) {
+		pr_err("invalid frequency table: %d\n", ret);
+		return ret;
+	}
+
+	policy->cpuinfo.transition_latency = transition_latency;
+	policy->cur = clk_get_rate(cpu_clk) / 1000;
+
+	policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+	cpumask_setall(policy->cpus);
+
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int hb_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	return 0;
+}
+
+static struct freq_attr *hb_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver hb_cpufreq_driver = {
+	.flags = CPUFREQ_STICKY,
+	.verify = hb_verify_speed,
+	.target = hb_set_target,
+	.get = hb_get_speed,
+	.init = hb_cpufreq_init,
+	.exit = hb_cpufreq_exit,
+	.name = "highbank-cpufreq",
+	.attr = hb_cpufreq_attr,
+};
+
+static int __devinit hb_cpufreq_driver_init(void)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = of_init_opp_table(cpu_dev);
+	if (ret) {
+		pr_err("failed to init OPP table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
+	if (ret) {
+		pr_err("failed to init cpufreq table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	if (of_property_read_u32(np, "transition-latency", &transition_latency))
+		transition_latency = CPUFREQ_ETERNAL;
+
+	ret = cpufreq_register_driver(&hb_cpufreq_driver);
+	if (ret) {
+		pr_err("failed register driver: %d\n", ret);
+		goto out_free_table;
+	}
+
+	of_node_put(np);
+	return 0;
+
+out_free_table:
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 0/6 v3] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-11-06 20:18 ` [PATCH 0/6 v3] " Mark Langsdorf
                     ` (5 preceding siblings ...)
  2012-11-06 20:18   ` [PATCH 6/6 v3] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2012-11-07 18:11   ` Mark Langsdorf
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-07 18:11 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, linux-pm, cpufreq

On 11/06/2012 02:18 PM, Mark Langsdorf wrote:
> This patch series adds cpufreq support for the Calxeda
> ECX-1000 (highbank) SoCs. The driver is based on the 
> cpufreq-cpu0 driver. Because of the unique way that 
> highbank uses the EnergyCore Management Engine to manage
> voltages, it was not possible to use the cpufreq-cpu0 driver.

I accidentally sent out old versions of the patches. Please ignore the
v3 series and look at the v4 instead.

--Mark Langsdorf


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 0/6 v4] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (8 preceding siblings ...)
  2012-11-06 20:18 ` [PATCH 0/6 v3] " Mark Langsdorf
@ 2012-11-07 18:32 ` Mark Langsdorf
  2012-11-07 18:32   ` [PATCH 1/6 v4] arm: use devicetree to get smp_twd clock Mark Langsdorf
                     ` (6 more replies)
  2012-11-27 15:04 ` [PATCH 0/6 v5] " Mark Langsdorf
                   ` (7 subsequent siblings)
  17 siblings, 7 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-07 18:32 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm

This patch series adds cpufreq support for the Calxeda
ECX-1000 (highbank) SoCs. The driver is based on the 
cpufreq-cpu0 driver. Because of the unique way that 
highbank uses the EnergyCore Management Engine to manage
voltages, it was not possible to use the cpufreq-cpu0 driver.

--Mark Langsdorf



^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/6 v4] arm: use devicetree to get smp_twd clock
  2012-11-07 18:32 ` [PATCH 0/6 v4] " Mark Langsdorf
@ 2012-11-07 18:32   ` Mark Langsdorf
  2012-11-07 18:32   ` [PATCH 2/6 v4] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-07 18:32 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm; +Cc: Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v3
	No longer setting *clk to NULL in twd_get_clock()
Changes from v2
	Turned the check for the node pointer into an if-then-else statement.
	Removed the second, redundant clk_get_rate
Changes from v1
        None.

 arch/arm/kernel/smp_twd.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index b22d700..af46b80 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -237,12 +237,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static struct clk *twd_get_clock(struct device_node *np)
 {
 	struct clk *clk;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
+	if (np)
+		clk = of_clk_get(np, 0);
+	else
+		clk = clk_get_sys("smp_twd", NULL);
 	if (IS_ERR(clk)) {
 		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
 		return clk;
@@ -263,6 +266,7 @@ static struct clk *twd_get_clock(void)
 		return ERR_PTR(err);
 	}
 
+	twd_timer_rate = clk_get_rate(clk);
 	return clk;
 }
 
@@ -273,12 +277,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
 	struct clock_event_device **this_cpu_clk;
 
-	if (!twd_clk)
-		twd_clk = twd_get_clock();
-
-	if (!IS_ERR_OR_NULL(twd_clk))
-		twd_timer_rate = clk_get_rate(twd_clk);
-	else
+	if (IS_ERR_OR_NULL(twd_clk))
 		twd_calibrate_rate();
 
 	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
@@ -349,6 +348,8 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
+	twd_clk = twd_get_clock(NULL);
+
 	return twd_local_timer_common_register();
 }
 
@@ -383,6 +384,8 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
+	twd_clk = twd_get_clock(np);
+
 	err = twd_local_timer_common_register();
 
 out:
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/6 v4] clk, highbank: Prevent glitches in non-bypass reset mode
  2012-11-07 18:32 ` [PATCH 0/6 v4] " Mark Langsdorf
  2012-11-07 18:32   ` [PATCH 1/6 v4] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2012-11-07 18:32   ` Mark Langsdorf
  2012-11-12 21:24     ` Mike Turquette
  2012-11-07 18:32   ` [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-07 18:32 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm; +Cc: Mark Langsdorf, Rob Herring, mturquette

The highbank clock will glitch with the current code if the
clock rate is reset without relocking the PLL. Program the PLL
correctly to preven glitches.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: mturquette@linaro.org
---
Changes from v3
	Changelog text and patch name now correspond to the actual patch
	was clk, highbank: remove non-bypass reset mode
Changes from v2
	None
Changes from v1:
        Removed erroneous reformating.

 drivers/clk/clk-highbank.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..3a0b723 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats
  2012-11-07 18:32 ` [PATCH 0/6 v4] " Mark Langsdorf
  2012-11-07 18:32   ` [PATCH 1/6 v4] arm: use devicetree to get smp_twd clock Mark Langsdorf
  2012-11-07 18:32   ` [PATCH 2/6 v4] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2012-11-07 18:32   ` Mark Langsdorf
  2012-11-11 16:38     ` Borislav Petkov
  2012-11-07 18:32   ` [PATCH 4/6 v4] arm highbank: add support for pl320 IPC Mark Langsdorf
                     ` (3 subsequent siblings)
  6 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-07 18:32 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm; +Cc: Mark Langsdorf, MyungJoo Ham

When collecting stats, if a frequency doesn't match the table, go through
the table again with both the search frequency and table values shifted
left by 10 bits.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: MyungJoo Ham <myungjoo.ham@gmail.com>
---
Changes from v3, v2
	None
Changes from v1:
        Implemented a simple round-up algorithm instead of the over/under
method that could cause errors on Intel processors with boost mode.

 drivers/cpufreq/cpufreq_stats.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 3998316..30aee36 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -161,6 +161,9 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
 	for (index = 0; index < stat->max_state; index++)
 		if (stat->freq_table[index] == freq)
 			return index;
+	for (index = 0; index < stat->max_state; index++)
+		if ((stat->freq_table[index] >> 10) == (freq >> 10))
+			return index;
 	return -1;
 }
 
@@ -251,6 +254,8 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
 	spin_lock(&cpufreq_stats_lock);
 	stat->last_time = get_jiffies_64();
 	stat->last_index = freq_table_get_index(stat, policy->cur);
+	if (stat->last_index > stat->max_state)
+		stat->last_index = stat->max_state - 1;
 	spin_unlock(&cpufreq_stats_lock);
 	cpufreq_cpu_put(data);
 	return 0;
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 4/6 v4] arm highbank: add support for pl320 IPC
  2012-11-07 18:32 ` [PATCH 0/6 v4] " Mark Langsdorf
                     ` (2 preceding siblings ...)
  2012-11-07 18:32   ` [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
@ 2012-11-07 18:32   ` Mark Langsdorf
  2012-11-14 14:03     ` Rob Herring
  2012-11-07 18:32   ` [PATCH 5/6 v4] power: export opp cpufreq functions Mark Langsdorf
                     ` (2 subsequent siblings)
  6 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-07 18:32 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm; +Cc: Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the highbank A9
and the EnergyCore Management Engine. The pl320 implements a straightforward
mailbox protocol.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
---
Changes from v3, v2
	None
Changes from v1
        Removed erroneous changes for cpufreq Kconfig

 arch/arm/include/asm/pl320-ipc.h                |  20 ++
 arch/arm/mach-highbank/Makefile                 |   2 +
 arch/arm/mach-highbank/include/mach/pl320-ipc.h |  20 ++
 arch/arm/mach-highbank/pl320-ipc.c              | 232 ++++++++++++++++++++++++
 4 files changed, 274 insertions(+)
 create mode 100644 arch/arm/include/asm/pl320-ipc.h
 create mode 100644 arch/arm/mach-highbank/include/mach/pl320-ipc.h
 create mode 100644 arch/arm/mach-highbank/pl320-ipc.c

diff --git a/arch/arm/include/asm/pl320-ipc.h b/arch/arm/include/asm/pl320-ipc.h
new file mode 100644
index 0000000..a0e58ee
--- /dev/null
+++ b/arch/arm/include/asm/pl320-ipc.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+int ipc_call_fast(u32 *data);
+int ipc_call_slow(u32 *data);
+
+extern int pl320_ipc_register_notifier(struct notifier_block *nb);
+extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);
diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile
index 3ec8bdd..b894708 100644
--- a/arch/arm/mach-highbank/Makefile
+++ b/arch/arm/mach-highbank/Makefile
@@ -7,3 +7,5 @@ obj-$(CONFIG_DEBUG_HIGHBANK_UART)	+= lluart.o
 obj-$(CONFIG_SMP)			+= platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
 obj-$(CONFIG_PM_SLEEP)			+= pm.o
+
+obj-y					+= pl320-ipc.o
diff --git a/arch/arm/mach-highbank/include/mach/pl320-ipc.h b/arch/arm/mach-highbank/include/mach/pl320-ipc.h
new file mode 100644
index 0000000..a0e58ee
--- /dev/null
+++ b/arch/arm/mach-highbank/include/mach/pl320-ipc.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+int ipc_call_fast(u32 *data);
+int ipc_call_slow(u32 *data);
+
+extern int pl320_ipc_register_notifier(struct notifier_block *nb);
+extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);
diff --git a/arch/arm/mach-highbank/pl320-ipc.c b/arch/arm/mach-highbank/pl320-ipc.c
new file mode 100644
index 0000000..0eb92e4
--- /dev/null
+++ b/arch/arm/mach-highbank/pl320-ipc.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <asm/pl320-ipc.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_FAST_MBOX		0
+#define IPC_SLOW_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_SPINLOCK(ipc_m0_lock);
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* non-blocking implementation from the A9 side, interrupt safe in theory */
+int ipc_call_fast(u32 *data)
+{
+	int timeout, ret;
+
+	spin_lock(&ipc_m0_lock);
+
+	__ipc_send(IPC_FAST_MBOX, data);
+
+	for (timeout = 500; timeout > 0; timeout--) {
+		if (__raw_readl(ipc_base + IPCMxSEND(IPC_FAST_MBOX)) == 0x2)
+			break;
+		udelay(100);
+	}
+	if (timeout == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_FAST_MBOX, data);
+out:
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_FAST_MBOX));
+	spin_unlock(&ipc_m0_lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipc_call_fast);
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int ipc_call_slow(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_SLOW_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_SLOW_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipc_call_slow);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_SLOW_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_SLOW_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+
+static int __devinit pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_FAST_MBOX));
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_SLOW_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init fast mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_FAST_MBOX));
+	set_destination(M3_SOURCE, IPC_FAST_MBOX);
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_SLOW_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_SLOW_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_SLOW_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 5/6 v4] power: export opp cpufreq functions
  2012-11-07 18:32 ` [PATCH 0/6 v4] " Mark Langsdorf
                     ` (3 preceding siblings ...)
  2012-11-07 18:32   ` [PATCH 4/6 v4] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2012-11-07 18:32   ` Mark Langsdorf
  2012-11-07 18:32   ` [PATCH 6/6 v4] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  2012-11-24 10:07   ` [PATCH 0/6 v4] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-07 18:32 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm; +Cc: Mark Langsdorf

These functions are needed to make the cpufreq-core0 and highbank-cpufreq
drivers loadable as modules.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Acked-by: Nishanth Menon <nm@ti.com>
---
Changes from v3
	includes linux/export.h instead of module.h
Changes from v2
	None.
Changes from v1
        Added Nishanth Menon's ack.
        Clarified the purpose of the change in the commit message.

 drivers/base/power/opp.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index d946864..4062ec3 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -23,6 +23,7 @@
 #include <linux/rcupdate.h>
 #include <linux/opp.h>
 #include <linux/of.h>
+#include <linux/export.h>
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -643,6 +644,7 @@ int opp_init_cpufreq_table(struct device *dev,
 
 	return 0;
 }
+EXPORT_SYMBOL(opp_init_cpufreq_table);
 
 /**
  * opp_free_cpufreq_table() - free the cpufreq table
@@ -660,6 +662,7 @@ void opp_free_cpufreq_table(struct device *dev,
 	kfree(*table);
 	*table = NULL;
 }
+EXPORT_SYMBOL(opp_free_cpufreq_table);
 #endif		/* CONFIG_CPU_FREQ */
 
 /**
@@ -720,4 +723,5 @@ int of_init_opp_table(struct device *dev)
 
 	return 0;
 }
+EXPORT_SYMBOL(of_init_opp_table);
 #endif
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 6/6 v4] cpufreq, highbank: add support for highbank cpufreq
  2012-11-07 18:32 ` [PATCH 0/6 v4] " Mark Langsdorf
                     ` (4 preceding siblings ...)
  2012-11-07 18:32   ` [PATCH 5/6 v4] power: export opp cpufreq functions Mark Langsdorf
@ 2012-11-07 18:32   ` Mark Langsdorf
  2012-11-07 18:51     ` Rob Herring
  2012-11-24 10:07   ` [PATCH 0/6 v4] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
  6 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-07 18:32 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm
  Cc: Mark Langsdorf, devicetree-discuss, Rafael J. Wysocki

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
highbank and ECME cores happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: devicetree-discuss@lists.ozlabs.org
Cc: Rafael J. Wysocki <rjw@sisk.pl>
---
Changes from v3
	None
Changes from v2
	Changed transition latency binding in code to match documentation
Changes from v1
        Added highbank specific Kconfig changes

 .../bindings/cpufreq/highbank-cpufreq.txt          |  53 +++++
 arch/arm/Kconfig                                   |   2 +
 arch/arm/boot/dts/highbank.dts                     |  10 +
 arch/arm/mach-highbank/Kconfig                     |   2 +
 drivers/cpufreq/Kconfig.arm                        |  15 ++
 drivers/cpufreq/Makefile                           |   1 +
 drivers/cpufreq/highbank-cpufreq.c                 | 229 +++++++++++++++++++++
 7 files changed, 312 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
new file mode 100644
index 0000000..3ec2cec
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
@@ -0,0 +1,53 @@
+Highbank cpufreq driver
+
+This is cpufreq driver for Calxeda ECX-1000 (highbank) processor. It is based
+on the generic cpu0 driver and uses a similar format for bindings. Since
+the EnergyCore Management Engine maintains the voltage based on the
+frequency, the voltage component of the operating points can be set to any
+arbitrary values.
+
+Both required properties listed below must be defined under node /cpus/cpu@0.
+
+Required properties:
+- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+  for details
+- transition-latency: Specify the possible maximum transition latency for clock,
+  in unit of nanoseconds.
+
+Examples:
+
+cpus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cpu@0 {
+		compatible = "arm,cortex-a9";
+		reg = <0>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz  ignored */
+			790000  1000000
+			396000  1000000
+			198000  1000000
+		>;
+		transition-latency = <200000>;
+	};
+
+	cpu@1 {
+		compatible = "arm,cortex-a9";
+		reg = <1>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@2 {
+		compatible = "arm,cortex-a9";
+		reg = <2>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@3 {
+		compatible = "arm,cortex-a9";
+		reg = <3>;
+		next-level-cache = <&L2>;
+	};
+};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ade7e92..4ed0b7b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -391,6 +391,8 @@ config ARCH_SIRF
 	select PINCTRL
 	select PINCTRL_SIRF
 	select USE_OF
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	help
 	  Support for CSR SiRFprimaII/Marco/Polo platforms
 
diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 0c6fc34..7c4c27d 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -36,6 +36,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			transition-latency = <100000>;
 		};
 
 		cpu@1 {
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 0e1d0a4..ee83af6 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -13,3 +13,5 @@ config ARCH_HIGHBANK
 	select HAVE_SMP
 	select SPARSE_IRQ
 	select USE_OF
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 5961e64..bc3ef55 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -76,3 +76,18 @@ config ARM_EXYNOS5250_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
+
+config ARM_HIGHBANK_CPUFREQ
+       tristate "Calxeda Highbank-based"
+       depends on ARCH_HIGHBANK
+       select CPU_FREQ_TABLE
+       select HAVE_CLK
+       select PM_OPP
+       select OF
+       default m
+       help
+         This adds the CPUFreq driver for Calxeda Highbank SoC
+         based boards.
+
+         If in doubt, say N.
+
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 1bc90e1..9e8f12a 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..a167073
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * derived from cpufreq-cpu0 by Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <asm/pl320-ipc.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE 0x80000001
+
+static unsigned int transition_latency;
+
+static struct device *cpu_dev;
+static struct clk *cpu_clk;
+static struct cpufreq_frequency_table *freq_table;
+
+static int hb_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int hb_get_speed(unsigned int cpu)
+{
+	return clk_get_rate(cpu_clk) / 1000;
+}
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[7];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000;
+	for (i = 2; i < 7; i++)
+		msg[i] = 0;
+
+	return ipc_call_slow(msg);
+}
+
+static int hb_set_target(struct cpufreq_policy *policy,
+			   unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned long freq_Hz;
+	unsigned int index, cpu;
+	int ret;
+
+	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+					     relation, &index);
+	if (ret) {
+		pr_err("failed to match target freqency %d: %d\n",
+		       target_freq, ret);
+		return ret;
+	}
+
+	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
+	if (freq_Hz < 0)
+		freq_Hz = freq_table[index].frequency * 1000;
+	freqs.new = freq_Hz / 1000;
+	freqs.old = clk_get_rate(cpu_clk) / 1000;
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	pr_debug("%u MHz --> %u MHz\n", freqs.old / 1000, freqs.new / 1000);
+
+	/* scaling up?  scale voltage before frequency */
+	if (freqs.new > freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+	if (ret) {
+		pr_err("failed to set clock rate: %d\n", ret);
+		hb_voltage_change(freqs.old);
+		return ret;
+	}
+
+	/* scaling down?  scale voltage after frequency */
+	if (freqs.new < freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			if (clk_set_rate(cpu_clk, freqs.old * 1000))
+				pr_err("also failed to reset freq\n");
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	return 0;
+}
+
+static int hb_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	if (ret) {
+		pr_err("invalid frequency table: %d\n", ret);
+		return ret;
+	}
+
+	policy->cpuinfo.transition_latency = transition_latency;
+	policy->cur = clk_get_rate(cpu_clk) / 1000;
+
+	policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+	cpumask_setall(policy->cpus);
+
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int hb_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	return 0;
+}
+
+static struct freq_attr *hb_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver hb_cpufreq_driver = {
+	.flags = CPUFREQ_STICKY,
+	.verify = hb_verify_speed,
+	.target = hb_set_target,
+	.get = hb_get_speed,
+	.init = hb_cpufreq_init,
+	.exit = hb_cpufreq_exit,
+	.name = "highbank-cpufreq",
+	.attr = hb_cpufreq_attr,
+};
+
+static int __devinit hb_cpufreq_driver_init(void)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = of_init_opp_table(cpu_dev);
+	if (ret) {
+		pr_err("failed to init OPP table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
+	if (ret) {
+		pr_err("failed to init cpufreq table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	if (of_property_read_u32(np, "transition-latency", &transition_latency))
+		transition_latency = CPUFREQ_ETERNAL;
+
+	ret = cpufreq_register_driver(&hb_cpufreq_driver);
+	if (ret) {
+		pr_err("failed register driver: %d\n", ret);
+		goto out_free_table;
+	}
+
+	of_node_put(np);
+	return 0;
+
+out_free_table:
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v4] cpufreq, highbank: add support for highbank cpufreq
  2012-11-07 18:32   ` [PATCH 6/6 v4] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2012-11-07 18:51     ` Rob Herring
  0 siblings, 0 replies; 142+ messages in thread
From: Rob Herring @ 2012-11-07 18:51 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, Rafael J. Wysocki, devicetree-discuss

On 11/07/2012 12:32 PM, Mark Langsdorf wrote:
> Highbank processors depend on the external ECME to perform voltage
> management based on a requested frequency. Communication between the
> highbank and ECME cores happens over the pl320 IPC channel.
> 
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> Cc: devicetree-discuss@lists.ozlabs.org
> Cc: Rafael J. Wysocki <rjw@sisk.pl>
> ---
> Changes from v3
> 	None
> Changes from v2
> 	Changed transition latency binding in code to match documentation
> Changes from v1
>         Added highbank specific Kconfig changes
> 
>  .../bindings/cpufreq/highbank-cpufreq.txt          |  53 +++++
>  arch/arm/Kconfig                                   |   2 +
>  arch/arm/boot/dts/highbank.dts                     |  10 +
>  arch/arm/mach-highbank/Kconfig                     |   2 +
>  drivers/cpufreq/Kconfig.arm                        |  15 ++
>  drivers/cpufreq/Makefile                           |   1 +
>  drivers/cpufreq/highbank-cpufreq.c                 | 229 +++++++++++++++++++++
>  7 files changed, 312 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
>  create mode 100644 drivers/cpufreq/highbank-cpufreq.c
> 
> diff --git a/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
> new file mode 100644
> index 0000000..3ec2cec
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
> @@ -0,0 +1,53 @@
> +Highbank cpufreq driver
> +
> +This is cpufreq driver for Calxeda ECX-1000 (highbank) processor. It is based
> +on the generic cpu0 driver and uses a similar format for bindings. Since
> +the EnergyCore Management Engine maintains the voltage based on the
> +frequency, the voltage component of the operating points can be set to any
> +arbitrary values.
> +
> +Both required properties listed below must be defined under node /cpus/cpu@0.
> +
> +Required properties:
> +- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
> +  for details
> +- transition-latency: Specify the possible maximum transition latency for clock,
> +  in unit of nanoseconds.
> +
> +Examples:
> +
> +cpus {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	cpu@0 {
> +		compatible = "arm,cortex-a9";
> +		reg = <0>;
> +		next-level-cache = <&L2>;
> +		operating-points = <
> +			/* kHz  ignored */
> +			790000  1000000
> +			396000  1000000
> +			198000  1000000
> +		>;
> +		transition-latency = <200000>;
> +	};
> +
> +	cpu@1 {
> +		compatible = "arm,cortex-a9";
> +		reg = <1>;
> +		next-level-cache = <&L2>;
> +	};
> +
> +	cpu@2 {
> +		compatible = "arm,cortex-a9";
> +		reg = <2>;
> +		next-level-cache = <&L2>;
> +	};
> +
> +	cpu@3 {
> +		compatible = "arm,cortex-a9";
> +		reg = <3>;
> +		next-level-cache = <&L2>;
> +	};
> +};
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index ade7e92..4ed0b7b 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -391,6 +391,8 @@ config ARCH_SIRF
>  	select PINCTRL
>  	select PINCTRL_SIRF
>  	select USE_OF
> +	select ARCH_HAS_CPUFREQ
> +	select ARCH_HAS_OPP

This hunk needs to be removed.

>  	help
>  	  Support for CSR SiRFprimaII/Marco/Polo platforms
>  
> diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
> index 0c6fc34..7c4c27d 100644
> --- a/arch/arm/boot/dts/highbank.dts
> +++ b/arch/arm/boot/dts/highbank.dts
> @@ -36,6 +36,16 @@
>  			next-level-cache = <&L2>;
>  			clocks = <&a9pll>;
>  			clock-names = "cpu";
> +			operating-points = <
> +				/* kHz    ignored */
> +				 1300000  1000000
> +				 1200000  1000000
> +				 1100000  1000000
> +				  800000  1000000
> +				  400000  1000000
> +				  200000  1000000
> +			>;
> +			transition-latency = <100000>;
>  		};
>  
>  		cpu@1 {
> diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
> index 0e1d0a4..ee83af6 100644
> --- a/arch/arm/mach-highbank/Kconfig
> +++ b/arch/arm/mach-highbank/Kconfig
> @@ -13,3 +13,5 @@ config ARCH_HIGHBANK
>  	select HAVE_SMP
>  	select SPARSE_IRQ
>  	select USE_OF
> +	select ARCH_HAS_CPUFREQ
> +	select ARCH_HAS_OPP

Sort these alphabetically.

> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 5961e64..bc3ef55 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -76,3 +76,18 @@ config ARM_EXYNOS5250_CPUFREQ
>  	help
>  	  This adds the CPUFreq driver for Samsung EXYNOS5250
>  	  SoC.
> +
> +config ARM_HIGHBANK_CPUFREQ
> +       tristate "Calxeda Highbank-based"
> +       depends on ARCH_HIGHBANK
> +       select CPU_FREQ_TABLE
> +       select HAVE_CLK

ARCH_HIGHBANK already selects this.

> +       select PM_OPP
> +       select OF

And this.

> +       default m
> +       help
> +         This adds the CPUFreq driver for Calxeda Highbank SoC
> +         based boards.
> +
> +         If in doubt, say N.
> +
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index 1bc90e1..9e8f12a 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
>  obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
>  obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
>  obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
> +obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
>  
>  ##################################################################################
>  # PowerPC platform drivers
> diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
> new file mode 100644
> index 0000000..a167073
> --- /dev/null
> +++ b/drivers/cpufreq/highbank-cpufreq.c
> @@ -0,0 +1,229 @@
> +/*
> + * Copyright (C) 2012 Calxeda, Inc.
> + *
> + * derived from cpufreq-cpu0 by Freescale Semiconductor
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
> +
> +#include <linux/clk.h>
> +#include <linux/cpu.h>
> +#include <linux/cpufreq.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/opp.h>
> +#include <linux/slab.h>
> +#include <asm/pl320-ipc.h>
> +
> +#define HB_CPUFREQ_CHANGE_NOTE 0x80000001
> +
> +static unsigned int transition_latency;
> +
> +static struct device *cpu_dev;
> +static struct clk *cpu_clk;
> +static struct cpufreq_frequency_table *freq_table;
> +
> +static int hb_verify_speed(struct cpufreq_policy *policy)
> +{
> +	return cpufreq_frequency_table_verify(policy, freq_table);
> +}
> +
> +static unsigned int hb_get_speed(unsigned int cpu)
> +{
> +	return clk_get_rate(cpu_clk) / 1000;
> +}
> +
> +static int hb_voltage_change(unsigned int freq)
> +{
> +	int i;
> +	u32 msg[7];
> +
> +	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
> +	msg[1] = freq / 1000;
> +	for (i = 2; i < 7; i++)
> +		msg[i] = 0;
> +
> +	return ipc_call_slow(msg);
> +}
> +
> +static int hb_set_target(struct cpufreq_policy *policy,
> +			   unsigned int target_freq, unsigned int relation)
> +{
> +	struct cpufreq_freqs freqs;
> +	unsigned long freq_Hz;
> +	unsigned int index, cpu;
> +	int ret;
> +
> +	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
> +					     relation, &index);
> +	if (ret) {
> +		pr_err("failed to match target freqency %d: %d\n",
> +		       target_freq, ret);
> +		return ret;
> +	}
> +
> +	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
> +	if (freq_Hz < 0)
> +		freq_Hz = freq_table[index].frequency * 1000;
> +	freqs.new = freq_Hz / 1000;
> +	freqs.old = clk_get_rate(cpu_clk) / 1000;
> +
> +	if (freqs.old == freqs.new)
> +		return 0;
> +
> +	for_each_online_cpu(cpu) {
> +		freqs.cpu = cpu;
> +		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> +	}
> +
> +	pr_debug("%u MHz --> %u MHz\n", freqs.old / 1000, freqs.new / 1000);
> +
> +	/* scaling up?  scale voltage before frequency */
> +	if (freqs.new > freqs.old) {
> +		ret = hb_voltage_change(freqs.new);
> +		if (ret) {
> +			freqs.new = freqs.old;
> +			return -EAGAIN;
> +		}
> +	}
> +
> +	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
> +	if (ret) {
> +		pr_err("failed to set clock rate: %d\n", ret);
> +		hb_voltage_change(freqs.old);
> +		return ret;
> +	}
> +
> +	/* scaling down?  scale voltage after frequency */
> +	if (freqs.new < freqs.old) {
> +		ret = hb_voltage_change(freqs.new);
> +		if (ret) {
> +			if (clk_set_rate(cpu_clk, freqs.old * 1000))
> +				pr_err("also failed to reset freq\n");
> +			freqs.new = freqs.old;
> +			return -EAGAIN;
> +		}
> +	}
> +
> +	for_each_online_cpu(cpu) {
> +		freqs.cpu = cpu;
> +		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> +	}
> +
> +	return 0;
> +}
> +
> +static int hb_cpufreq_init(struct cpufreq_policy *policy)
> +{
> +	int ret;
> +
> +	if (policy->cpu != 0)
> +		return -EINVAL;
> +
> +	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
> +	if (ret) {
> +		pr_err("invalid frequency table: %d\n", ret);
> +		return ret;
> +	}
> +
> +	policy->cpuinfo.transition_latency = transition_latency;
> +	policy->cur = clk_get_rate(cpu_clk) / 1000;
> +
> +	policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
> +	cpumask_setall(policy->cpus);
> +
> +	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
> +
> +	return 0;
> +}
> +
> +static int hb_cpufreq_exit(struct cpufreq_policy *policy)
> +{
> +	cpufreq_frequency_table_put_attr(policy->cpu);
> +
> +	return 0;
> +}
> +
> +static struct freq_attr *hb_cpufreq_attr[] = {
> +	&cpufreq_freq_attr_scaling_available_freqs,
> +	NULL,
> +};
> +
> +static struct cpufreq_driver hb_cpufreq_driver = {
> +	.flags = CPUFREQ_STICKY,
> +	.verify = hb_verify_speed,
> +	.target = hb_set_target,
> +	.get = hb_get_speed,
> +	.init = hb_cpufreq_init,
> +	.exit = hb_cpufreq_exit,
> +	.name = "highbank-cpufreq",
> +	.attr = hb_cpufreq_attr,
> +};
> +
> +static int __devinit hb_cpufreq_driver_init(void)
> +{
> +	struct device_node *np;
> +	int ret;
> +
> +	np = of_find_node_by_path("/cpus/cpu@0");
> +	if (!np) {
> +		pr_err("failed to find highbank cpufreq node\n");
> +		return -ENOENT;
> +	}
> +
> +	cpu_dev = get_cpu_device(0);
> +	if (!cpu_dev) {
> +		pr_err("failed to get highbank cpufreq device\n");
> +		ret = -ENODEV;
> +		goto out_put_node;
> +	}
> +
> +	cpu_dev->of_node = np;
> +
> +	cpu_clk = clk_get(cpu_dev, NULL);
> +	if (IS_ERR(cpu_clk)) {
> +		ret = PTR_ERR(cpu_clk);
> +		pr_err("failed to get cpu0 clock: %d\n", ret);
> +		goto out_put_node;
> +	}
> +
> +	ret = of_init_opp_table(cpu_dev);
> +	if (ret) {
> +		pr_err("failed to init OPP table: %d\n", ret);
> +		goto out_put_node;
> +	}
> +
> +	ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
> +	if (ret) {
> +		pr_err("failed to init cpufreq table: %d\n", ret);
> +		goto out_put_node;
> +	}
> +
> +	if (of_property_read_u32(np, "transition-latency", &transition_latency))
> +		transition_latency = CPUFREQ_ETERNAL;
> +
> +	ret = cpufreq_register_driver(&hb_cpufreq_driver);
> +	if (ret) {
> +		pr_err("failed register driver: %d\n", ret);
> +		goto out_free_table;
> +	}
> +
> +	of_node_put(np);
> +	return 0;
> +
> +out_free_table:
> +	opp_free_cpufreq_table(cpu_dev, &freq_table);
> +out_put_node:
> +	of_node_put(np);
> +	return ret;
> +}
> +late_initcall(hb_cpufreq_driver_init);
> +
> +MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
> +MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
> +MODULE_LICENSE("GPL");
> 


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats
  2012-11-07 18:32   ` [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
@ 2012-11-11 16:38     ` Borislav Petkov
  2012-11-12 16:35       ` Mark Langsdorf
  0 siblings, 1 reply; 142+ messages in thread
From: Borislav Petkov @ 2012-11-11 16:38 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq, linux-pm, MyungJoo Ham

On Wed, Nov 07, 2012 at 12:32:43PM -0600, Mark Langsdorf wrote:
> When collecting stats, if a frequency doesn't match the table, go through
> the table again with both the search frequency and table values shifted
> left by 10 bits.

Why would that second pass succeed?

And why is this in generic code (I'm assuming this is a Calxeda-specific
case)?

-- 
Regards/Gruss,
Boris.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats
  2012-11-11 16:38     ` Borislav Petkov
@ 2012-11-12 16:35       ` Mark Langsdorf
  2012-11-13 16:24         ` Borislav Petkov
  0 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-12 16:35 UTC (permalink / raw)
  To: Borislav Petkov; +Cc: linux-kernel, cpufreq, linux-pm, MyungJoo Ham

On 11/11/2012 10:38 AM, Borislav Petkov wrote:
> On Wed, Nov 07, 2012 at 12:32:43PM -0600, Mark Langsdorf wrote:
>> When collecting stats, if a frequency doesn't match the table, go through
>> the table again with both the search frequency and table values shifted
>> left by 10 bits.
> 
> Why would that second pass succeed?

It's effectively a divide by 1024 and minimizes any jitter in the
measured frequency value.

> And why is this in generic code (I'm assuming this is a Calxeda-specific
> case)?

The function is buried pretty deep in the cpufreq_stat code. It didn't
seem appropriate to make it a function pointer as part of struct
cpufreq_driver.

--Mark Langsdorf
Calxeda, Inc.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 2/6 v4] clk, highbank: Prevent glitches in non-bypass reset mode
  2012-11-07 18:32   ` [PATCH 2/6 v4] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2012-11-12 21:24     ` Mike Turquette
  2012-11-12 21:35       ` Mark Langsdorf
  0 siblings, 1 reply; 142+ messages in thread
From: Mike Turquette @ 2012-11-12 21:24 UTC (permalink / raw)
  To: Mark Langsdorf, linux-kernel, cpufreq, linux-pm
  Cc: Mark Langsdorf, Rob Herring

Quoting Mark Langsdorf (2012-11-07 10:32:42)
> The highbank clock will glitch with the current code if the
> clock rate is reset without relocking the PLL. Program the PLL
> correctly to preven glitches.
> 
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Cc: mturquette@linaro.org

Hi Mark,

Looks fine to me.

I seem to be missing the rest of this series in my mail.  Did you want
me to take only this patch (2/6) into clk-next or were you only looking
for my ACK?

Regards,
Mike

> ---
> Changes from v3
>         Changelog text and patch name now correspond to the actual patch
>         was clk, highbank: remove non-bypass reset mode
> Changes from v2
>         None
> Changes from v1:
>         Removed erroneous reformating.
> 
>  drivers/clk/clk-highbank.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
> index 52fecad..3a0b723 100644
> --- a/drivers/clk/clk-highbank.c
> +++ b/drivers/clk/clk-highbank.c
> @@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
>                 reg |= HB_PLL_EXT_ENA;
>                 reg &= ~HB_PLL_EXT_BYPASS;
>         } else {
> +               writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
>                 reg &= ~HB_PLL_DIVQ_MASK;
>                 reg |= divq << HB_PLL_DIVQ_SHIFT;
> +               writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
>         }
>         writel(reg, hbclk->reg);
>  
> -- 
> 1.7.11.7

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 2/6 v4] clk, highbank: Prevent glitches in non-bypass reset mode
  2012-11-12 21:24     ` Mike Turquette
@ 2012-11-12 21:35       ` Mark Langsdorf
  0 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-12 21:35 UTC (permalink / raw)
  To: Mike Turquette; +Cc: linux-kernel, cpufreq, linux-pm, Rob Herring

On 11/12/2012 03:24 PM, Mike Turquette wrote:
> Quoting Mark Langsdorf (2012-11-07 10:32:42)
>> The highbank clock will glitch with the current code if the
>> clock rate is reset without relocking the PLL. Program the PLL
>> correctly to preven glitches.
>>
>> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
>> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
>> Cc: mturquette@linaro.org
> 
> Hi Mark,
> 
> Looks fine to me.
> 
> I seem to be missing the rest of this series in my mail.  Did you want
> me to take only this patch (2/6) into clk-next or were you only looking
> for my ACK?

The entire series enables highbank cpufreq. Would you normally take this
patch through cpufreq-next with an ACK or directly through clk-next?

--Mark Langsdorf
Calxeda, Inc.

>> ---
>> Changes from v3
>>         Changelog text and patch name now correspond to the actual patch
>>         was clk, highbank: remove non-bypass reset mode
>> Changes from v2
>>         None
>> Changes from v1:
>>         Removed erroneous reformating.
>>
>>  drivers/clk/clk-highbank.c | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
>> index 52fecad..3a0b723 100644
>> --- a/drivers/clk/clk-highbank.c
>> +++ b/drivers/clk/clk-highbank.c
>> @@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
>>                 reg |= HB_PLL_EXT_ENA;
>>                 reg &= ~HB_PLL_EXT_BYPASS;
>>         } else {
>> +               writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
>>                 reg &= ~HB_PLL_DIVQ_MASK;
>>                 reg |= divq << HB_PLL_DIVQ_SHIFT;
>> +               writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
>>         }
>>         writel(reg, hbclk->reg);
>>  
>> -- 
>> 1.7.11.7


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats
  2012-11-12 16:35       ` Mark Langsdorf
@ 2012-11-13 16:24         ` Borislav Petkov
  2012-11-13 16:33           ` Mark Langsdorf
  0 siblings, 1 reply; 142+ messages in thread
From: Borislav Petkov @ 2012-11-13 16:24 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq, linux-pm, MyungJoo Ham

On Mon, Nov 12, 2012 at 10:35:49AM -0600, Mark Langsdorf wrote:
> The function is buried pretty deep in the cpufreq_stat code. It didn't
> seem appropriate to make it a function pointer as part of struct
> cpufreq_driver.

Right, what's cpufreq-speak for

	if (Calxeda)
		shift by 10

?

Better yet, add a flag or a bitfield called "minimize_jitter" or similar
and set it only on your hardware...

Thanks.

-- 
Regards/Gruss,
Boris.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats
  2012-11-13 16:24         ` Borislav Petkov
@ 2012-11-13 16:33           ` Mark Langsdorf
  2012-11-13 19:13             ` Mark Langsdorf
  0 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-13 16:33 UTC (permalink / raw)
  To: Borislav Petkov; +Cc: linux-kernel, cpufreq, linux-pm, MyungJoo Ham

On 11/13/2012 10:24 AM, Borislav Petkov wrote:
> On Mon, Nov 12, 2012 at 10:35:49AM -0600, Mark Langsdorf wrote:
>> The function is buried pretty deep in the cpufreq_stat code. It didn't
>> seem appropriate to make it a function pointer as part of struct
>> cpufreq_driver.
> 
> Right, what's cpufreq-speak for
> 
> 	if (Calxeda)
> 		shift by 10
> 
> ?
> 
> Better yet, add a flag or a bitfield called "minimize_jitter" or similar
> and set it only on your hardware...

Doing it in two passes has a similar effect: systems that have exact
frequencies will get caught in the first pass when the values match. But
adding a flag makes sense.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* RE: [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats
  2012-11-13 16:33           ` Mark Langsdorf
@ 2012-11-13 19:13             ` Mark Langsdorf
  2012-11-17 14:50               ` Borislav Petkov
  0 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-13 19:13 UTC (permalink / raw)
  To: Mark Langsdorf, Borislav Petkov
  Cc: linux-kernel, cpufreq, linux-pm, MyungJoo Ham

From: linux-pm-owner@vger.kernel.org [linux-pm-owner@vger.kernel.org] On Behalf Of Mark Langsdorf [mark.langsdorf@calxeda.com]

> On 11/13/2012 10:24 AM, Borislav Petkov wrote:
>> On Mon, Nov 12, 2012 at 10:35:49AM -0600, Mark Langsdorf wrote:
>>> The function is buried pretty deep in the cpufreq_stat code. It didn't
>>> seem appropriate to make it a function pointer as part of struct
>>> cpufreq_driver.
>>
>> Better yet, add a flag or a bitfield called "minimize_jitter" or similar
>> and set it only on your hardware...
>
> Doing it in two passes has a similar effect: systems that have exact
> frequencies will get caught in the first pass when the values match. But
> adding a flag makes sense.

I went back and looked at implementing this suggestion.

Although cpufreq_driver has a flag field, no part of cpufreq_driver is directly passed to the cpufreq_stat code. Only cpufreq_policy is. It's cleaner to do passes of the while loop than to copy the cpufreq_driver.flag field into cpufreq_policy and then store it again in cpufreq_stats.

--Mark Langsdorf
Calxeda, Inc.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 4/6 v4] arm highbank: add support for pl320 IPC
  2012-11-07 18:32   ` [PATCH 4/6 v4] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2012-11-14 14:03     ` Rob Herring
  0 siblings, 0 replies; 142+ messages in thread
From: Rob Herring @ 2012-11-14 14:03 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq, linux-pm

On 11/07/2012 12:32 PM, Mark Langsdorf wrote:
> From: Rob Herring <rob.herring@calxeda.com>
> 
> The pl320 IPC allows for interprocessor communication between the highbank A9
> and the EnergyCore Management Engine. The pl320 implements a straightforward
> mailbox protocol.
> 
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> ---
> Changes from v3, v2
> 	None
> Changes from v1
>         Removed erroneous changes for cpufreq Kconfig
> 
>  arch/arm/include/asm/pl320-ipc.h                |  20 ++

asm/hardware/ is probably more appropriate.

>  arch/arm/mach-highbank/Makefile                 |   2 +
>  arch/arm/mach-highbank/include/mach/pl320-ipc.h |  20 ++

Need to delete this file.

>  arch/arm/mach-highbank/pl320-ipc.c              | 232 ++++++++++++++++++++++++
>  4 files changed, 274 insertions(+)
>  create mode 100644 arch/arm/include/asm/pl320-ipc.h
>  create mode 100644 arch/arm/mach-highbank/include/mach/pl320-ipc.h
>  create mode 100644 arch/arm/mach-highbank/pl320-ipc.c
> 
> diff --git a/arch/arm/include/asm/pl320-ipc.h b/arch/arm/include/asm/pl320-ipc.h
> new file mode 100644
> index 0000000..a0e58ee
> --- /dev/null
> +++ b/arch/arm/include/asm/pl320-ipc.h
> @@ -0,0 +1,20 @@
> +/*
> + * Copyright 2010 Calxeda, Inc.

Update copyright.

> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +int ipc_call_fast(u32 *data);

We should get rid of fast and slow channels and just have a single tx
channel as it is all the same and we don't use the fast channel.

> +int ipc_call_slow(u32 *data);
> +
> +extern int pl320_ipc_register_notifier(struct notifier_block *nb);
> +extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);
> diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile
> index 3ec8bdd..b894708 100644
> --- a/arch/arm/mach-highbank/Makefile
> +++ b/arch/arm/mach-highbank/Makefile
> @@ -7,3 +7,5 @@ obj-$(CONFIG_DEBUG_HIGHBANK_UART)	+= lluart.o
>  obj-$(CONFIG_SMP)			+= platsmp.o
>  obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
>  obj-$(CONFIG_PM_SLEEP)			+= pm.o
> +
> +obj-y					+= pl320-ipc.o
> diff --git a/arch/arm/mach-highbank/include/mach/pl320-ipc.h b/arch/arm/mach-highbank/include/mach/pl320-ipc.h
> new file mode 100644
> index 0000000..a0e58ee
> --- /dev/null
> +++ b/arch/arm/mach-highbank/include/mach/pl320-ipc.h
> @@ -0,0 +1,20 @@
> +/*
> + * Copyright 2010 Calxeda, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +int ipc_call_fast(u32 *data);
> +int ipc_call_slow(u32 *data);
> +
> +extern int pl320_ipc_register_notifier(struct notifier_block *nb);
> +extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);
> diff --git a/arch/arm/mach-highbank/pl320-ipc.c b/arch/arm/mach-highbank/pl320-ipc.c
> new file mode 100644
> index 0000000..0eb92e4
> --- /dev/null
> +++ b/arch/arm/mach-highbank/pl320-ipc.c
> @@ -0,0 +1,232 @@
> +/*
> + * Copyright 2012 Calxeda, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#include <linux/types.h>
> +#include <linux/err.h>
> +#include <linux/delay.h>
> +#include <linux/export.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/completion.h>
> +#include <linux/mutex.h>
> +#include <linux/notifier.h>
> +#include <linux/spinlock.h>
> +#include <linux/device.h>
> +#include <linux/amba/bus.h>
> +
> +#include <asm/pl320-ipc.h>
> +
> +#define IPCMxSOURCE(m)		((m) * 0x40)
> +#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
> +#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
> +#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
> +#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
> +#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
> +#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
> +#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
> +#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
> +#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
> +
> +#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
> +#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
> +
> +#define MBOX_MASK(n)		(1 << (n))
> +#define IPC_FAST_MBOX		0
> +#define IPC_SLOW_MBOX		1
> +#define IPC_RX_MBOX		2
> +
> +#define CHAN_MASK(n)		(1 << (n))
> +#define A9_SOURCE		1
> +#define M3_SOURCE		0
> +
> +static void __iomem *ipc_base;
> +static int ipc_irq;
> +static DEFINE_SPINLOCK(ipc_m0_lock);
> +static DEFINE_MUTEX(ipc_m1_lock);
> +static DECLARE_COMPLETION(ipc_completion);
> +static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
> +
> +static inline void set_destination(int source, int mbox)
> +{
> +	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
> +	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
> +}
> +
> +static inline void clear_destination(int source, int mbox)
> +{
> +	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
> +	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
> +}
> +
> +static void __ipc_send(int mbox, u32 *data)
> +{
> +	int i;
> +	for (i = 0; i < 7; i++)
> +		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
> +	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
> +}
> +
> +static u32 __ipc_rcv(int mbox, u32 *data)
> +{
> +	int i;
> +	for (i = 0; i < 7; i++)
> +		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
> +	return data[1];
> +}
> +
> +/* non-blocking implementation from the A9 side, interrupt safe in theory */
> +int ipc_call_fast(u32 *data)
> +{
> +	int timeout, ret;
> +
> +	spin_lock(&ipc_m0_lock);
> +
> +	__ipc_send(IPC_FAST_MBOX, data);
> +
> +	for (timeout = 500; timeout > 0; timeout--) {
> +		if (__raw_readl(ipc_base + IPCMxSEND(IPC_FAST_MBOX)) == 0x2)
> +			break;
> +		udelay(100);
> +	}
> +	if (timeout == 0) {
> +		ret = -ETIMEDOUT;
> +		goto out;
> +	}
> +
> +	ret = __ipc_rcv(IPC_FAST_MBOX, data);
> +out:
> +	__raw_writel(0, ipc_base + IPCMxSEND(IPC_FAST_MBOX));
> +	spin_unlock(&ipc_m0_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL(ipc_call_fast);
> +
> +/* blocking implmentation from the A9 side, not usuable in interrupts! */
> +int ipc_call_slow(u32 *data)
> +{
> +	int ret;
> +
> +	mutex_lock(&ipc_m1_lock);
> +
> +	init_completion(&ipc_completion);
> +	__ipc_send(IPC_SLOW_MBOX, data);
> +	ret = wait_for_completion_timeout(&ipc_completion,
> +					  msecs_to_jiffies(1000));
> +	if (ret == 0) {
> +		ret = -ETIMEDOUT;
> +		goto out;
> +	}
> +
> +	ret = __ipc_rcv(IPC_SLOW_MBOX, data);
> +out:
> +	mutex_unlock(&ipc_m1_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL(ipc_call_slow);
> +
> +irqreturn_t ipc_handler(int irq, void *dev)
> +{
> +	u32 irq_stat;
> +	u32 data[7];
> +
> +	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
> +	if (irq_stat & MBOX_MASK(IPC_SLOW_MBOX)) {
> +		__raw_writel(0, ipc_base + IPCMxSEND(IPC_SLOW_MBOX));
> +		complete(&ipc_completion);
> +	}
> +	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
> +		__ipc_rcv(IPC_RX_MBOX, data);
> +		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
> +		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +int pl320_ipc_register_notifier(struct notifier_block *nb)
> +{
> +	return atomic_notifier_chain_register(&ipc_notifier, nb);
> +}
> +
> +int pl320_ipc_unregister_notifier(struct notifier_block *nb)
> +{
> +	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
> +}
> +
> +static int __devinit pl320_probe(struct amba_device *adev,
> +				const struct amba_id *id)
> +{
> +	int ret;
> +
> +	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
> +	if (ipc_base == NULL)
> +		return -ENOMEM;
> +
> +	__raw_writel(0, ipc_base + IPCMxSEND(IPC_FAST_MBOX));
> +	__raw_writel(0, ipc_base + IPCMxSEND(IPC_SLOW_MBOX));
> +
> +	ipc_irq = adev->irq[0];
> +	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
> +	if (ret < 0)
> +		goto err;
> +
> +	/* Init fast mailbox */
> +	__raw_writel(CHAN_MASK(A9_SOURCE),
> +			ipc_base + IPCMxSOURCE(IPC_FAST_MBOX));
> +	set_destination(M3_SOURCE, IPC_FAST_MBOX);
> +
> +	/* Init slow mailbox */
> +	__raw_writel(CHAN_MASK(A9_SOURCE),
> +			ipc_base + IPCMxSOURCE(IPC_SLOW_MBOX));
> +	__raw_writel(CHAN_MASK(M3_SOURCE),
> +			ipc_base + IPCMxDSET(IPC_SLOW_MBOX));
> +	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
> +		     ipc_base + IPCMxMSET(IPC_SLOW_MBOX));
> +
> +	/* Init receive mailbox */
> +	__raw_writel(CHAN_MASK(M3_SOURCE),
> +			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
> +	__raw_writel(CHAN_MASK(A9_SOURCE),
> +			ipc_base + IPCMxDSET(IPC_RX_MBOX));
> +	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
> +		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
> +
> +	return 0;
> +err:
> +	iounmap(ipc_base);
> +	return ret;
> +}
> +
> +static struct amba_id pl320_ids[] = {
> +	{
> +		.id	= 0x00041320,
> +		.mask	= 0x000fffff,
> +	},
> +	{ 0, 0 },
> +};
> +
> +static struct amba_driver pl320_driver = {
> +	.drv = {
> +		.name	= "pl320",
> +	},
> +	.id_table	= pl320_ids,
> +	.probe		= pl320_probe,
> +};
> +
> +static int __init ipc_init(void)
> +{
> +	return amba_driver_register(&pl320_driver);
> +}
> +module_init(ipc_init);
> 

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats
  2012-11-13 19:13             ` Mark Langsdorf
@ 2012-11-17 14:50               ` Borislav Petkov
  2012-11-24 10:05                 ` Rafael J. Wysocki
  0 siblings, 1 reply; 142+ messages in thread
From: Borislav Petkov @ 2012-11-17 14:50 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq, linux-pm, MyungJoo Ham

On Tue, Nov 13, 2012 at 02:13:38PM -0500, Mark Langsdorf wrote:
> Although cpufreq_driver has a flag field, no part of cpufreq_driver
> is directly passed to the cpufreq_stat code. Only cpufreq_policy
> is. It's cleaner to do passes of the while loop than to copy the
> cpufreq_driver.flag field into cpufreq_policy and then store it again
> in cpufreq_stats.

That maybe so but this newly added loop which is only Calxeda-relevant
is called in cpufreq_stat_notifier_trans, which is the frequency change
notifier call, AFAICT.

So each cpufreq driver will be paying that small and needless penalty
now for nothing and on each frequency change. Which adds to the
kernel-wide bloat and we absolutely don't want that.

So you probably need to find a slick way of detecting calxeda hw
somewhere along the init path of cpufreq_stats_init and set a
hw-specific flag instead of adding that cost to each driver.

Thanks.

-- 
Regards/Gruss,
Boris.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats
  2012-11-17 14:50               ` Borislav Petkov
@ 2012-11-24 10:05                 ` Rafael J. Wysocki
  2012-11-26 13:57                   ` Mark Langsdorf
  0 siblings, 1 reply; 142+ messages in thread
From: Rafael J. Wysocki @ 2012-11-24 10:05 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: Borislav Petkov, linux-kernel, cpufreq, linux-pm, MyungJoo Ham

On Saturday, November 17, 2012 03:50:48 PM Borislav Petkov wrote:
> On Tue, Nov 13, 2012 at 02:13:38PM -0500, Mark Langsdorf wrote:
> > Although cpufreq_driver has a flag field, no part of cpufreq_driver
> > is directly passed to the cpufreq_stat code. Only cpufreq_policy
> > is. It's cleaner to do passes of the while loop than to copy the
> > cpufreq_driver.flag field into cpufreq_policy and then store it again
> > in cpufreq_stats.
> 
> That maybe so but this newly added loop which is only Calxeda-relevant
> is called in cpufreq_stat_notifier_trans, which is the frequency change
> notifier call, AFAICT.
> 
> So each cpufreq driver will be paying that small and needless penalty
> now for nothing and on each frequency change. Which adds to the
> kernel-wide bloat and we absolutely don't want that.
> 
> So you probably need to find a slick way of detecting calxeda hw
> somewhere along the init path of cpufreq_stats_init and set a
> hw-specific flag instead of adding that cost to each driver.

Mark, I suppose you'd like me to take this series for v3.8, but the above
comment from Boris has to be addressed for that.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 0/6 v4] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-11-07 18:32 ` [PATCH 0/6 v4] " Mark Langsdorf
                     ` (5 preceding siblings ...)
  2012-11-07 18:32   ` [PATCH 6/6 v4] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2012-11-24 10:07   ` Rafael J. Wysocki
  6 siblings, 0 replies; 142+ messages in thread
From: Rafael J. Wysocki @ 2012-11-24 10:07 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq, linux-pm

Hi Mark,

On Wednesday, November 07, 2012 12:32:40 PM Mark Langsdorf wrote:
> This patch series adds cpufreq support for the Calxeda
> ECX-1000 (highbank) SoCs. The driver is based on the 
> cpufreq-cpu0 driver. Because of the unique way that 
> highbank uses the EnergyCore Management Engine to manage
> voltages, it was not possible to use the cpufreq-cpu0 driver.

Please address the reviewers' comments for patches [3-4/6] and [6/6].

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats
  2012-11-24 10:05                 ` Rafael J. Wysocki
@ 2012-11-26 13:57                   ` Mark Langsdorf
  2012-11-26 15:25                     ` Rafael J. Wysocki
  0 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-26 13:57 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Borislav Petkov, linux-kernel, cpufreq, linux-pm, MyungJoo Ham

On 11/24/2012 04:05 AM, Rafael J. Wysocki wrote:
> On Saturday, November 17, 2012 03:50:48 PM Borislav Petkov wrote:
>> On Tue, Nov 13, 2012 at 02:13:38PM -0500, Mark Langsdorf wrote:
>>> Although cpufreq_driver has a flag field, no part of cpufreq_driver
>>> is directly passed to the cpufreq_stat code. Only cpufreq_policy
>>> is. It's cleaner to do passes of the while loop than to copy the
>>> cpufreq_driver.flag field into cpufreq_policy and then store it again
>>> in cpufreq_stats.
>>
>> That maybe so but this newly added loop which is only Calxeda-relevant
>> is called in cpufreq_stat_notifier_trans, which is the frequency change
>> notifier call, AFAICT.

Drivers only go through the loop if they can't find an exact frequency.
So every driver that isn't Calxeda shouldn't see the issue.

>> So you probably need to find a slick way of detecting calxeda hw
>> somewhere along the init path of cpufreq_stats_init and set a
>> hw-specific flag instead of adding that cost to each driver.
> 
> Mark, I suppose you'd like me to take this series for v3.8, but the above
> comment from Boris has to be addressed for that.

I think I'd rather drop this particular patch and not have cpufreq_stat
support for Highbank. Redesigning it to meet Boris' requirements is
going to take more time than I currently have available.

Would it be acceptable to drop this patch and fix the issues with
patches 4 and 6 to get the series in?

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats
  2012-11-26 13:57                   ` Mark Langsdorf
@ 2012-11-26 15:25                     ` Rafael J. Wysocki
  0 siblings, 0 replies; 142+ messages in thread
From: Rafael J. Wysocki @ 2012-11-26 15:25 UTC (permalink / raw)
  To: linux-pm
  Cc: Mark Langsdorf, Borislav Petkov, linux-kernel, cpufreq, MyungJoo Ham

On Monday, November 26, 2012 07:57:30 AM Mark Langsdorf wrote:
> On 11/24/2012 04:05 AM, Rafael J. Wysocki wrote:
> > On Saturday, November 17, 2012 03:50:48 PM Borislav Petkov wrote:
> >> On Tue, Nov 13, 2012 at 02:13:38PM -0500, Mark Langsdorf wrote:
> >>> Although cpufreq_driver has a flag field, no part of cpufreq_driver
> >>> is directly passed to the cpufreq_stat code. Only cpufreq_policy
> >>> is. It's cleaner to do passes of the while loop than to copy the
> >>> cpufreq_driver.flag field into cpufreq_policy and then store it again
> >>> in cpufreq_stats.
> >>
> >> That maybe so but this newly added loop which is only Calxeda-relevant
> >> is called in cpufreq_stat_notifier_trans, which is the frequency change
> >> notifier call, AFAICT.
> 
> Drivers only go through the loop if they can't find an exact frequency.
> So every driver that isn't Calxeda shouldn't see the issue.
> 
> >> So you probably need to find a slick way of detecting calxeda hw
> >> somewhere along the init path of cpufreq_stats_init and set a
> >> hw-specific flag instead of adding that cost to each driver.
> > 
> > Mark, I suppose you'd like me to take this series for v3.8, but the above
> > comment from Boris has to be addressed for that.
> 
> I think I'd rather drop this particular patch and not have cpufreq_stat
> support for Highbank. Redesigning it to meet Boris' requirements is
> going to take more time than I currently have available.
> 
> Would it be acceptable to drop this patch and fix the issues with
> patches 4 and 6 to get the series in?

Yes, it would, but please resubmit ASAP.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 0/6 v5] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (9 preceding siblings ...)
  2012-11-07 18:32 ` [PATCH 0/6 v4] " Mark Langsdorf
@ 2012-11-27 15:04 ` Mark Langsdorf
  2012-11-27 15:04   ` [PATCH 1/6 v5] arm: use devicetree to get smp_twd clock Mark Langsdorf
                     ` (6 more replies)
  2012-11-27 20:04 ` [PATCH 0/6 v6] " Mark Langsdorf
                   ` (6 subsequent siblings)
  17 siblings, 7 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 15:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

This patch series adds cpufreq support for the Calxeda
ECX-1000 (highbank) SoCs. The driver is based on the 
cpufreq-cpu0 driver. Because of the unique way that 
highbank uses the EnergyCore Management Engine to manage
voltages, it was not possible to use the cpufreq-cpu0 driver.

--Mark Langsdorf


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/6 v5] arm: use devicetree to get smp_twd clock
  2012-11-27 15:04 ` [PATCH 0/6 v5] " Mark Langsdorf
@ 2012-11-27 15:04   ` Mark Langsdorf
  2012-11-27 15:04   ` [PATCH 2/6 v5] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 15:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v4
	None.
Changes from v3
        No longer setting *clk to NULL in twd_get_clock().
Changes from v2
        Turned the check for the node pointer into an if-then-else statement.
        Removed the second, redundant clk_get_rate.
Changes from v1
        None.

 arch/arm/kernel/smp_twd.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index b22d700..af46b80 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -237,12 +237,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static struct clk *twd_get_clock(struct device_node *np)
 {
 	struct clk *clk;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
+	if (np)
+		clk = of_clk_get(np, 0);
+	else
+		clk = clk_get_sys("smp_twd", NULL);
 	if (IS_ERR(clk)) {
 		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
 		return clk;
@@ -263,6 +266,7 @@ static struct clk *twd_get_clock(void)
 		return ERR_PTR(err);
 	}
 
+	twd_timer_rate = clk_get_rate(clk);
 	return clk;
 }
 
@@ -273,12 +277,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
 	struct clock_event_device **this_cpu_clk;
 
-	if (!twd_clk)
-		twd_clk = twd_get_clock();
-
-	if (!IS_ERR_OR_NULL(twd_clk))
-		twd_timer_rate = clk_get_rate(twd_clk);
-	else
+	if (IS_ERR_OR_NULL(twd_clk))
 		twd_calibrate_rate();
 
 	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
@@ -349,6 +348,8 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
+	twd_clk = twd_get_clock(NULL);
+
 	return twd_local_timer_common_register();
 }
 
@@ -383,6 +384,8 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
+	twd_clk = twd_get_clock(np);
+
 	err = twd_local_timer_common_register();
 
 out:
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/6 v5] clk, highbank: Prevent glitches in non-bypass reset mode
  2012-11-27 15:04 ` [PATCH 0/6 v5] " Mark Langsdorf
  2012-11-27 15:04   ` [PATCH 1/6 v5] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2012-11-27 15:04   ` Mark Langsdorf
  2012-11-27 18:15     ` Mike Turquette
  2012-11-27 15:04   ` [PATCH 3/6 v5] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 15:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring, mturquette

The highbank clock will glitch with the current code if the
clock rate is reset without relocking the PLL. Program the PLL
correctly to prevent glitches.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: mturquette@linaro.org
---
Changes from v4
	None.
Changes from v3
        Changelog text and patch name now correspond to the actual patch.
        was clk, highbank: remove non-bypass reset mode.
Changes from v2
        None.
Changes from v1:
        Removed erroneous reformating.

 drivers/clk/clk-highbank.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..3a0b723 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/6 v5] cpufreq: tolerate inexact values when collecting stats
  2012-11-27 15:04 ` [PATCH 0/6 v5] " Mark Langsdorf
  2012-11-27 15:04   ` [PATCH 1/6 v5] arm: use devicetree to get smp_twd clock Mark Langsdorf
  2012-11-27 15:04   ` [PATCH 2/6 v5] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2012-11-27 15:04   ` Mark Langsdorf
  2012-11-27 15:04   ` [PATCH 4/6 v5] arm highbank: add support for pl320 IPC Mark Langsdorf
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 15:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

This patch is withdrawn due to a need for severe rework.

Changes from v4
	Withdrawn.	
Changes from v3, v2
        None.
Changes from v1
        Implemented a simple round-up algorithm instead of the over/under
method that could cause errors on Intel processors with boost mode.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 4/6 v5] arm highbank: add support for pl320 IPC
  2012-11-27 15:04 ` [PATCH 0/6 v5] " Mark Langsdorf
                     ` (2 preceding siblings ...)
  2012-11-27 15:04   ` [PATCH 3/6 v5] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
@ 2012-11-27 15:04   ` Mark Langsdorf
  2012-11-27 16:12     ` Thomas Petazzoni
  2012-11-27 15:04   ` [PATCH 5/6 v5] power: export opp cpufreq functions Mark Langsdorf
                     ` (2 subsequent siblings)
  6 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 15:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring, Omar Ramirez Luna, Arnd Bergmann

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the highbank A9
and the EnergyCore Management Engine. The pl320 implements a straightforward
mailbox protocol.

This patch depends on Omar Ramirez Luna's <omar.luna@linaro.org>
mailbox driver patch series.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Omar Ramirez Luna <omar.luna@linaro.org>
Cc: Arnd Bergmann <arnd@arndb.de>
---
Changes from v4
	Moved pl320-ipc.c from arch/arm/mach-highbank to drivers/mailbox.
	Moved header information to include/linux/mailbox.h.
	Added Kconfig options to reflect the new code location.
	Change drivers/mailbox/Makefile to build the omap mailboxes only 
	when they are configured.
	Removed ipc_call_fast and renamed ipc_call_slow ipc_transmit
Changes from v3, v2
        None.
Changes from v1
        Removed erroneous changes for cpufreq Kconfig.

 arch/arm/mach-highbank/Kconfig |   2 +
 drivers/mailbox/Kconfig        |   9 ++
 drivers/mailbox/Makefile       |   4 +
 drivers/mailbox/pl320-ipc.c    | 197 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mailbox.h        |  19 +++-
 5 files changed, 230 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mailbox/Makefile
 create mode 100644 drivers/mailbox/pl320-ipc.c

diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 0e1d0a4..2896881 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -11,5 +11,7 @@ config ARCH_HIGHBANK
 	select GENERIC_CLOCKEVENTS
 	select HAVE_ARM_SCU
 	select HAVE_SMP
+	select MAILBOX
+	select PL320_MBOX
 	select SPARSE_IRQ
 	select USE_OF
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index be8cac0..e89fdb4 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -34,4 +34,13 @@ config OMAP_MBOX_KFIFO_SIZE
 	  This can also be changed at runtime (via the mbox_kfifo_size
 	  module parameter).
 
+config PL320_MBOX
+	bool "ARM PL320 Mailbox"
+	help
+	  An implementation of the ARM PL320 Interprocessor Communication
+	  Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to
+	  send short messages between Highbank's A9 cores and the EnergyCore
+	  Management Engine, primarily for cpufreq. Say Y here if you want
+	  to use the PL320 IPCM support.
+
 endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
new file mode 100644
index 0000000..c9f14c3
--- /dev/null
+++ b/drivers/mailbox/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_OMAP1_MBOX)	+= mailbox.o mailbox-omap1.o
+obj-$(CONFIG_OMAP2PLUS_MBOX)	+= mailbox.o mailbox-omap2.o
+obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
+
diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
new file mode 100644
index 0000000..33eb97f
--- /dev/null
+++ b/drivers/mailbox/pl320-ipc.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <linux/mailbox.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_TX_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int ipc_transmit(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_TX_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_TX_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL(ipc_transmit);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+
+static int __devinit pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_TX_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
diff --git a/include/linux/mailbox.h b/include/linux/mailbox.h
index e8e4131..ac50a03 100644
--- a/include/linux/mailbox.h
+++ b/include/linux/mailbox.h
@@ -1,4 +1,16 @@
-/* mailbox.h */
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 typedef u32 mbox_msg_t;
 struct omap_mbox;
@@ -20,3 +32,8 @@ void omap_mbox_save_ctx(struct omap_mbox *mbox);
 void omap_mbox_restore_ctx(struct omap_mbox *mbox);
 void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
 void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+
+int ipc_transmit(u32 *data);
+
+extern int pl320_ipc_register_notifier(struct notifier_block *nb);
+extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 5/6 v5] power: export opp cpufreq functions
  2012-11-27 15:04 ` [PATCH 0/6 v5] " Mark Langsdorf
                     ` (3 preceding siblings ...)
  2012-11-27 15:04   ` [PATCH 4/6 v5] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2012-11-27 15:04   ` Mark Langsdorf
  2012-11-27 15:04   ` [PATCH 6/6 v5] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  2012-11-27 19:04   ` [PATCH 0/6 v5] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 15:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

These functions are needed to make the cpufreq-core0 and highbank-cpufreq
drivers loadable as modules.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Acked-by: Nishanth Menon <nm@ti.com>
---
Changes from v4
	None.
Changes from v3
        includes linux/export.h instead of module.h.
Changes from v2
        None.
Changes from v1
        Added Nishanth Menon's ack.
        Clarified the purpose of the change in the commit message.

 drivers/base/power/opp.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index d946864..4062ec3 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -23,6 +23,7 @@
 #include <linux/rcupdate.h>
 #include <linux/opp.h>
 #include <linux/of.h>
+#include <linux/export.h>
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -643,6 +644,7 @@ int opp_init_cpufreq_table(struct device *dev,
 
 	return 0;
 }
+EXPORT_SYMBOL(opp_init_cpufreq_table);
 
 /**
  * opp_free_cpufreq_table() - free the cpufreq table
@@ -660,6 +662,7 @@ void opp_free_cpufreq_table(struct device *dev,
 	kfree(*table);
 	*table = NULL;
 }
+EXPORT_SYMBOL(opp_free_cpufreq_table);
 #endif		/* CONFIG_CPU_FREQ */
 
 /**
@@ -720,4 +723,5 @@ int of_init_opp_table(struct device *dev)
 
 	return 0;
 }
+EXPORT_SYMBOL(of_init_opp_table);
 #endif
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 6/6 v5] cpufreq, highbank: add support for highbank cpufreq
  2012-11-27 15:04 ` [PATCH 0/6 v5] " Mark Langsdorf
                     ` (4 preceding siblings ...)
  2012-11-27 15:04   ` [PATCH 5/6 v5] power: export opp cpufreq functions Mark Langsdorf
@ 2012-11-27 15:04   ` Mark Langsdorf
  2012-11-27 19:04   ` [PATCH 0/6 v5] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 15:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, devicetree-discuss

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
A9 cores and the ECME happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: devicetree-discuss@lists.ozlabs.org
---
Changes from v4
	Removed erroneous changes to arch/arm/Kconfig.
	Removed unnecessary changes to drivers/cpufreq/Kconfig.arm
	Alphabetized additions to arch/arm/mach-highbank/Kconfig
	Changed ipc call and header to match new ipc location in 
	drivers/mailbox.
Changes from v3
        None.
Changes from v2
        Changed transition latency binding in code to match documentation.
Changes from v1
        Added highbank specific Kconfig changes.

 .../bindings/cpufreq/highbank-cpufreq.txt          |  53 +++++
 arch/arm/boot/dts/highbank.dts                     |  10 +
 arch/arm/mach-highbank/Kconfig                     |   2 +
 drivers/cpufreq/Kconfig.arm                        |  13 ++
 drivers/cpufreq/Makefile                           |   1 +
 drivers/cpufreq/highbank-cpufreq.c                 | 229 +++++++++++++++++++++
 6 files changed, 308 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
new file mode 100644
index 0000000..1d5a836
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
@@ -0,0 +1,53 @@
+Highbank cpufreq driver
+
+This is cpufreq driver for Calxeda ECX-1000 (highbank) processor. It is based
+on the generic cpu0 driver and uses a similar format for bindings. Since
+the EnergyCore Management Engine maintains the voltage based on the
+frequency, the voltage component of the operating points can be set to any
+arbitrary values.
+
+Both required properties listed below must be defined under node /cpus/cpu@0.
+
+Required properties:
+- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+  for details
+- transition-latency: Specify the possible maximum transition latency for clock,
+  in unit of nanoseconds.
+
+Examples:
+
+cpus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cpu@0 {
+		compatible = "arm,cortex-a9";
+		reg = <0>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz  ignored */
+			790000  1000000
+			396000  1000000
+			198000  1000000
+		>;
+		transition-latency = <200000>;
+	};
+
+	cpu@1 {
+		compatible = "arm,cortex-a9";
+		reg = <1>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@2 {
+		compatible = "arm,cortex-a9";
+		reg = <2>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@3 {
+		compatible = "arm,cortex-a9";
+		reg = <3>;
+		next-level-cache = <&L2>;
+	};
+};
diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 0c6fc34..8624c94 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -36,6 +36,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			transition-latency = <100000>;
 		};
 
 		cpu@1 {
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 2896881..b7862da 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -1,5 +1,7 @@
 config ARCH_HIGHBANK
 	bool "Calxeda ECX-1000 (Highbank)" if ARCH_MULTI_V7
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_GIC
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 5961e64..7a8bcdc 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -76,3 +76,16 @@ config ARM_EXYNOS5250_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
+
+config ARM_HIGHBANK_CPUFREQ
+       tristate "Calxeda Highbank-based"
+       depends on ARCH_HIGHBANK
+       select CPU_FREQ_TABLE
+       select PM_OPP
+       default m
+       help
+         This adds the CPUFreq driver for Calxeda Highbank SoC
+         based boards.
+
+         If in doubt, say N.
+
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 1bc90e1..9e8f12a 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..f2ac342
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * derived from cpufreq-cpu0 by Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <linux/mailbox.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE 0x80000001
+
+static unsigned int transition_latency;
+
+static struct device *cpu_dev;
+static struct clk *cpu_clk;
+static struct cpufreq_frequency_table *freq_table;
+
+static int hb_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int hb_get_speed(unsigned int cpu)
+{
+	return clk_get_rate(cpu_clk) / 1000;
+}
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[7];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000;
+	for (i = 2; i < 7; i++)
+		msg[i] = 0;
+
+	return ipc_transmit(msg);
+}
+
+static int hb_set_target(struct cpufreq_policy *policy,
+			   unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned long freq_Hz;
+	unsigned int index, cpu;
+	int ret;
+
+	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+					     relation, &index);
+	if (ret) {
+		pr_err("failed to match target freqency %d: %d\n",
+		       target_freq, ret);
+		return ret;
+	}
+
+	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
+	if (freq_Hz < 0)
+		freq_Hz = freq_table[index].frequency * 1000;
+	freqs.new = freq_Hz / 1000;
+	freqs.old = clk_get_rate(cpu_clk) / 1000;
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	pr_debug("%u MHz --> %u MHz\n", freqs.old / 1000, freqs.new / 1000);
+
+	/* scaling up?  scale voltage before frequency */
+	if (freqs.new > freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+	if (ret) {
+		pr_err("failed to set clock rate: %d\n", ret);
+		hb_voltage_change(freqs.old);
+		return ret;
+	}
+
+	/* scaling down?  scale voltage after frequency */
+	if (freqs.new < freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			if (clk_set_rate(cpu_clk, freqs.old * 1000))
+				pr_err("also failed to reset freq\n");
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	return 0;
+}
+
+static int hb_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	if (ret) {
+		pr_err("invalid frequency table: %d\n", ret);
+		return ret;
+	}
+
+	policy->cpuinfo.transition_latency = transition_latency;
+	policy->cur = clk_get_rate(cpu_clk) / 1000;
+
+	policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+	cpumask_setall(policy->cpus);
+
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int hb_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	return 0;
+}
+
+static struct freq_attr *hb_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver hb_cpufreq_driver = {
+	.flags = CPUFREQ_STICKY,
+	.verify = hb_verify_speed,
+	.target = hb_set_target,
+	.get = hb_get_speed,
+	.init = hb_cpufreq_init,
+	.exit = hb_cpufreq_exit,
+	.name = "highbank-cpufreq",
+	.attr = hb_cpufreq_attr,
+};
+
+static int __devinit hb_cpufreq_driver_init(void)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = of_init_opp_table(cpu_dev);
+	if (ret) {
+		pr_err("failed to init OPP table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
+	if (ret) {
+		pr_err("failed to init cpufreq table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	if (of_property_read_u32(np, "transition-latency", &transition_latency))
+		transition_latency = CPUFREQ_ETERNAL;
+
+	ret = cpufreq_register_driver(&hb_cpufreq_driver);
+	if (ret) {
+		pr_err("failed register driver: %d\n", ret);
+		goto out_free_table;
+	}
+
+	of_node_put(np);
+	return 0;
+
+out_free_table:
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 4/6 v5] arm highbank: add support for pl320 IPC
  2012-11-27 15:04   ` [PATCH 4/6 v5] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2012-11-27 16:12     ` Thomas Petazzoni
  2012-11-27 19:53       ` Mark Langsdorf
       [not found]       ` <1354602789308-564771.post@n7.nabble.com>
  0 siblings, 2 replies; 142+ messages in thread
From: Thomas Petazzoni @ 2012-11-27 16:12 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel,
	Omar Ramirez Luna, Arnd Bergmann, Rob Herring

Dear Mark Langsdorf,

On Tue, 27 Nov 2012 09:04:32 -0600, Mark Langsdorf wrote:

> +int ipc_transmit(u32 *data);

ipc_transmit() looks to me like a way to generic name to be exposed to
the entire kernel.

> +extern int pl320_ipc_register_notifier(struct notifier_block *nb);
> +extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);

Why some "extern" here? You don't have these for the other functions in
this header file.

Thomas
-- 
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 2/6 v5] clk, highbank: Prevent glitches in non-bypass reset mode
  2012-11-27 15:04   ` [PATCH 2/6 v5] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2012-11-27 18:15     ` Mike Turquette
  0 siblings, 0 replies; 142+ messages in thread
From: Mike Turquette @ 2012-11-27 18:15 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, Rob Herring

On Tue, Nov 27, 2012 at 7:04 AM, Mark Langsdorf
<mark.langsdorf@calxeda.com> wrote:
>
> The highbank clock will glitch with the current code if the
> clock rate is reset without relocking the PLL. Program the PLL
> correctly to prevent glitches.
>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Cc: mturquette@linaro.org

Acked-by: Mike Turquette <mturquette@linaro.org>

Regards,
Mike

> ---
> Changes from v4
>         None.
> Changes from v3
>         Changelog text and patch name now correspond to the actual patch.
>         was clk, highbank: remove non-bypass reset mode.
> Changes from v2
>         None.
> Changes from v1:
>         Removed erroneous reformating.
>
>  drivers/clk/clk-highbank.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
> index 52fecad..3a0b723 100644
> --- a/drivers/clk/clk-highbank.c
> +++ b/drivers/clk/clk-highbank.c
> @@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
>                 reg |= HB_PLL_EXT_ENA;
>                 reg &= ~HB_PLL_EXT_BYPASS;
>         } else {
> +               writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
>                 reg &= ~HB_PLL_DIVQ_MASK;
>                 reg |= divq << HB_PLL_DIVQ_SHIFT;
> +               writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
>         }
>         writel(reg, hbclk->reg);
>
> --
> 1.7.11.7
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 0/6 v5] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-11-27 15:04 ` [PATCH 0/6 v5] " Mark Langsdorf
                     ` (5 preceding siblings ...)
  2012-11-27 15:04   ` [PATCH 6/6 v5] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2012-11-27 19:04   ` Rafael J. Wysocki
  6 siblings, 0 replies; 142+ messages in thread
From: Rafael J. Wysocki @ 2012-11-27 19:04 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-pm, linux-kernel, cpufreq, linux-arm-kernel, Thomas Petazzoni

On Tuesday, November 27, 2012 09:04:28 AM Mark Langsdorf wrote:
> This patch series adds cpufreq support for the Calxeda
> ECX-1000 (highbank) SoCs. The driver is based on the 
> cpufreq-cpu0 driver. Because of the unique way that 
> highbank uses the EnergyCore Management Engine to manage
> voltages, it was not possible to use the cpufreq-cpu0 driver.

Well, Thomas still seems to be unhappy with [4/6], although those don't seem
to be essential points.

Can you please address his comments?

I can't promise I'll take it to my first pull request during the upcoming merge
window, but it looks like there will be a second one anyway.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 4/6 v5] arm highbank: add support for pl320 IPC
  2012-11-27 16:12     ` Thomas Petazzoni
@ 2012-11-27 19:53       ` Mark Langsdorf
       [not found]       ` <1354602789308-564771.post@n7.nabble.com>
  1 sibling, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 19:53 UTC (permalink / raw)
  To: Thomas Petazzoni
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel,
	Omar Ramirez Luna, Arnd Bergmann, Rob Herring

On 11/27/2012 10:12 AM, Thomas Petazzoni wrote:
> Dear Mark Langsdorf,
> 
> On Tue, 27 Nov 2012 09:04:32 -0600, Mark Langsdorf wrote:
> 
>> +int ipc_transmit(u32 *data);
> 
> ipc_transmit() looks to me like a way to generic name to be exposed to
> the entire kernel.

Good point. Changed to pl320_ipc_transmit()

>> +extern int pl320_ipc_register_notifier(struct notifier_block *nb);
>> +extern int pl320_ipc_unregister_notifier(struct notifier_block *nb);
> 
> Why some "extern" here? You don't have these for the other functions in
> this header file.

Nice catch. Fixed to export them in cpufreq.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 0/6 v6] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (10 preceding siblings ...)
  2012-11-27 15:04 ` [PATCH 0/6 v5] " Mark Langsdorf
@ 2012-11-27 20:04 ` Mark Langsdorf
  2012-11-27 20:04   ` [PATCH 1/6 v6] arm: use devicetree to get smp_twd clock Mark Langsdorf
                     ` (5 more replies)
  2012-12-04 14:33 ` [PATCH 0/6 v7] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (5 subsequent siblings)
  17 siblings, 6 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 20:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

This patch series adds cpufreq support for the Calxeda
ECX-1000 (highbank) SoCs. The driver is based on the 
cpufreq-cpu0 driver. Because of the unique way that 
highbank uses the EnergyCore Management Engine to manage
voltages, it was not possible to use the cpufreq-cpu0 driver.

--Mark Langsdorf


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/6 v6] arm: use devicetree to get smp_twd clock
  2012-11-27 20:04 ` [PATCH 0/6 v6] " Mark Langsdorf
@ 2012-11-27 20:04   ` Mark Langsdorf
  2012-11-27 20:04   ` [PATCH 2/6 v6] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 20:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v4, v5
        None.
Changes from v3
        No longer setting *clk to NULL in twd_get_clock().
Changes from v2
        Turned the check for the node pointer into an if-then-else statement.
        Removed the second, redundant clk_get_rate.
Changes from v1
        None.

 arch/arm/kernel/smp_twd.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index b22d700..af46b80 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -237,12 +237,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static struct clk *twd_get_clock(struct device_node *np)
 {
 	struct clk *clk;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
+	if (np)
+		clk = of_clk_get(np, 0);
+	else
+		clk = clk_get_sys("smp_twd", NULL);
 	if (IS_ERR(clk)) {
 		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
 		return clk;
@@ -263,6 +266,7 @@ static struct clk *twd_get_clock(void)
 		return ERR_PTR(err);
 	}
 
+	twd_timer_rate = clk_get_rate(clk);
 	return clk;
 }
 
@@ -273,12 +277,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
 	struct clock_event_device **this_cpu_clk;
 
-	if (!twd_clk)
-		twd_clk = twd_get_clock();
-
-	if (!IS_ERR_OR_NULL(twd_clk))
-		twd_timer_rate = clk_get_rate(twd_clk);
-	else
+	if (IS_ERR_OR_NULL(twd_clk))
 		twd_calibrate_rate();
 
 	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
@@ -349,6 +348,8 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
+	twd_clk = twd_get_clock(NULL);
+
 	return twd_local_timer_common_register();
 }
 
@@ -383,6 +384,8 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
+	twd_clk = twd_get_clock(np);
+
 	err = twd_local_timer_common_register();
 
 out:
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/6 v6] clk, highbank: Prevent glitches in non-bypass reset mode
  2012-11-27 20:04 ` [PATCH 0/6 v6] " Mark Langsdorf
  2012-11-27 20:04   ` [PATCH 1/6 v6] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2012-11-27 20:04   ` Mark Langsdorf
  2012-11-27 20:04   ` [PATCH 3/6 v6] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 20:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

The highbank clock will glitch with the current code if the
clock rate is reset without relocking the PLL. Program the PLL
correctly to prevent glitches.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
---
Changes from v5
	Added Mike Turquette's ack.
Changes from v4
        None.
Changes from v3
        Changelog text and patch name now correspond to the actual patch.
        was clk, highbank: remove non-bypass reset mode.
Changes from v2
        None.
Changes from v1:
        Removed erroneous reformating.

 drivers/clk/clk-highbank.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..3a0b723 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/6 v6] cpufreq: tolerate inexact values when collecting stats
  2012-11-27 20:04 ` [PATCH 0/6 v6] " Mark Langsdorf
  2012-11-27 20:04   ` [PATCH 1/6 v6] arm: use devicetree to get smp_twd clock Mark Langsdorf
  2012-11-27 20:04   ` [PATCH 2/6 v6] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2012-11-27 20:04   ` Mark Langsdorf
  2012-11-27 20:04   ` [PATCH 4/6 v6] arm highbank: add support for pl320 IPC Mark Langsdorf
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 20:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

This patch is withdrawn due to a need for severe rework.

Changes from v4
        Withdrawn.      
Changes from v3, v2
        None.
Changes from v1
        Implemented a simple round-up algorithm instead of the over/under
method that could cause errors on Intel processors with boost mode.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 4/6 v6] arm highbank: add support for pl320 IPC
  2012-11-27 20:04 ` [PATCH 0/6 v6] " Mark Langsdorf
                     ` (2 preceding siblings ...)
  2012-11-27 20:04   ` [PATCH 3/6 v6] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
@ 2012-11-27 20:04   ` Mark Langsdorf
  2012-11-27 20:04   ` [PATCH 5/6 v6] power: export opp cpufreq functions Mark Langsdorf
  2012-11-27 20:04   ` [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 20:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring, Omar Ramirez Luna, Arnd Bergmann

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the highbank A9
and the EnergyCore Management Engine. The pl320 implements a straightforward
mailbox protocol.

This patch depends on Omar Ramirez Luna's <omar.luna@linaro.org>
mailbox driver patch series.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Omar Ramirez Luna <omar.luna@linaro.org>
Cc: Arnd Bergmann <arnd@arndb.de>
---
Changes from v5
	Renamed ipc_transmit() to pl320_ipc_transmit().
	Properly exported pl320_ipc_{un}register_notifier().
Changes from v4
        Moved pl320-ipc.c from arch/arm/mach-highbank to drivers/mailbox.
        Moved header information to include/linux/mailbox.h.
        Added Kconfig options to reflect the new code location.
        Change drivers/mailbox/Makefile to build the omap mailboxes only 
        when they are configured.
        Removed ipc_call_fast and renamed ipc_call_slow ipc_transmit.
Changes from v3, v2
        None.
Changes from v1
        Removed erroneous changes for cpufreq Kconfig.


 arch/arm/mach-highbank/Kconfig |   2 +
 drivers/mailbox/Kconfig        |   9 ++
 drivers/mailbox/Makefile       |   4 +
 drivers/mailbox/pl320-ipc.c    | 199 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mailbox.h        |  19 +++-
 5 files changed, 232 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mailbox/Makefile
 create mode 100644 drivers/mailbox/pl320-ipc.c

diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 0e1d0a4..2896881 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -11,5 +11,7 @@ config ARCH_HIGHBANK
 	select GENERIC_CLOCKEVENTS
 	select HAVE_ARM_SCU
 	select HAVE_SMP
+	select MAILBOX
+	select PL320_MBOX
 	select SPARSE_IRQ
 	select USE_OF
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index be8cac0..e89fdb4 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -34,4 +34,13 @@ config OMAP_MBOX_KFIFO_SIZE
 	  This can also be changed at runtime (via the mbox_kfifo_size
 	  module parameter).
 
+config PL320_MBOX
+	bool "ARM PL320 Mailbox"
+	help
+	  An implementation of the ARM PL320 Interprocessor Communication
+	  Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to
+	  send short messages between Highbank's A9 cores and the EnergyCore
+	  Management Engine, primarily for cpufreq. Say Y here if you want
+	  to use the PL320 IPCM support.
+
 endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
new file mode 100644
index 0000000..c9f14c3
--- /dev/null
+++ b/drivers/mailbox/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_OMAP1_MBOX)	+= mailbox.o mailbox-omap1.o
+obj-$(CONFIG_OMAP2PLUS_MBOX)	+= mailbox.o mailbox-omap2.o
+obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
+
diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
new file mode 100644
index 0000000..1a9d8e4
--- /dev/null
+++ b/drivers/mailbox/pl320-ipc.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <linux/mailbox.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_TX_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int pl320_ipc_transmit(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_TX_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_TX_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL(pl320_ipc_transmit);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_register_notifier);
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_unregister_notifier);
+
+static int __devinit pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_TX_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
diff --git a/include/linux/mailbox.h b/include/linux/mailbox.h
index e8e4131..e7829e5 100644
--- a/include/linux/mailbox.h
+++ b/include/linux/mailbox.h
@@ -1,4 +1,16 @@
-/* mailbox.h */
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 typedef u32 mbox_msg_t;
 struct omap_mbox;
@@ -20,3 +32,8 @@ void omap_mbox_save_ctx(struct omap_mbox *mbox);
 void omap_mbox_restore_ctx(struct omap_mbox *mbox);
 void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
 void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+
+int pl320_ipc_transmit(u32 *data);
+int pl320_ipc_register_notifier(struct notifier_block *nb);
+int pl320_ipc_unregister_notifier(struct notifier_block *nb);
+
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 5/6 v6] power: export opp cpufreq functions
  2012-11-27 20:04 ` [PATCH 0/6 v6] " Mark Langsdorf
                     ` (3 preceding siblings ...)
  2012-11-27 20:04   ` [PATCH 4/6 v6] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2012-11-27 20:04   ` Mark Langsdorf
  2012-11-27 20:04   ` [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 20:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

These functions are needed to make the cpufreq-core0 and highbank-cpufreq
drivers loadable as modules.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Acked-by: Nishanth Menon <nm@ti.com>
---
Changes from v4, v5
        None.
Changes from v3
        includes linux/export.h instead of module.h.
Changes from v2
        None.
Changes from v1
        Added Nishanth Menon's ack.
        Clarified the purpose of the change in the commit message.

 drivers/base/power/opp.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index d946864..4062ec3 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -23,6 +23,7 @@
 #include <linux/rcupdate.h>
 #include <linux/opp.h>
 #include <linux/of.h>
+#include <linux/export.h>
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -643,6 +644,7 @@ int opp_init_cpufreq_table(struct device *dev,
 
 	return 0;
 }
+EXPORT_SYMBOL(opp_init_cpufreq_table);
 
 /**
  * opp_free_cpufreq_table() - free the cpufreq table
@@ -660,6 +662,7 @@ void opp_free_cpufreq_table(struct device *dev,
 	kfree(*table);
 	*table = NULL;
 }
+EXPORT_SYMBOL(opp_free_cpufreq_table);
 #endif		/* CONFIG_CPU_FREQ */
 
 /**
@@ -720,4 +723,5 @@ int of_init_opp_table(struct device *dev)
 
 	return 0;
 }
+EXPORT_SYMBOL(of_init_opp_table);
 #endif
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-27 20:04 ` [PATCH 0/6 v6] " Mark Langsdorf
                     ` (4 preceding siblings ...)
  2012-11-27 20:04   ` [PATCH 5/6 v6] power: export opp cpufreq functions Mark Langsdorf
@ 2012-11-27 20:04   ` Mark Langsdorf
  2012-11-28  2:32     ` Shawn Guo
  5 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-27 20:04 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, devicetree-discuss

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
A9 cores and the ECME happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: devicetree-discuss@lists.ozlabs.org
---
Changes from v5
	Changed ipc_transmit() to pl320_ipc_transmit().
Changes from v4
        Removed erroneous changes to arch/arm/Kconfig.
        Removed unnecessary changes to drivers/cpufreq/Kconfig.arm
        Alphabetized additions to arch/arm/mach-highbank/Kconfig
        Changed ipc call and header to match new ipc location in 
        drivers/mailbox.
Changes from v3
        None.
Changes from v2
        Changed transition latency binding in code to match documentation.
Changes from v1
        Added highbank specific Kconfig changes.

 .../bindings/cpufreq/highbank-cpufreq.txt          |  53 +++++
 arch/arm/boot/dts/highbank.dts                     |  10 +
 arch/arm/mach-highbank/Kconfig                     |   2 +
 drivers/cpufreq/Kconfig.arm                        |  13 ++
 drivers/cpufreq/Makefile                           |   1 +
 drivers/cpufreq/highbank-cpufreq.c                 | 229 +++++++++++++++++++++
 6 files changed, 308 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
new file mode 100644
index 0000000..1d5a836
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt
@@ -0,0 +1,53 @@
+Highbank cpufreq driver
+
+This is cpufreq driver for Calxeda ECX-1000 (highbank) processor. It is based
+on the generic cpu0 driver and uses a similar format for bindings. Since
+the EnergyCore Management Engine maintains the voltage based on the
+frequency, the voltage component of the operating points can be set to any
+arbitrary values.
+
+Both required properties listed below must be defined under node /cpus/cpu@0.
+
+Required properties:
+- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+  for details
+- transition-latency: Specify the possible maximum transition latency for clock,
+  in unit of nanoseconds.
+
+Examples:
+
+cpus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cpu@0 {
+		compatible = "arm,cortex-a9";
+		reg = <0>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz  ignored */
+			790000  1000000
+			396000  1000000
+			198000  1000000
+		>;
+		transition-latency = <200000>;
+	};
+
+	cpu@1 {
+		compatible = "arm,cortex-a9";
+		reg = <1>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@2 {
+		compatible = "arm,cortex-a9";
+		reg = <2>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@3 {
+		compatible = "arm,cortex-a9";
+		reg = <3>;
+		next-level-cache = <&L2>;
+	};
+};
diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 0c6fc34..8624c94 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -36,6 +36,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			transition-latency = <100000>;
 		};
 
 		cpu@1 {
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 2896881..b7862da 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -1,5 +1,7 @@
 config ARCH_HIGHBANK
 	bool "Calxeda ECX-1000 (Highbank)" if ARCH_MULTI_V7
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_GIC
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 5961e64..7a8bcdc 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -76,3 +76,16 @@ config ARM_EXYNOS5250_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
+
+config ARM_HIGHBANK_CPUFREQ
+       tristate "Calxeda Highbank-based"
+       depends on ARCH_HIGHBANK
+       select CPU_FREQ_TABLE
+       select PM_OPP
+       default m
+       help
+         This adds the CPUFreq driver for Calxeda Highbank SoC
+         based boards.
+
+         If in doubt, say N.
+
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 1bc90e1..9e8f12a 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..878d3ff
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * derived from cpufreq-cpu0 by Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <linux/mailbox.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE 0x80000001
+
+static unsigned int transition_latency;
+
+static struct device *cpu_dev;
+static struct clk *cpu_clk;
+static struct cpufreq_frequency_table *freq_table;
+
+static int hb_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int hb_get_speed(unsigned int cpu)
+{
+	return clk_get_rate(cpu_clk) / 1000;
+}
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[7];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000;
+	for (i = 2; i < 7; i++)
+		msg[i] = 0;
+
+	return pl320_ipc_transmit(msg);
+}
+
+static int hb_set_target(struct cpufreq_policy *policy,
+			   unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned long freq_Hz;
+	unsigned int index, cpu;
+	int ret;
+
+	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+					     relation, &index);
+	if (ret) {
+		pr_err("failed to match target freqency %d: %d\n",
+		       target_freq, ret);
+		return ret;
+	}
+
+	freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
+	if (freq_Hz < 0)
+		freq_Hz = freq_table[index].frequency * 1000;
+	freqs.new = freq_Hz / 1000;
+	freqs.old = clk_get_rate(cpu_clk) / 1000;
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	pr_debug("%u MHz --> %u MHz\n", freqs.old / 1000, freqs.new / 1000);
+
+	/* scaling up?  scale voltage before frequency */
+	if (freqs.new > freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+	if (ret) {
+		pr_err("failed to set clock rate: %d\n", ret);
+		hb_voltage_change(freqs.old);
+		return ret;
+	}
+
+	/* scaling down?  scale voltage after frequency */
+	if (freqs.new < freqs.old) {
+		ret = hb_voltage_change(freqs.new);
+		if (ret) {
+			if (clk_set_rate(cpu_clk, freqs.old * 1000))
+				pr_err("also failed to reset freq\n");
+			freqs.new = freqs.old;
+			return -EAGAIN;
+		}
+	}
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	return 0;
+}
+
+static int hb_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	if (ret) {
+		pr_err("invalid frequency table: %d\n", ret);
+		return ret;
+	}
+
+	policy->cpuinfo.transition_latency = transition_latency;
+	policy->cur = clk_get_rate(cpu_clk) / 1000;
+
+	policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+	cpumask_setall(policy->cpus);
+
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int hb_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	return 0;
+}
+
+static struct freq_attr *hb_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver hb_cpufreq_driver = {
+	.flags = CPUFREQ_STICKY,
+	.verify = hb_verify_speed,
+	.target = hb_set_target,
+	.get = hb_get_speed,
+	.init = hb_cpufreq_init,
+	.exit = hb_cpufreq_exit,
+	.name = "highbank-cpufreq",
+	.attr = hb_cpufreq_attr,
+};
+
+static int __devinit hb_cpufreq_driver_init(void)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = of_init_opp_table(cpu_dev);
+	if (ret) {
+		pr_err("failed to init OPP table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
+	if (ret) {
+		pr_err("failed to init cpufreq table: %d\n", ret);
+		goto out_put_node;
+	}
+
+	if (of_property_read_u32(np, "transition-latency", &transition_latency))
+		transition_latency = CPUFREQ_ETERNAL;
+
+	ret = cpufreq_register_driver(&hb_cpufreq_driver);
+	if (ret) {
+		pr_err("failed register driver: %d\n", ret);
+		goto out_free_table;
+	}
+
+	of_node_put(np);
+	return 0;
+
+out_free_table:
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-27 20:04   ` [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2012-11-28  2:32     ` Shawn Guo
  2012-11-28 13:16       ` Mark Langsdorf
  0 siblings, 1 reply; 142+ messages in thread
From: Shawn Guo @ 2012-11-28  2:32 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, devicetree-discuss

On Tue, Nov 27, 2012 at 02:04:32PM -0600, Mark Langsdorf wrote:
> Highbank processors depend on the external ECME to perform voltage
> management based on a requested frequency. Communication between the
> A9 cores and the ECME happens over the pl320 IPC channel.

...

> +static int hb_voltage_change(unsigned int freq)
> +{
> +	int i;
> +	u32 msg[7];
> +
> +	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
> +	msg[1] = freq / 1000;
> +	for (i = 2; i < 7; i++)
> +		msg[i] = 0;
> +
> +	return pl320_ipc_transmit(msg);

Is it possible to have this handled inside clk_set_rate() call of cpu
clock?

Shawn

> +}


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-28  2:32     ` Shawn Guo
@ 2012-11-28 13:16       ` Mark Langsdorf
  2012-11-28 14:58         ` Shawn Guo
  0 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-28 13:16 UTC (permalink / raw)
  To: Shawn Guo
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, devicetree-discuss

On 11/27/2012 08:32 PM, Shawn Guo wrote:
> On Tue, Nov 27, 2012 at 02:04:32PM -0600, Mark Langsdorf wrote:
>> Highbank processors depend on the external ECME to perform voltage
>> management based on a requested frequency. Communication between the
>> A9 cores and the ECME happens over the pl320 IPC channel.
> 
> ...
> 
>> +static int hb_voltage_change(unsigned int freq)
>> +{
>> +	int i;
>> +	u32 msg[7];
>> +
>> +	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
>> +	msg[1] = freq / 1000;
>> +	for (i = 2; i < 7; i++)
>> +		msg[i] = 0;
>> +
>> +	return pl320_ipc_transmit(msg);
> 
> Is it possible to have this handled inside clk_set_rate() call of cpu
> clock?

Standard practice is to have cpufreq_set_target() handle voltage
transitions and leave clk_set_rate() handle the frequency changes. I'd
have to move most of the logic of hb_set_target() into
clk_highbank.c:clk_pll_set_rate() and then add extra logic for when
cpufreq is not enabled/loaded. I don't think the clk maintainers would
take that patch, either.

So no.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-28 13:16       ` Mark Langsdorf
@ 2012-11-28 14:58         ` Shawn Guo
  2012-11-28 15:17           ` Shawn Guo
  0 siblings, 1 reply; 142+ messages in thread
From: Shawn Guo @ 2012-11-28 14:58 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, devicetree-discuss

On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote:
> Standard practice is to have cpufreq_set_target() handle voltage
> transitions and leave clk_set_rate() handle the frequency changes.

The standard practice is to have cpufreq_set_target() handle both
voltage and frequency transitions, while voltage is handled by regulator
and frequency by clk API.

> I'd
> have to move most of the logic of hb_set_target() into
> clk_highbank.c:clk_pll_set_rate() and then add extra logic for when
> cpufreq is not enabled/loaded.

You only need to move hb_voltage_change() into cpu clock's .set_rate()
hook with no need of checking if cpufreq is enabled or not.

> I don't think the clk maintainers would
> take that patch, either.

This is all handled platform clock specific .set_rate() hook.  I doubt
it will concern clk maintainers at all, especially when doing so we
will avoid another cpufreq driver by just using cpufreq-cpu0 driver.

Shawn


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-28 15:17           ` Shawn Guo
@ 2012-11-28 15:01             ` Mark Langsdorf
  2012-11-28 16:01             ` Mike Turquette
  1 sibling, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-28 15:01 UTC (permalink / raw)
  To: Shawn Guo
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, devicetree-discuss

On 11/28/2012 09:17 AM, Shawn Guo wrote:
> On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote:
>> On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote:
>>> I'd
>>> have to move most of the logic of hb_set_target() into
>>> clk_highbank.c:clk_pll_set_rate() and then add extra logic for when
>>> cpufreq is not enabled/loaded.
>>
>> You only need to move hb_voltage_change() into cpu clock's .set_rate()
>> hook with no need of checking if cpufreq is enabled or not.
>>
> Need to also check whether frequency or voltage should be changed first
> in .set_rate() though.

Yes, that's entirely what I meant when I said that I would need to move
most of the hb_set_target() logic into .set_rate(). I would also need to
account for retries if the voltage set operation fails, which it
sometimes does.

The ECME handles changing the voltage but doesn't look like a voltage
regulator. Amongst other things, by design it doesn't export meaningful
voltage information to Linux. I tried to get cpufreq-clk0 to work with
the Highbank design and it ended up being much easier and more sane to
create a separate driver.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-28 14:58         ` Shawn Guo
@ 2012-11-28 15:17           ` Shawn Guo
  2012-11-28 15:01             ` Mark Langsdorf
  2012-11-28 16:01             ` Mike Turquette
  0 siblings, 2 replies; 142+ messages in thread
From: Shawn Guo @ 2012-11-28 15:17 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, devicetree-discuss

On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote:
> On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote:
> > I'd
> > have to move most of the logic of hb_set_target() into
> > clk_highbank.c:clk_pll_set_rate() and then add extra logic for when
> > cpufreq is not enabled/loaded.
> 
> You only need to move hb_voltage_change() into cpu clock's .set_rate()
> hook with no need of checking if cpufreq is enabled or not.
> 
Need to also check whether frequency or voltage should be changed first
in .set_rate() though.

Shawn


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-28 15:17           ` Shawn Guo
  2012-11-28 15:01             ` Mark Langsdorf
@ 2012-11-28 16:01             ` Mike Turquette
  2012-11-28 16:18               ` Mark Langsdorf
  2012-11-29  1:51               ` Shawn Guo
  1 sibling, 2 replies; 142+ messages in thread
From: Mike Turquette @ 2012-11-28 16:01 UTC (permalink / raw)
  To: Shawn Guo, Mark Langsdorf
  Cc: linux-arm-kernel, devicetree-discuss, linux-kernel, cpufreq, linux-pm

Quoting Shawn Guo (2012-11-28 07:17:44)
> On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote:
> > On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote:
> > > I'd
> > > have to move most of the logic of hb_set_target() into
> > > clk_highbank.c:clk_pll_set_rate() and then add extra logic for when
> > > cpufreq is not enabled/loaded.
> > 
> > You only need to move hb_voltage_change() into cpu clock's .set_rate()
> > hook with no need of checking if cpufreq is enabled or not.
> > 
> Need to also check whether frequency or voltage should be changed first
> in .set_rate() though.
> 
> Shawn
> 

The notifiers in the clk framework might be a better place for this than
just simply hacking the logic into the .set_rate callback.

I haven't looked at the definition of hb_voltage_change but does the
call graph make any clk api calls?  Are you talking over i2c to a
regulator?  If so then you'll probably hit the same reentrancy problem I
hit when trying to make a general solution.

Regards,
Mike

> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-28 16:01             ` Mike Turquette
@ 2012-11-28 16:18               ` Mark Langsdorf
  2012-11-28 21:05                 ` Mike Turquette
  2012-11-29  1:51               ` Shawn Guo
  1 sibling, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-28 16:18 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Shawn Guo, linux-arm-kernel, devicetree-discuss, linux-kernel,
	cpufreq, linux-pm

On 11/28/2012 10:01 AM, Mike Turquette wrote:
> Quoting Shawn Guo (2012-11-28 07:17:44)
>> On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote:
>>> On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote:
>>>> I'd
>>>> have to move most of the logic of hb_set_target() into
>>>> clk_highbank.c:clk_pll_set_rate() and then add extra logic for when
>>>> cpufreq is not enabled/loaded.
>>>
>>> You only need to move hb_voltage_change() into cpu clock's .set_rate()
>>> hook with no need of checking if cpufreq is enabled or not.
>>>
>> Need to also check whether frequency or voltage should be changed first
>> in .set_rate() though.
>>
>> Shawn
>>
> 
> The notifiers in the clk framework might be a better place for this than
> just simply hacking the logic into the .set_rate callback.

Unless the clk notifiers are different than the cpufreq notifiers, they
don't handle returning error conditions very well. And given that the
voltage change operation can fail (though it almost always succeeds on a
retry) I need to be able to handle and detect that error condition.

> I haven't looked at the definition of hb_voltage_change but does the
> call graph make any clk api calls?  Are you talking over i2c to a
> regulator?  If so then you'll probably hit the same reentrancy problem I
> hit when trying to make a general solution.

I'm talking over a pl320 Interprocessor Communication Mailbox to a
separate core running it's own RTOS. The RTOS might speak i2c to a
regulator but it's a black box to me.

hb_voltage_change() doesn't make any clk api calls. It changes the
voltages, and then hb_set_target() makes clk api calls to change the
frequency.

--Mark Langsdorf
Calxeda, Inc.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-28 16:18               ` Mark Langsdorf
@ 2012-11-28 21:05                 ` Mike Turquette
  2012-11-29  0:24                   ` Mark Langsdorf
  0 siblings, 1 reply; 142+ messages in thread
From: Mike Turquette @ 2012-11-28 21:05 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: Shawn Guo, linux-arm-kernel, devicetree-discuss, linux-kernel,
	cpufreq, linux-pm

Quoting Mark Langsdorf (2012-11-28 08:18:35)
> On 11/28/2012 10:01 AM, Mike Turquette wrote:
> > Quoting Shawn Guo (2012-11-28 07:17:44)
> >> On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote:
> >>> On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote:
> >>>> I'd
> >>>> have to move most of the logic of hb_set_target() into
> >>>> clk_highbank.c:clk_pll_set_rate() and then add extra logic for when
> >>>> cpufreq is not enabled/loaded.
> >>>
> >>> You only need to move hb_voltage_change() into cpu clock's .set_rate()
> >>> hook with no need of checking if cpufreq is enabled or not.
> >>>
> >> Need to also check whether frequency or voltage should be changed first
> >> in .set_rate() though.
> >>
> >> Shawn
> >>
> > 
> > The notifiers in the clk framework might be a better place for this than
> > just simply hacking the logic into the .set_rate callback.
> 
> Unless the clk notifiers are different than the cpufreq notifiers, they
> don't handle returning error conditions very well. And given that the
> voltage change operation can fail (though it almost always succeeds on a
> retry) I need to be able to handle and detect that error condition.
> 

The notifier handler can handle the case where the transition fails (and
needs to be retried).

Also you should check out the clk notifiers.  I think they handle
failure decently.  If a notifer returns an error code then everything
unrolls and the clk_set_rate operation aborts.

Regards,
Mike

> > I haven't looked at the definition of hb_voltage_change but does the
> > call graph make any clk api calls?  Are you talking over i2c to a
> > regulator?  If so then you'll probably hit the same reentrancy problem I
> > hit when trying to make a general solution.
> 
> I'm talking over a pl320 Interprocessor Communication Mailbox to a
> separate core running it's own RTOS. The RTOS might speak i2c to a
> regulator but it's a black box to me.
> 
> hb_voltage_change() doesn't make any clk api calls. It changes the
> voltages, and then hb_set_target() makes clk api calls to change the
> frequency.
> 
> --Mark Langsdorf
> Calxeda, Inc.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-28 21:05                 ` Mike Turquette
@ 2012-11-29  0:24                   ` Mark Langsdorf
  0 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-11-29  0:24 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Shawn Guo, linux-arm-kernel, devicetree-discuss, linux-kernel,
	cpufreq, linux-pm

On 11/28/2012 03:05 PM, Mike Turquette wrote:
> Quoting Mark Langsdorf (2012-11-28 08:18:35)
>> On 11/28/2012 10:01 AM, Mike Turquette wrote:
>>> Quoting Shawn Guo (2012-11-28 07:17:44)
>>>> On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote:
>>>>> On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote:
>>>>>> I'd
>>>>>> have to move most of the logic of hb_set_target() into
>>>>>> clk_highbank.c:clk_pll_set_rate() and then add extra logic for when
>>>>>> cpufreq is not enabled/loaded.
>>>>>
>>>>> You only need to move hb_voltage_change() into cpu clock's .set_rate()
>>>>> hook with no need of checking if cpufreq is enabled or not.
>>>>>
>>>> Need to also check whether frequency or voltage should be changed first
>>>> in .set_rate() though.
>>>>
>>>> Shawn
>>>>
>>>
>>> The notifiers in the clk framework might be a better place for this than
>>> just simply hacking the logic into the .set_rate callback.
>>
>> Unless the clk notifiers are different than the cpufreq notifiers, they
>> don't handle returning error conditions very well. And given that the
>> voltage change operation can fail (though it almost always succeeds on a
>> retry) I need to be able to handle and detect that error condition.
> 
> The notifier handler can handle the case where the transition fails (and
> needs to be retried).
> 
> Also you should check out the clk notifiers.  I think they handle
> failure decently.  If a notifer returns an error code then everything
> unrolls and the clk_set_rate operation aborts.

Thanks for the pointer. The clk notifier calls seem to be working with
cpufreq-cpu0.

I did enough surgery on the code that I want to run a lot of stress
tests before I resubmit. I'll try to have something for Tuesday.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-28 16:01             ` Mike Turquette
  2012-11-28 16:18               ` Mark Langsdorf
@ 2012-11-29  1:51               ` Shawn Guo
  2012-11-29  4:34                 ` Mike Turquette
  1 sibling, 1 reply; 142+ messages in thread
From: Shawn Guo @ 2012-11-29  1:51 UTC (permalink / raw)
  To: Mike Turquette
  Cc: Mark Langsdorf, linux-arm-kernel, devicetree-discuss,
	linux-kernel, cpufreq, linux-pm

> The notifiers in the clk framework might be a better place for this than
> just simply hacking the logic into the .set_rate callback.

Ah, right.  How did I forget about that nice piece?

> I haven't looked at the definition of hb_voltage_change but does the
> call graph make any clk api calls?  Are you talking over i2c to a
> regulator?  If so then you'll probably hit the same reentrancy problem I
> hit when trying to make a general solution.

So, how is your "reentrancy in the common clk framework" series[1]
going on?  Haven't seen any update since August.

Shawn

[1] http://thread.gmane.org/gmane.linux.ports.arm.kernel/182198


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq
  2012-11-29  1:51               ` Shawn Guo
@ 2012-11-29  4:34                 ` Mike Turquette
  0 siblings, 0 replies; 142+ messages in thread
From: Mike Turquette @ 2012-11-29  4:34 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Mark Langsdorf, linux-arm-kernel, devicetree-discuss,
	linux-kernel, cpufreq, linux-pm

Quoting Shawn Guo (2012-11-28 17:51:36)
> > The notifiers in the clk framework might be a better place for this than
> > just simply hacking the logic into the .set_rate callback.
> 
> Ah, right.  How did I forget about that nice piece?
> 
> > I haven't looked at the definition of hb_voltage_change but does the
> > call graph make any clk api calls?  Are you talking over i2c to a
> > regulator?  If so then you'll probably hit the same reentrancy problem I
> > hit when trying to make a general solution.
> 
> So, how is your "reentrancy in the common clk framework" series[1]
> going on?  Haven't seen any update since August.
> 

I've begun to look at a dvfs api that builds on top of the clock
framework, as opposed to using clk_set_rate as the dvfs api itself.
This eliminates the need for reentrancy, at least for the dvfs case.

I'll post more when I have it.  Honestly the reentrancy stuff was just
too ugly.  I might try again some day but for now I'm thinking a less
radical approach deserves consideration.

Thanks,
Mike

> Shawn
> 
> [1] http://thread.gmane.org/gmane.linux.ports.arm.kernel/182198

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 0/6 v7] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (11 preceding siblings ...)
  2012-11-27 20:04 ` [PATCH 0/6 v6] " Mark Langsdorf
@ 2012-12-04 14:33 ` Mark Langsdorf
  2012-12-04 14:33   ` [PATCH 1/6 v7] arm: use devicetree to get smp_twd clock Mark Langsdorf
                     ` (5 more replies)
  2012-12-05 16:48 ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (4 subsequent siblings)
  17 siblings, 6 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-04 14:33 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

This patch series adds cpufreq support for the Calxeda
ECX-1000 (highbank) SoCs. The EnergyCore Management Engine (ECME) on
the ECX-1000 manages the voltage for the part and communications with
Linux through a pl320 mailbox. clk notifications are used to control
when to send messages to the ECME.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/6 v7] arm: use devicetree to get smp_twd clock
  2012-12-04 14:33 ` [PATCH 0/6 v7] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
@ 2012-12-04 14:33   ` Mark Langsdorf
  2012-12-04 14:33   ` [PATCH 2/6 v7] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-04 14:33 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v4, v5, v6
        None.
Changes from v3
        No longer setting *clk to NULL in twd_get_clock().
Changes from v2
        Turned the check for the node pointer into an if-then-else statement.
        Removed the second, redundant clk_get_rate.
Changes from v1
        None.

 arch/arm/kernel/smp_twd.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index b22d700..af46b80 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -237,12 +237,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static struct clk *twd_get_clock(struct device_node *np)
 {
 	struct clk *clk;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
+	if (np)
+		clk = of_clk_get(np, 0);
+	else
+		clk = clk_get_sys("smp_twd", NULL);
 	if (IS_ERR(clk)) {
 		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
 		return clk;
@@ -263,6 +266,7 @@ static struct clk *twd_get_clock(void)
 		return ERR_PTR(err);
 	}
 
+	twd_timer_rate = clk_get_rate(clk);
 	return clk;
 }
 
@@ -273,12 +277,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
 	struct clock_event_device **this_cpu_clk;
 
-	if (!twd_clk)
-		twd_clk = twd_get_clock();
-
-	if (!IS_ERR_OR_NULL(twd_clk))
-		twd_timer_rate = clk_get_rate(twd_clk);
-	else
+	if (IS_ERR_OR_NULL(twd_clk))
 		twd_calibrate_rate();
 
 	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
@@ -349,6 +348,8 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
+	twd_clk = twd_get_clock(NULL);
+
 	return twd_local_timer_common_register();
 }
 
@@ -383,6 +384,8 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
+	twd_clk = twd_get_clock(np);
+
 	err = twd_local_timer_common_register();
 
 out:
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/6 v7] clk, highbank: Prevent glitches in non-bypass reset mode
  2012-12-04 14:33 ` [PATCH 0/6 v7] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2012-12-04 14:33   ` [PATCH 1/6 v7] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2012-12-04 14:33   ` Mark Langsdorf
  2012-12-04 14:33   ` [PATCH 3/6 v7] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-04 14:33 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

The highbank clock will glitch with the current code if the
clock rate is reset without relocking the PLL. Program the PLL
correctly to prevent glitches.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
---
Changes from v6
	None.
Changes from v5
        Added Mike Turquette's ack.
Changes from v4
        None.
Changes from v3
        Changelog text and patch name now correspond to the actual patch.
        was clk, highbank: remove non-bypass reset mode.
Changes from v2
        None.
Changes from v1:
        Removed erroneous reformating.

 drivers/clk/clk-highbank.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..3a0b723 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/6 v7] cpufreq: tolerate inexact values when collecting stats
  2012-12-04 14:33 ` [PATCH 0/6 v7] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2012-12-04 14:33   ` [PATCH 1/6 v7] arm: use devicetree to get smp_twd clock Mark Langsdorf
  2012-12-04 14:33   ` [PATCH 2/6 v7] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2012-12-04 14:33   ` Mark Langsdorf
  2012-12-04 14:34   ` [PATCH 4/6 v7] arm highbank: add support for pl320 IPC Mark Langsdorf
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-04 14:33 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

This patch is withdrawn due to a need for severe rework.

Changes from v4
        Withdrawn.      
Changes from v3, v2
        None.
Changes from v1
        Implemented a simple round-up algorithm instead of the over/under
method that could cause errors on Intel processors with boost mode.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 4/6 v7] arm highbank: add support for pl320 IPC
  2012-12-04 14:33 ` [PATCH 0/6 v7] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                     ` (2 preceding siblings ...)
  2012-12-04 14:33   ` [PATCH 3/6 v7] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
@ 2012-12-04 14:34   ` Mark Langsdorf
  2012-12-04 14:34   ` [PATCH 5/6 v7] power: export opp cpufreq functions Mark Langsdorf
  2012-12-04 14:34   ` [PATCH 6/6 v7] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-04 14:34 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring, Omar Ramirez Luna, Arnd Bergmann

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the highbank A9
and the EnergyCore Management Engine. The pl320 implements a straightforward
mailbox protocol.

This patch depends on Omar Ramirez Luna's <omar.luna@linaro.org>
mailbox driver patch series.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Omar Ramirez Luna <omar.luna@linaro.org>
Cc: Arnd Bergmann <arnd@arndb.de>
---
Changes from v6
	None.
Changes from v5
        Renamed ipc_transmit() to pl320_ipc_transmit().
        Properly exported pl320_ipc_{un}register_notifier().
Changes from v4
        Moved pl320-ipc.c from arch/arm/mach-highbank to drivers/mailbox.
        Moved header information to include/linux/mailbox.h.
        Added Kconfig options to reflect the new code location.
        Change drivers/mailbox/Makefile to build the omap mailboxes only 
        when they are configured.
        Removed ipc_call_fast and renamed ipc_call_slow ipc_transmit.
Changes from v3, v2
        None.
Changes from v1
        Removed erroneous changes for cpufreq Kconfig.

 arch/arm/mach-highbank/Kconfig |   2 +
 drivers/mailbox/Kconfig        |   9 ++
 drivers/mailbox/Makefile       |   4 +
 drivers/mailbox/pl320-ipc.c    | 199 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mailbox.h        |  19 +++-
 5 files changed, 232 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mailbox/Makefile
 create mode 100644 drivers/mailbox/pl320-ipc.c

diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 0e1d0a4..2896881 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -11,5 +11,7 @@ config ARCH_HIGHBANK
 	select GENERIC_CLOCKEVENTS
 	select HAVE_ARM_SCU
 	select HAVE_SMP
+	select MAILBOX
+	select PL320_MBOX
 	select SPARSE_IRQ
 	select USE_OF
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index be8cac0..e89fdb4 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -34,4 +34,13 @@ config OMAP_MBOX_KFIFO_SIZE
 	  This can also be changed at runtime (via the mbox_kfifo_size
 	  module parameter).
 
+config PL320_MBOX
+	bool "ARM PL320 Mailbox"
+	help
+	  An implementation of the ARM PL320 Interprocessor Communication
+	  Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to
+	  send short messages between Highbank's A9 cores and the EnergyCore
+	  Management Engine, primarily for cpufreq. Say Y here if you want
+	  to use the PL320 IPCM support.
+
 endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
new file mode 100644
index 0000000..c9f14c3
--- /dev/null
+++ b/drivers/mailbox/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_OMAP1_MBOX)	+= mailbox.o mailbox-omap1.o
+obj-$(CONFIG_OMAP2PLUS_MBOX)	+= mailbox.o mailbox-omap2.o
+obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
+
diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
new file mode 100644
index 0000000..1a9d8e4
--- /dev/null
+++ b/drivers/mailbox/pl320-ipc.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <linux/mailbox.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_TX_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int pl320_ipc_transmit(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_TX_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_TX_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL(pl320_ipc_transmit);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_register_notifier);
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_unregister_notifier);
+
+static int __devinit pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_TX_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
diff --git a/include/linux/mailbox.h b/include/linux/mailbox.h
index e8e4131..e7829e5 100644
--- a/include/linux/mailbox.h
+++ b/include/linux/mailbox.h
@@ -1,4 +1,16 @@
-/* mailbox.h */
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 typedef u32 mbox_msg_t;
 struct omap_mbox;
@@ -20,3 +32,8 @@ void omap_mbox_save_ctx(struct omap_mbox *mbox);
 void omap_mbox_restore_ctx(struct omap_mbox *mbox);
 void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
 void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+
+int pl320_ipc_transmit(u32 *data);
+int pl320_ipc_register_notifier(struct notifier_block *nb);
+int pl320_ipc_unregister_notifier(struct notifier_block *nb);
+
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 5/6 v7] power: export opp cpufreq functions
  2012-12-04 14:33 ` [PATCH 0/6 v7] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                     ` (3 preceding siblings ...)
  2012-12-04 14:34   ` [PATCH 4/6 v7] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2012-12-04 14:34   ` Mark Langsdorf
  2012-12-04 14:34   ` [PATCH 6/6 v7] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-04 14:34 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

These functions are needed to make the cpufreq-core0 and highbank-cpufreq
drivers loadable as modules.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Acked-by: Nishanth Menon <nm@ti.com>
---
Changes from v4, v5, v6
        None.
Changes from v3
        includes linux/export.h instead of module.h.
Changes from v2
        None.
Changes from v1
        Added Nishanth Menon's ack.
        Clarified the purpose of the change in the commit message.

 drivers/base/power/opp.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index d946864..4062ec3 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -23,6 +23,7 @@
 #include <linux/rcupdate.h>
 #include <linux/opp.h>
 #include <linux/of.h>
+#include <linux/export.h>
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -643,6 +644,7 @@ int opp_init_cpufreq_table(struct device *dev,
 
 	return 0;
 }
+EXPORT_SYMBOL(opp_init_cpufreq_table);
 
 /**
  * opp_free_cpufreq_table() - free the cpufreq table
@@ -660,6 +662,7 @@ void opp_free_cpufreq_table(struct device *dev,
 	kfree(*table);
 	*table = NULL;
 }
+EXPORT_SYMBOL(opp_free_cpufreq_table);
 #endif		/* CONFIG_CPU_FREQ */
 
 /**
@@ -720,4 +723,5 @@ int of_init_opp_table(struct device *dev)
 
 	return 0;
 }
+EXPORT_SYMBOL(of_init_opp_table);
 #endif
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 6/6 v7] cpufreq, highbank: add support for highbank cpufreq
  2012-12-04 14:33 ` [PATCH 0/6 v7] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                     ` (4 preceding siblings ...)
  2012-12-04 14:34   ` [PATCH 5/6 v7] power: export opp cpufreq functions Mark Langsdorf
@ 2012-12-04 14:34   ` Mark Langsdorf
  2012-12-04 16:21     ` Shawn Guo
  5 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-04 14:34 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, shawn.guo, mturquette

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
A9 cores and the ECME happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: shawn.guo@linaro.org
Cc: mturquette@ti.com
---
Changes from v6
	Removed devicetree bindings documentation.
	Restructured driver to use clk notifications.
	Core driver logic is now cpufreq-clk0.
Changes from v5
        Changed ipc_transmit() to pl320_ipc_transmit().
Changes from v4
        Removed erroneous changes to arch/arm/Kconfig.
        Removed unnecessary changes to drivers/cpufreq/Kconfig.arm
        Alphabetized additions to arch/arm/mach-highbank/Kconfig
        Changed ipc call and header to match new ipc location in 
        drivers/mailbox.
Changes from v3
        None.
Changes from v2
        Changed transition latency binding in code to match documentation.
Changes from v1
        Added highbank specific Kconfig changes.

 arch/arm/boot/dts/highbank.dts     |  10 ++++
 arch/arm/mach-highbank/Kconfig     |   2 +
 drivers/cpufreq/Kconfig.arm        |  16 ++++++
 drivers/cpufreq/Makefile           |   1 +
 drivers/cpufreq/highbank-cpufreq.c | 106 +++++++++++++++++++++++++++++++++++++
 5 files changed, 135 insertions(+)
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 0c6fc34..7c4c27d 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -36,6 +36,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			clock-latency = <100000>;
 		};
 
 		cpu@1 {
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 2896881..b7862da 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -1,5 +1,7 @@
 config ARCH_HIGHBANK
 	bool "Calxeda ECX-1000 (Highbank)" if ARCH_MULTI_V7
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_GIC
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 5961e64..7aaac9f 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -76,3 +76,19 @@ config ARM_EXYNOS5250_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
+
+config ARM_HIGHBANK_CPUFREQ
+	tristate "Calxeda Highbank-based"
+	depends on ARCH_HIGHBANK
+	select CPU_FREQ_TABLE
+	select GENERIC_CPUFREQ_CPU0
+	select PM_OPP
+	select REGULATOR
+
+	default m
+	help
+	  This adds the CPUFreq driver for Calxeda Highbank SoC
+	  based boards.
+
+	  If in doubt, say N.
+
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 1bc90e1..9e8f12a 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..25ef437
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * derived from cpufreq-cpu0 by Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <linux/mailbox.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE 0x80000001
+
+static struct device *cpu_dev;
+static struct clk *cpu_clk;
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[7];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000000;
+	for (i = 2; i < 7; i++)
+		msg[i] = 0;
+
+	return pl320_ipc_transmit(msg);
+}
+
+static int hb_cpufreq_clk_notify(struct notifier_block *nb, 
+				unsigned long action, void *hclk)
+{
+	struct clk_notifier_data *clk_data = hclk;
+	int i = 0;
+
+	if (action == PRE_RATE_CHANGE) {
+		if (clk_data->new_rate > clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > 15)
+					return NOTIFY_STOP;
+	} else if (action == POST_RATE_CHANGE)
+		if (clk_data->new_rate < clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > 15)
+					break;
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block hb_cpufreq_clk_nb = {
+	.notifier_call = hb_cpufreq_clk_notify,
+};
+
+static int __devinit hb_cpufreq_driver_init(void)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = clk_notifier_register(cpu_clk, &hb_cpufreq_clk_nb);
+	if (ret) {
+		pr_err("failed to register clk notifier: %d\n", ret);
+		goto out_put_node;
+	}
+
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v7] cpufreq, highbank: add support for highbank cpufreq
  2012-12-04 14:34   ` [PATCH 6/6 v7] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2012-12-04 16:21     ` Shawn Guo
  0 siblings, 0 replies; 142+ messages in thread
From: Shawn Guo @ 2012-12-04 16:21 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, mturquette

On Tue, Dec 04, 2012 at 08:34:02AM -0600, Mark Langsdorf wrote:
> Highbank processors depend on the external ECME to perform voltage
> management based on a requested frequency. Communication between the
> A9 cores and the ECME happens over the pl320 IPC channel.
> 
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> Cc: shawn.guo@linaro.org
> Cc: mturquette@ti.com
> ---
> Changes from v6
> 	Removed devicetree bindings documentation.
> 	Restructured driver to use clk notifications.
> 	Core driver logic is now cpufreq-clk0.

Great.  It saves some codes :)

> Changes from v5
>         Changed ipc_transmit() to pl320_ipc_transmit().
> Changes from v4
>         Removed erroneous changes to arch/arm/Kconfig.
>         Removed unnecessary changes to drivers/cpufreq/Kconfig.arm
>         Alphabetized additions to arch/arm/mach-highbank/Kconfig
>         Changed ipc call and header to match new ipc location in 
>         drivers/mailbox.
> Changes from v3
>         None.
> Changes from v2
>         Changed transition latency binding in code to match documentation.
> Changes from v1
>         Added highbank specific Kconfig changes.
> 
>  arch/arm/boot/dts/highbank.dts     |  10 ++++
>  arch/arm/mach-highbank/Kconfig     |   2 +
>  drivers/cpufreq/Kconfig.arm        |  16 ++++++
>  drivers/cpufreq/Makefile           |   1 +
>  drivers/cpufreq/highbank-cpufreq.c | 106 +++++++++++++++++++++++++++++++++++++
>  5 files changed, 135 insertions(+)
>  create mode 100644 drivers/cpufreq/highbank-cpufreq.c
> 
> diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
> index 0c6fc34..7c4c27d 100644
> --- a/arch/arm/boot/dts/highbank.dts
> +++ b/arch/arm/boot/dts/highbank.dts
> @@ -36,6 +36,16 @@
>  			next-level-cache = <&L2>;
>  			clocks = <&a9pll>;
>  			clock-names = "cpu";
> +			operating-points = <
> +				/* kHz    ignored */
> +				 1300000  1000000
> +				 1200000  1000000
> +				 1100000  1000000
> +				  800000  1000000
> +				  400000  1000000
> +				  200000  1000000
> +			>;
> +			clock-latency = <100000>;
>  		};
>  
>  		cpu@1 {
> diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
> index 2896881..b7862da 100644
> --- a/arch/arm/mach-highbank/Kconfig
> +++ b/arch/arm/mach-highbank/Kconfig
> @@ -1,5 +1,7 @@
>  config ARCH_HIGHBANK
>  	bool "Calxeda ECX-1000 (Highbank)" if ARCH_MULTI_V7
> +	select ARCH_HAS_CPUFREQ
> +	select ARCH_HAS_OPP
>  	select ARCH_WANT_OPTIONAL_GPIOLIB
>  	select ARM_AMBA
>  	select ARM_GIC
> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 5961e64..7aaac9f 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -76,3 +76,19 @@ config ARM_EXYNOS5250_CPUFREQ
>  	help
>  	  This adds the CPUFreq driver for Samsung EXYNOS5250
>  	  SoC.
> +
> +config ARM_HIGHBANK_CPUFREQ
> +	tristate "Calxeda Highbank-based"
> +	depends on ARCH_HIGHBANK
> +	select CPU_FREQ_TABLE
> +	select GENERIC_CPUFREQ_CPU0
> +	select PM_OPP
> +	select REGULATOR
> +
> +	default m
> +	help
> +	  This adds the CPUFreq driver for Calxeda Highbank SoC
> +	  based boards.
> +
> +	  If in doubt, say N.
> +
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index 1bc90e1..9e8f12a 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
>  obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
>  obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
>  obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
> +obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
>  
>  ##################################################################################
>  # PowerPC platform drivers
> diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
> new file mode 100644
> index 0000000..25ef437
> --- /dev/null
> +++ b/drivers/cpufreq/highbank-cpufreq.c
> @@ -0,0 +1,106 @@
> +/*
> + * Copyright (C) 2012 Calxeda, Inc.
> + *
> + * derived from cpufreq-cpu0 by Freescale Semiconductor

It's not any more, right?

> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/clk.h>
> +#include <linux/cpu.h>
> +#include <linux/err.h>
> +#include <linux/of.h>
> +#include <linux/opp.h>

Do you need this header?

> +#include <linux/slab.h>
> +#include <linux/mailbox.h>
> +
> +#define HB_CPUFREQ_CHANGE_NOTE 0x80000001
> +
> +static struct device *cpu_dev;
> +static struct clk *cpu_clk;

These two now can be local variables hb_cpufreq_driver_init().

> +
> +static int hb_voltage_change(unsigned int freq)
> +{
> +	int i;
> +	u32 msg[7];
> +
> +	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
> +	msg[1] = freq / 1000000;
> +	for (i = 2; i < 7; i++)
> +		msg[i] = 0;
> +
> +	return pl320_ipc_transmit(msg);
> +}
> +
> +static int hb_cpufreq_clk_notify(struct notifier_block *nb, 
> +				unsigned long action, void *hclk)
> +{
> +	struct clk_notifier_data *clk_data = hclk;
> +	int i = 0;
> +
> +	if (action == PRE_RATE_CHANGE) {
> +		if (clk_data->new_rate > clk_data->old_rate)
> +			while (hb_voltage_change(clk_data->new_rate))
> +				if (i++ > 15)
> +					return NOTIFY_STOP;
> +	} else if (action == POST_RATE_CHANGE)

Add a {} pair for else block or remove {} for if?

> +		if (clk_data->new_rate < clk_data->old_rate)
> +			while (hb_voltage_change(clk_data->new_rate))
> +				if (i++ > 15)
> +					break;
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static struct notifier_block hb_cpufreq_clk_nb = {
> +	.notifier_call = hb_cpufreq_clk_notify,
> +};
> +
> +static int __devinit hb_cpufreq_driver_init(void)

Isn't there a big series removing __devinit from the kernel tree
as CONFIG_HOTPLUG is going away?

Shawn

> +{
> +	struct device_node *np;
> +	int ret;
> +
> +	np = of_find_node_by_path("/cpus/cpu@0");
> +	if (!np) {
> +		pr_err("failed to find highbank cpufreq node\n");
> +		return -ENOENT;
> +	}
> +
> +	cpu_dev = get_cpu_device(0);
> +	if (!cpu_dev) {
> +		pr_err("failed to get highbank cpufreq device\n");
> +		ret = -ENODEV;
> +		goto out_put_node;
> +	}
> +
> +	cpu_dev->of_node = np;
> +
> +	cpu_clk = clk_get(cpu_dev, NULL);
> +	if (IS_ERR(cpu_clk)) {
> +		ret = PTR_ERR(cpu_clk);
> +		pr_err("failed to get cpu0 clock: %d\n", ret);
> +		goto out_put_node;
> +	}
> +
> +	ret = clk_notifier_register(cpu_clk, &hb_cpufreq_clk_nb);
> +	if (ret) {
> +		pr_err("failed to register clk notifier: %d\n", ret);
> +		goto out_put_node;
> +	}
> +
> +out_put_node:
> +	of_node_put(np);
> +	return ret;
> +}
> +late_initcall(hb_cpufreq_driver_init);
> +
> +MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
> +MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
> +MODULE_LICENSE("GPL");
> -- 
> 1.7.11.7
> 


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (12 preceding siblings ...)
  2012-12-04 14:33 ` [PATCH 0/6 v7] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
@ 2012-12-05 16:48 ` Mark Langsdorf
  2012-12-05 16:48   ` [PATCH 1/6 v8] arm: use devicetree to get smp_twd clock Mark Langsdorf
                     ` (6 more replies)
  2012-12-06 22:42 ` [PATCH 0/6 v9] " Mark Langsdorf
                   ` (3 subsequent siblings)
  17 siblings, 7 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-05 16:48 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

This patch series adds cpufreq support for the Calxeda
ECX-1000 (highbank) SoCs. The EnergyCore Management Engine (ECME) on
the ECX-1000 manages the voltage for the part and communications with
Linux through a pl320 mailbox. clk notifications are used to control
when to send messages to the ECME.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/6 v8] arm: use devicetree to get smp_twd clock
  2012-12-05 16:48 ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
@ 2012-12-05 16:48   ` Mark Langsdorf
  2012-12-05 16:48   ` [PATCH 2/6 v8] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-05 16:48 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v4, v5, v6, v7
        None.
Changes from v3
        No longer setting *clk to NULL in twd_get_clock().
Changes from v2
        Turned the check for the node pointer into an if-then-else statement.
        Removed the second, redundant clk_get_rate.
Changes from v1
        None.

 arch/arm/kernel/smp_twd.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index b22d700..af46b80 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -237,12 +237,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static struct clk *twd_get_clock(struct device_node *np)
 {
 	struct clk *clk;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
+	if (np)
+		clk = of_clk_get(np, 0);
+	else
+		clk = clk_get_sys("smp_twd", NULL);
 	if (IS_ERR(clk)) {
 		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
 		return clk;
@@ -263,6 +266,7 @@ static struct clk *twd_get_clock(void)
 		return ERR_PTR(err);
 	}
 
+	twd_timer_rate = clk_get_rate(clk);
 	return clk;
 }
 
@@ -273,12 +277,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
 	struct clock_event_device **this_cpu_clk;
 
-	if (!twd_clk)
-		twd_clk = twd_get_clock();
-
-	if (!IS_ERR_OR_NULL(twd_clk))
-		twd_timer_rate = clk_get_rate(twd_clk);
-	else
+	if (IS_ERR_OR_NULL(twd_clk))
 		twd_calibrate_rate();
 
 	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
@@ -349,6 +348,8 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
+	twd_clk = twd_get_clock(NULL);
+
 	return twd_local_timer_common_register();
 }
 
@@ -383,6 +384,8 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
+	twd_clk = twd_get_clock(np);
+
 	err = twd_local_timer_common_register();
 
 out:
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/6 v8] clk, highbank: Prevent glitches in non-bypass reset mode
  2012-12-05 16:48 ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2012-12-05 16:48   ` [PATCH 1/6 v8] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2012-12-05 16:48   ` Mark Langsdorf
  2012-12-05 18:02     ` Mike Turquette
  2012-12-05 16:48   ` [PATCH 3/6 v8] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-05 16:48 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring, mturquette

The highbank clock will glitch with the current code if the
clock rate is reset without relocking the PLL. Program the PLL
correctly to prevent glitches.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: mturquette@linaro.org
---
Changes from v6, v7
        None.
Changes from v5
        Added Mike Turquette's ack.
Changes from v4
        None.
Changes from v3
        Changelog text and patch name now correspond to the actual patch.
        was clk, highbank: remove non-bypass reset mode.
Changes from v2
        None.
Changes from v1
        Removed erroneous reformating.

 drivers/clk/clk-highbank.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..3a0b723 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/6 v8] cpufreq: tolerate inexact values when collecting stats
  2012-12-05 16:48 ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2012-12-05 16:48   ` [PATCH 1/6 v8] arm: use devicetree to get smp_twd clock Mark Langsdorf
  2012-12-05 16:48   ` [PATCH 2/6 v8] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2012-12-05 16:48   ` Mark Langsdorf
  2012-12-05 16:48   ` [PATCH 4/6 v8] arm highbank: add support for pl320 IPC Mark Langsdorf
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-05 16:48 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

This patch is withdrawn due to a need for severe rework.

Changes from v4
        Withdrawn.      
Changes from v3, v2
        None.
Changes from v1
        Implemented a simple round-up algorithm instead of the over/under
method that could cause errors on Intel processors with boost mode.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 4/6 v8] arm highbank: add support for pl320 IPC
  2012-12-05 16:48 ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                     ` (2 preceding siblings ...)
  2012-12-05 16:48   ` [PATCH 3/6 v8] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
@ 2012-12-05 16:48   ` Mark Langsdorf
  2012-12-05 16:48   ` [PATCH 5/6 v8] power: export opp cpufreq functions Mark Langsdorf
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-05 16:48 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring, Omar Ramirez Luna, Arnd Bergmann

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the highbank A9
and the EnergyCore Management Engine. The pl320 implements a straightforward
mailbox protocol.

This patch depends on Omar Ramirez Luna's <omar.luna@linaro.org>
mailbox driver patch series.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Omar Ramirez Luna <omar.luna@linaro.org>
Cc: Arnd Bergmann <arnd@arndb.de>
---
Changes from v6, v7
        None.
Changes from v5
        Renamed ipc_transmit() to pl320_ipc_transmit().
        Properly exported pl320_ipc_{un}register_notifier().
Changes from v4
        Moved pl320-ipc.c from arch/arm/mach-highbank to drivers/mailbox.
        Moved header information to include/linux/mailbox.h.
        Added Kconfig options to reflect the new code location.
        Change drivers/mailbox/Makefile to build the omap mailboxes only 
        when they are configured.
        Removed ipc_call_fast and renamed ipc_call_slow ipc_transmit.
Changes from v3, v2
        None.
Changes from v1
        Removed erroneous changes for cpufreq Kconfig.

 arch/arm/mach-highbank/Kconfig |   2 +
 drivers/mailbox/Kconfig        |   9 ++
 drivers/mailbox/Makefile       |   4 +
 drivers/mailbox/pl320-ipc.c    | 199 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mailbox.h        |  19 +++-
 5 files changed, 232 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mailbox/Makefile
 create mode 100644 drivers/mailbox/pl320-ipc.c

diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 0e1d0a4..2896881 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -11,5 +11,7 @@ config ARCH_HIGHBANK
 	select GENERIC_CLOCKEVENTS
 	select HAVE_ARM_SCU
 	select HAVE_SMP
+	select MAILBOX
+	select PL320_MBOX
 	select SPARSE_IRQ
 	select USE_OF
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index be8cac0..e89fdb4 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -34,4 +34,13 @@ config OMAP_MBOX_KFIFO_SIZE
 	  This can also be changed at runtime (via the mbox_kfifo_size
 	  module parameter).
 
+config PL320_MBOX
+	bool "ARM PL320 Mailbox"
+	help
+	  An implementation of the ARM PL320 Interprocessor Communication
+	  Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to
+	  send short messages between Highbank's A9 cores and the EnergyCore
+	  Management Engine, primarily for cpufreq. Say Y here if you want
+	  to use the PL320 IPCM support.
+
 endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
new file mode 100644
index 0000000..c9f14c3
--- /dev/null
+++ b/drivers/mailbox/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_OMAP1_MBOX)	+= mailbox.o mailbox-omap1.o
+obj-$(CONFIG_OMAP2PLUS_MBOX)	+= mailbox.o mailbox-omap2.o
+obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
+
diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
new file mode 100644
index 0000000..1a9d8e4
--- /dev/null
+++ b/drivers/mailbox/pl320-ipc.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <linux/mailbox.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_TX_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int pl320_ipc_transmit(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_TX_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_TX_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL(pl320_ipc_transmit);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_register_notifier);
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_unregister_notifier);
+
+static int __devinit pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_TX_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
diff --git a/include/linux/mailbox.h b/include/linux/mailbox.h
index e8e4131..e7829e5 100644
--- a/include/linux/mailbox.h
+++ b/include/linux/mailbox.h
@@ -1,4 +1,16 @@
-/* mailbox.h */
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 typedef u32 mbox_msg_t;
 struct omap_mbox;
@@ -20,3 +32,8 @@ void omap_mbox_save_ctx(struct omap_mbox *mbox);
 void omap_mbox_restore_ctx(struct omap_mbox *mbox);
 void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
 void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+
+int pl320_ipc_transmit(u32 *data);
+int pl320_ipc_register_notifier(struct notifier_block *nb);
+int pl320_ipc_unregister_notifier(struct notifier_block *nb);
+
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 5/6 v8] power: export opp cpufreq functions
  2012-12-05 16:48 ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                     ` (3 preceding siblings ...)
  2012-12-05 16:48   ` [PATCH 4/6 v8] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2012-12-05 16:48   ` Mark Langsdorf
  2012-12-05 16:48   ` [PATCH 6/6 v8] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  2012-12-27 13:12   ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
  6 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-05 16:48 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

These functions are needed to make the cpufreq-core0 and highbank-cpufreq
drivers loadable as modules.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Acked-by: Nishanth Menon <nm@ti.com>
---
Changes from v4, v5, v6, v7
        None.
Changes from v3
        includes linux/export.h instead of module.h.
Changes from v2
        None.
Changes from v1
        Added Nishanth Menon's ack.
        Clarified the purpose of the change in the commit message.

 drivers/base/power/opp.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index d946864..4062ec3 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -23,6 +23,7 @@
 #include <linux/rcupdate.h>
 #include <linux/opp.h>
 #include <linux/of.h>
+#include <linux/export.h>
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -643,6 +644,7 @@ int opp_init_cpufreq_table(struct device *dev,
 
 	return 0;
 }
+EXPORT_SYMBOL(opp_init_cpufreq_table);
 
 /**
  * opp_free_cpufreq_table() - free the cpufreq table
@@ -660,6 +662,7 @@ void opp_free_cpufreq_table(struct device *dev,
 	kfree(*table);
 	*table = NULL;
 }
+EXPORT_SYMBOL(opp_free_cpufreq_table);
 #endif		/* CONFIG_CPU_FREQ */
 
 /**
@@ -720,4 +723,5 @@ int of_init_opp_table(struct device *dev)
 
 	return 0;
 }
+EXPORT_SYMBOL(of_init_opp_table);
 #endif
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 6/6 v8] cpufreq, highbank: add support for highbank cpufreq
  2012-12-05 16:48 ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                     ` (4 preceding siblings ...)
  2012-12-05 16:48   ` [PATCH 5/6 v8] power: export opp cpufreq functions Mark Langsdorf
@ 2012-12-05 16:48   ` Mark Langsdorf
  2012-12-05 18:49     ` Mike Turquette
  2012-12-06  9:37     ` Shawn Guo
  2012-12-27 13:12   ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
  6 siblings, 2 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-05 16:48 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, shawn.guo, mturquette

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
A9 cores and the ECME happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Cc: shawn.guo@linaro.org
Cc: mturquette@linaro.org
---
Changes from v7
	Removed old attribution to cpufreq-cpu0.
	Added some description in the documentation.
	Made cpu_dev, cpu_clk into local variables.
	Removed __devinit.
	Removed some unneeded includes.
	Added a brace to clarify some nested if logic.
Changes from v6
        Removed devicetree bindings documentation.
        Restructured driver to use clk notifications.
        Core driver logic is now cpufreq-clk0.
Changes from v5
        Changed ipc_transmit() to pl320_ipc_transmit().
Changes from v4
        Removed erroneous changes to arch/arm/Kconfig.
        Removed unnecessary changes to drivers/cpufreq/Kconfig.arm
        Alphabetized additions to arch/arm/mach-highbank/Kconfig
        Changed ipc call and header to match new ipc location in 
        drivers/mailbox.
Changes from v3
        None.
Changes from v2
        Changed transition latency binding in code to match documentation.
Changes from v1
        Added highbank specific Kconfig changes.

 arch/arm/boot/dts/highbank.dts     |  10 ++++
 arch/arm/mach-highbank/Kconfig     |   2 +
 drivers/cpufreq/Kconfig.arm        |  16 ++++++
 drivers/cpufreq/Makefile           |   1 +
 drivers/cpufreq/highbank-cpufreq.c | 102 +++++++++++++++++++++++++++++++++++++
 5 files changed, 131 insertions(+)
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 0c6fc34..7c4c27d 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -36,6 +36,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			clock-latency = <100000>;
 		};
 
 		cpu@1 {
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 2896881..b7862da 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -1,5 +1,7 @@
 config ARCH_HIGHBANK
 	bool "Calxeda ECX-1000 (Highbank)" if ARCH_MULTI_V7
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_GIC
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 5961e64..7aaac9f 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -76,3 +76,19 @@ config ARM_EXYNOS5250_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
+
+config ARM_HIGHBANK_CPUFREQ
+	tristate "Calxeda Highbank-based"
+	depends on ARCH_HIGHBANK
+	select CPU_FREQ_TABLE
+	select GENERIC_CPUFREQ_CPU0
+	select PM_OPP
+	select REGULATOR
+
+	default m
+	help
+	  This adds the CPUFreq driver for Calxeda Highbank SoC
+	  based boards.
+
+	  If in doubt, say N.
+
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 1bc90e1..9e8f12a 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..1f28fa6
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/mailbox.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE 0x80000001
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[7];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000000;
+	for (i = 2; i < 7; i++)
+		msg[i] = 0;
+
+	return pl320_ipc_transmit(msg);
+}
+
+static int hb_cpufreq_clk_notify(struct notifier_block *nb, 
+				unsigned long action, void *hclk)
+{
+	struct clk_notifier_data *clk_data = hclk;
+	int i = 0;
+
+	if (action == PRE_RATE_CHANGE) {
+		if (clk_data->new_rate > clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > 15)
+					return NOTIFY_STOP;
+	} else if (action == POST_RATE_CHANGE) {
+		if (clk_data->new_rate < clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > 15)
+					break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block hb_cpufreq_clk_nb = {
+	.notifier_call = hb_cpufreq_clk_notify,
+};
+
+static int hb_cpufreq_driver_init(void)
+{
+	struct device *cpu_dev;
+	struct clk *cpu_clk;
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = clk_notifier_register(cpu_clk, &hb_cpufreq_clk_nb);
+	if (ret) {
+		pr_err("failed to register clk notifier: %d\n", ret);
+		goto out_put_node;
+	}
+
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 2/6 v8] clk, highbank: Prevent glitches in non-bypass reset mode
  2012-12-05 16:48   ` [PATCH 2/6 v8] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2012-12-05 18:02     ` Mike Turquette
  0 siblings, 0 replies; 142+ messages in thread
From: Mike Turquette @ 2012-12-05 18:02 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, Rob Herring

On Wed, Dec 5, 2012 at 8:48 AM, Mark Langsdorf
<mark.langsdorf@calxeda.com> wrote:
> The highbank clock will glitch with the current code if the
> clock rate is reset without relocking the PLL. Program the PLL
> correctly to prevent glitches.
>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Cc: mturquette@linaro.org
> ---
> Changes from v6, v7
>         None.
> Changes from v5
>         Added Mike Turquette's ack.

It appears that my Ack has not been added to this version of the patch.

Regards,
Mike

> Changes from v4
>         None.
> Changes from v3
>         Changelog text and patch name now correspond to the actual patch.
>         was clk, highbank: remove non-bypass reset mode.
> Changes from v2
>         None.
> Changes from v1
>         Removed erroneous reformating.
>
>  drivers/clk/clk-highbank.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
> index 52fecad..3a0b723 100644
> --- a/drivers/clk/clk-highbank.c
> +++ b/drivers/clk/clk-highbank.c
> @@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
>                 reg |= HB_PLL_EXT_ENA;
>                 reg &= ~HB_PLL_EXT_BYPASS;
>         } else {
> +               writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
>                 reg &= ~HB_PLL_DIVQ_MASK;
>                 reg |= divq << HB_PLL_DIVQ_SHIFT;
> +               writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
>         }
>         writel(reg, hbclk->reg);
>
> --
> 1.7.11.7
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v8] cpufreq, highbank: add support for highbank cpufreq
  2012-12-05 16:48   ` [PATCH 6/6 v8] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2012-12-05 18:49     ` Mike Turquette
  2012-12-05 22:09       ` Mark Langsdorf
  2012-12-06  9:37     ` Shawn Guo
  1 sibling, 1 reply; 142+ messages in thread
From: Mike Turquette @ 2012-12-05 18:49 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, Shawn Guo

On Wed, Dec 5, 2012 at 8:48 AM, Mark Langsdorf
<mark.langsdorf@calxeda.com> wrote:
> diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
> new file mode 100644
> index 0000000..1f28fa6
> --- /dev/null
> +++ b/drivers/cpufreq/highbank-cpufreq.c
> @@ -0,0 +1,102 @@

Looks pretty good to me.  Some tedious nitpicks and discussion below.
<snip>

> +static int hb_voltage_change(unsigned int freq)
> +{
> +       int i;
> +       u32 msg[7];
> +
> +       msg[0] = HB_CPUFREQ_CHANGE_NOTE;
> +       msg[1] = freq / 1000000;
> +       for (i = 2; i < 7; i++)
> +               msg[i] = 0;
> +
> +       return pl320_ipc_transmit(msg);
> +}
> +
> +static int hb_cpufreq_clk_notify(struct notifier_block *nb,
> +                               unsigned long action, void *hclk)
> +{
> +       struct clk_notifier_data *clk_data = hclk;
> +       int i = 0;
> +
> +       if (action == PRE_RATE_CHANGE) {
> +               if (clk_data->new_rate > clk_data->old_rate)
> +                       while (hb_voltage_change(clk_data->new_rate))
> +                               if (i++ > 15)

There are a few magic numbers here.  How about something like:

#define HB_VOLT_CHANGE_MAX_TRIES 15

Maybe do the same for the i2c message length?

> +                                       return NOTIFY_STOP;

How about NOTIFY_BAD?  It more clearly signals that an error has occurred.

You could also return notifier_from_errno(-ETIMEDOUT) here if you
prefer but that would only be for the sake of readability.
clk_set_rate doesn't actually return the notifier error code in the
event of a notifier abort.

> +       } else if (action == POST_RATE_CHANGE) {
> +               if (clk_data->new_rate < clk_data->old_rate)
> +                       while (hb_voltage_change(clk_data->new_rate))
> +                               if (i++ > 15)
> +                                       break;

Same as above.  It is true that the clock framework does nothing with
post-rate change notifier aborts but that might change in the future.

> +       }
> +
> +       return NOTIFY_DONE;
> +}
> +
> +static struct notifier_block hb_cpufreq_clk_nb = {
> +       .notifier_call = hb_cpufreq_clk_notify,
> +};
> +

Do you have any plans to convert your voltage change routine over to
the regulator framework?  Likewise do you plan to use the OPP library
in the future?  I can understand if you do not do that since your
regulator/dvfs programming model makes things very simple for you.

The reason I bring this up is that I did float a patch a while back
for a generalized dvfs notifier handler.  The prereqs for using it are
1) ccf, 2) regulator fwk, 3) opp definitions.  Here is the patch:
https://github.com/mturquette/linux/commit/05a280bbc0819a6858d73088a632666f0c7f68a4

And an example usage in the OMAP CPUfreq driver:
https://github.com/mturquette/linux/commit/958f10bb98a293aa912e7eb9cd6edbdc51c1c04a

I understand if this approach incurs too much software overhead for
you but I wanted to throw it out there.  It might working nicely in
the cpufreq-cpu0 driver or some other "generic" CPUfreq driver for
implementing DVFS.

Regards,
Mike

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v8] cpufreq, highbank: add support for highbank cpufreq
  2012-12-05 18:49     ` Mike Turquette
@ 2012-12-05 22:09       ` Mark Langsdorf
  0 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-05 22:09 UTC (permalink / raw)
  To: Mike Turquette
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, Shawn Guo

On 12/05/2012 12:49 PM, Mike Turquette wrote:
> On Wed, Dec 5, 2012 at 8:48 AM, Mark Langsdorf
> <mark.langsdorf@calxeda.com> wrote:
>> diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
>> new file mode 100644
>> index 0000000..1f28fa6
>> --- /dev/null
>> +++ b/drivers/cpufreq/highbank-cpufreq.c
>> @@ -0,0 +1,102 @@
> 
> Looks pretty good to me.  Some tedious nitpicks and discussion below.
> <snip>
> 
>> +static int hb_voltage_change(unsigned int freq)
>> +{
>> +       int i;
>> +       u32 msg[7];
>> +
>> +       msg[0] = HB_CPUFREQ_CHANGE_NOTE;
>> +       msg[1] = freq / 1000000;
>> +       for (i = 2; i < 7; i++)
>> +               msg[i] = 0;
>> +
>> +       return pl320_ipc_transmit(msg);
>> +}
>> +
>> +static int hb_cpufreq_clk_notify(struct notifier_block *nb,
>> +                               unsigned long action, void *hclk)
>> +{
>> +       struct clk_notifier_data *clk_data = hclk;
>> +       int i = 0;
>> +
>> +       if (action == PRE_RATE_CHANGE) {
>> +               if (clk_data->new_rate > clk_data->old_rate)
>> +                       while (hb_voltage_change(clk_data->new_rate))
>> +                               if (i++ > 15)
> 
> There are a few magic numbers here.  How about something like:
> 
> #define HB_VOLT_CHANGE_MAX_TRIES 15
> 
> Maybe do the same for the i2c message length?

Fixed.

>> +                                       return NOTIFY_STOP;
> 
> How about NOTIFY_BAD?  It more clearly signals that an error has occurred.

> Same as above.  It is true that the clock framework does nothing with
> post-rate change notifier aborts but that might change in the future.

Changed and added.

>> +       }
>> +
>> +       return NOTIFY_DONE;
>> +}
>> +
>> +static struct notifier_block hb_cpufreq_clk_nb = {
>> +       .notifier_call = hb_cpufreq_clk_notify,
>> +};
>> +
> 
> Do you have any plans to convert your voltage change routine over to
> the regulator framework?  Likewise do you plan to use the OPP library
> in the future?  I can understand if you do not do that since your
> regulator/dvfs programming model makes things very simple for you.

I looked at treating the ECME as a voltage regulator, but it was a very
bad fit. The ECME has a certain amount of intelligence built into it and
corporate plans are to treat voltage control as a black box.

The current solution is actually nicely generic from my perspective. The
clk notifiers guarantee we can make the voltage changes at the right
time regardless of the underlying cpufreq driver implementation. I don't
think we need more until we get into cpufreq QoS issues, and even then
I'd want to stick with something like the current structure.

--Mark Langsdorf
Calxeda, Inc.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v8] cpufreq, highbank: add support for highbank cpufreq
  2012-12-05 16:48   ` [PATCH 6/6 v8] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  2012-12-05 18:49     ` Mike Turquette
@ 2012-12-06  9:37     ` Shawn Guo
  1 sibling, 0 replies; 142+ messages in thread
From: Shawn Guo @ 2012-12-06  9:37 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, mturquette

On Wed, Dec 05, 2012 at 10:48:41AM -0600, Mark Langsdorf wrote:
> Highbank processors depend on the external ECME to perform voltage
> management based on a requested frequency. Communication between the
> A9 cores and the ECME happens over the pl320 IPC channel.
> 
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> Cc: shawn.guo@linaro.org

Reviewed-by: Shawn Guo <shawn.guo@linaro.org>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 0/6 v9] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (13 preceding siblings ...)
  2012-12-05 16:48 ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
@ 2012-12-06 22:42 ` Mark Langsdorf
  2012-12-06 22:42   ` [PATCH 1/6 v9] arm: use devicetree to get smp_twd clock Mark Langsdorf
                     ` (5 more replies)
  2013-01-04 16:35 ` [PATCH 0/4 v10] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (2 subsequent siblings)
  17 siblings, 6 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-06 22:42 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

This patch series adds cpufreq support for the Calxeda
ECX-1000 (highbank) SoCs. The EnergyCore Management Engine (ECME) on
the ECX-1000 manages the voltage for the part and communications with
Linux through a pl320 mailbox. clk notifications are used to control
when to send messages to the ECME.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/6 v9] arm: use devicetree to get smp_twd clock
  2012-12-06 22:42 ` [PATCH 0/6 v9] " Mark Langsdorf
@ 2012-12-06 22:42   ` Mark Langsdorf
  2012-12-07 14:55     ` Thiago Farina
  2012-12-27  5:11     ` Prashant Gaikwad
  2012-12-06 22:42   ` [PATCH 2/6 v9] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
                     ` (4 subsequent siblings)
  5 siblings, 2 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-06 22:42 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v4, v5, v6, v7, v8
        None.
Changes from v3
        No longer setting *clk to NULL in twd_get_clock().
Changes from v2
        Turned the check for the node pointer into an if-then-else statement.
        Removed the second, redundant clk_get_rate.
Changes from v1
        None.

 arch/arm/kernel/smp_twd.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index b22d700..af46b80 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -237,12 +237,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static struct clk *twd_get_clock(struct device_node *np)
 {
 	struct clk *clk;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
+	if (np)
+		clk = of_clk_get(np, 0);
+	else
+		clk = clk_get_sys("smp_twd", NULL);
 	if (IS_ERR(clk)) {
 		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
 		return clk;
@@ -263,6 +266,7 @@ static struct clk *twd_get_clock(void)
 		return ERR_PTR(err);
 	}
 
+	twd_timer_rate = clk_get_rate(clk);
 	return clk;
 }
 
@@ -273,12 +277,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
 	struct clock_event_device **this_cpu_clk;
 
-	if (!twd_clk)
-		twd_clk = twd_get_clock();
-
-	if (!IS_ERR_OR_NULL(twd_clk))
-		twd_timer_rate = clk_get_rate(twd_clk);
-	else
+	if (IS_ERR_OR_NULL(twd_clk))
 		twd_calibrate_rate();
 
 	__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
@@ -349,6 +348,8 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
+	twd_clk = twd_get_clock(NULL);
+
 	return twd_local_timer_common_register();
 }
 
@@ -383,6 +384,8 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
+	twd_clk = twd_get_clock(np);
+
 	err = twd_local_timer_common_register();
 
 out:
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/6 v9] clk, highbank: Prevent glitches in non-bypass reset mode
  2012-12-06 22:42 ` [PATCH 0/6 v9] " Mark Langsdorf
  2012-12-06 22:42   ` [PATCH 1/6 v9] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2012-12-06 22:42   ` Mark Langsdorf
  2012-12-06 22:42   ` [PATCH 3/6 v9] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-06 22:42 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

The highbank clock will glitch with the current code if the
clock rate is reset without relocking the PLL. Program the PLL
correctly to prevent glitches.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
---
Changes from v6, v7, v8
        None.
Changes from v5
        Added Mike Turquette's ack.
Changes from v4
        None.
Changes from v3
        Changelog text and patch name now correspond to the actual patch.
        was clk, highbank: remove non-bypass reset mode.
Changes from v2
        None.
Changes from v1
        Removed erroneous reformating.

 drivers/clk/clk-highbank.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..3a0b723 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/6 v9] cpufreq: tolerate inexact values when collecting stats
  2012-12-06 22:42 ` [PATCH 0/6 v9] " Mark Langsdorf
  2012-12-06 22:42   ` [PATCH 1/6 v9] arm: use devicetree to get smp_twd clock Mark Langsdorf
  2012-12-06 22:42   ` [PATCH 2/6 v9] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2012-12-06 22:42   ` Mark Langsdorf
  2012-12-06 22:42   ` [PATCH 4/6 v9] arm highbank: add support for pl320 IPC Mark Langsdorf
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-06 22:42 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

This patch is withdrawn due to a need for severe rework.

Changes from v4
        Withdrawn.      
Changes from v3, v2
        None.
Changes from v1
        Implemented a simple round-up algorithm instead of the over/under
method that could cause errors on Intel processors with boost mode.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 4/6 v9] arm highbank: add support for pl320 IPC
  2012-12-06 22:42 ` [PATCH 0/6 v9] " Mark Langsdorf
                     ` (2 preceding siblings ...)
  2012-12-06 22:42   ` [PATCH 3/6 v9] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
@ 2012-12-06 22:42   ` Mark Langsdorf
  2012-12-06 22:42   ` [PATCH 5/6 v9] power: export opp cpufreq functions Mark Langsdorf
  2012-12-06 22:42   ` [PATCH 6/6 v9] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-06 22:42 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring, Omar Ramirez Luna, Arnd Bergmann

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the highbank A9
and the EnergyCore Management Engine. The pl320 implements a straightforward
mailbox protocol.

This patch depends on Omar Ramirez Luna's <omar.luna@linaro.org>
mailbox driver patch series.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Omar Ramirez Luna <omar.luna@linaro.org>
Cc: Arnd Bergmann <arnd@arndb.de>
---
Changes from v6, v7, v8
        None.
Changes from v5
        Renamed ipc_transmit() to pl320_ipc_transmit().
        Properly exported pl320_ipc_{un}register_notifier().
Changes from v4
        Moved pl320-ipc.c from arch/arm/mach-highbank to drivers/mailbox.
        Moved header information to include/linux/mailbox.h.
        Added Kconfig options to reflect the new code location.
        Change drivers/mailbox/Makefile to build the omap mailboxes only 
        when they are configured.
        Removed ipc_call_fast and renamed ipc_call_slow ipc_transmit.
Changes from v3, v2
        None.
Changes from v1
        Removed erroneous changes for cpufreq Kconfig.

 arch/arm/mach-highbank/Kconfig |   2 +
 drivers/mailbox/Kconfig        |   9 ++
 drivers/mailbox/Makefile       |   4 +
 drivers/mailbox/pl320-ipc.c    | 199 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mailbox.h        |  19 +++-
 5 files changed, 232 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mailbox/Makefile
 create mode 100644 drivers/mailbox/pl320-ipc.c

diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 0e1d0a4..2896881 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -11,5 +11,7 @@ config ARCH_HIGHBANK
 	select GENERIC_CLOCKEVENTS
 	select HAVE_ARM_SCU
 	select HAVE_SMP
+	select MAILBOX
+	select PL320_MBOX
 	select SPARSE_IRQ
 	select USE_OF
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index be8cac0..e89fdb4 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -34,4 +34,13 @@ config OMAP_MBOX_KFIFO_SIZE
 	  This can also be changed at runtime (via the mbox_kfifo_size
 	  module parameter).
 
+config PL320_MBOX
+	bool "ARM PL320 Mailbox"
+	help
+	  An implementation of the ARM PL320 Interprocessor Communication
+	  Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to
+	  send short messages between Highbank's A9 cores and the EnergyCore
+	  Management Engine, primarily for cpufreq. Say Y here if you want
+	  to use the PL320 IPCM support.
+
 endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
new file mode 100644
index 0000000..c9f14c3
--- /dev/null
+++ b/drivers/mailbox/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_OMAP1_MBOX)	+= mailbox.o mailbox-omap1.o
+obj-$(CONFIG_OMAP2PLUS_MBOX)	+= mailbox.o mailbox-omap2.o
+obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
+
diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
new file mode 100644
index 0000000..1a9d8e4
--- /dev/null
+++ b/drivers/mailbox/pl320-ipc.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <linux/mailbox.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_TX_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int pl320_ipc_transmit(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_TX_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_TX_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL(pl320_ipc_transmit);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_register_notifier);
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_unregister_notifier);
+
+static int __devinit pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_TX_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
diff --git a/include/linux/mailbox.h b/include/linux/mailbox.h
index e8e4131..e7829e5 100644
--- a/include/linux/mailbox.h
+++ b/include/linux/mailbox.h
@@ -1,4 +1,16 @@
-/* mailbox.h */
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 typedef u32 mbox_msg_t;
 struct omap_mbox;
@@ -20,3 +32,8 @@ void omap_mbox_save_ctx(struct omap_mbox *mbox);
 void omap_mbox_restore_ctx(struct omap_mbox *mbox);
 void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
 void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+
+int pl320_ipc_transmit(u32 *data);
+int pl320_ipc_register_notifier(struct notifier_block *nb);
+int pl320_ipc_unregister_notifier(struct notifier_block *nb);
+
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 5/6 v9] power: export opp cpufreq functions
  2012-12-06 22:42 ` [PATCH 0/6 v9] " Mark Langsdorf
                     ` (3 preceding siblings ...)
  2012-12-06 22:42   ` [PATCH 4/6 v9] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2012-12-06 22:42   ` Mark Langsdorf
  2012-12-06 22:42   ` [PATCH 6/6 v9] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  5 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-06 22:42 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

These functions are needed to make the cpufreq-core0 and highbank-cpufreq
drivers loadable as modules.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Acked-by: Nishanth Menon <nm@ti.com>
---
Changes from v4, v5, v6, v7, v8
        None.
Changes from v3
        includes linux/export.h instead of module.h.
Changes from v2
        None.
Changes from v1
        Added Nishanth Menon's ack.
        Clarified the purpose of the change in the commit message.

 drivers/base/power/opp.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index d946864..4062ec3 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -23,6 +23,7 @@
 #include <linux/rcupdate.h>
 #include <linux/opp.h>
 #include <linux/of.h>
+#include <linux/export.h>
 
 /*
  * Internal data structure organization with the OPP layer library is as
@@ -643,6 +644,7 @@ int opp_init_cpufreq_table(struct device *dev,
 
 	return 0;
 }
+EXPORT_SYMBOL(opp_init_cpufreq_table);
 
 /**
  * opp_free_cpufreq_table() - free the cpufreq table
@@ -660,6 +662,7 @@ void opp_free_cpufreq_table(struct device *dev,
 	kfree(*table);
 	*table = NULL;
 }
+EXPORT_SYMBOL(opp_free_cpufreq_table);
 #endif		/* CONFIG_CPU_FREQ */
 
 /**
@@ -720,4 +723,5 @@ int of_init_opp_table(struct device *dev)
 
 	return 0;
 }
+EXPORT_SYMBOL(of_init_opp_table);
 #endif
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 6/6 v9] cpufreq, highbank: add support for highbank cpufreq
  2012-12-06 22:42 ` [PATCH 0/6 v9] " Mark Langsdorf
                     ` (4 preceding siblings ...)
  2012-12-06 22:42   ` [PATCH 5/6 v9] power: export opp cpufreq functions Mark Langsdorf
@ 2012-12-06 22:42   ` Mark Langsdorf
  2012-12-07  7:04     ` Mike Turquette
  5 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-06 22:42 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, mturquette

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
A9 cores and the ECME happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Reviewed-by: Shawn Guo <shawn.guo@linaro.org>
Cc: mturquette@linaro.org
---
Changes from v8
	Added Shawn Guo's reviewed by.
	Removed some magic numbers.
	Changed failure returns in clk_notify from NOTIFY_STOP to NOTIFY_BAD.
Changes from v7
        Removed old attribution to cpufreq-cpu0.
        Added some description in the documentation.
        Made cpu_dev, cpu_clk into local variables.
        Removed __devinit.
        Removed some unneeded includes.
        Added a brace to clarify some nested if logic.
Changes from v6
        Removed devicetree bindings documentation.
        Restructured driver to use clk notifications.
        Core driver logic is now cpufreq-clk0.
Changes from v5
        Changed ipc_transmit() to pl320_ipc_transmit().
Changes from v4
        Removed erroneous changes to arch/arm/Kconfig.
        Removed unnecessary changes to drivers/cpufreq/Kconfig.arm
        Alphabetized additions to arch/arm/mach-highbank/Kconfig
        Changed ipc call and header to match new ipc location in 
        drivers/mailbox.
Changes from v3
        None.
Changes from v2
        Changed transition latency binding in code to match documentation.
Changes from v1
        Added highbank specific Kconfig changes.

 arch/arm/boot/dts/highbank.dts     |  10 ++++
 arch/arm/mach-highbank/Kconfig     |   2 +
 drivers/cpufreq/Kconfig.arm        |  16 ++++++
 drivers/cpufreq/Makefile           |   1 +
 drivers/cpufreq/highbank-cpufreq.c | 109 +++++++++++++++++++++++++++++++++++++
 5 files changed, 138 insertions(+)
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 0c6fc34..7c4c27d 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -36,6 +36,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			clock-latency = <100000>;
 		};
 
 		cpu@1 {
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 2896881..b7862da 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -1,5 +1,7 @@
 config ARCH_HIGHBANK
 	bool "Calxeda ECX-1000 (Highbank)" if ARCH_MULTI_V7
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_GIC
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 5961e64..7aaac9f 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -76,3 +76,19 @@ config ARM_EXYNOS5250_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
+
+config ARM_HIGHBANK_CPUFREQ
+	tristate "Calxeda Highbank-based"
+	depends on ARCH_HIGHBANK
+	select CPU_FREQ_TABLE
+	select GENERIC_CPUFREQ_CPU0
+	select PM_OPP
+	select REGULATOR
+
+	default m
+	help
+	  This adds the CPUFreq driver for Calxeda Highbank SoC
+	  based boards.
+
+	  If in doubt, say N.
+
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 1bc90e1..9e8f12a 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..863bb39
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver provides the clk notifier callbacks that are used when
+ * the cpufreq-cpu0 driver changes to frequency to alert the highbank
+ * EnergyCore Management Engine (ECME) about the need to change
+ * voltage. The ECME interfaces with the actual voltage regulators.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/mailbox.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE	0x80000001
+#define HB_CPUFREQ_IPC_LEN	7
+#define HB_CPUFREQ_VOLT_RETRIES	15
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[HB_CPUFREQ_IPC_LEN];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000000;
+	for (i = 2; i < HB_CPUFREQ_IPC_LEN; i++)
+		msg[i] = 0;
+
+	return pl320_ipc_transmit(msg);
+}
+
+static int hb_cpufreq_clk_notify(struct notifier_block *nb, 
+				unsigned long action, void *hclk)
+{
+	struct clk_notifier_data *clk_data = hclk;
+	int i = 0;
+
+	if (action == PRE_RATE_CHANGE) {
+		if (clk_data->new_rate > clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+					return NOTIFY_BAD;
+	} else if (action == POST_RATE_CHANGE) {
+		if (clk_data->new_rate < clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+					return NOTIFY_BAD;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block hb_cpufreq_clk_nb = {
+	.notifier_call = hb_cpufreq_clk_notify,
+};
+
+static int hb_cpufreq_driver_init(void)
+{
+	struct device *cpu_dev;
+	struct clk *cpu_clk;
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = clk_notifier_register(cpu_clk, &hb_cpufreq_clk_nb);
+	if (ret) {
+		pr_err("failed to register clk notifier: %d\n", ret);
+		goto out_put_node;
+	}
+
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 6/6 v9] cpufreq, highbank: add support for highbank cpufreq
  2012-12-06 22:42   ` [PATCH 6/6 v9] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2012-12-07  7:04     ` Mike Turquette
  0 siblings, 0 replies; 142+ messages in thread
From: Mike Turquette @ 2012-12-07  7:04 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

On Thu, Dec 6, 2012 at 2:42 PM, Mark Langsdorf
<mark.langsdorf@calxeda.com> wrote:
> Highbank processors depend on the external ECME to perform voltage
> management based on a requested frequency. Communication between the
> A9 cores and the ECME happens over the pl320 IPC channel.
>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> Reviewed-by: Shawn Guo <shawn.guo@linaro.org>
> Cc: mturquette@linaro.org

Looks good to me.

Reviewed-by: Mike Turquette <mturquette@linaro.org>

Regards,
Mike

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/6 v9] arm: use devicetree to get smp_twd clock
  2012-12-06 22:42   ` [PATCH 1/6 v9] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2012-12-07 14:55     ` Thiago Farina
  2012-12-27  5:11     ` Prashant Gaikwad
  1 sibling, 0 replies; 142+ messages in thread
From: Thiago Farina @ 2012-12-07 14:55 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, Rob Herring

On Thu, Dec 6, 2012 at 8:42 PM, Mark Langsdorf
<mark.langsdorf@calxeda.com> wrote:
> From: Rob Herring <rob.herring@calxeda.com>
>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> ---
> Changes from v4, v5, v6, v7, v8
Why you keep sending these emails without real changes? Is this a
rebase process or what? I saw at least two other emails where you do
the same thing.

Thank you!

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/6 v9] arm: use devicetree to get smp_twd clock
  2012-12-06 22:42   ` [PATCH 1/6 v9] arm: use devicetree to get smp_twd clock Mark Langsdorf
  2012-12-07 14:55     ` Thiago Farina
@ 2012-12-27  5:11     ` Prashant Gaikwad
  1 sibling, 0 replies; 142+ messages in thread
From: Prashant Gaikwad @ 2012-12-27  5:11 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, Rob Herring

On Friday 07 December 2012 04:12 AM, Mark Langsdorf wrote:
> From: Rob Herring <rob.herring@calxeda.com>
>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> ---
> Changes from v4, v5, v6, v7, v8
>          None.
> Changes from v3
>          No longer setting *clk to NULL in twd_get_clock().
> Changes from v2
>          Turned the check for the node pointer into an if-then-else statement.
>          Removed the second, redundant clk_get_rate.
> Changes from v1
>          None.
>
>   arch/arm/kernel/smp_twd.c | 19 +++++++++++--------
>   1 file changed, 11 insertions(+), 8 deletions(-)

Hi Mark,

What is the status of this patch?

Regards,
PrashantG

> diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
> index b22d700..af46b80 100644
> --- a/arch/arm/kernel/smp_twd.c
> +++ b/arch/arm/kernel/smp_twd.c
> @@ -237,12 +237,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
>   	return IRQ_NONE;
>   }
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-12-05 16:48 ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                     ` (5 preceding siblings ...)
  2012-12-05 16:48   ` [PATCH 6/6 v8] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2012-12-27 13:12   ` Rafael J. Wysocki
  2012-12-27 13:28     ` Mark Langsdorf
  6 siblings, 1 reply; 142+ messages in thread
From: Rafael J. Wysocki @ 2012-12-27 13:12 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

On Wednesday, December 05, 2012 10:48:35 AM Mark Langsdorf wrote:
> This patch series adds cpufreq support for the Calxeda
> ECX-1000 (highbank) SoCs. The EnergyCore Management Engine (ECME) on
> the ECX-1000 manages the voltage for the part and communications with
> Linux through a pl320 mailbox. clk notifications are used to control
> when to send messages to the ECME.

If you want me to handle this, can you please resend the whole patchset (with
all of the comments addressed, if possible)?

Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* RE: [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-12-27 13:12   ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
@ 2012-12-27 13:28     ` Mark Langsdorf
  2012-12-27 14:43       ` Rafael J. Wysocki
  0 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2012-12-27 13:28 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

I thought I had addressed all the issues with the v9 version. The only comments I got on it was Mike's reviewed-by and I didn't think that warranted a resend.

If you do want me to send it again, do you want it  updated to current top-of-tree? That may take a bit, since there's an unrelated bug that's preventing my test box from booting.

--Mark Langsdorf
Calxeda, Inc.


________________________________________
From: Rafael J. Wysocki [rjw@sisk.pl]
Sent: Thursday, December 27, 2012 7:12 AM
To: Mark Langsdorf
Cc: linux-kernel@vger.kernel.org; cpufreq@vger.kernel.org; linux-pm@vger.kernel.org; linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank)

On Wednesday, December 05, 2012 10:48:35 AM Mark Langsdorf wrote:
> This patch series adds cpufreq support for the Calxeda
> ECX-1000 (highbank) SoCs. The EnergyCore Management Engine (ECME) on
> the ECX-1000 manages the voltage for the part and communications with
> Linux through a pl320 mailbox. clk notifications are used to control
> when to send messages to the ECME.

If you want me to handle this, can you please resend the whole patchset (with
all of the comments addressed, if possible)?

Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-12-27 13:28     ` Mark Langsdorf
@ 2012-12-27 14:43       ` Rafael J. Wysocki
  0 siblings, 0 replies; 142+ messages in thread
From: Rafael J. Wysocki @ 2012-12-27 14:43 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

On Thursday, December 27, 2012 08:28:22 AM Mark Langsdorf wrote:
> I thought I had addressed all the issues with the v9 version. The only
> comments I got on it was Mike's reviewed-by and I didn't think that
> warranted a resend.
> 
> If you do want me to send it again, do you want it  updated to current
> top-of-tree?

Yes, please.

> That may take a bit, since there's an unrelated bug that's preventing my
> test box from booting.

Sure.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 0/4 v10] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (14 preceding siblings ...)
  2012-12-06 22:42 ` [PATCH 0/6 v9] " Mark Langsdorf
@ 2013-01-04 16:35 ` Mark Langsdorf
  2013-01-04 16:35   ` [PATCH 1/4 v10] arm: use devicetree to get smp_twd clock Mark Langsdorf
                     ` (3 more replies)
  2013-01-25 19:46 ` [PATCH 0/4 v11] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2013-01-28 16:13 ` [PATCH 0/4 v12] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  17 siblings, 4 replies; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-04 16:35 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

This patch series adds cpufreq support for the Calxeda
ECX-1000 (highbank) SoCs. The EnergyCore Management Engine (ECME) on
the ECX-1000 manages the voltage for the part and communications with
Linux through a pl320 mailbox. clk notifications are used to control
when to send messages to the ECME.

Previous versions of this patch set include two other patches. One has
been dropped as unworkable and the other got picked up and included in
3.8.0.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/4 v10] arm: use devicetree to get smp_twd clock
  2013-01-04 16:35 ` [PATCH 0/4 v10] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
@ 2013-01-04 16:35   ` Mark Langsdorf
  2013-01-10 23:34     ` Russell King - ARM Linux
  2013-01-04 16:35   ` [PATCH 2/4 v10] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-04 16:35 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v9
	Updated to work with 3.8 kernel.
Changes from v4, v5, v6, v7, v8
        None.
Changes from v3
        No longer setting *clk to NULL in twd_get_clock().
Changes from v2
        Turned the check for the node pointer into an if-then-else statement.
        Removed the second, redundant clk_get_rate.
Changes from v1
        None.

 arch/arm/kernel/smp_twd.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 49f335d..dad2d81 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -239,12 +239,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static struct clk *twd_get_clock(struct device_node *np)
 {
 	struct clk *clk;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
+	if (np)
+		clk = of_clk_get(np, 0);
+	else
+		clk = clk_get_sys("smp_twd", NULL);
 	if (IS_ERR(clk)) {
 		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
 		return clk;
@@ -257,6 +260,7 @@ static struct clk *twd_get_clock(void)
 		return ERR_PTR(err);
 	}
 
+	twd_timer_rate = clk_get_rate(clk);
 	return clk;
 }
 
@@ -285,7 +289,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 	 * during the runtime of the system.
 	 */
 	if (!common_setup_called) {
-		twd_clk = twd_get_clock();
+		twd_clk = twd_get_clock(NULL);
 
 		/*
 		 * We use IS_ERR_OR_NULL() here, because if the clock stubs
@@ -373,6 +377,8 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
+	twd_clk = twd_get_clock(NULL);
+
 	return twd_local_timer_common_register();
 }
 
@@ -405,6 +411,8 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
+	twd_clk = twd_get_clock(np);
+
 	err = twd_local_timer_common_register();
 
 out:
-- 
1.8.0.2


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/4 v10] clk, highbank: Prevent glitches in non-bypass reset mode
  2013-01-04 16:35 ` [PATCH 0/4 v10] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2013-01-04 16:35   ` [PATCH 1/4 v10] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2013-01-04 16:35   ` Mark Langsdorf
  2013-01-04 16:35   ` [PATCH 3/4 v10] arm highbank: add support for pl320 IPC Mark Langsdorf
  2013-01-04 16:35   ` [PATCH 4/4 v10] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  3 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-04 16:35 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

The highbank clock will glitch with the current code if the
clock rate is reset without relocking the PLL. Program the PLL
correctly to prevent glitches.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
---
Changes from v6, v7, v8, v9
        None.
Changes from v5
        Added Mike Turquette's ack.
Changes from v4
        None.
Changes from v3
        Changelog text and patch name now correspond to the actual patch.
        was clk, highbank: remove non-bypass reset mode.
Changes from v2
        None.
Changes from v1
        Removed erroneous reformating.

 drivers/clk/clk-highbank.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..3a0b723 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.8.0.2


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/4 v10] arm highbank: add support for pl320 IPC
  2013-01-04 16:35 ` [PATCH 0/4 v10] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2013-01-04 16:35   ` [PATCH 1/4 v10] arm: use devicetree to get smp_twd clock Mark Langsdorf
  2013-01-04 16:35   ` [PATCH 2/4 v10] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2013-01-04 16:35   ` Mark Langsdorf
  2013-01-04 16:35   ` [PATCH 4/4 v10] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  3 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-04 16:35 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring, Omar Ramirez Luna, Arnd Bergmann

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the highbank A9
and the EnergyCore Management Engine. The pl320 implements a straightforward
mailbox protocol.

This patch depends on Omar Ramirez Luna's <omar.luna@linaro.org>
mailbox driver patch series.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Omar Ramirez Luna <omar.luna@linaro.org>
Cc: Arnd Bergmann <arnd@arndb.de>
---
Changes from v9
	Used to be the 4th patch in the series.
Changes from v6, v7, v8
        None.
Changes from v5
        Renamed ipc_transmit() to pl320_ipc_transmit().
        Properly exported pl320_ipc_{un}register_notifier().
Changes from v4
        Moved pl320-ipc.c from arch/arm/mach-highbank to drivers/mailbox.
        Moved header information to include/linux/mailbox.h.
        Added Kconfig options to reflect the new code location.
        Change drivers/mailbox/Makefile to build the omap mailboxes only 
        when they are configured.
        Removed ipc_call_fast and renamed ipc_call_slow ipc_transmit.
Changes from v3, v2
        None.
Changes from v1
        Removed erroneous changes for cpufreq Kconfig.

 arch/arm/mach-highbank/Kconfig |   2 +
 drivers/mailbox/Kconfig        |   9 ++
 drivers/mailbox/Makefile       |   6 +-
 drivers/mailbox/Makefile.rej   |   7 ++
 drivers/mailbox/pl320-ipc.c    | 199 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 220 insertions(+), 3 deletions(-)
 create mode 100644 drivers/mailbox/Makefile.rej
 create mode 100644 drivers/mailbox/pl320-ipc.c

diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 551c97e..2388085 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -11,5 +11,7 @@ config ARCH_HIGHBANK
 	select GENERIC_CLOCKEVENTS
 	select HAVE_ARM_SCU
 	select HAVE_SMP
+	select MAILBOX
+	select PL320_MBOX
 	select SPARSE_IRQ
 	select USE_OF
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index be8cac0..e89fdb4 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -34,4 +34,13 @@ config OMAP_MBOX_KFIFO_SIZE
 	  This can also be changed at runtime (via the mbox_kfifo_size
 	  module parameter).
 
+config PL320_MBOX
+	bool "ARM PL320 Mailbox"
+	help
+	  An implementation of the ARM PL320 Interprocessor Communication
+	  Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to
+	  send short messages between Highbank's A9 cores and the EnergyCore
+	  Management Engine, primarily for cpufreq. Say Y here if you want
+	  to use the PL320 IPCM support.
+
 endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index fa71fab..dc3fbc5 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_MAILBOX) += mailbox.o
+obj-$(CONFIG_OMAP1_MBOX)	+= mailbox-omap1.o mailbox.o
+obj-$(CONFIG_OMAP2PLUS_MBOX)	+= mailbox-omap2.o mailbox.o
+obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
 
-obj-$(CONFIG_OMAP1_MBOX)	+= mailbox-omap1.o
-obj-$(CONFIG_OMAP2PLUS_MBOX)	+= mailbox-omap2.o
diff --git a/drivers/mailbox/Makefile.rej b/drivers/mailbox/Makefile.rej
new file mode 100644
index 0000000..62ade60
--- /dev/null
+++ b/drivers/mailbox/Makefile.rej
@@ -0,0 +1,7 @@
+--- /dev/null
++++ drivers/mailbox/Makefile
+@@ -0,0 +1,4 @@
++obj-$(CONFIG_OMAP1_MBOX)	+= mailbox.o mailbox-omap1.o
++obj-$(CONFIG_OMAP2PLUS_MBOX)	+= mailbox.o mailbox-omap2.o
++obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
++
diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
new file mode 100644
index 0000000..1a9d8e4
--- /dev/null
+++ b/drivers/mailbox/pl320-ipc.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <linux/mailbox.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_TX_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int pl320_ipc_transmit(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_TX_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_TX_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL(pl320_ipc_transmit);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_register_notifier);
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_unregister_notifier);
+
+static int __devinit pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_TX_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
-- 
1.8.0.2


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 4/4 v10] cpufreq, highbank: add support for highbank cpufreq
  2013-01-04 16:35 ` [PATCH 0/4 v10] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                     ` (2 preceding siblings ...)
  2013-01-04 16:35   ` [PATCH 3/4 v10] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2013-01-04 16:35   ` Mark Langsdorf
  3 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-04 16:35 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
A9 cores and the ECME happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Reviewed-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Mike Turquette <mturquette@linaro.org>
---
Changes from v9
	Added Mike Turquette's reviewed by.
	Used to be the 6th patch in the series.
Changes from v8
        Added Shawn Guo's reviewed by.
        Removed some magic numbers.
        Changed failure returns in clk_notify from NOTIFY_STOP to NOTIFY_BAD.
Changes from v7
        Removed old attribution to cpufreq-cpu0.
        Added some description in the documentation.
        Made cpu_dev, cpu_clk into local variables.
        Removed __devinit.
        Removed some unneeded includes.
        Added a brace to clarify some nested if logic.
Changes from v6
        Removed devicetree bindings documentation.
        Restructured driver to use clk notifications.
        Core driver logic is now cpufreq-clk0.
Changes from v5
        Changed ipc_transmit() to pl320_ipc_transmit().
Changes from v4
        Removed erroneous changes to arch/arm/Kconfig.
        Removed unnecessary changes to drivers/cpufreq/Kconfig.arm
        Alphabetized additions to arch/arm/mach-highbank/Kconfig
        Changed ipc call and header to match new ipc location in 
        drivers/mailbox.
Changes from v3
        None.
Changes from v2
        Changed transition latency binding in code to match documentation.
Changes from v1
        Added highbank specific Kconfig changes.

 arch/arm/boot/dts/highbank.dts     |  10 ++++
 arch/arm/mach-highbank/Kconfig     |   2 +
 drivers/cpufreq/Kconfig.arm        |  15 +++++
 drivers/cpufreq/Makefile           |   1 +
 drivers/cpufreq/highbank-cpufreq.c | 109 +++++++++++++++++++++++++++++++++++++
 5 files changed, 137 insertions(+)
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index a9ae5d3..202f12e 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -36,6 +36,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			clock-latency = <100000>;
 		};
 
 		cpu@1 {
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 2388085..44b12f9 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -1,5 +1,7 @@
 config ARCH_HIGHBANK
 	bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_GIC
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index a0b3661..7c71c1b 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -83,3 +83,18 @@ config ARM_SPEAR_CPUFREQ
 	default y
 	help
 	  This adds the CPUFreq driver support for SPEAr SOCs.
+
+config ARM_HIGHBANK_CPUFREQ
+	tristate "Calxeda Highbank-based"
+	depends on ARCH_HIGHBANK
+	select CPU_FREQ_TABLE
+	select GENERIC_CPUFREQ_CPU0
+	select PM_OPP
+	select REGULATOR
+
+	default m
+	help
+	   This adds the CPUFreq driver for Calxeda Highbank SoC
+	   based boards.
+
+	   If in doubt, say N.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 1f254ec0..2f7ab0b 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
 obj-$(CONFIG_ARM_SPEAR_CPUFREQ)		+= spear-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..8c85608
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver provides the clk notifier callbacks that are used when
+ * the cpufreq-cpu0 driver changes to frequency to alert the highbank
+ * EnergyCore Management Engine (ECME) about the need to change
+ * voltage. The ECME interfaces with the actual voltage regulators.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/mailbox.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE	0x80000001
+#define HB_CPUFREQ_IPC_LEN	7
+#define HB_CPUFREQ_VOLT_RETRIES	15
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[HB_CPUFREQ_IPC_LEN];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000000;
+	for (i = 2; i < HB_CPUFREQ_IPC_LEN; i++)
+		msg[i] = 0;
+
+	return pl320_ipc_transmit(msg);
+}
+
+static int hb_cpufreq_clk_notify(struct notifier_block *nb,
+				unsigned long action, void *hclk)
+{
+	struct clk_notifier_data *clk_data = hclk;
+	int i = 0;
+
+	if (action == PRE_RATE_CHANGE) {
+		if (clk_data->new_rate > clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+					return NOTIFY_BAD;
+	} else if (action == POST_RATE_CHANGE) {
+		if (clk_data->new_rate < clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+					return NOTIFY_BAD;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block hb_cpufreq_clk_nb = {
+	.notifier_call = hb_cpufreq_clk_notify,
+};
+
+static int hb_cpufreq_driver_init(void)
+{
+	struct device *cpu_dev;
+	struct clk *cpu_clk;
+	struct device_node *np;
+	int ret;
+
+	np = of_find_node_by_path("/cpus/cpu@0");
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = clk_notifier_register(cpu_clk, &hb_cpufreq_clk_nb);
+	if (ret) {
+		pr_err("failed to register clk notifier: %d\n", ret);
+		goto out_put_node;
+	}
+
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+late_initcall(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.8.0.2


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/4 v10] arm: use devicetree to get smp_twd clock
  2013-01-04 16:35   ` [PATCH 1/4 v10] arm: use devicetree to get smp_twd clock Mark Langsdorf
@ 2013-01-10 23:34     ` Russell King - ARM Linux
  2013-01-11 14:40       ` Rob Herring
  0 siblings, 1 reply; 142+ messages in thread
From: Russell King - ARM Linux @ 2013-01-10 23:34 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, Rob Herring

Mark,

Rafael just asked me to look at this patch, though I guess these comments
should be directed to Rob who was the original patch author.

On Fri, Jan 04, 2013 at 10:35:43AM -0600, Mark Langsdorf wrote:
> diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
> index 49f335d..dad2d81 100644
> --- a/arch/arm/kernel/smp_twd.c
> +++ b/arch/arm/kernel/smp_twd.c
> @@ -239,12 +239,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
>  	return IRQ_NONE;
>  }
>  
> -static struct clk *twd_get_clock(void)
> +static struct clk *twd_get_clock(struct device_node *np)
>  {
>  	struct clk *clk;
>  	int err;
>  
> -	clk = clk_get_sys("smp_twd", NULL);
> +	if (np)
> +		clk = of_clk_get(np, 0);
> +	else
> +		clk = clk_get_sys("smp_twd", NULL);
>  	if (IS_ERR(clk)) {
>  		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
>  		return clk;
> @@ -257,6 +260,7 @@ static struct clk *twd_get_clock(void)
>  		return ERR_PTR(err);
>  	}
>  
> +	twd_timer_rate = clk_get_rate(clk);

Hmm, so this overrides the later clk_get_rate() in twd_timer_setup(), making
the later one redundant.  However...

>  	return clk;
>  }
>  
> @@ -285,7 +289,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
>  	 * during the runtime of the system.
>  	 */
>  	if (!common_setup_called) {
> -		twd_clk = twd_get_clock();
> +		twd_clk = twd_get_clock(NULL);
>  
>  		/*
>  		 * We use IS_ERR_OR_NULL() here, because if the clock stubs
> @@ -373,6 +377,8 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
>  	if (!twd_base)
>  		return -ENOMEM;
>  
> +	twd_clk = twd_get_clock(NULL);
> +
>  	return twd_local_timer_common_register();

Ok, so this sets up twd_clk, and also twd_timer_rate, but
twd_local_timer_common_register() just ends up registering the set of
function pointers with the local timer code.  Some point later, the
->setup function is called, and that will happen with common_setup_called
false.  The result will be another call to twd_get_clock().

>  }
>  
> @@ -405,6 +411,8 @@ void __init twd_local_timer_of_register(void)
>  		goto out;
>  	}
>  
> +	twd_clk = twd_get_clock(np);
> +
>  	err = twd_local_timer_common_register();

And a similar thing happens here.  Except... the twd_clk gets overwritten
by the call to twd_get_clock(NULL) from twd_timer_setup().

I wonder if it would be much better to move twd_get_clock() out of
twd_timer_setup() entirely, moving it into twd_local_timer_common_register().
twd_local_timer_common_register() would have to take the dev node.
Also, leave the setting of twd_timer_rate in twd_timer_setup().

An alternative strategy would be to move the initialization of the
timer rate also into twd_local_timer_common_register(), detect the
NULL or error clock, and run the calibration from there (I don't think
we can move the calibration).  If that's chosen, then "common_setup_called"
should probably be renamed to "twd_calibration_done".

What do you think?

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/4 v10] arm: use devicetree to get smp_twd clock
  2013-01-10 23:34     ` Russell King - ARM Linux
@ 2013-01-11 14:40       ` Rob Herring
  0 siblings, 0 replies; 142+ messages in thread
From: Rob Herring @ 2013-01-11 14:40 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Mark Langsdorf, linux-kernel, cpufreq, linux-pm, linux-arm-kernel

On 01/10/2013 05:34 PM, Russell King - ARM Linux wrote:
> Mark,
> 
> Rafael just asked me to look at this patch, though I guess these comments
> should be directed to Rob who was the original patch author.
> 
> On Fri, Jan 04, 2013 at 10:35:43AM -0600, Mark Langsdorf wrote:
>> diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
>> index 49f335d..dad2d81 100644
>> --- a/arch/arm/kernel/smp_twd.c
>> +++ b/arch/arm/kernel/smp_twd.c
>> @@ -239,12 +239,15 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
>>  	return IRQ_NONE;
>>  }
>>  
>> -static struct clk *twd_get_clock(void)
>> +static struct clk *twd_get_clock(struct device_node *np)
>>  {
>>  	struct clk *clk;
>>  	int err;
>>  
>> -	clk = clk_get_sys("smp_twd", NULL);
>> +	if (np)
>> +		clk = of_clk_get(np, 0);
>> +	else
>> +		clk = clk_get_sys("smp_twd", NULL);
>>  	if (IS_ERR(clk)) {
>>  		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
>>  		return clk;
>> @@ -257,6 +260,7 @@ static struct clk *twd_get_clock(void)
>>  		return ERR_PTR(err);
>>  	}
>>  
>> +	twd_timer_rate = clk_get_rate(clk);
> 
> Hmm, so this overrides the later clk_get_rate() in twd_timer_setup(), making
> the later one redundant.  However...
> 
>>  	return clk;
>>  }
>>  
>> @@ -285,7 +289,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
>>  	 * during the runtime of the system.
>>  	 */
>>  	if (!common_setup_called) {
>> -		twd_clk = twd_get_clock();
>> +		twd_clk = twd_get_clock(NULL);
>>  
>>  		/*
>>  		 * We use IS_ERR_OR_NULL() here, because if the clock stubs
>> @@ -373,6 +377,8 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
>>  	if (!twd_base)
>>  		return -ENOMEM;
>>  
>> +	twd_clk = twd_get_clock(NULL);
>> +
>>  	return twd_local_timer_common_register();
> 
> Ok, so this sets up twd_clk, and also twd_timer_rate, but
> twd_local_timer_common_register() just ends up registering the set of
> function pointers with the local timer code.  Some point later, the
> ->setup function is called, and that will happen with common_setup_called
> false.  The result will be another call to twd_get_clock().
> 
>>  }
>>  
>> @@ -405,6 +411,8 @@ void __init twd_local_timer_of_register(void)
>>  		goto out;
>>  	}
>>  
>> +	twd_clk = twd_get_clock(np);
>> +
>>  	err = twd_local_timer_common_register();
> 
> And a similar thing happens here.  Except... the twd_clk gets overwritten
> by the call to twd_get_clock(NULL) from twd_timer_setup().
> 
> I wonder if it would be much better to move twd_get_clock() out of
> twd_timer_setup() entirely, moving it into twd_local_timer_common_register().
> twd_local_timer_common_register() would have to take the dev node.
> Also, leave the setting of twd_timer_rate in twd_timer_setup().
> 
> An alternative strategy would be to move the initialization of the
> timer rate also into twd_local_timer_common_register(), detect the
> NULL or error clock, and run the calibration from there (I don't think
> we can move the calibration).  If that's chosen, then "common_setup_called"
> should probably be renamed to "twd_calibration_done".
> 
> What do you think?

Yes, things can be simplified a bit. How about this patch? I moved the clk
setup to twd_local_timer_common_register. Then we just rely on twd_timer_rate
being 0 when there is no clock and we need to do calibration. Then we can get
rid of common_setup_called altogether.

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index dc9bb01..2201e2d 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -30,7 +30,6 @@ static void __iomem *twd_base;
 
 static struct clk *twd_clk;
 static unsigned long twd_timer_rate;
-static bool common_setup_called;
 static DEFINE_PER_CPU(bool, percpu_setup_called);
 
 static struct clock_event_device __percpu **twd_evt;
@@ -238,25 +237,28 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static void twd_get_clock(struct device_node *np)
 {
-	struct clk *clk;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
-	if (IS_ERR(clk)) {
-		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
-		return clk;
+	if (np)
+		twd_clk = of_clk_get(np, 0);
+	else
+		twd_clk = clk_get_sys("smp_twd", NULL);
+
+	if (IS_ERR(twd_clk)) {
+		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(twd_clk));
+		return;
 	}
 
-	err = clk_prepare_enable(clk);
+	err = clk_prepare_enable(twd_clk);
 	if (err) {
 		pr_err("smp_twd: clock failed to prepare+enable: %d\n", err);
-		clk_put(clk);
-		return ERR_PTR(err);
+		clk_put(twd_clk);
+		return;
 	}
 
-	return clk;
+	twd_timer_rate = clk_get_rate(twd_clk);
 }
 
 /*
@@ -279,26 +281,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 	}
 	per_cpu(percpu_setup_called, cpu) = true;
 
-	/*
-	 * This stuff only need to be done once for the entire TWD cluster
-	 * during the runtime of the system.
-	 */
-	if (!common_setup_called) {
-		twd_clk = twd_get_clock();
-
-		/*
-		 * We use IS_ERR_OR_NULL() here, because if the clock stubs
-		 * are active we will get a valid clk reference which is
-		 * however NULL and will return the rate 0. In that case we
-		 * need to calibrate the rate instead.
-		 */
-		if (!IS_ERR_OR_NULL(twd_clk))
-			twd_timer_rate = clk_get_rate(twd_clk);
-		else
-			twd_calibrate_rate();
-
-		common_setup_called = true;
-	}
+	twd_calibrate_rate();
 
 	/*
 	 * The following is done once per CPU the first time .setup() is
@@ -329,7 +312,7 @@ static struct local_timer_ops twd_lt_ops __cpuinitdata = {
 	.stop	= twd_timer_stop,
 };
 
-static int __init twd_local_timer_common_register(void)
+static int __init twd_local_timer_common_register(struct device_node *np)
 {
 	int err;
 
@@ -349,6 +332,8 @@ static int __init twd_local_timer_common_register(void)
 	if (err)
 		goto out_irq;
 
+	twd_get_clock(np);
+
 	return 0;
 
 out_irq:
@@ -372,7 +357,7 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
-	return twd_local_timer_common_register();
+	return twd_local_timer_common_register(NULL);
 }
 
 #ifdef CONFIG_OF
@@ -404,7 +389,7 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
-	err = twd_local_timer_common_register();
+	err = twd_local_timer_common_register(np);
 
 out:
 	WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
 

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 0/4 v11] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (15 preceding siblings ...)
  2013-01-04 16:35 ` [PATCH 0/4 v10] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
@ 2013-01-25 19:46 ` Mark Langsdorf
  2013-01-25 19:46   ` [PATCH 1/4 v11] arm: use device tree to get smp_twd clock Mark Langsdorf
                     ` (3 more replies)
  2013-01-28 16:13 ` [PATCH 0/4 v12] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  17 siblings, 4 replies; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-25 19:46 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

This patch series adds cpufreq support for the Calxeda
ECX-1000 (highbank) SoCs. The EnergyCore Management Engine (ECME) on
the ECX-1000 manages the voltage for the part and communications with
Linux through a pl320 mailbox. clk notifications are used to control
when to send messages to the ECME.

Previous versions of this patch set include two other patches. One has
been dropped as unworkable and the other turned out to be unnecessary.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/4 v11] arm: use device tree to get smp_twd clock
  2013-01-25 19:46 ` [PATCH 0/4 v11] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
@ 2013-01-25 19:46   ` Mark Langsdorf
  2013-01-25 21:03     ` Rafael J. Wysocki
  2013-01-25 19:46   ` [PATCH 2/4 v11] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-25 19:46 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

Move clk setup to twd_local_timer_common_register and rely on
twd_timer_rate being 0 to force calibration if there is no clock.
Remove common_setup_called as it is no longer needed.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v10
	Reworked to simplify the logic as suggested by Russell King.
Changes from v9
        Updated to work with 3.8 kernel.
Changes from v4, v5, v6, v7, v8
        None.
Changes from v3
        No longer setting *clk to NULL in twd_get_clock().
Changes from v2
        Turned the check for the node pointer into an if-then-else statement.
        Removed the second, redundant clk_get_rate.
Changes from v1
        None.

 arch/arm/kernel/smp_twd.c | 53 +++++++++++++++++------------------------------
 1 file changed, 19 insertions(+), 34 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 49f335d..ae0c7bb 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -31,7 +31,6 @@ static void __iomem *twd_base;
 
 static struct clk *twd_clk;
 static unsigned long twd_timer_rate;
-static bool common_setup_called;
 static DEFINE_PER_CPU(bool, percpu_setup_called);
 
 static struct clock_event_device __percpu **twd_evt;
@@ -239,25 +238,28 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static void twd_get_clock(struct device_node *np)
 {
-	struct clk *clk;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
-	if (IS_ERR(clk)) {
-		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
-		return clk;
+	if (np)
+		twd_clk = of_clk_get(np, 0);
+	else
+		twd_clk = clk_get_sys("smp_twd", NULL);
+
+	if (IS_ERR(twd_clk)) {
+		pr_err("smp_twd: clock not found %d\n", (int) PTR_ERR(twd_clk));
+		return;
 	}
 
-	err = clk_prepare_enable(clk);
+	err = clk_prepare_enable(twd_clk);
 	if (err) {
 		pr_err("smp_twd: clock failed to prepare+enable: %d\n", err);
-		clk_put(clk);
-		return ERR_PTR(err);
+		clk_put(twd_clk);
+		return;
 	}
 
-	return clk;
+	twd_timer_rate = clk_get_rate(twd_clk);
 }
 
 /*
@@ -280,26 +282,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 	}
 	per_cpu(percpu_setup_called, cpu) = true;
 
-	/*
-	 * This stuff only need to be done once for the entire TWD cluster
-	 * during the runtime of the system.
-	 */
-	if (!common_setup_called) {
-		twd_clk = twd_get_clock();
-
-		/*
-		 * We use IS_ERR_OR_NULL() here, because if the clock stubs
-		 * are active we will get a valid clk reference which is
-		 * however NULL and will return the rate 0. In that case we
-		 * need to calibrate the rate instead.
-		 */
-		if (!IS_ERR_OR_NULL(twd_clk))
-			twd_timer_rate = clk_get_rate(twd_clk);
-		else
-			twd_calibrate_rate();
-
-		common_setup_called = true;
-	}
+	twd_calibrate_rate();
 
 	/*
 	 * The following is done once per CPU the first time .setup() is
@@ -330,7 +313,7 @@ static struct local_timer_ops twd_lt_ops __cpuinitdata = {
 	.stop	= twd_timer_stop,
 };
 
-static int __init twd_local_timer_common_register(void)
+static int __init twd_local_timer_common_register(struct device_node *np)
 {
 	int err;
 
@@ -350,6 +333,8 @@ static int __init twd_local_timer_common_register(void)
 	if (err)
 		goto out_irq;
 
+	twd_get_clock(np);
+
 	return 0;
 
 out_irq:
@@ -373,7 +358,7 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
-	return twd_local_timer_common_register();
+	return twd_local_timer_common_register(NULL);
 }
 
 #ifdef CONFIG_OF
@@ -405,7 +390,7 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
-	err = twd_local_timer_common_register();
+	err = twd_local_timer_common_register(np);
 
 out:
 	WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/4 v11] clk, highbank: Prevent glitches in non-bypass reset mode
  2013-01-25 19:46 ` [PATCH 0/4 v11] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2013-01-25 19:46   ` [PATCH 1/4 v11] arm: use device tree to get smp_twd clock Mark Langsdorf
@ 2013-01-25 19:46   ` Mark Langsdorf
  2013-01-25 19:46   ` [PATCH 3/4 v11] arm highbank: add support for pl320 IPC Mark Langsdorf
  2013-01-25 19:46   ` [PATCH 4/4] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  3 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-25 19:46 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

The highbank clock will glitch with the current code if the
clock rate is reset without relocking the PLL. Program the PLL
correctly to prevent glitches.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
---
Changes from v6, v7, v8, v9, v10
        None.
Changes from v5
        Added Mike Turquette's ack.
Changes from v4
        None.
Changes from v3
        Changelog text and patch name now correspond to the actual patch.
        was clk, highbank: remove non-bypass reset mode.
Changes from v2
        None.
Changes from v1
        Removed erroneous reformating.

 drivers/clk/clk-highbank.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..3a0b723 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/4 v11] arm highbank: add support for pl320 IPC
  2013-01-25 19:46 ` [PATCH 0/4 v11] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2013-01-25 19:46   ` [PATCH 1/4 v11] arm: use device tree to get smp_twd clock Mark Langsdorf
  2013-01-25 19:46   ` [PATCH 2/4 v11] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2013-01-25 19:46   ` Mark Langsdorf
  2013-01-28 12:49     ` Rafael J. Wysocki
  2013-01-25 19:46   ` [PATCH 4/4] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  3 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-25 19:46 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring, Omar Ramirez Luna, Arnd Bergmann

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the highbank A9
and the EnergyCore Management Engine. The pl320 implements a straightforward
mailbox protocol.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Omar Ramirez Luna <omar.luna@linaro.org>
Cc: Arnd Bergmann <arnd@arndb.de>
---
Changes from v10
	Removed deependency on Omar Ramirez Luna's mailbox code. Now the
	patch creates the directory itself.
Changes from v9
        Used to be the 4th patch in the series.
Changes from v6, v7, v8
        None.
Changes from v5
        Renamed ipc_transmit() to pl320_ipc_transmit().
        Properly exported pl320_ipc_{un}register_notifier().
Changes from v4
        Moved pl320-ipc.c from arch/arm/mach-highbank to drivers/mailbox.
        Moved header information to include/linux/mailbox.h.
        Added Kconfig options to reflect the new code location.
        Change drivers/mailbox/Makefile to build the omap mailboxes only 
        when they are configured.
        Removed ipc_call_fast and renamed ipc_call_slow ipc_transmit.
Changes from v3, v2
        None.
Changes from v1
        Removed erroneous changes for cpufreq Kconfig.

 arch/arm/mach-highbank/Kconfig |   2 +
 drivers/mailbox/Kconfig        |  18 ++++
 drivers/mailbox/Makefile       |   1 +
 drivers/mailbox/pl320-ipc.c    | 199 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mailbox.h        |  18 ++++
 5 files changed, 238 insertions(+)
 create mode 100644 drivers/mailbox/Kconfig
 create mode 100644 drivers/mailbox/Makefile
 create mode 100644 drivers/mailbox/pl320-ipc.c
 create mode 100644 include/linux/mailbox.h

diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 551c97e..2388085 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -11,5 +11,7 @@ config ARCH_HIGHBANK
 	select GENERIC_CLOCKEVENTS
 	select HAVE_ARM_SCU
 	select HAVE_SMP
+	select MAILBOX
+	select PL320_MBOX
 	select SPARSE_IRQ
 	select USE_OF
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
new file mode 100644
index 0000000..9489554
--- /dev/null
+++ b/drivers/mailbox/Kconfig
@@ -0,0 +1,18 @@
+menuconfig MAILBOX
+	bool "Mailbox Hardware Support"
+	help
+	  Mailbox is a framework to control hardware communication between
+	  on-chip processors through queued messages and interrupt driven
+	  signals. Say Y if your platform supports hardware mailboxes.
+
+if MAILBOX
+config PL320_MBOX
+	bool "ARM PL320 Mailbox"
+	help
+	  An implementation of the ARM PL320 Interprocessor Communication
+	  Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to
+	  send short messages between Highbank's A9 cores and the EnergyCore
+	  Management Engine, primarily for cpufreq. Say Y here if you want
+	  to use the PL320 IPCM support.
+
+endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
new file mode 100644
index 0000000..543ad6a
--- /dev/null
+++ b/drivers/mailbox/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
new file mode 100644
index 0000000..68c0d50
--- /dev/null
+++ b/drivers/mailbox/pl320-ipc.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <linux/mailbox.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_TX_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int pl320_ipc_transmit(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_TX_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_TX_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL(pl320_ipc_transmit);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_register_notifier);
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL(pl320_ipc_unregister_notifier);
+
+static int __init pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_TX_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
diff --git a/include/linux/mailbox.h b/include/linux/mailbox.h
new file mode 100644
index 0000000..911cb28
--- /dev/null
+++ b/include/linux/mailbox.h
@@ -0,0 +1,18 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+int pl320_ipc_transmit(u32 *data);
+int pl320_ipc_register_notifier(struct notifier_block *nb);
+int pl320_ipc_unregister_notifier(struct notifier_block *nb);
+
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 4/4] cpufreq, highbank: add support for highbank cpufreq
  2013-01-25 19:46 ` [PATCH 0/4 v11] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                     ` (2 preceding siblings ...)
  2013-01-25 19:46   ` [PATCH 3/4 v11] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2013-01-25 19:46   ` Mark Langsdorf
  2013-01-26 14:39     ` Shawn Guo
  3 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-25 19:46 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
A9 cores and the ECME happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Reviewed-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Mike Turquette <mturquette@linaro.org>
---
Changes from v10
	Now finds a cpu node by searching under /cpus and looking for something
	with an operating-points descriptor. This applies to both 
	highbank-cpufreq and cpufreq-cpu0.
Changes from v9
        Added Mike Turquette's reviewed by.
        Used to be the 6th patch in the series.
Changes from v8
        Added Shawn Guo's reviewed by.
        Removed some magic numbers.
        Changed failure returns in clk_notify from NOTIFY_STOP to NOTIFY_BAD.
Changes from v7
        Removed old attribution to cpufreq-cpu0.
        Added some description in the documentation.
        Made cpu_dev, cpu_clk into local variables.
        Removed __devinit.
        Removed some unneeded includes.
        Added a brace to clarify some nested if logic.
Changes from v6
        Removed devicetree bindings documentation.
        Restructured driver to use clk notifications.
        Core driver logic is now cpufreq-clk0.
Changes from v5
        Changed ipc_transmit() to pl320_ipc_transmit().
Changes from v4
        Removed erroneous changes to arch/arm/Kconfig.
        Removed unnecessary changes to drivers/cpufreq/Kconfig.arm
        Alphabetized additions to arch/arm/mach-highbank/Kconfig
        Changed ipc call and header to match new ipc location in 
        drivers/mailbox.
Changes from v3
        None.
Changes from v2
        Changed transition latency binding in code to match documentation.
Changes from v1
        Added highbank specific Kconfig changes.

 arch/arm/boot/dts/highbank.dts     |  10 ++++
 arch/arm/mach-highbank/Kconfig     |   2 +
 drivers/cpufreq/Kconfig.arm        |  15 +++++
 drivers/cpufreq/Makefile           |   3 +-
 drivers/cpufreq/cpufreq-cpu0.c     |   6 +-
 drivers/cpufreq/highbank-cpufreq.c | 112 +++++++++++++++++++++++++++++++++++++
 6 files changed, 146 insertions(+), 2 deletions(-)
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 5927a8d..6aad34a 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -37,6 +37,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			clock-latency = <100000>;
 		};
 
 		cpu@901 {
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 2388085..44b12f9 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -1,5 +1,7 @@
 config ARCH_HIGHBANK
 	bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_GIC
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index a0b3661..ffe55b8 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -83,3 +83,18 @@ config ARM_SPEAR_CPUFREQ
 	default y
 	help
 	  This adds the CPUFreq driver support for SPEAr SOCs.
+
+config ARM_HIGHBANK_CPUFREQ
+	tristate "Calxeda Highbank-based"
+	depends on ARCH_HIGHBANK
+	select CPU_FREQ_TABLE
+	select GENERIC_CPUFREQ_CPU0
+	select PM_OPP
+	select REGULATOR
+
+	default m
+	help
+	  This adds the CPUFreq driver for Calxeda Highbank SoC
+	  based boards.
+
+	  If in doubt, say N.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index fadc4d4..31e6f19 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -50,8 +50,9 @@ obj-$(CONFIG_ARM_EXYNOS_CPUFREQ)	+= exynos-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
-obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)	+= omap-cpufreq.o
 obj-$(CONFIG_ARM_SPEAR_CPUFREQ)		+= spear-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index 52bf36d..90e9d73 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -179,7 +179,11 @@ static int cpu0_cpufreq_driver_init(void)
 	struct device_node *np;
 	int ret;
 
-	np = of_find_node_by_path("/cpus/cpu@0");
+	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+		if (of_get_property(np, "operating-points", NULL))
+			break;
+	}
+
 	if (!np) {
 		pr_err("failed to find cpu0 node\n");
 		return -ENOENT;
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..a5bad89
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver provides the clk notifier callbacks that are used when
+ * the cpufreq-cpu0 driver changes to frequency to alert the highbank
+ * EnergyCore Management Engine (ECME) about the need to change
+ * voltage. The ECME interfaces with the actual voltage regulators.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/mailbox.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE	0x80000001
+#define HB_CPUFREQ_IPC_LEN	7
+#define HB_CPUFREQ_VOLT_RETRIES	15
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[HB_CPUFREQ_IPC_LEN];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000000;
+	for (i = 2; i < HB_CPUFREQ_IPC_LEN; i++)
+		msg[i] = 0;
+
+	return pl320_ipc_transmit(msg);
+}
+
+static int hb_cpufreq_clk_notify(struct notifier_block *nb,
+				unsigned long action, void *hclk)
+{
+	struct clk_notifier_data *clk_data = hclk;
+	int i = 0;
+
+	if (action == PRE_RATE_CHANGE) {
+		if (clk_data->new_rate > clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+					return NOTIFY_BAD;
+	} else if (action == POST_RATE_CHANGE) {
+		if (clk_data->new_rate < clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+					return NOTIFY_BAD;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block hb_cpufreq_clk_nb = {
+	.notifier_call = hb_cpufreq_clk_notify,
+};
+
+static int hb_cpufreq_driver_init(void)
+{
+	struct device *cpu_dev;
+	struct clk *cpu_clk;
+	struct device_node *np;
+	int ret;
+
+	for_each_child_of_node(of_find_node_by_path("/cpus"), np)
+		if (of_get_property(np, "operating-points", NULL))
+			break;
+
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = clk_notifier_register(cpu_clk, &hb_cpufreq_clk_nb);
+	if (ret) {
+		pr_err("failed to register clk notifier: %d\n", ret);
+		goto out_put_node;
+	}
+
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+module_init(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/4 v11] arm: use device tree to get smp_twd clock
  2013-01-25 19:46   ` [PATCH 1/4 v11] arm: use device tree to get smp_twd clock Mark Langsdorf
@ 2013-01-25 21:03     ` Rafael J. Wysocki
  2013-01-25 21:40       ` Russell King - ARM Linux
  0 siblings, 1 reply; 142+ messages in thread
From: Rafael J. Wysocki @ 2013-01-25 21:03 UTC (permalink / raw)
  To: Mark Langsdorf, Russell King - ARM Linux
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, Rob Herring

On Friday, January 25, 2013 01:46:42 PM Mark Langsdorf wrote:
> From: Rob Herring <rob.herring@calxeda.com>
> 
> Move clk setup to twd_local_timer_common_register and rely on
> twd_timer_rate being 0 to force calibration if there is no clock.
> Remove common_setup_called as it is no longer needed.
> 
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>

Russell, is this fine with you?

Rafael


> ---
> Changes from v10
> 	Reworked to simplify the logic as suggested by Russell King.
> Changes from v9
>         Updated to work with 3.8 kernel.
> Changes from v4, v5, v6, v7, v8
>         None.
> Changes from v3
>         No longer setting *clk to NULL in twd_get_clock().
> Changes from v2
>         Turned the check for the node pointer into an if-then-else statement.
>         Removed the second, redundant clk_get_rate.
> Changes from v1
>         None.
> 
>  arch/arm/kernel/smp_twd.c | 53 +++++++++++++++++------------------------------
>  1 file changed, 19 insertions(+), 34 deletions(-)
> 
> diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
> index 49f335d..ae0c7bb 100644
> --- a/arch/arm/kernel/smp_twd.c
> +++ b/arch/arm/kernel/smp_twd.c
> @@ -31,7 +31,6 @@ static void __iomem *twd_base;
>  
>  static struct clk *twd_clk;
>  static unsigned long twd_timer_rate;
> -static bool common_setup_called;
>  static DEFINE_PER_CPU(bool, percpu_setup_called);
>  
>  static struct clock_event_device __percpu **twd_evt;
> @@ -239,25 +238,28 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
>  	return IRQ_NONE;
>  }
>  
> -static struct clk *twd_get_clock(void)
> +static void twd_get_clock(struct device_node *np)
>  {
> -	struct clk *clk;
>  	int err;
>  
> -	clk = clk_get_sys("smp_twd", NULL);
> -	if (IS_ERR(clk)) {
> -		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
> -		return clk;
> +	if (np)
> +		twd_clk = of_clk_get(np, 0);
> +	else
> +		twd_clk = clk_get_sys("smp_twd", NULL);
> +
> +	if (IS_ERR(twd_clk)) {
> +		pr_err("smp_twd: clock not found %d\n", (int) PTR_ERR(twd_clk));
> +		return;
>  	}
>  
> -	err = clk_prepare_enable(clk);
> +	err = clk_prepare_enable(twd_clk);
>  	if (err) {
>  		pr_err("smp_twd: clock failed to prepare+enable: %d\n", err);
> -		clk_put(clk);
> -		return ERR_PTR(err);
> +		clk_put(twd_clk);
> +		return;
>  	}
>  
> -	return clk;
> +	twd_timer_rate = clk_get_rate(twd_clk);
>  }
>  
>  /*
> @@ -280,26 +282,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
>  	}
>  	per_cpu(percpu_setup_called, cpu) = true;
>  
> -	/*
> -	 * This stuff only need to be done once for the entire TWD cluster
> -	 * during the runtime of the system.
> -	 */
> -	if (!common_setup_called) {
> -		twd_clk = twd_get_clock();
> -
> -		/*
> -		 * We use IS_ERR_OR_NULL() here, because if the clock stubs
> -		 * are active we will get a valid clk reference which is
> -		 * however NULL and will return the rate 0. In that case we
> -		 * need to calibrate the rate instead.
> -		 */
> -		if (!IS_ERR_OR_NULL(twd_clk))
> -			twd_timer_rate = clk_get_rate(twd_clk);
> -		else
> -			twd_calibrate_rate();
> -
> -		common_setup_called = true;
> -	}
> +	twd_calibrate_rate();
>  
>  	/*
>  	 * The following is done once per CPU the first time .setup() is
> @@ -330,7 +313,7 @@ static struct local_timer_ops twd_lt_ops __cpuinitdata = {
>  	.stop	= twd_timer_stop,
>  };
>  
> -static int __init twd_local_timer_common_register(void)
> +static int __init twd_local_timer_common_register(struct device_node *np)
>  {
>  	int err;
>  
> @@ -350,6 +333,8 @@ static int __init twd_local_timer_common_register(void)
>  	if (err)
>  		goto out_irq;
>  
> +	twd_get_clock(np);
> +
>  	return 0;
>  
>  out_irq:
> @@ -373,7 +358,7 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
>  	if (!twd_base)
>  		return -ENOMEM;
>  
> -	return twd_local_timer_common_register();
> +	return twd_local_timer_common_register(NULL);
>  }
>  
>  #ifdef CONFIG_OF
> @@ -405,7 +390,7 @@ void __init twd_local_timer_of_register(void)
>  		goto out;
>  	}
>  
> -	err = twd_local_timer_common_register();
> +	err = twd_local_timer_common_register(np);
>  
>  out:
>  	WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
> 
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/4 v11] arm: use device tree to get smp_twd clock
  2013-01-25 21:03     ` Rafael J. Wysocki
@ 2013-01-25 21:40       ` Russell King - ARM Linux
  2013-01-25 22:15         ` Rafael J. Wysocki
  0 siblings, 1 reply; 142+ messages in thread
From: Russell King - ARM Linux @ 2013-01-25 21:40 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Mark Langsdorf, linux-kernel, cpufreq, linux-pm,
	linux-arm-kernel, Rob Herring

On Fri, Jan 25, 2013 at 10:03:05PM +0100, Rafael J. Wysocki wrote:
> On Friday, January 25, 2013 01:46:42 PM Mark Langsdorf wrote:
> > From: Rob Herring <rob.herring@calxeda.com>
> > 
> > Move clk setup to twd_local_timer_common_register and rely on
> > twd_timer_rate being 0 to force calibration if there is no clock.
> > Remove common_setup_called as it is no longer needed.
> > 
> > Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> > Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> 
> Russell, is this fine with you?

Looks fine to me, though I had to check twd_calibrate_rate() to make
sure it wouldn't run if the twd_timer_rate was non-zero.

If you want an acked-by:

Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>

Thanks.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/4 v11] arm: use device tree to get smp_twd clock
  2013-01-25 21:40       ` Russell King - ARM Linux
@ 2013-01-25 22:15         ` Rafael J. Wysocki
  0 siblings, 0 replies; 142+ messages in thread
From: Rafael J. Wysocki @ 2013-01-25 22:15 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Mark Langsdorf, linux-kernel, cpufreq, linux-pm,
	linux-arm-kernel, Rob Herring

On Friday, January 25, 2013 09:40:00 PM Russell King - ARM Linux wrote:
> On Fri, Jan 25, 2013 at 10:03:05PM +0100, Rafael J. Wysocki wrote:
> > On Friday, January 25, 2013 01:46:42 PM Mark Langsdorf wrote:
> > > From: Rob Herring <rob.herring@calxeda.com>
> > > 
> > > Move clk setup to twd_local_timer_common_register and rely on
> > > twd_timer_rate being 0 to force calibration if there is no clock.
> > > Remove common_setup_called as it is no longer needed.
> > > 
> > > Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> > > Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> > 
> > Russell, is this fine with you?
> 
> Looks fine to me, though I had to check twd_calibrate_rate() to make
> sure it wouldn't run if the twd_timer_rate was non-zero.
> 
> If you want an acked-by:
> 
> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>

I will, thanks a lot!

Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 4/4] cpufreq, highbank: add support for highbank cpufreq
  2013-01-25 19:46   ` [PATCH 4/4] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
@ 2013-01-26 14:39     ` Shawn Guo
  2013-01-26 22:24       ` Rafael J. Wysocki
  0 siblings, 1 reply; 142+ messages in thread
From: Shawn Guo @ 2013-01-26 14:39 UTC (permalink / raw)
  To: Mark Langsdorf; +Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

Mark,

On Fri, Jan 25, 2013 at 01:46:45PM -0600, Mark Langsdorf wrote:
> +static int hb_cpufreq_driver_init(void)
> +{
> +	struct device *cpu_dev;
> +	struct clk *cpu_clk;
> +	struct device_node *np;
> +	int ret;
> +
> +	for_each_child_of_node(of_find_node_by_path("/cpus"), np)
> +		if (of_get_property(np, "operating-points", NULL))
> +			break;
> +
> +	if (!np) {
> +		pr_err("failed to find highbank cpufreq node\n");
> +		return -ENOENT;
> +	}
> +
...
> +out_put_node:
> +	of_node_put(np);
> +	return ret;
> +}
> +module_init(hb_cpufreq_driver_init);

As we are moving to multiplatform build, this init function will run
on all other platforms built together with highbank.  We should
probably eliminate that effect.  cpufreq-cpu0 driver is facing the
same problem, and I just sent a patch "cpufreq: instantiate cpufreq-cpu0
as a platform_driver" to address that.

Shawn


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 4/4] cpufreq, highbank: add support for highbank cpufreq
  2013-01-26 14:39     ` Shawn Guo
@ 2013-01-26 22:24       ` Rafael J. Wysocki
  2013-01-28  8:37         ` Shawn Guo
  0 siblings, 1 reply; 142+ messages in thread
From: Rafael J. Wysocki @ 2013-01-26 22:24 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Mark Langsdorf, linux-kernel, cpufreq, linux-pm, linux-arm-kernel

On Saturday, January 26, 2013 10:39:53 PM Shawn Guo wrote:
> Mark,
> 
> On Fri, Jan 25, 2013 at 01:46:45PM -0600, Mark Langsdorf wrote:
> > +static int hb_cpufreq_driver_init(void)
> > +{
> > +	struct device *cpu_dev;
> > +	struct clk *cpu_clk;
> > +	struct device_node *np;
> > +	int ret;
> > +
> > +	for_each_child_of_node(of_find_node_by_path("/cpus"), np)
> > +		if (of_get_property(np, "operating-points", NULL))
> > +			break;
> > +
> > +	if (!np) {
> > +		pr_err("failed to find highbank cpufreq node\n");
> > +		return -ENOENT;
> > +	}
> > +
> ...
> > +out_put_node:
> > +	of_node_put(np);
> > +	return ret;
> > +}
> > +module_init(hb_cpufreq_driver_init);
> 
> As we are moving to multiplatform build, this init function will run
> on all other platforms built together with highbank.  We should
> probably eliminate that effect.

That change can be made on top of the Mark's patches I think, right?

If so, I'd prefer it that way.  The Mark's patches have been in a limbo for
too long already and that issue doesn't seem to be serious enough to block
them any longer.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 4/4] cpufreq, highbank: add support for highbank cpufreq
  2013-01-26 22:24       ` Rafael J. Wysocki
@ 2013-01-28  8:37         ` Shawn Guo
  0 siblings, 0 replies; 142+ messages in thread
From: Shawn Guo @ 2013-01-28  8:37 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Mark Langsdorf, linux-kernel, cpufreq, linux-pm, linux-arm-kernel

Rafael,

On Sat, Jan 26, 2013 at 11:24:12PM +0100, Rafael J. Wysocki wrote:
> > As we are moving to multiplatform build, this init function will run
> > on all other platforms built together with highbank.  We should
> > probably eliminate that effect.
> 
> That change can be made on top of the Mark's patches I think, right?
> 
Yes.

> If so, I'd prefer it that way.  The Mark's patches have been in a limbo for
> too long already and that issue doesn't seem to be serious enough to block
> them any longer.
> 
Ok, I will take care of the changes needed on highbank.  Do you have
a branch with Mark's series and the EXPORT_SYMBOL() one applied,
so that I can start my patch from there.

Shawn


^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 3/4 v11] arm highbank: add support for pl320 IPC
  2013-01-25 19:46   ` [PATCH 3/4 v11] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2013-01-28 12:49     ` Rafael J. Wysocki
  2013-01-28 13:44       ` Mark Langsdorf
  0 siblings, 1 reply; 142+ messages in thread
From: Rafael J. Wysocki @ 2013-01-28 12:49 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, Rob Herring,
	Omar Ramirez Luna, Arnd Bergmann

On Friday, January 25, 2013 01:46:44 PM Mark Langsdorf wrote:
> From: Rob Herring <rob.herring@calxeda.com>
> 
> The pl320 IPC allows for interprocessor communication between the highbank A9
> and the EnergyCore Management Engine. The pl320 implements a straightforward
> mailbox protocol.
> 
> Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Cc: Omar Ramirez Luna <omar.luna@linaro.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> ---
> Changes from v10
> 	Removed deependency on Omar Ramirez Luna's mailbox code. Now the
> 	patch creates the directory itself.
> Changes from v9
>         Used to be the 4th patch in the series.
> Changes from v6, v7, v8
>         None.
> Changes from v5
>         Renamed ipc_transmit() to pl320_ipc_transmit().
>         Properly exported pl320_ipc_{un}register_notifier().
> Changes from v4
>         Moved pl320-ipc.c from arch/arm/mach-highbank to drivers/mailbox.
>         Moved header information to include/linux/mailbox.h.
>         Added Kconfig options to reflect the new code location.
>         Change drivers/mailbox/Makefile to build the omap mailboxes only 
>         when they are configured.
>         Removed ipc_call_fast and renamed ipc_call_slow ipc_transmit.
> Changes from v3, v2
>         None.
> Changes from v1
>         Removed erroneous changes for cpufreq Kconfig.
> 
>  arch/arm/mach-highbank/Kconfig |   2 +
>  drivers/mailbox/Kconfig        |  18 ++++
>  drivers/mailbox/Makefile       |   1 +
>  drivers/mailbox/pl320-ipc.c    | 199 +++++++++++++++++++++++++++++++++++++++++
>  include/linux/mailbox.h        |  18 ++++
>  5 files changed, 238 insertions(+)
>  create mode 100644 drivers/mailbox/Kconfig
>  create mode 100644 drivers/mailbox/Makefile
>  create mode 100644 drivers/mailbox/pl320-ipc.c
>  create mode 100644 include/linux/mailbox.h
> 
> diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
> index 551c97e..2388085 100644
> --- a/arch/arm/mach-highbank/Kconfig
> +++ b/arch/arm/mach-highbank/Kconfig
> @@ -11,5 +11,7 @@ config ARCH_HIGHBANK
>  	select GENERIC_CLOCKEVENTS
>  	select HAVE_ARM_SCU
>  	select HAVE_SMP
> +	select MAILBOX
> +	select PL320_MBOX
>  	select SPARSE_IRQ
>  	select USE_OF
> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
> new file mode 100644
> index 0000000..9489554
> --- /dev/null
> +++ b/drivers/mailbox/Kconfig
> @@ -0,0 +1,18 @@
> +menuconfig MAILBOX
> +	bool "Mailbox Hardware Support"
> +	help
> +	  Mailbox is a framework to control hardware communication between
> +	  on-chip processors through queued messages and interrupt driven
> +	  signals. Say Y if your platform supports hardware mailboxes.
> +
> +if MAILBOX
> +config PL320_MBOX
> +	bool "ARM PL320 Mailbox"
> +	help
> +	  An implementation of the ARM PL320 Interprocessor Communication
> +	  Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to
> +	  send short messages between Highbank's A9 cores and the EnergyCore
> +	  Management Engine, primarily for cpufreq. Say Y here if you want
> +	  to use the PL320 IPCM support.
> +
> +endif
> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> new file mode 100644
> index 0000000..543ad6a
> --- /dev/null
> +++ b/drivers/mailbox/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
> diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
> new file mode 100644
> index 0000000..68c0d50
> --- /dev/null
> +++ b/drivers/mailbox/pl320-ipc.c
> @@ -0,0 +1,199 @@
> +/*
> + * Copyright 2012 Calxeda, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#include <linux/types.h>
> +#include <linux/err.h>
> +#include <linux/delay.h>
> +#include <linux/export.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/completion.h>
> +#include <linux/mutex.h>
> +#include <linux/notifier.h>
> +#include <linux/spinlock.h>
> +#include <linux/device.h>
> +#include <linux/amba/bus.h>
> +
> +#include <linux/mailbox.h>
> +
> +#define IPCMxSOURCE(m)		((m) * 0x40)
> +#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
> +#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
> +#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
> +#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
> +#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
> +#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
> +#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
> +#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
> +#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
> +
> +#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
> +#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
> +
> +#define MBOX_MASK(n)		(1 << (n))
> +#define IPC_TX_MBOX		1
> +#define IPC_RX_MBOX		2
> +
> +#define CHAN_MASK(n)		(1 << (n))
> +#define A9_SOURCE		1
> +#define M3_SOURCE		0
> +
> +static void __iomem *ipc_base;
> +static int ipc_irq;
> +static DEFINE_MUTEX(ipc_m1_lock);
> +static DECLARE_COMPLETION(ipc_completion);
> +static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
> +
> +static inline void set_destination(int source, int mbox)
> +{
> +	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
> +	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
> +}
> +
> +static inline void clear_destination(int source, int mbox)
> +{
> +	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
> +	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
> +}
> +
> +static void __ipc_send(int mbox, u32 *data)
> +{
> +	int i;
> +	for (i = 0; i < 7; i++)
> +		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
> +	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
> +}
> +
> +static u32 __ipc_rcv(int mbox, u32 *data)
> +{
> +	int i;
> +	for (i = 0; i < 7; i++)
> +		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
> +	return data[1];
> +}
> +
> +/* blocking implmentation from the A9 side, not usuable in interrupts! */
> +int pl320_ipc_transmit(u32 *data)
> +{
> +	int ret;
> +
> +	mutex_lock(&ipc_m1_lock);
> +
> +	init_completion(&ipc_completion);
> +	__ipc_send(IPC_TX_MBOX, data);
> +	ret = wait_for_completion_timeout(&ipc_completion,
> +					  msecs_to_jiffies(1000));
> +	if (ret == 0) {
> +		ret = -ETIMEDOUT;
> +		goto out;
> +	}
> +
> +	ret = __ipc_rcv(IPC_TX_MBOX, data);
> +out:
> +	mutex_unlock(&ipc_m1_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL(pl320_ipc_transmit);
> +
> +irqreturn_t ipc_handler(int irq, void *dev)
> +{
> +	u32 irq_stat;
> +	u32 data[7];
> +
> +	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
> +	if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
> +		__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
> +		complete(&ipc_completion);
> +	}
> +	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
> +		__ipc_rcv(IPC_RX_MBOX, data);
> +		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
> +		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +int pl320_ipc_register_notifier(struct notifier_block *nb)
> +{
> +	return atomic_notifier_chain_register(&ipc_notifier, nb);
> +}
> +EXPORT_SYMBOL(pl320_ipc_register_notifier);
> +
> +int pl320_ipc_unregister_notifier(struct notifier_block *nb)
> +{
> +	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
> +}
> +EXPORT_SYMBOL(pl320_ipc_unregister_notifier);

I need all of your symbols to be exported with EXPORT_SYMBOL_GPL().

Is it OK to make that change when applying the patch or do you want to send
a new one?

Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 3/4 v11] arm highbank: add support for pl320 IPC
  2013-01-28 12:49     ` Rafael J. Wysocki
@ 2013-01-28 13:44       ` Mark Langsdorf
  2013-01-28 20:48         ` Rafael J. Wysocki
  0 siblings, 1 reply; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-28 13:44 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, Rob Herring,
	Omar Ramirez Luna, Arnd Bergmann

On 01/28/2013 06:49 AM, Rafael J. Wysocki wrote:

>> +int pl320_ipc_register_notifier(struct notifier_block *nb)
>> +{
>> +	return atomic_notifier_chain_register(&ipc_notifier, nb);
>> +}
>> +EXPORT_SYMBOL(pl320_ipc_register_notifier);
>> +
>> +int pl320_ipc_unregister_notifier(struct notifier_block *nb)
>> +{
>> +	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
>> +}
>> +EXPORT_SYMBOL(pl320_ipc_unregister_notifier);
> 
> I need all of your symbols to be exported with EXPORT_SYMBOL_GPL().
> 
> Is it OK to make that change when applying the patch or do you want to send
> a new one?

I probably should resend so I can include the drivers level Kconfig and
Makefile.

I'll get that out this morning.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 0/4 v12] cpufreq: add support for Calxeda ECX-1000 (highbank)
  2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                   ` (16 preceding siblings ...)
  2013-01-25 19:46 ` [PATCH 0/4 v11] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
@ 2013-01-28 16:13 ` Mark Langsdorf
  2013-01-28 16:13   ` [PATCH 1/4 v12] arm: use device tree to get smp_twd clock Mark Langsdorf
                     ` (3 more replies)
  17 siblings, 4 replies; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-28 16:13 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel

This patch series adds cpufreq support for the Calxeda
ECX-1000 (highbank) SoCs. The EnergyCore Management Engine (ECME) on
the ECX-1000 manages the voltage for the part and communications with
Linux through a pl320 mailbox. clk notifications are used to control
when to send messages to the ECME.

Previous versions of this patch set include two other patches. One has
been dropped as unworkable and the other turned out to be unnecessary.

--Mark Langsdorf
Calxeda, Inc.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/4 v12] arm: use device tree to get smp_twd clock
  2013-01-28 16:13 ` [PATCH 0/4 v12] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
@ 2013-01-28 16:13   ` Mark Langsdorf
  2013-01-28 16:13   ` [PATCH 2/4 v12] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-28 16:13 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

From: Rob Herring <rob.herring@calxeda.com>

Move clk setup to twd_local_timer_common_register and rely on
twd_timer_rate being 0 to force calibration if there is no clock.
Remove common_setup_called as it is no longer needed.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
Changes from v11
	Added Russell King's acked-by.
Changes from v10
        Reworked to simplify the logic as suggested by Russell King.
Changes from v9
        Updated to work with 3.8 kernel.
Changes from v4, v5, v6, v7, v8
        None.
Changes from v3
        No longer setting *clk to NULL in twd_get_clock().
Changes from v2
        Turned the check for the node pointer into an if-then-else statement.
        Removed the second, redundant clk_get_rate.
Changes from v1
        None.

 arch/arm/kernel/smp_twd.c | 53 +++++++++++++++++------------------------------
 1 file changed, 19 insertions(+), 34 deletions(-)

diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 49f335d..ae0c7bb 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -31,7 +31,6 @@ static void __iomem *twd_base;
 
 static struct clk *twd_clk;
 static unsigned long twd_timer_rate;
-static bool common_setup_called;
 static DEFINE_PER_CPU(bool, percpu_setup_called);
 
 static struct clock_event_device __percpu **twd_evt;
@@ -239,25 +238,28 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
 	return IRQ_NONE;
 }
 
-static struct clk *twd_get_clock(void)
+static void twd_get_clock(struct device_node *np)
 {
-	struct clk *clk;
 	int err;
 
-	clk = clk_get_sys("smp_twd", NULL);
-	if (IS_ERR(clk)) {
-		pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
-		return clk;
+	if (np)
+		twd_clk = of_clk_get(np, 0);
+	else
+		twd_clk = clk_get_sys("smp_twd", NULL);
+
+	if (IS_ERR(twd_clk)) {
+		pr_err("smp_twd: clock not found %d\n", (int) PTR_ERR(twd_clk));
+		return;
 	}
 
-	err = clk_prepare_enable(clk);
+	err = clk_prepare_enable(twd_clk);
 	if (err) {
 		pr_err("smp_twd: clock failed to prepare+enable: %d\n", err);
-		clk_put(clk);
-		return ERR_PTR(err);
+		clk_put(twd_clk);
+		return;
 	}
 
-	return clk;
+	twd_timer_rate = clk_get_rate(twd_clk);
 }
 
 /*
@@ -280,26 +282,7 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
 	}
 	per_cpu(percpu_setup_called, cpu) = true;
 
-	/*
-	 * This stuff only need to be done once for the entire TWD cluster
-	 * during the runtime of the system.
-	 */
-	if (!common_setup_called) {
-		twd_clk = twd_get_clock();
-
-		/*
-		 * We use IS_ERR_OR_NULL() here, because if the clock stubs
-		 * are active we will get a valid clk reference which is
-		 * however NULL and will return the rate 0. In that case we
-		 * need to calibrate the rate instead.
-		 */
-		if (!IS_ERR_OR_NULL(twd_clk))
-			twd_timer_rate = clk_get_rate(twd_clk);
-		else
-			twd_calibrate_rate();
-
-		common_setup_called = true;
-	}
+	twd_calibrate_rate();
 
 	/*
 	 * The following is done once per CPU the first time .setup() is
@@ -330,7 +313,7 @@ static struct local_timer_ops twd_lt_ops __cpuinitdata = {
 	.stop	= twd_timer_stop,
 };
 
-static int __init twd_local_timer_common_register(void)
+static int __init twd_local_timer_common_register(struct device_node *np)
 {
 	int err;
 
@@ -350,6 +333,8 @@ static int __init twd_local_timer_common_register(void)
 	if (err)
 		goto out_irq;
 
+	twd_get_clock(np);
+
 	return 0;
 
 out_irq:
@@ -373,7 +358,7 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt)
 	if (!twd_base)
 		return -ENOMEM;
 
-	return twd_local_timer_common_register();
+	return twd_local_timer_common_register(NULL);
 }
 
 #ifdef CONFIG_OF
@@ -405,7 +390,7 @@ void __init twd_local_timer_of_register(void)
 		goto out;
 	}
 
-	err = twd_local_timer_common_register();
+	err = twd_local_timer_common_register(np);
 
 out:
 	WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 2/4 v12] clk, highbank: Prevent glitches in non-bypass reset mode
  2013-01-28 16:13 ` [PATCH 0/4 v12] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2013-01-28 16:13   ` [PATCH 1/4 v12] arm: use device tree to get smp_twd clock Mark Langsdorf
@ 2013-01-28 16:13   ` Mark Langsdorf
  2013-01-28 16:13   ` [PATCH 3/4 v12] arm highbank: add support for pl320 IPC Mark Langsdorf
  2013-01-28 16:13   ` [PATCH 4/4 v12] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  3 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-28 16:13 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring

The highbank clock will glitch with the current code if the
clock rate is reset without relocking the PLL. Program the PLL
correctly to prevent glitches.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
---
Changes from v6, v7, v8, v9, v10, v11
        None.
Changes from v5
        Added Mike Turquette's ack.
Changes from v4
        None.
Changes from v3
        Changelog text and patch name now correspond to the actual patch.
        was clk, highbank: remove non-bypass reset mode.
Changes from v2
        None.
Changes from v1
        Removed erroneous reformating.

 drivers/clk/clk-highbank.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecad..3a0b723 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -182,8 +182,10 @@ static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
 		reg |= HB_PLL_EXT_ENA;
 		reg &= ~HB_PLL_EXT_BYPASS;
 	} else {
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 		reg &= ~HB_PLL_DIVQ_MASK;
 		reg |= divq << HB_PLL_DIVQ_SHIFT;
+		writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
 	}
 	writel(reg, hbclk->reg);
 
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 3/4 v12] arm highbank: add support for pl320 IPC
  2013-01-28 16:13 ` [PATCH 0/4 v12] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
  2013-01-28 16:13   ` [PATCH 1/4 v12] arm: use device tree to get smp_twd clock Mark Langsdorf
  2013-01-28 16:13   ` [PATCH 2/4 v12] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
@ 2013-01-28 16:13   ` Mark Langsdorf
  2013-01-28 16:13   ` [PATCH 4/4 v12] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
  3 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-28 16:13 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel
  Cc: Mark Langsdorf, Rob Herring, Omar Ramirez Luna, Arnd Bergmann

From: Rob Herring <rob.herring@calxeda.com>

The pl320 IPC allows for interprocessor communication between the 
highbank A9 and the EnergyCore Management Engine. The pl320 implements 
a straightforward mailbox protocol.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Cc: Omar Ramirez Luna <omar.luna@linaro.org>
Cc: Arnd Bergmann <arnd@arndb.de>
---
Changes from v11
	EXPORT_SYMBOL_GPL used instead of EXPORT_SYMBOL.
	Added driver/Kconfig and driver/Makefile changes.
Changes from v10
        Removed deependency on Omar Ramirez Luna's mailbox code. Now the
        patch creates the directory itself.
Changes from v9
        Used to be the 4th patch in the series.
Changes from v6, v7, v8
        None.
Changes from v5
        Renamed ipc_transmit() to pl320_ipc_transmit().
        Properly exported pl320_ipc_{un}register_notifier().
Changes from v4
        Moved pl320-ipc.c from arch/arm/mach-highbank to drivers/mailbox.
        Moved header information to include/linux/mailbox.h.
        Added Kconfig options to reflect the new code location.
        Change drivers/mailbox/Makefile to build the omap mailboxes only 
        when they are configured.
        Removed ipc_call_fast and renamed ipc_call_slow ipc_transmit.
Changes from v3, v2
        None.
Changes from v1
        Removed erroneous changes for cpufreq Kconfig.

 arch/arm/mach-highbank/Kconfig |   2 +
 drivers/Kconfig                |   2 +
 drivers/Makefile               |   1 +
 drivers/mailbox/Kconfig        |  18 ++++
 drivers/mailbox/Makefile       |   1 +
 drivers/mailbox/pl320-ipc.c    | 199 +++++++++++++++++++++++++++++++++++++++++
 include/linux/mailbox.h        |  18 ++++
 7 files changed, 241 insertions(+)
 create mode 100644 drivers/mailbox/Kconfig
 create mode 100644 drivers/mailbox/Makefile
 create mode 100644 drivers/mailbox/pl320-ipc.c
 create mode 100644 include/linux/mailbox.h

diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 551c97e..2388085 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -11,5 +11,7 @@ config ARCH_HIGHBANK
 	select GENERIC_CLOCKEVENTS
 	select HAVE_ARM_SCU
 	select HAVE_SMP
+	select MAILBOX
+	select PL320_MBOX
 	select SPARSE_IRQ
 	select USE_OF
diff --git a/drivers/Kconfig b/drivers/Kconfig
index f5fb072..2b4e89b 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -134,6 +134,8 @@ source "drivers/hwspinlock/Kconfig"
 
 source "drivers/clocksource/Kconfig"
 
+source "drivers/mailbox/Kconfig"
+
 source "drivers/iommu/Kconfig"
 
 source "drivers/remoteproc/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 7863b9f..a8d32f1 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -130,6 +130,7 @@ obj-y				+= platform/
 #common clk code
 obj-y				+= clk/
 
+obj-$(CONFIG_MAILBOX)		+= mailbox/
 obj-$(CONFIG_HWSPINLOCK)	+= hwspinlock/
 obj-$(CONFIG_NFC)		+= nfc/
 obj-$(CONFIG_IOMMU_SUPPORT)	+= iommu/
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
new file mode 100644
index 0000000..9489554
--- /dev/null
+++ b/drivers/mailbox/Kconfig
@@ -0,0 +1,18 @@
+menuconfig MAILBOX
+	bool "Mailbox Hardware Support"
+	help
+	  Mailbox is a framework to control hardware communication between
+	  on-chip processors through queued messages and interrupt driven
+	  signals. Say Y if your platform supports hardware mailboxes.
+
+if MAILBOX
+config PL320_MBOX
+	bool "ARM PL320 Mailbox"
+	help
+	  An implementation of the ARM PL320 Interprocessor Communication
+	  Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to
+	  send short messages between Highbank's A9 cores and the EnergyCore
+	  Management Engine, primarily for cpufreq. Say Y here if you want
+	  to use the PL320 IPCM support.
+
+endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
new file mode 100644
index 0000000..543ad6a
--- /dev/null
+++ b/drivers/mailbox/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PL320_MBOX)	+= pl320-ipc.o
diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c
new file mode 100644
index 0000000..ba8293f
--- /dev/null
+++ b/drivers/mailbox/pl320-ipc.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/amba/bus.h>
+
+#include <linux/mailbox.h>
+
+#define IPCMxSOURCE(m)		((m) * 0x40)
+#define IPCMxDSET(m)		(((m) * 0x40) + 0x004)
+#define IPCMxDCLEAR(m)		(((m) * 0x40) + 0x008)
+#define IPCMxDSTATUS(m)		(((m) * 0x40) + 0x00C)
+#define IPCMxMODE(m)		(((m) * 0x40) + 0x010)
+#define IPCMxMSET(m)		(((m) * 0x40) + 0x014)
+#define IPCMxMCLEAR(m)		(((m) * 0x40) + 0x018)
+#define IPCMxMSTATUS(m)		(((m) * 0x40) + 0x01C)
+#define IPCMxSEND(m)		(((m) * 0x40) + 0x020)
+#define IPCMxDR(m, dr)		(((m) * 0x40) + ((dr) * 4) + 0x024)
+
+#define IPCMMIS(irq)		(((irq) * 8) + 0x800)
+#define IPCMRIS(irq)		(((irq) * 8) + 0x804)
+
+#define MBOX_MASK(n)		(1 << (n))
+#define IPC_TX_MBOX		1
+#define IPC_RX_MBOX		2
+
+#define CHAN_MASK(n)		(1 << (n))
+#define A9_SOURCE		1
+#define M3_SOURCE		0
+
+static void __iomem *ipc_base;
+static int ipc_irq;
+static DEFINE_MUTEX(ipc_m1_lock);
+static DECLARE_COMPLETION(ipc_completion);
+static ATOMIC_NOTIFIER_HEAD(ipc_notifier);
+
+static inline void set_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDSET(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMSET(mbox));
+}
+
+static inline void clear_destination(int source, int mbox)
+{
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxDCLEAR(mbox));
+	__raw_writel(CHAN_MASK(source), ipc_base + IPCMxMCLEAR(mbox));
+}
+
+static void __ipc_send(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		__raw_writel(data[i], ipc_base + IPCMxDR(mbox, i));
+	__raw_writel(0x1, ipc_base + IPCMxSEND(mbox));
+}
+
+static u32 __ipc_rcv(int mbox, u32 *data)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		data[i] = __raw_readl(ipc_base + IPCMxDR(mbox, i));
+	return data[1];
+}
+
+/* blocking implmentation from the A9 side, not usuable in interrupts! */
+int pl320_ipc_transmit(u32 *data)
+{
+	int ret;
+
+	mutex_lock(&ipc_m1_lock);
+
+	init_completion(&ipc_completion);
+	__ipc_send(IPC_TX_MBOX, data);
+	ret = wait_for_completion_timeout(&ipc_completion,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto out;
+	}
+
+	ret = __ipc_rcv(IPC_TX_MBOX, data);
+out:
+	mutex_unlock(&ipc_m1_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pl320_ipc_transmit);
+
+irqreturn_t ipc_handler(int irq, void *dev)
+{
+	u32 irq_stat;
+	u32 data[7];
+
+	irq_stat = __raw_readl(ipc_base + IPCMMIS(1));
+	if (irq_stat & MBOX_MASK(IPC_TX_MBOX)) {
+		__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+		complete(&ipc_completion);
+	}
+	if (irq_stat & MBOX_MASK(IPC_RX_MBOX)) {
+		__ipc_rcv(IPC_RX_MBOX, data);
+		atomic_notifier_call_chain(&ipc_notifier, data[0], data + 1);
+		__raw_writel(2, ipc_base + IPCMxSEND(IPC_RX_MBOX));
+	}
+
+	return IRQ_HANDLED;
+}
+
+int pl320_ipc_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(pl320_ipc_register_notifier);
+
+int pl320_ipc_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(pl320_ipc_unregister_notifier);
+
+static int __init pl320_probe(struct amba_device *adev,
+				const struct amba_id *id)
+{
+	int ret;
+
+	ipc_base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (ipc_base == NULL)
+		return -ENOMEM;
+
+	__raw_writel(0, ipc_base + IPCMxSEND(IPC_TX_MBOX));
+
+	ipc_irq = adev->irq[0];
+	ret = request_irq(ipc_irq, ipc_handler, 0, dev_name(&adev->dev), NULL);
+	if (ret < 0)
+		goto err;
+
+	/* Init slow mailbox */
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxDSET(IPC_TX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_TX_MBOX));
+
+	/* Init receive mailbox */
+	__raw_writel(CHAN_MASK(M3_SOURCE),
+			ipc_base + IPCMxSOURCE(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(A9_SOURCE),
+			ipc_base + IPCMxDSET(IPC_RX_MBOX));
+	__raw_writel(CHAN_MASK(M3_SOURCE) | CHAN_MASK(A9_SOURCE),
+		     ipc_base + IPCMxMSET(IPC_RX_MBOX));
+
+	return 0;
+err:
+	iounmap(ipc_base);
+	return ret;
+}
+
+static struct amba_id pl320_ids[] = {
+	{
+		.id	= 0x00041320,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl320_driver = {
+	.drv = {
+		.name	= "pl320",
+	},
+	.id_table	= pl320_ids,
+	.probe		= pl320_probe,
+};
+
+static int __init ipc_init(void)
+{
+	return amba_driver_register(&pl320_driver);
+}
+module_init(ipc_init);
diff --git a/include/linux/mailbox.h b/include/linux/mailbox.h
new file mode 100644
index 0000000..911cb28
--- /dev/null
+++ b/include/linux/mailbox.h
@@ -0,0 +1,18 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+int pl320_ipc_transmit(u32 *data);
+int pl320_ipc_register_notifier(struct notifier_block *nb);
+int pl320_ipc_unregister_notifier(struct notifier_block *nb);
+
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 4/4 v12] cpufreq, highbank: add support for highbank cpufreq
  2013-01-28 16:13 ` [PATCH 0/4 v12] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
                     ` (2 preceding siblings ...)
  2013-01-28 16:13   ` [PATCH 3/4 v12] arm highbank: add support for pl320 IPC Mark Langsdorf
@ 2013-01-28 16:13   ` Mark Langsdorf
  3 siblings, 0 replies; 142+ messages in thread
From: Mark Langsdorf @ 2013-01-28 16:13 UTC (permalink / raw)
  To: linux-kernel, cpufreq, linux-pm, linux-arm-kernel; +Cc: Mark Langsdorf

Highbank processors depend on the external ECME to perform voltage
management based on a requested frequency. Communication between the
A9 cores and the ECME happens over the pl320 IPC channel.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
Reviewed-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Mike Turquette <mturquette@linaro.org>
---
Changes from v11
	Added a compatible check against calxeda,highbank.
Changes from v10
        Now finds a cpu node by searching under /cpus and looking for something
        with an operating-points descriptor. This applies to both 
        highbank-cpufreq and cpufreq-cpu0.
Changes from v9
        Added Mike Turquette's reviewed by.
        Used to be the 6th patch in the series.
Changes from v8
        Added Shawn Guo's reviewed by.
        Removed some magic numbers.
        Changed failure returns in clk_notify from NOTIFY_STOP to NOTIFY_BAD.
Changes from v7
        Removed old attribution to cpufreq-cpu0.
        Added some description in the documentation.
        Made cpu_dev, cpu_clk into local variables.
        Removed __devinit.
        Removed some unneeded includes.
        Added a brace to clarify some nested if logic.
Changes from v6
        Removed devicetree bindings documentation.
        Restructured driver to use clk notifications.
        Core driver logic is now cpufreq-clk0.
Changes from v5
        Changed ipc_transmit() to pl320_ipc_transmit().
Changes from v4
        Removed erroneous changes to arch/arm/Kconfig.
        Removed unnecessary changes to drivers/cpufreq/Kconfig.arm
        Alphabetized additions to arch/arm/mach-highbank/Kconfig
        Changed ipc call and header to match new ipc location in 
        drivers/mailbox.
Changes from v3
        None.
Changes from v2
        Changed transition latency binding in code to match documentation.
Changes from v1
        Added highbank specific Kconfig changes.

 arch/arm/boot/dts/highbank.dts     |  10 ++++
 arch/arm/mach-highbank/Kconfig     |   2 +
 drivers/cpufreq/Kconfig.arm        |  15 +++++
 drivers/cpufreq/Makefile           |   3 +-
 drivers/cpufreq/cpufreq-cpu0.c     |   6 +-
 drivers/cpufreq/highbank-cpufreq.c | 115 +++++++++++++++++++++++++++++++++++++
 6 files changed, 149 insertions(+), 2 deletions(-)
 create mode 100644 drivers/cpufreq/highbank-cpufreq.c

diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
index 5927a8d..6aad34a 100644
--- a/arch/arm/boot/dts/highbank.dts
+++ b/arch/arm/boot/dts/highbank.dts
@@ -37,6 +37,16 @@
 			next-level-cache = <&L2>;
 			clocks = <&a9pll>;
 			clock-names = "cpu";
+			operating-points = <
+				/* kHz    ignored */
+				 1300000  1000000
+				 1200000  1000000
+				 1100000  1000000
+				  800000  1000000
+				  400000  1000000
+				  200000  1000000
+			>;
+			clock-latency = <100000>;
 		};
 
 		cpu@901 {
diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig
index 2388085..44b12f9 100644
--- a/arch/arm/mach-highbank/Kconfig
+++ b/arch/arm/mach-highbank/Kconfig
@@ -1,5 +1,7 @@
 config ARCH_HIGHBANK
 	bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7
+	select ARCH_HAS_CPUFREQ
+	select ARCH_HAS_OPP
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_AMBA
 	select ARM_GIC
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index a0b3661..ffe55b8 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -83,3 +83,18 @@ config ARM_SPEAR_CPUFREQ
 	default y
 	help
 	  This adds the CPUFreq driver support for SPEAr SOCs.
+
+config ARM_HIGHBANK_CPUFREQ
+	tristate "Calxeda Highbank-based"
+	depends on ARCH_HIGHBANK
+	select CPU_FREQ_TABLE
+	select GENERIC_CPUFREQ_CPU0
+	select PM_OPP
+	select REGULATOR
+
+	default m
+	help
+	  This adds the CPUFreq driver for Calxeda Highbank SoC
+	  based boards.
+
+	  If in doubt, say N.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index fadc4d4..31e6f19 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -50,8 +50,9 @@ obj-$(CONFIG_ARM_EXYNOS_CPUFREQ)	+= exynos-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)	+= exynos4210-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ)	+= exynos4x12-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
-obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)     += omap-cpufreq.o
+obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)	+= omap-cpufreq.o
 obj-$(CONFIG_ARM_SPEAR_CPUFREQ)		+= spear-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index 52bf36d..90e9d73 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -179,7 +179,11 @@ static int cpu0_cpufreq_driver_init(void)
 	struct device_node *np;
 	int ret;
 
-	np = of_find_node_by_path("/cpus/cpu@0");
+	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+		if (of_get_property(np, "operating-points", NULL))
+			break;
+	}
+
 	if (!np) {
 		pr_err("failed to find cpu0 node\n");
 		return -ENOENT;
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
new file mode 100644
index 0000000..2ea6276
--- /dev/null
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 Calxeda, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver provides the clk notifier callbacks that are used when
+ * the cpufreq-cpu0 driver changes to frequency to alert the highbank
+ * EnergyCore Management Engine (ECME) about the need to change
+ * voltage. The ECME interfaces with the actual voltage regulators.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/mailbox.h>
+
+#define HB_CPUFREQ_CHANGE_NOTE	0x80000001
+#define HB_CPUFREQ_IPC_LEN	7
+#define HB_CPUFREQ_VOLT_RETRIES	15
+
+static int hb_voltage_change(unsigned int freq)
+{
+	int i;
+	u32 msg[HB_CPUFREQ_IPC_LEN];
+
+	msg[0] = HB_CPUFREQ_CHANGE_NOTE;
+	msg[1] = freq / 1000000;
+	for (i = 2; i < HB_CPUFREQ_IPC_LEN; i++)
+		msg[i] = 0;
+
+	return pl320_ipc_transmit(msg);
+}
+
+static int hb_cpufreq_clk_notify(struct notifier_block *nb, 
+				unsigned long action, void *hclk)
+{
+	struct clk_notifier_data *clk_data = hclk;
+	int i = 0;
+
+	if (action == PRE_RATE_CHANGE) {
+		if (clk_data->new_rate > clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+					return NOTIFY_BAD;
+	} else if (action == POST_RATE_CHANGE) {
+		if (clk_data->new_rate < clk_data->old_rate)
+			while (hb_voltage_change(clk_data->new_rate))
+				if (i++ > HB_CPUFREQ_VOLT_RETRIES)
+					return NOTIFY_BAD;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block hb_cpufreq_clk_nb = {
+	.notifier_call = hb_cpufreq_clk_notify,
+};
+
+static int hb_cpufreq_driver_init(void)
+{
+	struct device *cpu_dev;
+	struct clk *cpu_clk;
+	struct device_node *np;
+	int ret;
+
+	if (!of_machine_is_compatible("calxeda,highbank"))
+		return -ENODEV;
+
+	for_each_child_of_node(of_find_node_by_path("/cpus"), np)
+		if (of_get_property(np, "operating-points", NULL))
+			break;
+
+	if (!np) {
+		pr_err("failed to find highbank cpufreq node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	cpu_dev->of_node = np;
+
+	cpu_clk = clk_get(cpu_dev, NULL);
+	if (IS_ERR(cpu_clk)) {
+		ret = PTR_ERR(cpu_clk);
+		pr_err("failed to get cpu0 clock: %d\n", ret);
+		goto out_put_node;
+	}
+
+	ret = clk_notifier_register(cpu_clk, &hb_cpufreq_clk_nb);
+	if (ret) {
+		pr_err("failed to register clk notifier: %d\n", ret);
+		goto out_put_node;
+	}
+
+out_put_node:
+	of_node_put(np);
+	return ret;
+}
+module_init(hb_cpufreq_driver_init);
+
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
+MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.11.7


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 3/4 v11] arm highbank: add support for pl320 IPC
  2013-01-28 13:44       ` Mark Langsdorf
@ 2013-01-28 20:48         ` Rafael J. Wysocki
  0 siblings, 0 replies; 142+ messages in thread
From: Rafael J. Wysocki @ 2013-01-28 20:48 UTC (permalink / raw)
  To: Mark Langsdorf
  Cc: linux-kernel, cpufreq, linux-pm, linux-arm-kernel, Rob Herring,
	Omar Ramirez Luna, Arnd Bergmann

On Monday, January 28, 2013 07:44:13 AM Mark Langsdorf wrote:
> On 01/28/2013 06:49 AM, Rafael J. Wysocki wrote:
> 
> >> +int pl320_ipc_register_notifier(struct notifier_block *nb)
> >> +{
> >> +	return atomic_notifier_chain_register(&ipc_notifier, nb);
> >> +}
> >> +EXPORT_SYMBOL(pl320_ipc_register_notifier);
> >> +
> >> +int pl320_ipc_unregister_notifier(struct notifier_block *nb)
> >> +{
> >> +	return atomic_notifier_chain_unregister(&ipc_notifier, nb);
> >> +}
> >> +EXPORT_SYMBOL(pl320_ipc_unregister_notifier);
> > 
> > I need all of your symbols to be exported with EXPORT_SYMBOL_GPL().
> > 
> > Is it OK to make that change when applying the patch or do you want to send
> > a new one?
> 
> I probably should resend so I can include the drivers level Kconfig and
> Makefile.
> 
> I'll get that out this morning.

OK, thanks!

Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 4/6 v5] arm highbank: add support for pl320 IPC
       [not found]       ` <1354602789308-564771.post@n7.nabble.com>
@ 2013-01-29  2:26         ` liuhuan123
  2013-02-06  5:43         ` liuhuan123
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 142+ messages in thread
From: liuhuan123 @ 2013-01-29  2:26 UTC (permalink / raw)
  To: linux-kernel

Inside the mid eighties your Nike sneaker business came out with a amount of
cast new cossack styles, a lot of distinctively created for the accurate
contest area that had usually backed Nike so properly. As able-bodied as
aboriginal models, during this aeon Nike  start here ?
<http://sportshoes2u.net/Air-Jordan-10-Retro-category-13.html>   adjourned a
acknowledged arrangement with Michal Jordan, any well-known, and aswell
awful well-liked, basketball gamer. Within the up advancing twenty years
Nike ability abide the band of Jordan sneakers in assorted designs, even
afterwards Jordan's retirement active advancing from acclimatized baseball.

Christian Louboutin is a cossack artist from France. He is the architect of
the cast that bears his name. His cossack designs accept a appropriate
attending which incorporates agleam and red-lacquered soles. This has about
become his signature style.Christian  christian louboutin shop
<http://onlycl.com>   Louboutin was built-in in January 1963. He showed
little absorption in studies and larboard academy at a actual adolescent
age. Louboutin claims that he got absorbed with shoes if he went to the
Mus¨|e civic des Arts d'Afrique et d'Oc¨|anie. Located on the admission
Daumesnil, this cairn was the afflatus that got him abstraction shoe designs
appropriate from his aboriginal teens.

In such a different social, archetypal has become the accomplished and how
to be a new cocky is abundant added important. Going a appropriate alley
seems added real. Now, it’s no best the difficult botheration that puzzles
us. Isabel Marant applies for four seasons’  tory burch shoes uk
<http://cheapboots4u.net/goods-79-Tenley-Flat-Riding-Boot.html>   shoes and
you don’t anguish whether four seasons shoes all can bout our wearing. It
architecture abstraction is on the base of affair customer and you can
accept your a lot of satisfactory. Now I will acquaint something about
Isabel Marant Shoes.




--
View this message in context: http://linux-kernel.2935.n7.nabble.com/PATCH-0-6-cpufreq-add-support-for-Calxeda-ECX-1000-highbank-tp380026p590962.html
Sent from the Linux Kernel mailing list archive at Nabble.com.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 4/6 v5] arm highbank: add support for pl320 IPC
       [not found]       ` <1354602789308-564771.post@n7.nabble.com>
  2013-01-29  2:26         ` liuhuan123
@ 2013-02-06  5:43         ` liuhuan123
  2013-02-21  5:11         ` liuhuan123
  2013-03-12  5:29         ` liuhuan123
  3 siblings, 0 replies; 142+ messages in thread
From: liuhuan123 @ 2013-02-06  5:43 UTC (permalink / raw)
  To: linux-kernel

great deal of like ugg for 2 things, some for its aesthetic appears to be
like and some many people for its trendsetting appeal. Previously, ugg boots
are solely built for winter season and peoplebootswear them all too often if
the climate is cold. But in latest periods,  jimmy choo gold glitter shoes
<http://topredshoes.net/goods-439-Suede-Platform-Shoe.html>   these boots
arrive inside an unique line of kinds catered towards the specifications of
your contemporary and model consciouswomen. For example, owing to shorter
height design, ugg classic small boot is ideally suited less than or around
jeans / pants. ugg basic limited boots is crafted from premium Merino
(A-grade) sheepskinand finest fleece to keep your foot dry and cozy in all
climates. This UGG traditional boot offers resilient match stemming from
strengthened heel guard.<br /><br />louboutin is hot and popular among girls
at miumiushoessale.com. Every one dreams of owning a pair of high heel
shoes. At christian louboutin's world, you can find a lot of amazing shoes, 
buy christian louboutin shoes
<http://topclonline.com/goods-968-Discount-Christian-Louboutin-Booties-Coussin-140mm-Black.html>  
including louboutin wedding shoes, christian louboutin peep toe pumps and so
on.<br /><br />Over the years Uggs Australia have produced a wide range of
beautiful and comfortable boots. The most recent one to hit the market is
the cheap cardy  Click Here to Visit
<http://bootssalemall.net/goods-54-Ash-Reverso-Slouch-Leather-Black-Ankle-Boot.html>  
which was not due to be released until Spring 2008. But this one is somewhat
different from the more traditional styles of boots that Ugg Australia boots
have produced before.<br /><br />Taka Hayashi has applied different skills
and materials to design the unique shoe style. Therefore, how could you miss
this series if you are a person who is keen on skateboarding. In the autumn
and winter of 2007, VANS specially cooperated with the Japanese-American
designer Taka Hayashi and created Taka Hayashi, which was a joint shoe
style. There was no doubt that as for such a special and limited edition
shoe style, it firstly would be published in a unique place.  learn more …
<http://myvanssale.com/goods-83-Canvas-Rata-Vulc-Boys-Classic-Blue-Chili-Pepper-Red.html>  
has many fans, so in order to let them experience different feelings, the
Taiwan general agency of VANS made its decision to choose Babe 18.<br /><br
/>Taka Hayashi has applied different skills and materials to design the
unique shoe style. Therefore, how could you miss this series if you are a
person who is keen on skateboarding. In the autumn and winter of 2007, VANS
specially cooperated with the Japanese-American designer Taka Hayashi and
created Taka Hayashi, which was a joint shoe style. There was no doubt that
as for such a special and limited edition shoe style, it firstly would be
published in a unique place.  ash shoes bloomingdales
<http://ashshoe.com/goods-81-Ash-Valium-Black-Leather-Chain-amp-Buckle-Trainer.html>  
has many fans, so in order to let them experience different feelings, the
Taiwan general agency of VANS made its decision to choose Babe 18.<br />



--
View this message in context: http://linux-kernel.2935.n7.nabble.com/PATCH-0-6-cpufreq-add-support-for-Calxeda-ECX-1000-highbank-tp380026p596114.html
Sent from the Linux Kernel mailing list archive at Nabble.com.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 4/6 v5] arm highbank: add support for pl320 IPC
       [not found]       ` <1354602789308-564771.post@n7.nabble.com>
  2013-01-29  2:26         ` liuhuan123
  2013-02-06  5:43         ` liuhuan123
@ 2013-02-21  5:11         ` liuhuan123
  2013-03-21  4:01           ` liuhuan123
  2013-03-12  5:29         ` liuhuan123
  3 siblings, 1 reply; 142+ messages in thread
From: liuhuan123 @ 2013-02-21  5:11 UTC (permalink / raw)
  To: linux-kernel

These are a fashionable choice and they are reusable also. Plastic bags are
getting unexpected popularity in the daily life. These have been
transformed, changed and diversified with several types to fulfill the
different expectations of the customers. More frequently poly  Check out
this
<http://stylebagshotshop.com/goods-2633-Chanel-Shopping-Bags-69019-Black-Leather-With-Chain.html>  
are used and several improvements are made to the designs and materials.
With the material polyethylene, bags have become to carry any object from
light to heavy weight. These bags give extra storage space for bulky items
and you can get then in different patterns.<br /><br />Winter is about
wearing thick clothing and on the best choice of jackets can be found at the 
Find Out More
<http://warmjackets.net/goods-3-Moncler-Long-Down-Black-Coat-Men.html>  
outlet. They have fashionable jackets available that come in different
sizes, styles and designs. Wearing one can surely give warmth especially
during the coldest weather in the year. If you want to buy a Moncler coat,
you do not need to find an outlet or boutique their store can be found
online through this website<br /><br />The UGG boots for women are
accessible inside a wide quantity of colours for instance purple and pink.
The men's boots even so are offered in neutral colours.   ash jalouse suede
boots <http://ishoesmall.net/goods-17-ASH-skull-biker-boot.html>   Some
boots have chunky laces and heels while some are slip on type footwear with
flat heels. The boots from UGG have a casual and trendy seem and compliment
different sorts of clothing. These boots are very good to wear during the
winter season as they are exceptionally warm. For women and girls, the boots
from UGG will seem beneficial with tight legged jeans which must be tucked
into them.



--
View this message in context: http://linux-kernel.2935.n7.nabble.com/PATCH-0-6-cpufreq-add-support-for-Calxeda-ECX-1000-highbank-tp380026p604598.html
Sent from the Linux Kernel mailing list archive at Nabble.com.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 4/6 v5] arm highbank: add support for pl320 IPC
       [not found]       ` <1354602789308-564771.post@n7.nabble.com>
                           ` (2 preceding siblings ...)
  2013-02-21  5:11         ` liuhuan123
@ 2013-03-12  5:29         ` liuhuan123
  3 siblings, 0 replies; 142+ messages in thread
From: liuhuan123 @ 2013-03-12  5:29 UTC (permalink / raw)
  To: linux-kernel

Hermes replica totes are actually ambrosial in accretion to about apprenticed
that you acquire complete admiring for those who acquire 1. Irrespective of
your breadth activity to, accepting a afflicted by  hermes belt kit women
<http://justhermes.net/goods-29-UK-Hermes-Belts-New-Arrivals-86.html>  , you
should not all-overs any bootless affliction. Every abandoned afflicted will
be anxiously bogus to accomplish it abide best than it's competitors on the
market. This can be a haversack an abandoned broker by appliance delight. If
you're a sweetheart with out them these these reproductions, that you are
accepting larboard aback with the assets of Hermes. There're below than this
18-carat ones and the identical axial development. Hermes won't discriminate
rolling about in its carriers.



--
View this message in context: http://linux-kernel.2935.n7.nabble.com/PATCH-0-6-cpufreq-add-support-for-Calxeda-ECX-1000-highbank-tp380026p614406.html
Sent from the Linux Kernel mailing list archive at Nabble.com.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 4/6 v5] arm highbank: add support for pl320 IPC
  2013-02-21  5:11         ` liuhuan123
@ 2013-03-21  4:01           ` liuhuan123
  0 siblings, 0 replies; 142+ messages in thread
From: liuhuan123 @ 2013-03-21  4:01 UTC (permalink / raw)
  To: linux-kernel

This actualization of shoes for women acquire heel and sole able connected.
This acquaint of shoes are complete abounding in trend from the accept few
years. This acquaint of shoes for women http://onlyashshoes.com/ ash sales
acquire usually a blubbery anchor sole and the architectonics that achieve
them complete able to chafe and airing in. The bets of wedges shoes for
women is that they go able with lots of adapted outfits. Online arcade for
shoes will board you the accepting to huge abuttals of designs, sizes and
colors. So whenever you appetite to buy wedges shoes, you can go online and
shop.



--
View this message in context: http://linux-kernel.2935.n7.nabble.com/PATCH-0-6-cpufreq-add-support-for-Calxeda-ECX-1000-highbank-tp380026p620257.html
Sent from the Linux Kernel mailing list archive at Nabble.com.

^ permalink raw reply	[flat|nested] 142+ messages in thread

end of thread, other threads:[~2013-03-21  4:01 UTC | newest]

Thread overview: 142+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-30 21:04 [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
2012-10-30 21:04 ` [PATCH 1/6] arm: use devicetree to get smp_twd clock Mark Langsdorf
2012-10-30 21:04 ` [PATCH 2/6] clk, highbank: remove non-bypass reset mode Mark Langsdorf
2012-10-30 21:04 ` [PATCH 3/6] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
2012-10-30 21:04 ` [PATCH 4/6] arm highbank: add support for pl320 IPC Mark Langsdorf
2012-10-30 21:04 ` [PATCH 5/6] power: export opp cpufreq functions Mark Langsdorf
2012-10-31  1:17   ` Nishanth Menon
2012-10-30 21:04 ` [PATCH 6/6] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
2012-10-31  0:21 ` [PATCH 0/6] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
2012-11-02 18:51 ` [PATCH 0/6 v2] " Mark Langsdorf
2012-11-02 18:51   ` [PATCH 1/6 v2] arm: use devicetree to get smp_twd clock Mark Langsdorf
2012-11-04 10:08     ` Russell King - ARM Linux
2012-11-05 22:28       ` Mark Langsdorf
2012-11-05 22:31         ` Russell King - ARM Linux
2012-11-05 22:49           ` Mark Langsdorf
2012-11-02 18:51   ` [PATCH 2/6 v2] clk, highbank: remove non-bypass reset mode Mark Langsdorf
2012-11-02 18:51   ` [PATCH 3/6 v2] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
2012-11-02 18:51   ` [PATCH 4/6 v2] arm highbank: add support for pl320 IPC Mark Langsdorf
2012-11-02 18:51   ` [PATCH 5/6 v2] power: export opp cpufreq functions Mark Langsdorf
2012-11-02 18:51   ` [PATCH 6/6 v2] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
2012-11-02 21:45   ` [PATCH 0/6 v2] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
2012-11-06 20:18 ` [PATCH 0/6 v3] " Mark Langsdorf
2012-11-06 20:18   ` [PATCH 1/6 v3] arm: use devicetree to get smp_twd clock Mark Langsdorf
2012-11-06 20:18   ` [PATCH 2/6 v3] clk, highbank: remove non-bypass reset mode Mark Langsdorf
2012-11-06 20:18   ` [PATCH 3/6 v3] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
2012-11-06 20:18   ` [PATCH 4/6 v3] arm highbank: add support for pl320 IPC Mark Langsdorf
2012-11-06 20:18   ` [PATCH 5/6 v3] power: export opp cpufreq functions Mark Langsdorf
2012-11-06 20:18   ` [PATCH 6/6 v3] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
2012-11-07 18:11   ` [PATCH 0/6 v3] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
2012-11-07 18:32 ` [PATCH 0/6 v4] " Mark Langsdorf
2012-11-07 18:32   ` [PATCH 1/6 v4] arm: use devicetree to get smp_twd clock Mark Langsdorf
2012-11-07 18:32   ` [PATCH 2/6 v4] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
2012-11-12 21:24     ` Mike Turquette
2012-11-12 21:35       ` Mark Langsdorf
2012-11-07 18:32   ` [PATCH 3/6 v4] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
2012-11-11 16:38     ` Borislav Petkov
2012-11-12 16:35       ` Mark Langsdorf
2012-11-13 16:24         ` Borislav Petkov
2012-11-13 16:33           ` Mark Langsdorf
2012-11-13 19:13             ` Mark Langsdorf
2012-11-17 14:50               ` Borislav Petkov
2012-11-24 10:05                 ` Rafael J. Wysocki
2012-11-26 13:57                   ` Mark Langsdorf
2012-11-26 15:25                     ` Rafael J. Wysocki
2012-11-07 18:32   ` [PATCH 4/6 v4] arm highbank: add support for pl320 IPC Mark Langsdorf
2012-11-14 14:03     ` Rob Herring
2012-11-07 18:32   ` [PATCH 5/6 v4] power: export opp cpufreq functions Mark Langsdorf
2012-11-07 18:32   ` [PATCH 6/6 v4] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
2012-11-07 18:51     ` Rob Herring
2012-11-24 10:07   ` [PATCH 0/6 v4] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
2012-11-27 15:04 ` [PATCH 0/6 v5] " Mark Langsdorf
2012-11-27 15:04   ` [PATCH 1/6 v5] arm: use devicetree to get smp_twd clock Mark Langsdorf
2012-11-27 15:04   ` [PATCH 2/6 v5] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
2012-11-27 18:15     ` Mike Turquette
2012-11-27 15:04   ` [PATCH 3/6 v5] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
2012-11-27 15:04   ` [PATCH 4/6 v5] arm highbank: add support for pl320 IPC Mark Langsdorf
2012-11-27 16:12     ` Thomas Petazzoni
2012-11-27 19:53       ` Mark Langsdorf
     [not found]       ` <1354602789308-564771.post@n7.nabble.com>
2013-01-29  2:26         ` liuhuan123
2013-02-06  5:43         ` liuhuan123
2013-02-21  5:11         ` liuhuan123
2013-03-21  4:01           ` liuhuan123
2013-03-12  5:29         ` liuhuan123
2012-11-27 15:04   ` [PATCH 5/6 v5] power: export opp cpufreq functions Mark Langsdorf
2012-11-27 15:04   ` [PATCH 6/6 v5] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
2012-11-27 19:04   ` [PATCH 0/6 v5] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
2012-11-27 20:04 ` [PATCH 0/6 v6] " Mark Langsdorf
2012-11-27 20:04   ` [PATCH 1/6 v6] arm: use devicetree to get smp_twd clock Mark Langsdorf
2012-11-27 20:04   ` [PATCH 2/6 v6] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
2012-11-27 20:04   ` [PATCH 3/6 v6] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
2012-11-27 20:04   ` [PATCH 4/6 v6] arm highbank: add support for pl320 IPC Mark Langsdorf
2012-11-27 20:04   ` [PATCH 5/6 v6] power: export opp cpufreq functions Mark Langsdorf
2012-11-27 20:04   ` [PATCH 6/6 v6] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
2012-11-28  2:32     ` Shawn Guo
2012-11-28 13:16       ` Mark Langsdorf
2012-11-28 14:58         ` Shawn Guo
2012-11-28 15:17           ` Shawn Guo
2012-11-28 15:01             ` Mark Langsdorf
2012-11-28 16:01             ` Mike Turquette
2012-11-28 16:18               ` Mark Langsdorf
2012-11-28 21:05                 ` Mike Turquette
2012-11-29  0:24                   ` Mark Langsdorf
2012-11-29  1:51               ` Shawn Guo
2012-11-29  4:34                 ` Mike Turquette
2012-12-04 14:33 ` [PATCH 0/6 v7] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
2012-12-04 14:33   ` [PATCH 1/6 v7] arm: use devicetree to get smp_twd clock Mark Langsdorf
2012-12-04 14:33   ` [PATCH 2/6 v7] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
2012-12-04 14:33   ` [PATCH 3/6 v7] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
2012-12-04 14:34   ` [PATCH 4/6 v7] arm highbank: add support for pl320 IPC Mark Langsdorf
2012-12-04 14:34   ` [PATCH 5/6 v7] power: export opp cpufreq functions Mark Langsdorf
2012-12-04 14:34   ` [PATCH 6/6 v7] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
2012-12-04 16:21     ` Shawn Guo
2012-12-05 16:48 ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
2012-12-05 16:48   ` [PATCH 1/6 v8] arm: use devicetree to get smp_twd clock Mark Langsdorf
2012-12-05 16:48   ` [PATCH 2/6 v8] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
2012-12-05 18:02     ` Mike Turquette
2012-12-05 16:48   ` [PATCH 3/6 v8] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
2012-12-05 16:48   ` [PATCH 4/6 v8] arm highbank: add support for pl320 IPC Mark Langsdorf
2012-12-05 16:48   ` [PATCH 5/6 v8] power: export opp cpufreq functions Mark Langsdorf
2012-12-05 16:48   ` [PATCH 6/6 v8] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
2012-12-05 18:49     ` Mike Turquette
2012-12-05 22:09       ` Mark Langsdorf
2012-12-06  9:37     ` Shawn Guo
2012-12-27 13:12   ` [PATCH 0/6 v8] cpufreq: add support for Calxeda ECX-1000 (highbank) Rafael J. Wysocki
2012-12-27 13:28     ` Mark Langsdorf
2012-12-27 14:43       ` Rafael J. Wysocki
2012-12-06 22:42 ` [PATCH 0/6 v9] " Mark Langsdorf
2012-12-06 22:42   ` [PATCH 1/6 v9] arm: use devicetree to get smp_twd clock Mark Langsdorf
2012-12-07 14:55     ` Thiago Farina
2012-12-27  5:11     ` Prashant Gaikwad
2012-12-06 22:42   ` [PATCH 2/6 v9] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
2012-12-06 22:42   ` [PATCH 3/6 v9] cpufreq: tolerate inexact values when collecting stats Mark Langsdorf
2012-12-06 22:42   ` [PATCH 4/6 v9] arm highbank: add support for pl320 IPC Mark Langsdorf
2012-12-06 22:42   ` [PATCH 5/6 v9] power: export opp cpufreq functions Mark Langsdorf
2012-12-06 22:42   ` [PATCH 6/6 v9] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
2012-12-07  7:04     ` Mike Turquette
2013-01-04 16:35 ` [PATCH 0/4 v10] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
2013-01-04 16:35   ` [PATCH 1/4 v10] arm: use devicetree to get smp_twd clock Mark Langsdorf
2013-01-10 23:34     ` Russell King - ARM Linux
2013-01-11 14:40       ` Rob Herring
2013-01-04 16:35   ` [PATCH 2/4 v10] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
2013-01-04 16:35   ` [PATCH 3/4 v10] arm highbank: add support for pl320 IPC Mark Langsdorf
2013-01-04 16:35   ` [PATCH 4/4 v10] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
2013-01-25 19:46 ` [PATCH 0/4 v11] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
2013-01-25 19:46   ` [PATCH 1/4 v11] arm: use device tree to get smp_twd clock Mark Langsdorf
2013-01-25 21:03     ` Rafael J. Wysocki
2013-01-25 21:40       ` Russell King - ARM Linux
2013-01-25 22:15         ` Rafael J. Wysocki
2013-01-25 19:46   ` [PATCH 2/4 v11] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
2013-01-25 19:46   ` [PATCH 3/4 v11] arm highbank: add support for pl320 IPC Mark Langsdorf
2013-01-28 12:49     ` Rafael J. Wysocki
2013-01-28 13:44       ` Mark Langsdorf
2013-01-28 20:48         ` Rafael J. Wysocki
2013-01-25 19:46   ` [PATCH 4/4] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf
2013-01-26 14:39     ` Shawn Guo
2013-01-26 22:24       ` Rafael J. Wysocki
2013-01-28  8:37         ` Shawn Guo
2013-01-28 16:13 ` [PATCH 0/4 v12] cpufreq: add support for Calxeda ECX-1000 (highbank) Mark Langsdorf
2013-01-28 16:13   ` [PATCH 1/4 v12] arm: use device tree to get smp_twd clock Mark Langsdorf
2013-01-28 16:13   ` [PATCH 2/4 v12] clk, highbank: Prevent glitches in non-bypass reset mode Mark Langsdorf
2013-01-28 16:13   ` [PATCH 3/4 v12] arm highbank: add support for pl320 IPC Mark Langsdorf
2013-01-28 16:13   ` [PATCH 4/4 v12] cpufreq, highbank: add support for highbank cpufreq Mark Langsdorf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).