All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-07 17:14 ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-07 17:14 UTC (permalink / raw)
  To: rjw
  Cc: cpufreq, linux-pm, linux-kernel, robin.randhawa, Steve.Bannister,
	Liviu.Dudau, charles.garcia-tobin, linaro-kernel, mark.hambleton,
	linux-arm-kernel, linux, devicetree-discuss, Viresh Kumar,
	Sudeep KarkadaNagesha

big LITTLE is ARM's new Architecture focussing power/performance needs of modern
world. More information about big LITTLE can be found here:

http://www.arm.com/products/processors/technologies/biglittleprocessing.php
http://lwn.net/Articles/481055/

In order to keep cpufreq support for all big LITTLE platforms simple/generic,
this patch tries to add a generic cpufreq driver layer for all big LITTLE
platforms.

The driver is divided into two parts:
- Core driver: Generic and shared across all big LITTLE SoC's
- Glue drivers: Per platform drivers providing ops to the core driver

This patch adds in a generic glue driver which would extract information from
Device Tree.

Future SoC's can either reuse the DT glue or write their own depending on the
need.

Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---

V1->V2:
- s/IS_ERR_OR_NULL/IS_ERR for return value of clk_get
- Added "depends on HAVE_CLK" in Kconfig
- Removed "default n" from Kconfig
- Renamed cluster clk to "cpu-cluster.%u" and added it as dev_id instead of
  con_id and using clk_get_sys() instead of clk_get()
- Removed setting clk to freq_table to NULL on put_clk_and_freq_table call.

 .../bindings/cpufreq/arm_big_little_dt.txt         |  29 +++
 MAINTAINERS                                        |  11 +
 drivers/cpufreq/Kconfig.arm                        |  12 +
 drivers/cpufreq/Makefile                           |   4 +
 drivers/cpufreq/arm_big_little.c                   | 276 +++++++++++++++++++++
 drivers/cpufreq/arm_big_little.h                   |  40 +++
 drivers/cpufreq/arm_big_little_dt.c                | 125 ++++++++++
 7 files changed, 497 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
 create mode 100644 drivers/cpufreq/arm_big_little.c
 create mode 100644 drivers/cpufreq/arm_big_little.h
 create mode 100644 drivers/cpufreq/arm_big_little_dt.c

diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
new file mode 100644
index 0000000..6f534eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
@@ -0,0 +1,29 @@
+Generic ARM big LITTLE cpufreq driver's DT glue
+-----------------------------------------------
+
+It is DT specific glue layer for generic cpufreq driver for big LITTLE systems.
+
+Both required and optional properties listed below must be defined under node
+cluster*. * can be 0 or 1.
+
+Required properties:
+- freqs: List of all supported frequencies.
+
+Optional properties:
+- clock-latency: Specify the possible maximum transition latency for clock, in
+  unit of nanoseconds.
+
+Examples:
+
+cluster0: cluster@0 {
+        ..
+
+	freqs = <500000000 600000000 700000000 800000000 900000000 1000000000 1100000000 1200000000>;
+	clock-latency = <200000>;
+
+	..
+
+        cores {
+		..
+        };
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index 554fd30..b14b749 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2206,6 +2206,17 @@ S:	Maintained
 F:	drivers/cpufreq/
 F:	include/linux/cpufreq.h
 
+CPU FREQUENCY DRIVERS - ARM BIG LITTLE
+M:	Viresh Kumar <viresh.kumar@linaro.org>
+M:	Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+L:	cpufreq@vger.kernel.org
+L:	linux-pm@vger.kernel.org
+W:	http://www.arm.com/products/processors/technologies/biglittleprocessing.php
+S:	Maintained
+F:	drivers/cpufreq/arm_big_little.h
+F:	drivers/cpufreq/arm_big_little.c
+F:	drivers/cpufreq/arm_big_little_dt.c
+
 CPUID/MSR DRIVER
 M:	"H. Peter Anvin" <hpa@zytor.com>
 S:	Maintained
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 030ddf6..87b7e48 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -2,6 +2,18 @@
 # ARM CPU Frequency scaling drivers
 #
 
+config ARM_BIG_LITTLE_CPUFREQ
+	tristate
+	depends on ARM_CPU_TOPOLOGY
+
+config ARM_DT_BL_CPUFREQ
+	tristate "Generic ARM big LITTLE CPUfreq driver probed via DT"
+	select ARM_BIG_LITTLE_CPUFREQ
+	depends on OF && HAVE_CLK
+	help
+	  This enables the Generic CPUfreq driver for ARM big.LITTLE platform.
+	  This gets frequency tables from DT.
+
 config ARM_OMAP2PLUS_CPUFREQ
 	bool "TI OMAP2+"
 	depends on ARCH_OMAP2PLUS
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 863fd18..d1b0832 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -44,6 +44,10 @@ obj-$(CONFIG_X86_INTEL_PSTATE)		+= intel_pstate.o
 
 ##################################################################################
 # ARM SoC drivers
+obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ)	+= arm_big_little.o
+# big LITTLE per platform glues. Keep DT_BL_CPUFREQ as the last entry in all big
+# LITTLE drivers, so that it is probed last.
+obj-$(CONFIG_ARM_DT_BL_CPUFREQ)	+= arm_big_little_dt.o
 obj-$(CONFIG_UX500_SOC_DB8500)		+= dbx500-cpufreq.o
 obj-$(CONFIG_ARM_S3C2416_CPUFREQ)	+= s3c2416-cpufreq.o
 obj-$(CONFIG_ARM_S3C64XX_CPUFREQ)	+= s3c64xx-cpufreq.o
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
new file mode 100644
index 0000000..8b8b07e
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little.c
@@ -0,0 +1,276 @@
+/*
+ * ARM big.LITTLE Platforms CPUFreq support
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
+#include <linux/export.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/topology.h>
+#include <linux/types.h>
+
+#include "arm_big_little.h"
+
+/* Currently we support only two clusters */
+#define MAX_CLUSTERS	2
+
+static struct cpufreq_arm_bL_ops *arm_bL_ops;
+static struct clk *clk[MAX_CLUSTERS];
+static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
+static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)};
+
+static int cpu_to_cluster(int cpu)
+{
+	return topology_physical_package_id(cpu);
+}
+
+static unsigned int bL_cpufreq_get(unsigned int cpu)
+{
+	u32 cur_cluster = cpu_to_cluster(cpu);
+
+	return clk_get_rate(clk[cur_cluster]) / 1000;
+}
+
+/* Validate policy frequency range */
+static int bL_cpufreq_verify_policy(struct cpufreq_policy *policy)
+{
+	u32 cur_cluster = cpu_to_cluster(policy->cpu);
+
+	return cpufreq_frequency_table_verify(policy, freq_table[cur_cluster]);
+}
+
+/* Set clock frequency */
+static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
+		unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	u32 cpu = policy->cpu, freq_tab_idx, cur_cluster;
+	int ret = 0;
+
+	cur_cluster = cpu_to_cluster(policy->cpu);
+
+	freqs.old = bL_cpufreq_get(policy->cpu);
+
+	/* Determine valid target frequency using freq_table */
+	cpufreq_frequency_table_target(policy, freq_table[cur_cluster],
+			target_freq, relation, &freq_tab_idx);
+	freqs.new = freq_table[cur_cluster][freq_tab_idx].frequency;
+
+	freqs.cpu = policy->cpu;
+
+	pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n",
+			__func__, cpu, cur_cluster, freqs.old, target_freq,
+			freqs.new);
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_cpu(freqs.cpu, policy->cpus)
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000);
+	if (ret) {
+		pr_err("clk_set_rate failed: %d\n", ret);
+		return ret;
+	}
+
+	policy->cur = freqs.new;
+
+	for_each_cpu(freqs.cpu, policy->cpus)
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return ret;
+}
+
+/* translate the integer array into cpufreq_frequency_table entries */
+struct cpufreq_frequency_table *
+arm_bL_copy_table_from_array(unsigned int *table, int count)
+{
+	int i;
+
+	struct cpufreq_frequency_table *freq_table;
+
+	pr_debug("%s: table: %p, count: %d\n", __func__, table, count);
+
+	freq_table = kmalloc(sizeof(*freq_table) * (count + 1), GFP_KERNEL);
+	if (!freq_table)
+		return NULL;
+
+	for (i = 0; i < count; i++) {
+		pr_debug("%s: index: %d, freq: %d\n", __func__, i, table[i]);
+		freq_table[i].index = i;
+		freq_table[i].frequency = table[i]; /* in kHZ */
+	}
+
+	freq_table[i].index = count;
+	freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	return freq_table;
+}
+EXPORT_SYMBOL_GPL(arm_bL_copy_table_from_array);
+
+void arm_bL_free_freq_table(u32 cluster)
+{
+	pr_debug("%s: free freq table\n", __func__);
+
+	kfree(freq_table[cluster]);
+}
+EXPORT_SYMBOL_GPL(arm_bL_free_freq_table);
+
+static void put_cluster_clk_and_freq_table(u32 cluster)
+{
+	if (!atomic_dec_return(&cluster_usage[cluster])) {
+		clk_put(clk[cluster]);
+		arm_bL_ops->put_freq_tbl(cluster);
+		pr_debug("%s: cluster: %d\n", __func__, cluster);
+	}
+}
+
+static int get_cluster_clk_and_freq_table(u32 cluster)
+{
+	char name[14] = "cpu-cluster.";
+	int count;
+
+	if (atomic_inc_return(&cluster_usage[cluster]) != 1)
+		return 0;
+
+	freq_table[cluster] = arm_bL_ops->get_freq_tbl(cluster, &count);
+	if (!freq_table[cluster])
+		goto atomic_dec;
+
+	name[12] = cluster + '0';
+	clk[cluster] = clk_get_sys(name, NULL);
+	if (!IS_ERR(clk[cluster])) {
+		pr_debug("%s: clk: %p & freq table: %p, cluster: %d\n",
+				__func__, clk[cluster], freq_table[cluster],
+				cluster);
+		return 0;
+	}
+
+	arm_bL_ops->put_freq_tbl(cluster);
+
+atomic_dec:
+	atomic_dec(&cluster_usage[cluster]);
+	pr_err("%s: Failed to get data for cluster: %d\n", __func__, cluster);
+	return -ENODATA;
+}
+
+/* Per-CPU initialization */
+static int bL_cpufreq_init(struct cpufreq_policy *policy)
+{
+	u32 cur_cluster = cpu_to_cluster(policy->cpu);
+	int result;
+
+	result = get_cluster_clk_and_freq_table(cur_cluster);
+	if (result)
+		return result;
+
+	result = cpufreq_frequency_table_cpuinfo(policy,
+			freq_table[cur_cluster]);
+	if (result) {
+		pr_err("CPU %d, cluster: %d invalid freq table\n", policy->cpu,
+				cur_cluster);
+		put_cluster_clk_and_freq_table(cur_cluster);
+		return result;
+	}
+
+	cpufreq_frequency_table_get_attr(freq_table[cur_cluster], policy->cpu);
+
+	policy->cpuinfo.transition_latency =
+		arm_bL_ops->get_transition_latency(cur_cluster);
+	policy->cur = bL_cpufreq_get(policy->cpu);
+
+	cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
+
+	pr_info("CPU %d initialized\n", policy->cpu);
+	return 0;
+}
+
+static int bL_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	put_cluster_clk_and_freq_table(cpu_to_cluster(policy->cpu));
+	pr_debug("%s: Exited, cpu: %d\n", __func__, policy->cpu);
+
+	return 0;
+}
+
+/* Export freq_table to sysfs */
+static struct freq_attr *bL_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver bL_cpufreq_driver = {
+	.name	= "arm-big-little",
+	.flags	= CPUFREQ_STICKY,
+	.verify	= bL_cpufreq_verify_policy,
+	.target	= bL_cpufreq_set_target,
+	.get	= bL_cpufreq_get,
+	.init	= bL_cpufreq_init,
+	.exit	= bL_cpufreq_exit,
+	.attr	= bL_cpufreq_attr,
+};
+
+int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
+{
+	int ret;
+
+	if (arm_bL_ops) {
+		pr_debug("%s: Already registered: %s, exiting\n", __func__,
+				arm_bL_ops->name);
+		return -EBUSY;
+	}
+
+	if (!ops || !strlen(ops->name) || !ops->get_freq_tbl) {
+		pr_err("%s: Invalid arm_bL_ops, exiting\n", __func__);
+		return -ENODEV;
+	}
+
+	arm_bL_ops = ops;
+
+	ret = cpufreq_register_driver(&bL_cpufreq_driver);
+	if (ret) {
+		pr_info("%s: Failed registering platform driver: %s, err: %d\n",
+				__func__, ops->name, ret);
+		arm_bL_ops = NULL;
+	} else {
+		pr_info("%s: Registered platform driver: %s\n", __func__,
+				ops->name);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(bL_cpufreq_register);
+
+void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
+{
+	if (arm_bL_ops != ops) {
+		pr_info("%s: Registered with: %s, can't unregister, exiting\n",
+				__func__, arm_bL_ops->name);
+	}
+
+	cpufreq_unregister_driver(&bL_cpufreq_driver);
+	pr_info("%s: Un-registered platform driver: %s\n", __func__,
+			arm_bL_ops->name);
+	arm_bL_ops = NULL;
+}
+EXPORT_SYMBOL_GPL(bL_cpufreq_unregister);
diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h
new file mode 100644
index 0000000..049e15d
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little.h
@@ -0,0 +1,40 @@
+/*
+ * ARM big.LITTLE platform's CPUFreq header file
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef CPUFREQ_ARM_BIG_LITTLE_H
+#define CPUFREQ_ARM_BIG_LITTLE_H
+
+#include <linux/cpufreq.h>
+#include <linux/types.h>
+
+struct cpufreq_arm_bL_ops {
+	char name[CPUFREQ_NAME_LEN];
+	u32 (*get_transition_latency)(u32 cluster);
+	struct cpufreq_frequency_table *(*get_freq_tbl)(u32 cluster,
+			int *count);
+	void (*put_freq_tbl)(u32 cluster);
+};
+
+struct cpufreq_frequency_table *
+arm_bL_copy_table_from_array(unsigned int *table, int count);
+void arm_bL_free_freq_table(u32 cluster);
+
+int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
+void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops);
+
+#endif /* CPUFREQ_ARM_BIG_LITTLE_H */
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
new file mode 100644
index 0000000..c1eee50
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -0,0 +1,125 @@
+/*
+ * Generic big.LITTLE CPUFreq Interface driver
+ *
+ * It provides necessary ops to arm_big_little cpufreq driver and gets
+ * Frequency information from Device Tree. Freq table in DT must be in KHz.
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cpufreq.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "arm_big_little.h"
+
+static struct cpufreq_frequency_table *generic_get_freq_tbl(u32 cluster,
+		int *count)
+{
+	struct device_node *np = NULL;
+	const struct property *pp;
+	unsigned int *table = NULL;
+	int cluster_id;
+	struct cpufreq_frequency_table *cpufreq_table;
+
+	while ((np = of_find_node_by_name(np, "cluster"))) {
+		if (of_property_read_u32(np, "reg", &cluster_id))
+			continue;
+
+		if (cluster_id != cluster)
+			continue;
+
+		pp = of_find_property(np, "freqs", NULL);
+		if (!pp)
+			continue;
+
+		*count = pp->length / sizeof(u32);
+		if (!*count)
+			continue;
+
+		table = kmalloc(sizeof(*table) * (*count), GFP_KERNEL);
+		if (!table) {
+			pr_err("%s: Failed to allocate memory for table\n",
+					__func__);
+			return NULL;
+		}
+
+		of_property_read_u32_array(np, "freqs", table, *count);
+		break;
+	}
+
+	if (!table) {
+		pr_err("%s: Unable to retrieve Freq table from Device Tree",
+				__func__);
+		return NULL;
+	}
+
+	cpufreq_table = arm_bL_copy_table_from_array(table, *count);
+	kfree(table);
+
+	return cpufreq_table;
+}
+
+static void generic_put_freq_tbl(u32 cluster)
+{
+	arm_bL_free_freq_table(cluster);
+}
+
+static u32 get_transition_latency(u32 cluster)
+{
+	struct device_node *np = NULL;
+	u32 transition_latency = CPUFREQ_ETERNAL;
+	int cluster_id;
+
+	while ((np = of_find_node_by_name(np, "cluster"))) {
+		if (of_property_read_u32(np, "reg", &cluster_id))
+			continue;
+
+		if (cluster_id != cluster)
+			continue;
+
+		of_property_read_u32(np, "clock-latency", &transition_latency);
+		return transition_latency;
+	}
+
+	pr_err("%s: Unable to get clock-latency from DT, use CPUFREQ_ETERNAL",
+			__func__);
+
+	return transition_latency;
+}
+
+static struct cpufreq_arm_bL_ops generic_bL_ops = {
+	.name	= "generic-bl",
+	.get_transition_latency = get_transition_latency,
+	.get_freq_tbl = generic_get_freq_tbl,
+	.put_freq_tbl = generic_put_freq_tbl,
+};
+
+static int generic_bL_init(void)
+{
+	return bL_cpufreq_register(&generic_bL_ops);
+}
+module_init(generic_bL_init);
+
+static void generic_bL_exit(void)
+{
+	return bL_cpufreq_unregister(&generic_bL_ops);
+}
+module_exit(generic_bL_exit);
+
+MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.12.rc2.18.g61b472e


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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-07 17:14 ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-07 17:14 UTC (permalink / raw)
  To: linux-arm-kernel

big LITTLE is ARM's new Architecture focussing power/performance needs of modern
world. More information about big LITTLE can be found here:

http://www.arm.com/products/processors/technologies/biglittleprocessing.php
http://lwn.net/Articles/481055/

In order to keep cpufreq support for all big LITTLE platforms simple/generic,
this patch tries to add a generic cpufreq driver layer for all big LITTLE
platforms.

The driver is divided into two parts:
- Core driver: Generic and shared across all big LITTLE SoC's
- Glue drivers: Per platform drivers providing ops to the core driver

This patch adds in a generic glue driver which would extract information from
Device Tree.

Future SoC's can either reuse the DT glue or write their own depending on the
need.

Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---

V1->V2:
- s/IS_ERR_OR_NULL/IS_ERR for return value of clk_get
- Added "depends on HAVE_CLK" in Kconfig
- Removed "default n" from Kconfig
- Renamed cluster clk to "cpu-cluster.%u" and added it as dev_id instead of
  con_id and using clk_get_sys() instead of clk_get()
- Removed setting clk to freq_table to NULL on put_clk_and_freq_table call.

 .../bindings/cpufreq/arm_big_little_dt.txt         |  29 +++
 MAINTAINERS                                        |  11 +
 drivers/cpufreq/Kconfig.arm                        |  12 +
 drivers/cpufreq/Makefile                           |   4 +
 drivers/cpufreq/arm_big_little.c                   | 276 +++++++++++++++++++++
 drivers/cpufreq/arm_big_little.h                   |  40 +++
 drivers/cpufreq/arm_big_little_dt.c                | 125 ++++++++++
 7 files changed, 497 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
 create mode 100644 drivers/cpufreq/arm_big_little.c
 create mode 100644 drivers/cpufreq/arm_big_little.h
 create mode 100644 drivers/cpufreq/arm_big_little_dt.c

diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
new file mode 100644
index 0000000..6f534eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
@@ -0,0 +1,29 @@
+Generic ARM big LITTLE cpufreq driver's DT glue
+-----------------------------------------------
+
+It is DT specific glue layer for generic cpufreq driver for big LITTLE systems.
+
+Both required and optional properties listed below must be defined under node
+cluster*. * can be 0 or 1.
+
+Required properties:
+- freqs: List of all supported frequencies.
+
+Optional properties:
+- clock-latency: Specify the possible maximum transition latency for clock, in
+  unit of nanoseconds.
+
+Examples:
+
+cluster0: cluster at 0 {
+        ..
+
+	freqs = <500000000 600000000 700000000 800000000 900000000 1000000000 1100000000 1200000000>;
+	clock-latency = <200000>;
+
+	..
+
+        cores {
+		..
+        };
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index 554fd30..b14b749 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2206,6 +2206,17 @@ S:	Maintained
 F:	drivers/cpufreq/
 F:	include/linux/cpufreq.h
 
+CPU FREQUENCY DRIVERS - ARM BIG LITTLE
+M:	Viresh Kumar <viresh.kumar@linaro.org>
+M:	Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+L:	cpufreq at vger.kernel.org
+L:	linux-pm at vger.kernel.org
+W:	http://www.arm.com/products/processors/technologies/biglittleprocessing.php
+S:	Maintained
+F:	drivers/cpufreq/arm_big_little.h
+F:	drivers/cpufreq/arm_big_little.c
+F:	drivers/cpufreq/arm_big_little_dt.c
+
 CPUID/MSR DRIVER
 M:	"H. Peter Anvin" <hpa@zytor.com>
 S:	Maintained
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 030ddf6..87b7e48 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -2,6 +2,18 @@
 # ARM CPU Frequency scaling drivers
 #
 
+config ARM_BIG_LITTLE_CPUFREQ
+	tristate
+	depends on ARM_CPU_TOPOLOGY
+
+config ARM_DT_BL_CPUFREQ
+	tristate "Generic ARM big LITTLE CPUfreq driver probed via DT"
+	select ARM_BIG_LITTLE_CPUFREQ
+	depends on OF && HAVE_CLK
+	help
+	  This enables the Generic CPUfreq driver for ARM big.LITTLE platform.
+	  This gets frequency tables from DT.
+
 config ARM_OMAP2PLUS_CPUFREQ
 	bool "TI OMAP2+"
 	depends on ARCH_OMAP2PLUS
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 863fd18..d1b0832 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -44,6 +44,10 @@ obj-$(CONFIG_X86_INTEL_PSTATE)		+= intel_pstate.o
 
 ##################################################################################
 # ARM SoC drivers
+obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ)	+= arm_big_little.o
+# big LITTLE per platform glues. Keep DT_BL_CPUFREQ as the last entry in all big
+# LITTLE drivers, so that it is probed last.
+obj-$(CONFIG_ARM_DT_BL_CPUFREQ)	+= arm_big_little_dt.o
 obj-$(CONFIG_UX500_SOC_DB8500)		+= dbx500-cpufreq.o
 obj-$(CONFIG_ARM_S3C2416_CPUFREQ)	+= s3c2416-cpufreq.o
 obj-$(CONFIG_ARM_S3C64XX_CPUFREQ)	+= s3c64xx-cpufreq.o
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
new file mode 100644
index 0000000..8b8b07e
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little.c
@@ -0,0 +1,276 @@
+/*
+ * ARM big.LITTLE Platforms CPUFreq support
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
+#include <linux/export.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/topology.h>
+#include <linux/types.h>
+
+#include "arm_big_little.h"
+
+/* Currently we support only two clusters */
+#define MAX_CLUSTERS	2
+
+static struct cpufreq_arm_bL_ops *arm_bL_ops;
+static struct clk *clk[MAX_CLUSTERS];
+static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
+static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)};
+
+static int cpu_to_cluster(int cpu)
+{
+	return topology_physical_package_id(cpu);
+}
+
+static unsigned int bL_cpufreq_get(unsigned int cpu)
+{
+	u32 cur_cluster = cpu_to_cluster(cpu);
+
+	return clk_get_rate(clk[cur_cluster]) / 1000;
+}
+
+/* Validate policy frequency range */
+static int bL_cpufreq_verify_policy(struct cpufreq_policy *policy)
+{
+	u32 cur_cluster = cpu_to_cluster(policy->cpu);
+
+	return cpufreq_frequency_table_verify(policy, freq_table[cur_cluster]);
+}
+
+/* Set clock frequency */
+static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
+		unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	u32 cpu = policy->cpu, freq_tab_idx, cur_cluster;
+	int ret = 0;
+
+	cur_cluster = cpu_to_cluster(policy->cpu);
+
+	freqs.old = bL_cpufreq_get(policy->cpu);
+
+	/* Determine valid target frequency using freq_table */
+	cpufreq_frequency_table_target(policy, freq_table[cur_cluster],
+			target_freq, relation, &freq_tab_idx);
+	freqs.new = freq_table[cur_cluster][freq_tab_idx].frequency;
+
+	freqs.cpu = policy->cpu;
+
+	pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n",
+			__func__, cpu, cur_cluster, freqs.old, target_freq,
+			freqs.new);
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_cpu(freqs.cpu, policy->cpus)
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000);
+	if (ret) {
+		pr_err("clk_set_rate failed: %d\n", ret);
+		return ret;
+	}
+
+	policy->cur = freqs.new;
+
+	for_each_cpu(freqs.cpu, policy->cpus)
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return ret;
+}
+
+/* translate the integer array into cpufreq_frequency_table entries */
+struct cpufreq_frequency_table *
+arm_bL_copy_table_from_array(unsigned int *table, int count)
+{
+	int i;
+
+	struct cpufreq_frequency_table *freq_table;
+
+	pr_debug("%s: table: %p, count: %d\n", __func__, table, count);
+
+	freq_table = kmalloc(sizeof(*freq_table) * (count + 1), GFP_KERNEL);
+	if (!freq_table)
+		return NULL;
+
+	for (i = 0; i < count; i++) {
+		pr_debug("%s: index: %d, freq: %d\n", __func__, i, table[i]);
+		freq_table[i].index = i;
+		freq_table[i].frequency = table[i]; /* in kHZ */
+	}
+
+	freq_table[i].index = count;
+	freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	return freq_table;
+}
+EXPORT_SYMBOL_GPL(arm_bL_copy_table_from_array);
+
+void arm_bL_free_freq_table(u32 cluster)
+{
+	pr_debug("%s: free freq table\n", __func__);
+
+	kfree(freq_table[cluster]);
+}
+EXPORT_SYMBOL_GPL(arm_bL_free_freq_table);
+
+static void put_cluster_clk_and_freq_table(u32 cluster)
+{
+	if (!atomic_dec_return(&cluster_usage[cluster])) {
+		clk_put(clk[cluster]);
+		arm_bL_ops->put_freq_tbl(cluster);
+		pr_debug("%s: cluster: %d\n", __func__, cluster);
+	}
+}
+
+static int get_cluster_clk_and_freq_table(u32 cluster)
+{
+	char name[14] = "cpu-cluster.";
+	int count;
+
+	if (atomic_inc_return(&cluster_usage[cluster]) != 1)
+		return 0;
+
+	freq_table[cluster] = arm_bL_ops->get_freq_tbl(cluster, &count);
+	if (!freq_table[cluster])
+		goto atomic_dec;
+
+	name[12] = cluster + '0';
+	clk[cluster] = clk_get_sys(name, NULL);
+	if (!IS_ERR(clk[cluster])) {
+		pr_debug("%s: clk: %p & freq table: %p, cluster: %d\n",
+				__func__, clk[cluster], freq_table[cluster],
+				cluster);
+		return 0;
+	}
+
+	arm_bL_ops->put_freq_tbl(cluster);
+
+atomic_dec:
+	atomic_dec(&cluster_usage[cluster]);
+	pr_err("%s: Failed to get data for cluster: %d\n", __func__, cluster);
+	return -ENODATA;
+}
+
+/* Per-CPU initialization */
+static int bL_cpufreq_init(struct cpufreq_policy *policy)
+{
+	u32 cur_cluster = cpu_to_cluster(policy->cpu);
+	int result;
+
+	result = get_cluster_clk_and_freq_table(cur_cluster);
+	if (result)
+		return result;
+
+	result = cpufreq_frequency_table_cpuinfo(policy,
+			freq_table[cur_cluster]);
+	if (result) {
+		pr_err("CPU %d, cluster: %d invalid freq table\n", policy->cpu,
+				cur_cluster);
+		put_cluster_clk_and_freq_table(cur_cluster);
+		return result;
+	}
+
+	cpufreq_frequency_table_get_attr(freq_table[cur_cluster], policy->cpu);
+
+	policy->cpuinfo.transition_latency =
+		arm_bL_ops->get_transition_latency(cur_cluster);
+	policy->cur = bL_cpufreq_get(policy->cpu);
+
+	cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
+
+	pr_info("CPU %d initialized\n", policy->cpu);
+	return 0;
+}
+
+static int bL_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	put_cluster_clk_and_freq_table(cpu_to_cluster(policy->cpu));
+	pr_debug("%s: Exited, cpu: %d\n", __func__, policy->cpu);
+
+	return 0;
+}
+
+/* Export freq_table to sysfs */
+static struct freq_attr *bL_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver bL_cpufreq_driver = {
+	.name	= "arm-big-little",
+	.flags	= CPUFREQ_STICKY,
+	.verify	= bL_cpufreq_verify_policy,
+	.target	= bL_cpufreq_set_target,
+	.get	= bL_cpufreq_get,
+	.init	= bL_cpufreq_init,
+	.exit	= bL_cpufreq_exit,
+	.attr	= bL_cpufreq_attr,
+};
+
+int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
+{
+	int ret;
+
+	if (arm_bL_ops) {
+		pr_debug("%s: Already registered: %s, exiting\n", __func__,
+				arm_bL_ops->name);
+		return -EBUSY;
+	}
+
+	if (!ops || !strlen(ops->name) || !ops->get_freq_tbl) {
+		pr_err("%s: Invalid arm_bL_ops, exiting\n", __func__);
+		return -ENODEV;
+	}
+
+	arm_bL_ops = ops;
+
+	ret = cpufreq_register_driver(&bL_cpufreq_driver);
+	if (ret) {
+		pr_info("%s: Failed registering platform driver: %s, err: %d\n",
+				__func__, ops->name, ret);
+		arm_bL_ops = NULL;
+	} else {
+		pr_info("%s: Registered platform driver: %s\n", __func__,
+				ops->name);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(bL_cpufreq_register);
+
+void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
+{
+	if (arm_bL_ops != ops) {
+		pr_info("%s: Registered with: %s, can't unregister, exiting\n",
+				__func__, arm_bL_ops->name);
+	}
+
+	cpufreq_unregister_driver(&bL_cpufreq_driver);
+	pr_info("%s: Un-registered platform driver: %s\n", __func__,
+			arm_bL_ops->name);
+	arm_bL_ops = NULL;
+}
+EXPORT_SYMBOL_GPL(bL_cpufreq_unregister);
diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h
new file mode 100644
index 0000000..049e15d
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little.h
@@ -0,0 +1,40 @@
+/*
+ * ARM big.LITTLE platform's CPUFreq header file
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef CPUFREQ_ARM_BIG_LITTLE_H
+#define CPUFREQ_ARM_BIG_LITTLE_H
+
+#include <linux/cpufreq.h>
+#include <linux/types.h>
+
+struct cpufreq_arm_bL_ops {
+	char name[CPUFREQ_NAME_LEN];
+	u32 (*get_transition_latency)(u32 cluster);
+	struct cpufreq_frequency_table *(*get_freq_tbl)(u32 cluster,
+			int *count);
+	void (*put_freq_tbl)(u32 cluster);
+};
+
+struct cpufreq_frequency_table *
+arm_bL_copy_table_from_array(unsigned int *table, int count);
+void arm_bL_free_freq_table(u32 cluster);
+
+int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
+void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops);
+
+#endif /* CPUFREQ_ARM_BIG_LITTLE_H */
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
new file mode 100644
index 0000000..c1eee50
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -0,0 +1,125 @@
+/*
+ * Generic big.LITTLE CPUFreq Interface driver
+ *
+ * It provides necessary ops to arm_big_little cpufreq driver and gets
+ * Frequency information from Device Tree. Freq table in DT must be in KHz.
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cpufreq.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "arm_big_little.h"
+
+static struct cpufreq_frequency_table *generic_get_freq_tbl(u32 cluster,
+		int *count)
+{
+	struct device_node *np = NULL;
+	const struct property *pp;
+	unsigned int *table = NULL;
+	int cluster_id;
+	struct cpufreq_frequency_table *cpufreq_table;
+
+	while ((np = of_find_node_by_name(np, "cluster"))) {
+		if (of_property_read_u32(np, "reg", &cluster_id))
+			continue;
+
+		if (cluster_id != cluster)
+			continue;
+
+		pp = of_find_property(np, "freqs", NULL);
+		if (!pp)
+			continue;
+
+		*count = pp->length / sizeof(u32);
+		if (!*count)
+			continue;
+
+		table = kmalloc(sizeof(*table) * (*count), GFP_KERNEL);
+		if (!table) {
+			pr_err("%s: Failed to allocate memory for table\n",
+					__func__);
+			return NULL;
+		}
+
+		of_property_read_u32_array(np, "freqs", table, *count);
+		break;
+	}
+
+	if (!table) {
+		pr_err("%s: Unable to retrieve Freq table from Device Tree",
+				__func__);
+		return NULL;
+	}
+
+	cpufreq_table = arm_bL_copy_table_from_array(table, *count);
+	kfree(table);
+
+	return cpufreq_table;
+}
+
+static void generic_put_freq_tbl(u32 cluster)
+{
+	arm_bL_free_freq_table(cluster);
+}
+
+static u32 get_transition_latency(u32 cluster)
+{
+	struct device_node *np = NULL;
+	u32 transition_latency = CPUFREQ_ETERNAL;
+	int cluster_id;
+
+	while ((np = of_find_node_by_name(np, "cluster"))) {
+		if (of_property_read_u32(np, "reg", &cluster_id))
+			continue;
+
+		if (cluster_id != cluster)
+			continue;
+
+		of_property_read_u32(np, "clock-latency", &transition_latency);
+		return transition_latency;
+	}
+
+	pr_err("%s: Unable to get clock-latency from DT, use CPUFREQ_ETERNAL",
+			__func__);
+
+	return transition_latency;
+}
+
+static struct cpufreq_arm_bL_ops generic_bL_ops = {
+	.name	= "generic-bl",
+	.get_transition_latency = get_transition_latency,
+	.get_freq_tbl = generic_get_freq_tbl,
+	.put_freq_tbl = generic_put_freq_tbl,
+};
+
+static int generic_bL_init(void)
+{
+	return bL_cpufreq_register(&generic_bL_ops);
+}
+module_init(generic_bL_init);
+
+static void generic_bL_exit(void)
+{
+	return bL_cpufreq_unregister(&generic_bL_ops);
+}
+module_exit(generic_bL_exit);
+
+MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.12.rc2.18.g61b472e

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
  2013-03-07 17:14 ` Viresh Kumar
@ 2013-03-07 21:56   ` Guennadi Liakhovetski
  -1 siblings, 0 replies; 29+ messages in thread
From: Guennadi Liakhovetski @ 2013-03-07 21:56 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: rjw, Steve.Bannister, linux, linux-pm, Sudeep KarkadaNagesha,
	devicetree-discuss, Liviu.Dudau, linux-kernel, cpufreq,
	robin.randhawa, linux-arm-kernel, mark.hambleton, linaro-kernel,
	charles.garcia-tobin

Hi Viresh

On Fri, 8 Mar 2013, Viresh Kumar wrote:

> big LITTLE is ARM's new Architecture focussing power/performance needs of modern
> world. More information about big LITTLE can be found here:
> 
> http://www.arm.com/products/processors/technologies/biglittleprocessing.php
> http://lwn.net/Articles/481055/
> 
> In order to keep cpufreq support for all big LITTLE platforms simple/generic,
> this patch tries to add a generic cpufreq driver layer for all big LITTLE
> platforms.

I like generic drivers :) cpufreq-cpu0 is yet another such generic 
(cpufreq) driver. Now, comparing the functionality of the two:

[snip]

> +/* Set clock frequency */
> +static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
> +		unsigned int target_freq, unsigned int relation)
> +{
> +	struct cpufreq_freqs freqs;
> +	u32 cpu = policy->cpu, freq_tab_idx, cur_cluster;
> +	int ret = 0;
> +
> +	cur_cluster = cpu_to_cluster(policy->cpu);
> +
> +	freqs.old = bL_cpufreq_get(policy->cpu);
> +
> +	/* Determine valid target frequency using freq_table */
> +	cpufreq_frequency_table_target(policy, freq_table[cur_cluster],
> +			target_freq, relation, &freq_tab_idx);
> +	freqs.new = freq_table[cur_cluster][freq_tab_idx].frequency;
> +
> +	freqs.cpu = policy->cpu;
> +
> +	pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n",
> +			__func__, cpu, cur_cluster, freqs.old, target_freq,
> +			freqs.new);
> +
> +	if (freqs.old == freqs.new)
> +		return 0;
> +
> +	for_each_cpu(freqs.cpu, policy->cpus)
> +		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> +
> +	ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000);

we see, that this driver "only" switches CPU clock frequencies. Whereas 
the cpufreq-cpu0 driver also manipulates a regulator (if available) 
directly. I understand, power-saving is also an important consideration 
for big.LITTLE systems. So, I presume, you plan to implement voltage 
switching in cpufreq notifiers? Now, my question is: is this (notifier) 
actually the preferred method and the cpufreq-cpu0 driver is doing it 
"wrongly?"

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-07 21:56   ` Guennadi Liakhovetski
  0 siblings, 0 replies; 29+ messages in thread
From: Guennadi Liakhovetski @ 2013-03-07 21:56 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Viresh

On Fri, 8 Mar 2013, Viresh Kumar wrote:

> big LITTLE is ARM's new Architecture focussing power/performance needs of modern
> world. More information about big LITTLE can be found here:
> 
> http://www.arm.com/products/processors/technologies/biglittleprocessing.php
> http://lwn.net/Articles/481055/
> 
> In order to keep cpufreq support for all big LITTLE platforms simple/generic,
> this patch tries to add a generic cpufreq driver layer for all big LITTLE
> platforms.

I like generic drivers :) cpufreq-cpu0 is yet another such generic 
(cpufreq) driver. Now, comparing the functionality of the two:

[snip]

> +/* Set clock frequency */
> +static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
> +		unsigned int target_freq, unsigned int relation)
> +{
> +	struct cpufreq_freqs freqs;
> +	u32 cpu = policy->cpu, freq_tab_idx, cur_cluster;
> +	int ret = 0;
> +
> +	cur_cluster = cpu_to_cluster(policy->cpu);
> +
> +	freqs.old = bL_cpufreq_get(policy->cpu);
> +
> +	/* Determine valid target frequency using freq_table */
> +	cpufreq_frequency_table_target(policy, freq_table[cur_cluster],
> +			target_freq, relation, &freq_tab_idx);
> +	freqs.new = freq_table[cur_cluster][freq_tab_idx].frequency;
> +
> +	freqs.cpu = policy->cpu;
> +
> +	pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n",
> +			__func__, cpu, cur_cluster, freqs.old, target_freq,
> +			freqs.new);
> +
> +	if (freqs.old == freqs.new)
> +		return 0;
> +
> +	for_each_cpu(freqs.cpu, policy->cpus)
> +		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> +
> +	ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000);

we see, that this driver "only" switches CPU clock frequencies. Whereas 
the cpufreq-cpu0 driver also manipulates a regulator (if available) 
directly. I understand, power-saving is also an important consideration 
for big.LITTLE systems. So, I presume, you plan to implement voltage 
switching in cpufreq notifiers? Now, my question is: is this (notifier) 
actually the preferred method and the cpufreq-cpu0 driver is doing it 
"wrongly?"

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
  2013-03-07 21:56   ` Guennadi Liakhovetski
@ 2013-03-08  4:20     ` Viresh Kumar
  -1 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-08  4:20 UTC (permalink / raw)
  To: Guennadi Liakhovetski
  Cc: rjw, Steve.Bannister, linux, linux-pm, Sudeep KarkadaNagesha,
	devicetree-discuss, Liviu.Dudau, linux-kernel, cpufreq,
	robin.randhawa, linux-arm-kernel, mark.hambleton, linaro-kernel,
	charles.garcia-tobin

On 8 March 2013 05:56, Guennadi Liakhovetski <g.liakhovetski@gmx.de> wrote:
> I like generic drivers :)

Me too :)

> cpufreq-cpu0 is yet another such generic
> (cpufreq) driver. Now, comparing the functionality of the two:

Great!!

> we see, that this driver "only" switches CPU clock frequencies. Whereas
> the cpufreq-cpu0 driver also manipulates a regulator (if available)
> directly. I understand, power-saving is also an important consideration
> for big.LITTLE systems. So, I presume, you plan to implement voltage
> switching in cpufreq notifiers?

So the platform on which we are currently testing these is ARM TC2 Soc
and this switching is done by the firmware instead. And so didn't went
for regulator hookups initially.. Obviously in future regulator hookups would
find some space in this driver but not required for now.

> Now, my question is: is this (notifier)
> actually the preferred method and the cpufreq-cpu0 driver is doing it
> "wrongly?"

What notifiers are you talking about? I believe using the regulator framework
is the right way of doing this. And that would be part of this code later on.

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-08  4:20     ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-08  4:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 8 March 2013 05:56, Guennadi Liakhovetski <g.liakhovetski@gmx.de> wrote:
> I like generic drivers :)

Me too :)

> cpufreq-cpu0 is yet another such generic
> (cpufreq) driver. Now, comparing the functionality of the two:

Great!!

> we see, that this driver "only" switches CPU clock frequencies. Whereas
> the cpufreq-cpu0 driver also manipulates a regulator (if available)
> directly. I understand, power-saving is also an important consideration
> for big.LITTLE systems. So, I presume, you plan to implement voltage
> switching in cpufreq notifiers?

So the platform on which we are currently testing these is ARM TC2 Soc
and this switching is done by the firmware instead. And so didn't went
for regulator hookups initially.. Obviously in future regulator hookups would
find some space in this driver but not required for now.

> Now, my question is: is this (notifier)
> actually the preferred method and the cpufreq-cpu0 driver is doing it
> "wrongly?"

What notifiers are you talking about? I believe using the regulator framework
is the right way of doing this. And that would be part of this code later on.

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
  2013-03-08  4:20     ` Viresh Kumar
@ 2013-03-08  6:11       ` Guennadi Liakhovetski
  -1 siblings, 0 replies; 29+ messages in thread
From: Guennadi Liakhovetski @ 2013-03-08  6:11 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: rjw, Steve.Bannister, linux, linux-pm, Sudeep KarkadaNagesha,
	devicetree-discuss, Liviu.Dudau, linux-kernel, cpufreq,
	robin.randhawa, linux-arm-kernel, mark.hambleton, linaro-kernel,
	charles.garcia-tobin

Hi Viresh

On Fri, 8 Mar 2013, Viresh Kumar wrote:

> On 8 March 2013 05:56, Guennadi Liakhovetski <g.liakhovetski@gmx.de> wrote:
> > I like generic drivers :)
> 
> Me too :)
> 
> > cpufreq-cpu0 is yet another such generic
> > (cpufreq) driver. Now, comparing the functionality of the two:
> 
> Great!!
> 
> > we see, that this driver "only" switches CPU clock frequencies. Whereas
> > the cpufreq-cpu0 driver also manipulates a regulator (if available)
> > directly. I understand, power-saving is also an important consideration
> > for big.LITTLE systems. So, I presume, you plan to implement voltage
> > switching in cpufreq notifiers?
> 
> So the platform on which we are currently testing these is ARM TC2 Soc
> and this switching is done by the firmware instead. And so didn't went
> for regulator hookups initially.. Obviously in future regulator hookups would
> find some space in this driver but not required for now.
> 
> > Now, my question is: is this (notifier)
> > actually the preferred method and the cpufreq-cpu0 driver is doing it
> > "wrongly?"
> 
> What notifiers are you talking about? I believe using the regulator framework
> is the right way of doing this. And that would be part of this code later on.

Also in your driver you're doing

		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
		...
		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);

So, theoretically you could install such notifiers to adjust CPU voltages 
(using regulators too). But adding regulator calls directly to the driver 
would make it consistent with cpufreq-cpu0.c, so, if this doesn't violate 
any concepts, I think, it would be good to add those when suitable systems 
appear.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-08  6:11       ` Guennadi Liakhovetski
  0 siblings, 0 replies; 29+ messages in thread
From: Guennadi Liakhovetski @ 2013-03-08  6:11 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Viresh

On Fri, 8 Mar 2013, Viresh Kumar wrote:

> On 8 March 2013 05:56, Guennadi Liakhovetski <g.liakhovetski@gmx.de> wrote:
> > I like generic drivers :)
> 
> Me too :)
> 
> > cpufreq-cpu0 is yet another such generic
> > (cpufreq) driver. Now, comparing the functionality of the two:
> 
> Great!!
> 
> > we see, that this driver "only" switches CPU clock frequencies. Whereas
> > the cpufreq-cpu0 driver also manipulates a regulator (if available)
> > directly. I understand, power-saving is also an important consideration
> > for big.LITTLE systems. So, I presume, you plan to implement voltage
> > switching in cpufreq notifiers?
> 
> So the platform on which we are currently testing these is ARM TC2 Soc
> and this switching is done by the firmware instead. And so didn't went
> for regulator hookups initially.. Obviously in future regulator hookups would
> find some space in this driver but not required for now.
> 
> > Now, my question is: is this (notifier)
> > actually the preferred method and the cpufreq-cpu0 driver is doing it
> > "wrongly?"
> 
> What notifiers are you talking about? I believe using the regulator framework
> is the right way of doing this. And that would be part of this code later on.

Also in your driver you're doing

		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
		...
		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);

So, theoretically you could install such notifiers to adjust CPU voltages 
(using regulators too). But adding regulator calls directly to the driver 
would make it consistent with cpufreq-cpu0.c, so, if this doesn't violate 
any concepts, I think, it would be good to add those when suitable systems 
appear.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
  2013-03-08  6:11       ` Guennadi Liakhovetski
@ 2013-03-09  3:06         ` Viresh Kumar
  -1 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-09  3:06 UTC (permalink / raw)
  To: Guennadi Liakhovetski
  Cc: rjw, Steve.Bannister, linux, linux-pm, Sudeep KarkadaNagesha,
	devicetree-discuss, Liviu.Dudau, linux-kernel, cpufreq,
	robin.randhawa, linux-arm-kernel, mark.hambleton, linaro-kernel,
	charles.garcia-tobin

On 8 March 2013 14:11, Guennadi Liakhovetski <g.liakhovetski@gmx.de> wrote:
> Also in your driver you're doing
>
>                 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
>                 ...
>                 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
>
> So, theoretically you could install such notifiers to adjust CPU voltages
> (using regulators too). But adding regulator calls directly to the driver
> would make it consistent with cpufreq-cpu0.c.

Yes

>  so, if this doesn't violate
> any concepts, I think, it would be good to add those when suitable systems
> appear.

That's what i thought :)

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-09  3:06         ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-09  3:06 UTC (permalink / raw)
  To: linux-arm-kernel

On 8 March 2013 14:11, Guennadi Liakhovetski <g.liakhovetski@gmx.de> wrote:
> Also in your driver you're doing
>
>                 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
>                 ...
>                 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
>
> So, theoretically you could install such notifiers to adjust CPU voltages
> (using regulators too). But adding regulator calls directly to the driver
> would make it consistent with cpufreq-cpu0.c.

Yes

>  so, if this doesn't violate
> any concepts, I think, it would be good to add those when suitable systems
> appear.

That's what i thought :)

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
  2013-03-07 17:14 ` Viresh Kumar
@ 2013-03-10 15:58   ` Francesco Lavra
  -1 siblings, 0 replies; 29+ messages in thread
From: Francesco Lavra @ 2013-03-10 15:58 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: rjw, Steve.Bannister, linux, linux-pm, Sudeep KarkadaNagesha,
	devicetree-discuss, Liviu.Dudau, linux-kernel, cpufreq,
	robin.randhawa, linux-arm-kernel, mark.hambleton, linaro-kernel,
	charles.garcia-tobin

Hi,
On 03/07/2013 06:14 PM, Viresh Kumar wrote:
> big LITTLE is ARM's new Architecture focussing power/performance needs of modern
> world. More information about big LITTLE can be found here:
> 
> http://www.arm.com/products/processors/technologies/biglittleprocessing.php
> http://lwn.net/Articles/481055/
> 
> In order to keep cpufreq support for all big LITTLE platforms simple/generic,
> this patch tries to add a generic cpufreq driver layer for all big LITTLE
> platforms.
> 
> The driver is divided into two parts:
> - Core driver: Generic and shared across all big LITTLE SoC's
> - Glue drivers: Per platform drivers providing ops to the core driver
> 
> This patch adds in a generic glue driver which would extract information from
> Device Tree.
> 
> Future SoC's can either reuse the DT glue or write their own depending on the
> need.
> 
> Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
[...]
> +void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
> +{
> +	if (arm_bL_ops != ops) {
> +		pr_info("%s: Registered with: %s, can't unregister, exiting\n",
> +				__func__, arm_bL_ops->name);
> +	}

The code is not doing what the info message says.

> +
> +	cpufreq_unregister_driver(&bL_cpufreq_driver);
> +	pr_info("%s: Un-registered platform driver: %s\n", __func__,
> +			arm_bL_ops->name);
> +	arm_bL_ops = NULL;
> +}
> +EXPORT_SYMBOL_GPL(bL_cpufreq_unregister);

--
Francesco

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-10 15:58   ` Francesco Lavra
  0 siblings, 0 replies; 29+ messages in thread
From: Francesco Lavra @ 2013-03-10 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,
On 03/07/2013 06:14 PM, Viresh Kumar wrote:
> big LITTLE is ARM's new Architecture focussing power/performance needs of modern
> world. More information about big LITTLE can be found here:
> 
> http://www.arm.com/products/processors/technologies/biglittleprocessing.php
> http://lwn.net/Articles/481055/
> 
> In order to keep cpufreq support for all big LITTLE platforms simple/generic,
> this patch tries to add a generic cpufreq driver layer for all big LITTLE
> platforms.
> 
> The driver is divided into two parts:
> - Core driver: Generic and shared across all big LITTLE SoC's
> - Glue drivers: Per platform drivers providing ops to the core driver
> 
> This patch adds in a generic glue driver which would extract information from
> Device Tree.
> 
> Future SoC's can either reuse the DT glue or write their own depending on the
> need.
> 
> Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
[...]
> +void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
> +{
> +	if (arm_bL_ops != ops) {
> +		pr_info("%s: Registered with: %s, can't unregister, exiting\n",
> +				__func__, arm_bL_ops->name);
> +	}

The code is not doing what the info message says.

> +
> +	cpufreq_unregister_driver(&bL_cpufreq_driver);
> +	pr_info("%s: Un-registered platform driver: %s\n", __func__,
> +			arm_bL_ops->name);
> +	arm_bL_ops = NULL;
> +}
> +EXPORT_SYMBOL_GPL(bL_cpufreq_unregister);

--
Francesco

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-11  0:57     ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-11  0:57 UTC (permalink / raw)
  To: Francesco Lavra
  Cc: rjw, Steve.Bannister, linux, linux-pm, Sudeep KarkadaNagesha,
	devicetree-discuss, Liviu.Dudau, linux-kernel, cpufreq,
	robin.randhawa, linux-arm-kernel, mark.hambleton, linaro-kernel,
	charles.garcia-tobin

On 10 March 2013 23:58, Francesco Lavra <francescolavra.fl@gmail.com> wrote:
> On 03/07/2013 06:14 PM, Viresh Kumar wrote:
>> +void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
>> +{
>> +     if (arm_bL_ops != ops) {
>> +             pr_info("%s: Registered with: %s, can't unregister, exiting\n",
>> +                             __func__, arm_bL_ops->name);
>> +     }
>
> The code is not doing what the info message says.

Yes, following is the improvement:

diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index 8b8b07e..9d449cf 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -264,8 +264,9 @@ EXPORT_SYMBOL_GPL(bL_cpufreq_register);
 void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
 {
        if (arm_bL_ops != ops) {
-               pr_info("%s: Registered with: %s, can't unregister, exiting\n",
+               pr_err("%s: Registered with: %s, can't unregister, exiting\n",
                                __func__, arm_bL_ops->name);
+               return;
        }

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-11  0:57     ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-11  0:57 UTC (permalink / raw)
  To: Francesco Lavra
  Cc: Steve.Bannister-5wv7dgnIgG8, linux-lFZ/pmaqli7XmaaqVzeoHQ,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Sudeep KarkadaNagesha,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	Liviu.Dudau-5wv7dgnIgG8, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	cpufreq-u79uwXL29TY76Z2rM5mHXA, rjw-KKrjLPT3xs0,
	robin.randhawa-5wv7dgnIgG8,
	mark.hambleton-dY08KVG/lbpWk0Htik3J/w,
	linaro-kernel-cunTk1MwBs8s++Sfvej+rw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	charles.garcia-tobin-5wv7dgnIgG8

On 10 March 2013 23:58, Francesco Lavra <francescolavra.fl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On 03/07/2013 06:14 PM, Viresh Kumar wrote:
>> +void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
>> +{
>> +     if (arm_bL_ops != ops) {
>> +             pr_info("%s: Registered with: %s, can't unregister, exiting\n",
>> +                             __func__, arm_bL_ops->name);
>> +     }
>
> The code is not doing what the info message says.

Yes, following is the improvement:

diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index 8b8b07e..9d449cf 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -264,8 +264,9 @@ EXPORT_SYMBOL_GPL(bL_cpufreq_register);
 void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
 {
        if (arm_bL_ops != ops) {
-               pr_info("%s: Registered with: %s, can't unregister, exiting\n",
+               pr_err("%s: Registered with: %s, can't unregister, exiting\n",
                                __func__, arm_bL_ops->name);
+               return;
        }

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-11  0:57     ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-11  0:57 UTC (permalink / raw)
  To: linux-arm-kernel

On 10 March 2013 23:58, Francesco Lavra <francescolavra.fl@gmail.com> wrote:
> On 03/07/2013 06:14 PM, Viresh Kumar wrote:
>> +void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
>> +{
>> +     if (arm_bL_ops != ops) {
>> +             pr_info("%s: Registered with: %s, can't unregister, exiting\n",
>> +                             __func__, arm_bL_ops->name);
>> +     }
>
> The code is not doing what the info message says.

Yes, following is the improvement:

diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index 8b8b07e..9d449cf 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -264,8 +264,9 @@ EXPORT_SYMBOL_GPL(bL_cpufreq_register);
 void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
 {
        if (arm_bL_ops != ops) {
-               pr_info("%s: Registered with: %s, can't unregister, exiting\n",
+               pr_err("%s: Registered with: %s, can't unregister, exiting\n",
                                __func__, arm_bL_ops->name);
+               return;
        }

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
  2013-03-11  0:57     ` Viresh Kumar
@ 2013-03-21 23:50       ` Rafael J. Wysocki
  -1 siblings, 0 replies; 29+ messages in thread
From: Rafael J. Wysocki @ 2013-03-21 23:50 UTC (permalink / raw)
  To: Viresh Kumar, robin.randhawa
  Cc: Francesco Lavra, Steve.Bannister, linux, linux-pm,
	Sudeep KarkadaNagesha, devicetree-discuss, Liviu.Dudau,
	linux-kernel, linux-arm-kernel, mark.hambleton, linaro-kernel,
	charles.garcia-tobin

On Monday, March 11, 2013 08:57:49 AM Viresh Kumar wrote:
> On 10 March 2013 23:58, Francesco Lavra <francescolavra.fl@gmail.com> wrote:
> > On 03/07/2013 06:14 PM, Viresh Kumar wrote:
> >> +void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
> >> +{
> >> +     if (arm_bL_ops != ops) {
> >> +             pr_info("%s: Registered with: %s, can't unregister, exiting\n",
> >> +                             __func__, arm_bL_ops->name);
> >> +     }
> >
> > The code is not doing what the info message says.
> 
> Yes, following is the improvement:

Please post a complete update patch if you want me to take it.  I'd also would
like it to be ACKed by someone involved in the big-LITTLE work on the arch
side.

Thanks,
Rafael


> diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
> index 8b8b07e..9d449cf 100644
> --- a/drivers/cpufreq/arm_big_little.c
> +++ b/drivers/cpufreq/arm_big_little.c
> @@ -264,8 +264,9 @@ EXPORT_SYMBOL_GPL(bL_cpufreq_register);
>  void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
>  {
>         if (arm_bL_ops != ops) {
> -               pr_info("%s: Registered with: %s, can't unregister, exiting\n",
> +               pr_err("%s: Registered with: %s, can't unregister, exiting\n",
>                                 __func__, arm_bL_ops->name);
> +               return;
>         }
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-21 23:50       ` Rafael J. Wysocki
  0 siblings, 0 replies; 29+ messages in thread
From: Rafael J. Wysocki @ 2013-03-21 23:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday, March 11, 2013 08:57:49 AM Viresh Kumar wrote:
> On 10 March 2013 23:58, Francesco Lavra <francescolavra.fl@gmail.com> wrote:
> > On 03/07/2013 06:14 PM, Viresh Kumar wrote:
> >> +void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
> >> +{
> >> +     if (arm_bL_ops != ops) {
> >> +             pr_info("%s: Registered with: %s, can't unregister, exiting\n",
> >> +                             __func__, arm_bL_ops->name);
> >> +     }
> >
> > The code is not doing what the info message says.
> 
> Yes, following is the improvement:

Please post a complete update patch if you want me to take it.  I'd also would
like it to be ACKed by someone involved in the big-LITTLE work on the arch
side.

Thanks,
Rafael


> diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
> index 8b8b07e..9d449cf 100644
> --- a/drivers/cpufreq/arm_big_little.c
> +++ b/drivers/cpufreq/arm_big_little.c
> @@ -264,8 +264,9 @@ EXPORT_SYMBOL_GPL(bL_cpufreq_register);
>  void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
>  {
>         if (arm_bL_ops != ops) {
> -               pr_info("%s: Registered with: %s, can't unregister, exiting\n",
> +               pr_err("%s: Registered with: %s, can't unregister, exiting\n",
>                                 __func__, arm_bL_ops->name);
> +               return;
>         }
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
  2013-03-21 23:50       ` Rafael J. Wysocki
@ 2013-03-22  2:21         ` Viresh Kumar
  -1 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-22  2:21 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: robin.randhawa, Francesco Lavra, Steve.Bannister, linux,
	linux-pm, Sudeep KarkadaNagesha, devicetree-discuss, Liviu.Dudau,
	linux-kernel, linux-arm-kernel, mark.hambleton, linaro-kernel,
	charles.garcia-tobin

On 22 March 2013 05:20, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> Please post a complete update patch if you want me to take it.  I'd also would
> like it to be ACKed by someone involved in the big-LITTLE work on the arch
> side.

Okay.

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-22  2:21         ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-22  2:21 UTC (permalink / raw)
  To: linux-arm-kernel

On 22 March 2013 05:20, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> Please post a complete update patch if you want me to take it.  I'd also would
> like it to be ACKed by someone involved in the big-LITTLE work on the arch
> side.

Okay.

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
  2013-04-13 20:13   ` Francesco Lavra
@ 2013-04-15  7:02     ` Viresh Kumar
  -1 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-04-15  7:02 UTC (permalink / raw)
  To: Francesco Lavra
  Cc: rjw, nicolas.pitre, robin.randhawa, linux, mark.hambleton,
	linux-pm, Sudeep KarkadaNagesha, devicetree-discuss, Liviu.Dudau,
	linux-kernel, cpufreq, linaro-kernel, Steve.Bannister,
	arvind.chauhan, linux-arm-kernel, charles.garcia-tobin

On 14 April 2013 01:43, Francesco Lavra <francescolavra.fl@gmail.com> wrote:

>> +     for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
>
> If of_find_node_by_path() returns NULL, there will be a NULL pointer
> dereference.
>
>> +             if (count++ != cpu_dev->id)
>> +                     continue;
>> +             if (!of_get_property(np, "operating-points", NULL))
>> +                     return -ENODATA;
>> +
>> +             cpu_dev->of_node = np;
>> +
>> +             ret = of_init_opp_table(cpu_dev);
>> +             if (ret)
>> +                     return ret;
>> +
>> +             return 0;
>
> of_node_put() should be called on np before returning.
> Also, the reference count of the parent node should be decremented as well.
>
> These comments apply to the below function dt_get_transition_latency() too.

Thanks Francesco.

Below fixes this (I will send it separately to Rafael):

Subject: [PATCH 1/2] cpufreq: ARM big LITTLE: put DT nodes after using them

DT nodes should be put using of_node_put() to balance their usage counts. This
is not done properly in ARM's big LITTLE driver. Fix it.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/cpufreq/arm_big_little_dt.c | 43 +++++++++++++++++++++++++------------
 1 file changed, 29 insertions(+), 14 deletions(-)

diff --git a/drivers/cpufreq/arm_big_little_dt.c
b/drivers/cpufreq/arm_big_little_dt.c
index 452ff46..44be311 100644
--- a/drivers/cpufreq/arm_big_little_dt.c
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -31,22 +31,28 @@

 static int dt_init_opp_table(struct device *cpu_dev)
 {
-	struct device_node *np = NULL;
+	struct device_node *np, *parent;
 	int count = 0, ret;

-	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+	parent = of_find_node_by_path("/cpus");
+	if (!parent) {
+		pr_err("failed to find OF /cpus\n");
+		return -ENOENT;
+	}
+
+	for_each_child_of_node(parent, np) {
 		if (count++ != cpu_dev->id)
 			continue;
-		if (!of_get_property(np, "operating-points", NULL))
-			return -ENODATA;
-
-		cpu_dev->of_node = np;
-
-		ret = of_init_opp_table(cpu_dev);
-		if (ret)
-			return ret;
-
-		return 0;
+		if (!of_get_property(np, "operating-points", NULL)) {
+			ret = -ENODATA;
+		} else {
+			cpu_dev->of_node = np;
+			ret = of_init_opp_table(cpu_dev);
+		}
+		of_node_put(np);
+		of_node_put(parent);
+
+		return ret;
 	}

 	return -ENODEV;
@@ -54,15 +60,24 @@ static int dt_init_opp_table(struct device *cpu_dev)

 static int dt_get_transition_latency(struct device *cpu_dev)
 {
-	struct device_node *np = NULL;
+	struct device_node *np, *parent;
 	u32 transition_latency = CPUFREQ_ETERNAL;
 	int count = 0;

-	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+	parent = of_find_node_by_path("/cpus");
+	if (!parent) {
+		pr_err("failed to find OF /cpus\n");
+		return -ENOENT;
+	}
+
+	for_each_child_of_node(parent, np) {
 		if (count++ != cpu_dev->id)
 			continue;

 		of_property_read_u32(np, "clock-latency", &transition_latency);
+		of_node_put(np);
+		of_node_put(parent);
+
 		return 0;
 	}

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-04-15  7:02     ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-04-15  7:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 14 April 2013 01:43, Francesco Lavra <francescolavra.fl@gmail.com> wrote:

>> +     for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
>
> If of_find_node_by_path() returns NULL, there will be a NULL pointer
> dereference.
>
>> +             if (count++ != cpu_dev->id)
>> +                     continue;
>> +             if (!of_get_property(np, "operating-points", NULL))
>> +                     return -ENODATA;
>> +
>> +             cpu_dev->of_node = np;
>> +
>> +             ret = of_init_opp_table(cpu_dev);
>> +             if (ret)
>> +                     return ret;
>> +
>> +             return 0;
>
> of_node_put() should be called on np before returning.
> Also, the reference count of the parent node should be decremented as well.
>
> These comments apply to the below function dt_get_transition_latency() too.

Thanks Francesco.

Below fixes this (I will send it separately to Rafael):

Subject: [PATCH 1/2] cpufreq: ARM big LITTLE: put DT nodes after using them

DT nodes should be put using of_node_put() to balance their usage counts. This
is not done properly in ARM's big LITTLE driver. Fix it.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/cpufreq/arm_big_little_dt.c | 43 +++++++++++++++++++++++++------------
 1 file changed, 29 insertions(+), 14 deletions(-)

diff --git a/drivers/cpufreq/arm_big_little_dt.c
b/drivers/cpufreq/arm_big_little_dt.c
index 452ff46..44be311 100644
--- a/drivers/cpufreq/arm_big_little_dt.c
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -31,22 +31,28 @@

 static int dt_init_opp_table(struct device *cpu_dev)
 {
-	struct device_node *np = NULL;
+	struct device_node *np, *parent;
 	int count = 0, ret;

-	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+	parent = of_find_node_by_path("/cpus");
+	if (!parent) {
+		pr_err("failed to find OF /cpus\n");
+		return -ENOENT;
+	}
+
+	for_each_child_of_node(parent, np) {
 		if (count++ != cpu_dev->id)
 			continue;
-		if (!of_get_property(np, "operating-points", NULL))
-			return -ENODATA;
-
-		cpu_dev->of_node = np;
-
-		ret = of_init_opp_table(cpu_dev);
-		if (ret)
-			return ret;
-
-		return 0;
+		if (!of_get_property(np, "operating-points", NULL)) {
+			ret = -ENODATA;
+		} else {
+			cpu_dev->of_node = np;
+			ret = of_init_opp_table(cpu_dev);
+		}
+		of_node_put(np);
+		of_node_put(parent);
+
+		return ret;
 	}

 	return -ENODEV;
@@ -54,15 +60,24 @@ static int dt_init_opp_table(struct device *cpu_dev)

 static int dt_get_transition_latency(struct device *cpu_dev)
 {
-	struct device_node *np = NULL;
+	struct device_node *np, *parent;
 	u32 transition_latency = CPUFREQ_ETERNAL;
 	int count = 0;

-	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+	parent = of_find_node_by_path("/cpus");
+	if (!parent) {
+		pr_err("failed to find OF /cpus\n");
+		return -ENOENT;
+	}
+
+	for_each_child_of_node(parent, np) {
 		if (count++ != cpu_dev->id)
 			continue;

 		of_property_read_u32(np, "clock-latency", &transition_latency);
+		of_node_put(np);
+		of_node_put(parent);
+
 		return 0;
 	}

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
  2013-03-26  9:51 ` Viresh Kumar
@ 2013-04-13 20:13   ` Francesco Lavra
  -1 siblings, 0 replies; 29+ messages in thread
From: Francesco Lavra @ 2013-04-13 20:13 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: rjw, nicolas.pitre, robin.randhawa, linux, mark.hambleton,
	linux-pm, Sudeep KarkadaNagesha, devicetree-discuss, Liviu.Dudau,
	linux-kernel, cpufreq, linaro-kernel, Steve.Bannister,
	arvind.chauhan, linux-arm-kernel, charles.garcia-tobin

On 03/26/2013 10:51 AM, Viresh Kumar wrote:
> big LITTLE is ARM's new Architecture focussing power/performance needs of modern
> world. More information about big LITTLE can be found here:
> 
> http://www.arm.com/products/processors/technologies/biglittleprocessing.php
> http://lwn.net/Articles/481055/
> 
> In order to keep cpufreq support for all big LITTLE platforms simple/generic,
> this patch tries to add a generic cpufreq driver layer for all big LITTLE
> platforms.
> 
> The driver is divided into two parts:
> - Core driver: Generic and shared across all big LITTLE SoC's
> - Glue drivers: Per platform drivers providing ops to the core driver
> 
> This patch adds in a generic glue driver which would extract information from
> Device Tree.
> 
> Future SoC's can either reuse the DT glue or write their own depending on the
> need.
> 
> Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
[...]
> diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
> new file mode 100644
> index 0000000..452ff46
> --- /dev/null
> +++ b/drivers/cpufreq/arm_big_little_dt.c
> @@ -0,0 +1,92 @@
> +/*
> + * Generic big.LITTLE CPUFreq Interface driver
> + *
> + * It provides necessary ops to arm_big_little cpufreq driver and gets
> + * Frequency information from Device Tree. Freq table in DT must be in KHz.
> + *
> + * Copyright (C) 2013 Linaro.
> + * Viresh Kumar <viresh.kumar@linaro.org>
> + *
> + * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/cpufreq.h>
> +#include <linux/device.h>
> +#include <linux/export.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/opp.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include "arm_big_little.h"
> +
> +static int dt_init_opp_table(struct device *cpu_dev)
> +{
> +	struct device_node *np = NULL;
> +	int count = 0, ret;
> +
> +	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {

If of_find_node_by_path() returns NULL, there will be a NULL pointer
dereference.

> +		if (count++ != cpu_dev->id)
> +			continue;
> +		if (!of_get_property(np, "operating-points", NULL))
> +			return -ENODATA;
> +
> +		cpu_dev->of_node = np;
> +
> +		ret = of_init_opp_table(cpu_dev);
> +		if (ret)
> +			return ret;
> +
> +		return 0;

of_node_put() should be called on np before returning.
Also, the reference count of the parent node should be decremented as well.

These comments apply to the below function dt_get_transition_latency() too.

> +	}
> +
> +	return -ENODEV;
> +}
> +
> +static int dt_get_transition_latency(struct device *cpu_dev)
> +{
> +	struct device_node *np = NULL;
> +	u32 transition_latency = CPUFREQ_ETERNAL;
> +	int count = 0;
> +
> +	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
> +		if (count++ != cpu_dev->id)
> +			continue;
> +
> +		of_property_read_u32(np, "clock-latency", &transition_latency);
> +		return 0;
> +	}
> +
> +	return -ENODEV;
> +}

--
Francesco

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-04-13 20:13   ` Francesco Lavra
  0 siblings, 0 replies; 29+ messages in thread
From: Francesco Lavra @ 2013-04-13 20:13 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/26/2013 10:51 AM, Viresh Kumar wrote:
> big LITTLE is ARM's new Architecture focussing power/performance needs of modern
> world. More information about big LITTLE can be found here:
> 
> http://www.arm.com/products/processors/technologies/biglittleprocessing.php
> http://lwn.net/Articles/481055/
> 
> In order to keep cpufreq support for all big LITTLE platforms simple/generic,
> this patch tries to add a generic cpufreq driver layer for all big LITTLE
> platforms.
> 
> The driver is divided into two parts:
> - Core driver: Generic and shared across all big LITTLE SoC's
> - Glue drivers: Per platform drivers providing ops to the core driver
> 
> This patch adds in a generic glue driver which would extract information from
> Device Tree.
> 
> Future SoC's can either reuse the DT glue or write their own depending on the
> need.
> 
> Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
[...]
> diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
> new file mode 100644
> index 0000000..452ff46
> --- /dev/null
> +++ b/drivers/cpufreq/arm_big_little_dt.c
> @@ -0,0 +1,92 @@
> +/*
> + * Generic big.LITTLE CPUFreq Interface driver
> + *
> + * It provides necessary ops to arm_big_little cpufreq driver and gets
> + * Frequency information from Device Tree. Freq table in DT must be in KHz.
> + *
> + * Copyright (C) 2013 Linaro.
> + * Viresh Kumar <viresh.kumar@linaro.org>
> + *
> + * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/cpufreq.h>
> +#include <linux/device.h>
> +#include <linux/export.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/opp.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include "arm_big_little.h"
> +
> +static int dt_init_opp_table(struct device *cpu_dev)
> +{
> +	struct device_node *np = NULL;
> +	int count = 0, ret;
> +
> +	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {

If of_find_node_by_path() returns NULL, there will be a NULL pointer
dereference.

> +		if (count++ != cpu_dev->id)
> +			continue;
> +		if (!of_get_property(np, "operating-points", NULL))
> +			return -ENODATA;
> +
> +		cpu_dev->of_node = np;
> +
> +		ret = of_init_opp_table(cpu_dev);
> +		if (ret)
> +			return ret;
> +
> +		return 0;

of_node_put() should be called on np before returning.
Also, the reference count of the parent node should be decremented as well.

These comments apply to the below function dt_get_transition_latency() too.

> +	}
> +
> +	return -ENODEV;
> +}
> +
> +static int dt_get_transition_latency(struct device *cpu_dev)
> +{
> +	struct device_node *np = NULL;
> +	u32 transition_latency = CPUFREQ_ETERNAL;
> +	int count = 0;
> +
> +	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
> +		if (count++ != cpu_dev->id)
> +			continue;
> +
> +		of_property_read_u32(np, "clock-latency", &transition_latency);
> +		return 0;
> +	}
> +
> +	return -ENODEV;
> +}

--
Francesco

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
  2013-03-26 13:17   ` Rob Herring
@ 2013-03-26 14:30     ` Viresh Kumar
  -1 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-26 14:30 UTC (permalink / raw)
  To: Rob Herring
  Cc: Rafael J. Wysocki, nicolas.pitre, robin.randhawa, linux,
	mark.hambleton, linux-pm, Sudeep KarkadaNagesha,
	devicetree-discuss, Liviu.Dudau, linux-kernel, cpufreq,
	linaro-kernel, Steve.Bannister, arvind.chauhan, linux-arm-kernel,
	charles.garcia-tobin, Mark Langsdorf, Shawn Guo

On 26 March 2013 18:47, Rob Herring <robherring2@gmail.com> wrote:
> On 03/26/2013 04:51 AM, Viresh Kumar wrote:
> I fail to see anything bL specific here. This is just multi-cluster, but
> even for that I don't see anything new other than simply allowing per
> cpu or per cluster opp's. The fact that we have one opp for a cluster is
> simply an implementation decision in CortexA cores.

For now it is a very simple driver and yes probably multi-cluster only. It
will be updated with In Kernel Switcher support as soon as Linaro makes
a decision to opensource that (likely to happen soon).

Yes, there can be implementations, like krait, which can have per cpu
control of opp, but we will wait for any such platform before making this
driver complex.

>> +NOTE: Cpus should boot in the order specified in DT and all cpus for a cluster
>> +must be present contiguously. Generic DT driver will check only node 'x' for
>> +cpu:x.
>
> The OS cannot necessarily control the order. The OS should be able to
> boot on which ever core comes up first.

This should be a FIXME instead (will update it). I am waiting for
final DT bindings
from ARM guys before this can be written on stone.

For now this is the limitation and it should go away as soon as DT bindings are
finalized.

>> +Optional properties:
>> +- clock-latency: Specify the possible maximum transition latency for clock,
>> +  in unit of nanoseconds.
>
> Don't we already have "transition-latency" defined?

No, its clock-latency.

$ git grep "clock-latency" Documentation/devicetree/bindings/
Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt:-
clock-latency: Specify the possible maximum transition latency for
clock,
Documentation/devicetree/bindings/cpufreq/cpufreq-spear.txt:-
clock-latency: Specify the possible maximum transition latency for
clock, in

Though transition-latency is mentioned by the example of cpufreq-cpu0.
I will fix it.

> Don't create
> something new. Ideally, this should have had "-ns" appended, but the
> binding is already defined.

I had the same intention.

>> diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
> What is specific to bL? This looks like just a multi-cluster cpufreq
> driver and should be generalized to that. Also, why can't the existing
> cpufreq-cpu0 driver be extended to support this?

With IKS code in, it will be a complete big LITTLE driver.

>> +/* Currently we support only two clusters */
>> +#define MAX_CLUSTERS 2
>
> Why? Because that is what the define is or there are other limitations?
> Seems like this could and should be dynamically discovered with DT.

To keep it simple, as for now as all early systems (atleast which are announced)
have dual cluster systems only.

We will update it once we have some real systems breaking this law.

--
viresh

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-26 14:30     ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-26 14:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 26 March 2013 18:47, Rob Herring <robherring2@gmail.com> wrote:
> On 03/26/2013 04:51 AM, Viresh Kumar wrote:
> I fail to see anything bL specific here. This is just multi-cluster, but
> even for that I don't see anything new other than simply allowing per
> cpu or per cluster opp's. The fact that we have one opp for a cluster is
> simply an implementation decision in CortexA cores.

For now it is a very simple driver and yes probably multi-cluster only. It
will be updated with In Kernel Switcher support as soon as Linaro makes
a decision to opensource that (likely to happen soon).

Yes, there can be implementations, like krait, which can have per cpu
control of opp, but we will wait for any such platform before making this
driver complex.

>> +NOTE: Cpus should boot in the order specified in DT and all cpus for a cluster
>> +must be present contiguously. Generic DT driver will check only node 'x' for
>> +cpu:x.
>
> The OS cannot necessarily control the order. The OS should be able to
> boot on which ever core comes up first.

This should be a FIXME instead (will update it). I am waiting for
final DT bindings
from ARM guys before this can be written on stone.

For now this is the limitation and it should go away as soon as DT bindings are
finalized.

>> +Optional properties:
>> +- clock-latency: Specify the possible maximum transition latency for clock,
>> +  in unit of nanoseconds.
>
> Don't we already have "transition-latency" defined?

No, its clock-latency.

$ git grep "clock-latency" Documentation/devicetree/bindings/
Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt:-
clock-latency: Specify the possible maximum transition latency for
clock,
Documentation/devicetree/bindings/cpufreq/cpufreq-spear.txt:-
clock-latency: Specify the possible maximum transition latency for
clock, in

Though transition-latency is mentioned by the example of cpufreq-cpu0.
I will fix it.

> Don't create
> something new. Ideally, this should have had "-ns" appended, but the
> binding is already defined.

I had the same intention.

>> diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
> What is specific to bL? This looks like just a multi-cluster cpufreq
> driver and should be generalized to that. Also, why can't the existing
> cpufreq-cpu0 driver be extended to support this?

With IKS code in, it will be a complete big LITTLE driver.

>> +/* Currently we support only two clusters */
>> +#define MAX_CLUSTERS 2
>
> Why? Because that is what the define is or there are other limitations?
> Seems like this could and should be dynamically discovered with DT.

To keep it simple, as for now as all early systems (atleast which are announced)
have dual cluster systems only.

We will update it once we have some real systems breaking this law.

--
viresh

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

* Re: [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
  2013-03-26  9:51 ` Viresh Kumar
@ 2013-03-26 13:17   ` Rob Herring
  -1 siblings, 0 replies; 29+ messages in thread
From: Rob Herring @ 2013-03-26 13:17 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: Rafael J. Wysocki, nicolas.pitre, robin.randhawa, linux,
	mark.hambleton, linux-pm, Sudeep KarkadaNagesha,
	devicetree-discuss, Liviu.Dudau, linux-kernel, cpufreq,
	linaro-kernel, Steve.Bannister, arvind.chauhan, linux-arm-kernel,
	charles.garcia-tobin, Mark Langsdorf, Shawn Guo

On 03/26/2013 04:51 AM, Viresh Kumar wrote:
> big LITTLE is ARM's new Architecture focussing power/performance needs of modern
> world. More information about big LITTLE can be found here:
> 
> http://www.arm.com/products/processors/technologies/biglittleprocessing.php
> http://lwn.net/Articles/481055/
> 
> In order to keep cpufreq support for all big LITTLE platforms simple/generic,
> this patch tries to add a generic cpufreq driver layer for all big LITTLE
> platforms.
> 
> The driver is divided into two parts:
> - Core driver: Generic and shared across all big LITTLE SoC's
> - Glue drivers: Per platform drivers providing ops to the core driver
> 
> This patch adds in a generic glue driver which would extract information from
> Device Tree.
> 
> Future SoC's can either reuse the DT glue or write their own depending on the
> need.
> 
> Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> ---
> V1->V2:
> - It was reviewed here earlier: https://lkml.org/lkml/2013/3/4/614
> - It supports OPP library now and doesn't create a new binding for cpufreq table
> - It doesn't add any dependency on cluster node in DT, rather we work with
>   existing cpu nodes, Documentation updated.
> - cpu_dev used because of OPP library and hence dev_err/dbg/info used at
>   multiple places.
> - Interface with glue driver updated a bit
> - IS_ERR_OR_NULL replaced with IS_ERR for clk_get
> - clk_get_sys used instead of clk_get and name of clk is also updated
> - Few more minor cleanups done.
> 
> It is pushed here:
> 
> http://git.linaro.org/gitweb?p=people/vireshk/linux.git;a=shortlog;h=refs/heads/cpufreq-biglittle
> 
>  .../bindings/cpufreq/arm_big_little_dt.txt         |  65 +++++
>  MAINTAINERS                                        |  11 +
>  drivers/cpufreq/Kconfig.arm                        |  12 +
>  drivers/cpufreq/Makefile                           |   4 +
>  drivers/cpufreq/arm_big_little.c                   | 282 +++++++++++++++++++++
>  drivers/cpufreq/arm_big_little.h                   |  40 +++
>  drivers/cpufreq/arm_big_little_dt.c                |  92 +++++++
>  7 files changed, 506 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
>  create mode 100644 drivers/cpufreq/arm_big_little.c
>  create mode 100644 drivers/cpufreq/arm_big_little.h
>  create mode 100644 drivers/cpufreq/arm_big_little_dt.c
> 
> diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
> new file mode 100644
> index 0000000..34a460d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
> @@ -0,0 +1,65 @@
> +Generic ARM big LITTLE cpufreq driver's DT glue
> +-----------------------------------------------
> +
> +This is DT specific glue layer for generic cpufreq driver for big LITTLE
> +systems.

I fail to see anything bL specific here. This is just multi-cluster, but
even for that I don't see anything new other than simply allowing per
cpu or per cluster opp's. The fact that we have one opp for a cluster is
simply an implementation decision in CortexA cores.

> +
> +Both required and optional properties listed below must be defined
> +under node /cpus/cpu@x. Where x is the first cpu inside a cluster.
> +
> +NOTE: Cpus should boot in the order specified in DT and all cpus for a cluster
> +must be present contiguously. Generic DT driver will check only node 'x' for
> +cpu:x.

The OS cannot necessarily control the order. The OS should be able to
boot on which ever core comes up first.

> +
> +Required properties:
> +- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
> +  for details
> +
> +Optional properties:
> +- clock-latency: Specify the possible maximum transition latency for clock,
> +  in unit of nanoseconds.

Don't we already have "transition-latency" defined? Don't create
something new. Ideally, this should have had "-ns" appended, but the
binding is already defined.

> +
> +Examples:
> +
> +cpus {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	cpu@0 {
> +		compatible = "arm,cortex-a15";
> +		reg = <0>;
> +		next-level-cache = <&L2>;
> +		operating-points = <
> +			/* kHz    uV */
> +			792000  1100000
> +			396000  950000
> +			198000  850000
> +		>;
> +		clock-latency = <61036>; /* two CLK32 periods */
> +	};
> +
> +	cpu@1 {
> +		compatible = "arm,cortex-a15";
> +		reg = <1>;
> +		next-level-cache = <&L2>;
> +	};
> +
> +	cpu@100 {
> +		compatible = "arm,cortex-a7";
> +		reg = <100>;
> +		next-level-cache = <&L2>;
> +		operating-points = <
> +			/* kHz    uV */
> +			792000  950000
> +			396000  750000
> +			198000  450000
> +		>;
> +		clock-latency = <61036>; /* two CLK32 periods */
> +	};
> +
> +	cpu@101 {
> +		compatible = "arm,cortex-a7";
> +		reg = <101>;
> +		next-level-cache = <&L2>;
> +	};
> +};
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 4cf5fd3..4071b71 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2206,6 +2206,17 @@ S:	Maintained
>  F:	drivers/cpufreq/
>  F:	include/linux/cpufreq.h
>  
> +CPU FREQUENCY DRIVERS - ARM BIG LITTLE
> +M:	Viresh Kumar <viresh.kumar@linaro.org>
> +M:	Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> +L:	cpufreq@vger.kernel.org
> +L:	linux-pm@vger.kernel.org
> +W:	http://www.arm.com/products/processors/technologies/biglittleprocessing.php
> +S:	Maintained
> +F:	drivers/cpufreq/arm_big_little.h
> +F:	drivers/cpufreq/arm_big_little.c
> +F:	drivers/cpufreq/arm_big_little_dt.c
> +
>  CPUID/MSR DRIVER
>  M:	"H. Peter Anvin" <hpa@zytor.com>
>  S:	Maintained
> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 030ddf6..87b7e48 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -2,6 +2,18 @@
>  # ARM CPU Frequency scaling drivers
>  #
>  
> +config ARM_BIG_LITTLE_CPUFREQ
> +	tristate
> +	depends on ARM_CPU_TOPOLOGY
> +
> +config ARM_DT_BL_CPUFREQ
> +	tristate "Generic ARM big LITTLE CPUfreq driver probed via DT"
> +	select ARM_BIG_LITTLE_CPUFREQ
> +	depends on OF && HAVE_CLK
> +	help
> +	  This enables the Generic CPUfreq driver for ARM big.LITTLE platform.
> +	  This gets frequency tables from DT.
> +
>  config ARM_OMAP2PLUS_CPUFREQ
>  	bool "TI OMAP2+"
>  	depends on ARCH_OMAP2PLUS
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index 863fd18..d1b0832 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -44,6 +44,10 @@ obj-$(CONFIG_X86_INTEL_PSTATE)		+= intel_pstate.o
>  
>  ##################################################################################
>  # ARM SoC drivers
> +obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ)	+= arm_big_little.o
> +# big LITTLE per platform glues. Keep DT_BL_CPUFREQ as the last entry in all big
> +# LITTLE drivers, so that it is probed last.
> +obj-$(CONFIG_ARM_DT_BL_CPUFREQ)	+= arm_big_little_dt.o
>  obj-$(CONFIG_UX500_SOC_DB8500)		+= dbx500-cpufreq.o
>  obj-$(CONFIG_ARM_S3C2416_CPUFREQ)	+= s3c2416-cpufreq.o
>  obj-$(CONFIG_ARM_S3C64XX_CPUFREQ)	+= s3c64xx-cpufreq.o
> diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
> new file mode 100644
> index 0000000..1d29d1a
> --- /dev/null
> +++ b/drivers/cpufreq/arm_big_little.c
> @@ -0,0 +1,282 @@
> +/*
> + * ARM big.LITTLE Platforms CPUFreq support

What is specific to bL? This looks like just a multi-cluster cpufreq
driver and should be generalized to that. Also, why can't the existing
cpufreq-cpu0 driver be extended to support this?

> + * Copyright (C) 2013 ARM Ltd.
> + * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> + *
> + * Copyright (C) 2013 Linaro.
> + * Viresh Kumar <viresh.kumar@linaro.org>
> + *
> + * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/clk.h>
> +#include <linux/cpu.h>
> +#include <linux/cpufreq.h>
> +#include <linux/cpumask.h>
> +#include <linux/export.h>
> +#include <linux/of_platform.h>
> +#include <linux/opp.h>
> +#include <linux/slab.h>
> +#include <linux/topology.h>
> +#include <linux/types.h>
> +
> +#include "arm_big_little.h"
> +
> +/* Currently we support only two clusters */
> +#define MAX_CLUSTERS	2

Why? Because that is what the define is or there are other limitations?
Seems like this could and should be dynamically discovered with DT.

Rob


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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-26 13:17   ` Rob Herring
  0 siblings, 0 replies; 29+ messages in thread
From: Rob Herring @ 2013-03-26 13:17 UTC (permalink / raw)
  To: linux-arm-kernel

On 03/26/2013 04:51 AM, Viresh Kumar wrote:
> big LITTLE is ARM's new Architecture focussing power/performance needs of modern
> world. More information about big LITTLE can be found here:
> 
> http://www.arm.com/products/processors/technologies/biglittleprocessing.php
> http://lwn.net/Articles/481055/
> 
> In order to keep cpufreq support for all big LITTLE platforms simple/generic,
> this patch tries to add a generic cpufreq driver layer for all big LITTLE
> platforms.
> 
> The driver is divided into two parts:
> - Core driver: Generic and shared across all big LITTLE SoC's
> - Glue drivers: Per platform drivers providing ops to the core driver
> 
> This patch adds in a generic glue driver which would extract information from
> Device Tree.
> 
> Future SoC's can either reuse the DT glue or write their own depending on the
> need.
> 
> Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
> ---
> V1->V2:
> - It was reviewed here earlier: https://lkml.org/lkml/2013/3/4/614
> - It supports OPP library now and doesn't create a new binding for cpufreq table
> - It doesn't add any dependency on cluster node in DT, rather we work with
>   existing cpu nodes, Documentation updated.
> - cpu_dev used because of OPP library and hence dev_err/dbg/info used at
>   multiple places.
> - Interface with glue driver updated a bit
> - IS_ERR_OR_NULL replaced with IS_ERR for clk_get
> - clk_get_sys used instead of clk_get and name of clk is also updated
> - Few more minor cleanups done.
> 
> It is pushed here:
> 
> http://git.linaro.org/gitweb?p=people/vireshk/linux.git;a=shortlog;h=refs/heads/cpufreq-biglittle
> 
>  .../bindings/cpufreq/arm_big_little_dt.txt         |  65 +++++
>  MAINTAINERS                                        |  11 +
>  drivers/cpufreq/Kconfig.arm                        |  12 +
>  drivers/cpufreq/Makefile                           |   4 +
>  drivers/cpufreq/arm_big_little.c                   | 282 +++++++++++++++++++++
>  drivers/cpufreq/arm_big_little.h                   |  40 +++
>  drivers/cpufreq/arm_big_little_dt.c                |  92 +++++++
>  7 files changed, 506 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
>  create mode 100644 drivers/cpufreq/arm_big_little.c
>  create mode 100644 drivers/cpufreq/arm_big_little.h
>  create mode 100644 drivers/cpufreq/arm_big_little_dt.c
> 
> diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
> new file mode 100644
> index 0000000..34a460d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
> @@ -0,0 +1,65 @@
> +Generic ARM big LITTLE cpufreq driver's DT glue
> +-----------------------------------------------
> +
> +This is DT specific glue layer for generic cpufreq driver for big LITTLE
> +systems.

I fail to see anything bL specific here. This is just multi-cluster, but
even for that I don't see anything new other than simply allowing per
cpu or per cluster opp's. The fact that we have one opp for a cluster is
simply an implementation decision in CortexA cores.

> +
> +Both required and optional properties listed below must be defined
> +under node /cpus/cpu at x. Where x is the first cpu inside a cluster.
> +
> +NOTE: Cpus should boot in the order specified in DT and all cpus for a cluster
> +must be present contiguously. Generic DT driver will check only node 'x' for
> +cpu:x.

The OS cannot necessarily control the order. The OS should be able to
boot on which ever core comes up first.

> +
> +Required properties:
> +- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
> +  for details
> +
> +Optional properties:
> +- clock-latency: Specify the possible maximum transition latency for clock,
> +  in unit of nanoseconds.

Don't we already have "transition-latency" defined? Don't create
something new. Ideally, this should have had "-ns" appended, but the
binding is already defined.

> +
> +Examples:
> +
> +cpus {
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	cpu at 0 {
> +		compatible = "arm,cortex-a15";
> +		reg = <0>;
> +		next-level-cache = <&L2>;
> +		operating-points = <
> +			/* kHz    uV */
> +			792000  1100000
> +			396000  950000
> +			198000  850000
> +		>;
> +		clock-latency = <61036>; /* two CLK32 periods */
> +	};
> +
> +	cpu at 1 {
> +		compatible = "arm,cortex-a15";
> +		reg = <1>;
> +		next-level-cache = <&L2>;
> +	};
> +
> +	cpu at 100 {
> +		compatible = "arm,cortex-a7";
> +		reg = <100>;
> +		next-level-cache = <&L2>;
> +		operating-points = <
> +			/* kHz    uV */
> +			792000  950000
> +			396000  750000
> +			198000  450000
> +		>;
> +		clock-latency = <61036>; /* two CLK32 periods */
> +	};
> +
> +	cpu at 101 {
> +		compatible = "arm,cortex-a7";
> +		reg = <101>;
> +		next-level-cache = <&L2>;
> +	};
> +};
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 4cf5fd3..4071b71 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2206,6 +2206,17 @@ S:	Maintained
>  F:	drivers/cpufreq/
>  F:	include/linux/cpufreq.h
>  
> +CPU FREQUENCY DRIVERS - ARM BIG LITTLE
> +M:	Viresh Kumar <viresh.kumar@linaro.org>
> +M:	Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> +L:	cpufreq at vger.kernel.org
> +L:	linux-pm at vger.kernel.org
> +W:	http://www.arm.com/products/processors/technologies/biglittleprocessing.php
> +S:	Maintained
> +F:	drivers/cpufreq/arm_big_little.h
> +F:	drivers/cpufreq/arm_big_little.c
> +F:	drivers/cpufreq/arm_big_little_dt.c
> +
>  CPUID/MSR DRIVER
>  M:	"H. Peter Anvin" <hpa@zytor.com>
>  S:	Maintained
> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 030ddf6..87b7e48 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -2,6 +2,18 @@
>  # ARM CPU Frequency scaling drivers
>  #
>  
> +config ARM_BIG_LITTLE_CPUFREQ
> +	tristate
> +	depends on ARM_CPU_TOPOLOGY
> +
> +config ARM_DT_BL_CPUFREQ
> +	tristate "Generic ARM big LITTLE CPUfreq driver probed via DT"
> +	select ARM_BIG_LITTLE_CPUFREQ
> +	depends on OF && HAVE_CLK
> +	help
> +	  This enables the Generic CPUfreq driver for ARM big.LITTLE platform.
> +	  This gets frequency tables from DT.
> +
>  config ARM_OMAP2PLUS_CPUFREQ
>  	bool "TI OMAP2+"
>  	depends on ARCH_OMAP2PLUS
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index 863fd18..d1b0832 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -44,6 +44,10 @@ obj-$(CONFIG_X86_INTEL_PSTATE)		+= intel_pstate.o
>  
>  ##################################################################################
>  # ARM SoC drivers
> +obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ)	+= arm_big_little.o
> +# big LITTLE per platform glues. Keep DT_BL_CPUFREQ as the last entry in all big
> +# LITTLE drivers, so that it is probed last.
> +obj-$(CONFIG_ARM_DT_BL_CPUFREQ)	+= arm_big_little_dt.o
>  obj-$(CONFIG_UX500_SOC_DB8500)		+= dbx500-cpufreq.o
>  obj-$(CONFIG_ARM_S3C2416_CPUFREQ)	+= s3c2416-cpufreq.o
>  obj-$(CONFIG_ARM_S3C64XX_CPUFREQ)	+= s3c64xx-cpufreq.o
> diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
> new file mode 100644
> index 0000000..1d29d1a
> --- /dev/null
> +++ b/drivers/cpufreq/arm_big_little.c
> @@ -0,0 +1,282 @@
> +/*
> + * ARM big.LITTLE Platforms CPUFreq support

What is specific to bL? This looks like just a multi-cluster cpufreq
driver and should be generalized to that. Also, why can't the existing
cpufreq-cpu0 driver be extended to support this?

> + * Copyright (C) 2013 ARM Ltd.
> + * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> + *
> + * Copyright (C) 2013 Linaro.
> + * Viresh Kumar <viresh.kumar@linaro.org>
> + *
> + * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/clk.h>
> +#include <linux/cpu.h>
> +#include <linux/cpufreq.h>
> +#include <linux/cpumask.h>
> +#include <linux/export.h>
> +#include <linux/of_platform.h>
> +#include <linux/opp.h>
> +#include <linux/slab.h>
> +#include <linux/topology.h>
> +#include <linux/types.h>
> +
> +#include "arm_big_little.h"
> +
> +/* Currently we support only two clusters */
> +#define MAX_CLUSTERS	2

Why? Because that is what the define is or there are other limitations?
Seems like this could and should be dynamically discovered with DT.

Rob

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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-26  9:51 ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-26  9:51 UTC (permalink / raw)
  To: rjw, nicolas.pitre
  Cc: cpufreq, linux-pm, linux-kernel, linaro-kernel, arvind.chauhan,
	robin.randhawa, Steve.Bannister, Liviu.Dudau,
	charles.garcia-tobin, mark.hambleton, linux-arm-kernel, linux,
	devicetree-discuss, Viresh Kumar, Sudeep KarkadaNagesha

big LITTLE is ARM's new Architecture focussing power/performance needs of modern
world. More information about big LITTLE can be found here:

http://www.arm.com/products/processors/technologies/biglittleprocessing.php
http://lwn.net/Articles/481055/

In order to keep cpufreq support for all big LITTLE platforms simple/generic,
this patch tries to add a generic cpufreq driver layer for all big LITTLE
platforms.

The driver is divided into two parts:
- Core driver: Generic and shared across all big LITTLE SoC's
- Glue drivers: Per platform drivers providing ops to the core driver

This patch adds in a generic glue driver which would extract information from
Device Tree.

Future SoC's can either reuse the DT glue or write their own depending on the
need.

Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
V1->V2:
- It was reviewed here earlier: https://lkml.org/lkml/2013/3/4/614
- It supports OPP library now and doesn't create a new binding for cpufreq table
- It doesn't add any dependency on cluster node in DT, rather we work with
  existing cpu nodes, Documentation updated.
- cpu_dev used because of OPP library and hence dev_err/dbg/info used at
  multiple places.
- Interface with glue driver updated a bit
- IS_ERR_OR_NULL replaced with IS_ERR for clk_get
- clk_get_sys used instead of clk_get and name of clk is also updated
- Few more minor cleanups done.

It is pushed here:

http://git.linaro.org/gitweb?p=people/vireshk/linux.git;a=shortlog;h=refs/heads/cpufreq-biglittle

 .../bindings/cpufreq/arm_big_little_dt.txt         |  65 +++++
 MAINTAINERS                                        |  11 +
 drivers/cpufreq/Kconfig.arm                        |  12 +
 drivers/cpufreq/Makefile                           |   4 +
 drivers/cpufreq/arm_big_little.c                   | 282 +++++++++++++++++++++
 drivers/cpufreq/arm_big_little.h                   |  40 +++
 drivers/cpufreq/arm_big_little_dt.c                |  92 +++++++
 7 files changed, 506 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
 create mode 100644 drivers/cpufreq/arm_big_little.c
 create mode 100644 drivers/cpufreq/arm_big_little.h
 create mode 100644 drivers/cpufreq/arm_big_little_dt.c

diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
new file mode 100644
index 0000000..34a460d
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
@@ -0,0 +1,65 @@
+Generic ARM big LITTLE cpufreq driver's DT glue
+-----------------------------------------------
+
+This is DT specific glue layer for generic cpufreq driver for big LITTLE
+systems.
+
+Both required and optional properties listed below must be defined
+under node /cpus/cpu@x. Where x is the first cpu inside a cluster.
+
+NOTE: Cpus should boot in the order specified in DT and all cpus for a cluster
+must be present contiguously. Generic DT driver will check only node 'x' for
+cpu:x.
+
+Required properties:
+- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+  for details
+
+Optional properties:
+- 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-a15";
+		reg = <0>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz    uV */
+			792000  1100000
+			396000  950000
+			198000  850000
+		>;
+		clock-latency = <61036>; /* two CLK32 periods */
+	};
+
+	cpu@1 {
+		compatible = "arm,cortex-a15";
+		reg = <1>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu@100 {
+		compatible = "arm,cortex-a7";
+		reg = <100>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz    uV */
+			792000  950000
+			396000  750000
+			198000  450000
+		>;
+		clock-latency = <61036>; /* two CLK32 periods */
+	};
+
+	cpu@101 {
+		compatible = "arm,cortex-a7";
+		reg = <101>;
+		next-level-cache = <&L2>;
+	};
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index 4cf5fd3..4071b71 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2206,6 +2206,17 @@ S:	Maintained
 F:	drivers/cpufreq/
 F:	include/linux/cpufreq.h
 
+CPU FREQUENCY DRIVERS - ARM BIG LITTLE
+M:	Viresh Kumar <viresh.kumar@linaro.org>
+M:	Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+L:	cpufreq@vger.kernel.org
+L:	linux-pm@vger.kernel.org
+W:	http://www.arm.com/products/processors/technologies/biglittleprocessing.php
+S:	Maintained
+F:	drivers/cpufreq/arm_big_little.h
+F:	drivers/cpufreq/arm_big_little.c
+F:	drivers/cpufreq/arm_big_little_dt.c
+
 CPUID/MSR DRIVER
 M:	"H. Peter Anvin" <hpa@zytor.com>
 S:	Maintained
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 030ddf6..87b7e48 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -2,6 +2,18 @@
 # ARM CPU Frequency scaling drivers
 #
 
+config ARM_BIG_LITTLE_CPUFREQ
+	tristate
+	depends on ARM_CPU_TOPOLOGY
+
+config ARM_DT_BL_CPUFREQ
+	tristate "Generic ARM big LITTLE CPUfreq driver probed via DT"
+	select ARM_BIG_LITTLE_CPUFREQ
+	depends on OF && HAVE_CLK
+	help
+	  This enables the Generic CPUfreq driver for ARM big.LITTLE platform.
+	  This gets frequency tables from DT.
+
 config ARM_OMAP2PLUS_CPUFREQ
 	bool "TI OMAP2+"
 	depends on ARCH_OMAP2PLUS
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 863fd18..d1b0832 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -44,6 +44,10 @@ obj-$(CONFIG_X86_INTEL_PSTATE)		+= intel_pstate.o
 
 ##################################################################################
 # ARM SoC drivers
+obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ)	+= arm_big_little.o
+# big LITTLE per platform glues. Keep DT_BL_CPUFREQ as the last entry in all big
+# LITTLE drivers, so that it is probed last.
+obj-$(CONFIG_ARM_DT_BL_CPUFREQ)	+= arm_big_little_dt.o
 obj-$(CONFIG_UX500_SOC_DB8500)		+= dbx500-cpufreq.o
 obj-$(CONFIG_ARM_S3C2416_CPUFREQ)	+= s3c2416-cpufreq.o
 obj-$(CONFIG_ARM_S3C64XX_CPUFREQ)	+= s3c64xx-cpufreq.o
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
new file mode 100644
index 0000000..1d29d1a
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little.c
@@ -0,0 +1,282 @@
+/*
+ * ARM big.LITTLE Platforms CPUFreq support
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
+#include <linux/export.h>
+#include <linux/of_platform.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <linux/topology.h>
+#include <linux/types.h>
+
+#include "arm_big_little.h"
+
+/* Currently we support only two clusters */
+#define MAX_CLUSTERS	2
+
+static struct cpufreq_arm_bL_ops *arm_bL_ops;
+static struct clk *clk[MAX_CLUSTERS];
+static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
+static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)};
+
+static int cpu_to_cluster(int cpu)
+{
+	return topology_physical_package_id(cpu);
+}
+
+static unsigned int bL_cpufreq_get(unsigned int cpu)
+{
+	u32 cur_cluster = cpu_to_cluster(cpu);
+
+	return clk_get_rate(clk[cur_cluster]) / 1000;
+}
+
+/* Validate policy frequency range */
+static int bL_cpufreq_verify_policy(struct cpufreq_policy *policy)
+{
+	u32 cur_cluster = cpu_to_cluster(policy->cpu);
+
+	return cpufreq_frequency_table_verify(policy, freq_table[cur_cluster]);
+}
+
+/* Set clock frequency */
+static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
+		unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	u32 cpu = policy->cpu, freq_tab_idx, cur_cluster;
+	int ret = 0;
+
+	cur_cluster = cpu_to_cluster(policy->cpu);
+
+	freqs.old = bL_cpufreq_get(policy->cpu);
+
+	/* Determine valid target frequency using freq_table */
+	cpufreq_frequency_table_target(policy, freq_table[cur_cluster],
+			target_freq, relation, &freq_tab_idx);
+	freqs.new = freq_table[cur_cluster][freq_tab_idx].frequency;
+
+	freqs.cpu = policy->cpu;
+
+	pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n",
+			__func__, cpu, cur_cluster, freqs.old, target_freq,
+			freqs.new);
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_cpu(freqs.cpu, policy->cpus)
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000);
+	if (ret) {
+		pr_err("clk_set_rate failed: %d\n", ret);
+		return ret;
+	}
+
+	policy->cur = freqs.new;
+
+	for_each_cpu(freqs.cpu, policy->cpus)
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return ret;
+}
+
+static void put_cluster_clk_and_freq_table(struct device *cpu_dev)
+{
+	u32 cluster = cpu_to_cluster(cpu_dev->id);
+
+	if (!atomic_dec_return(&cluster_usage[cluster])) {
+		clk_put(clk[cluster]);
+		opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
+		dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster);
+	}
+}
+
+static int get_cluster_clk_and_freq_table(struct device *cpu_dev)
+{
+	u32 cluster = cpu_to_cluster(cpu_dev->id);
+	char name[14] = "cpu-cluster.";
+	int ret;
+
+	if (atomic_inc_return(&cluster_usage[cluster]) != 1)
+		return 0;
+
+	ret = arm_bL_ops->init_opp_table(cpu_dev);
+	if (ret) {
+		dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n",
+				__func__, cpu_dev->id, ret);
+		goto atomic_dec;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]);
+	if (ret) {
+		dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n",
+				__func__, cpu_dev->id, ret);
+		goto atomic_dec;
+	}
+
+	name[12] = cluster + '0';
+	clk[cluster] = clk_get_sys(name, NULL);
+	if (!IS_ERR(clk[cluster])) {
+		dev_dbg(cpu_dev, "%s: clk: %p & freq table: %p, cluster: %d\n",
+				__func__, clk[cluster], freq_table[cluster],
+				cluster);
+		return 0;
+	}
+
+	dev_err(cpu_dev, "%s: Failed to get clk for cpu: %d, cluster: %d\n",
+			__func__, cpu_dev->id, cluster);
+	ret = PTR_ERR(clk[cluster]);
+	opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
+
+atomic_dec:
+	atomic_dec(&cluster_usage[cluster]);
+	dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__,
+			cluster);
+	return ret;
+}
+
+/* Per-CPU initialization */
+static int bL_cpufreq_init(struct cpufreq_policy *policy)
+{
+	u32 cur_cluster = cpu_to_cluster(policy->cpu);
+	struct device *cpu_dev;
+	int ret;
+
+	cpu_dev = get_cpu_device(policy->cpu);
+	if (!cpu_dev) {
+		pr_err("%s: failed to get cpu%d device\n", __func__,
+				policy->cpu);
+		return -ENODEV;
+	}
+
+	ret = get_cluster_clk_and_freq_table(cpu_dev);
+	if (ret)
+		return ret;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table[cur_cluster]);
+	if (ret) {
+		dev_err(cpu_dev, "CPU %d, cluster: %d invalid freq table\n",
+				policy->cpu, cur_cluster);
+		put_cluster_clk_and_freq_table(cpu_dev);
+		return ret;
+	}
+
+	cpufreq_frequency_table_get_attr(freq_table[cur_cluster], policy->cpu);
+
+	if (arm_bL_ops->get_transition_latency)
+		policy->cpuinfo.transition_latency =
+			arm_bL_ops->get_transition_latency(cpu_dev);
+	else
+		policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+
+	policy->cur = bL_cpufreq_get(policy->cpu);
+
+	cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
+
+	dev_info(cpu_dev, "CPU %d initialized\n", policy->cpu);
+	return 0;
+}
+
+static int bL_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	struct device *cpu_dev;
+
+	cpu_dev = get_cpu_device(policy->cpu);
+	if (!cpu_dev) {
+		pr_err("%s: failed to get cpu%d device\n", __func__,
+				policy->cpu);
+		return -ENODEV;
+	}
+
+	put_cluster_clk_and_freq_table(cpu_dev);
+	dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu);
+
+	return 0;
+}
+
+/* Export freq_table to sysfs */
+static struct freq_attr *bL_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver bL_cpufreq_driver = {
+	.name			= "arm-big-little",
+	.flags			= CPUFREQ_STICKY,
+	.verify			= bL_cpufreq_verify_policy,
+	.target			= bL_cpufreq_set_target,
+	.get			= bL_cpufreq_get,
+	.init			= bL_cpufreq_init,
+	.exit			= bL_cpufreq_exit,
+	.have_multiple_policies	= true,
+	.attr			= bL_cpufreq_attr,
+};
+
+int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
+{
+	int ret;
+
+	if (arm_bL_ops) {
+		pr_debug("%s: Already registered: %s, exiting\n", __func__,
+				arm_bL_ops->name);
+		return -EBUSY;
+	}
+
+	if (!ops || !strlen(ops->name) || !ops->init_opp_table) {
+		pr_err("%s: Invalid arm_bL_ops, exiting\n", __func__);
+		return -ENODEV;
+	}
+
+	arm_bL_ops = ops;
+
+	ret = cpufreq_register_driver(&bL_cpufreq_driver);
+	if (ret) {
+		pr_info("%s: Failed registering platform driver: %s, err: %d\n",
+				__func__, ops->name, ret);
+		arm_bL_ops = NULL;
+	} else {
+		pr_info("%s: Registered platform driver: %s\n", __func__,
+				ops->name);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(bL_cpufreq_register);
+
+void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
+{
+	if (arm_bL_ops != ops) {
+		pr_err("%s: Registered with: %s, can't unregister, exiting\n",
+				__func__, arm_bL_ops->name);
+		return;
+	}
+
+	cpufreq_unregister_driver(&bL_cpufreq_driver);
+	pr_info("%s: Un-registered platform driver: %s\n", __func__,
+			arm_bL_ops->name);
+	arm_bL_ops = NULL;
+}
+EXPORT_SYMBOL_GPL(bL_cpufreq_unregister);
diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h
new file mode 100644
index 0000000..70f18fc
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little.h
@@ -0,0 +1,40 @@
+/*
+ * ARM big.LITTLE platform's CPUFreq header file
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef CPUFREQ_ARM_BIG_LITTLE_H
+#define CPUFREQ_ARM_BIG_LITTLE_H
+
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/types.h>
+
+struct cpufreq_arm_bL_ops {
+	char name[CPUFREQ_NAME_LEN];
+	int (*get_transition_latency)(struct device *cpu_dev);
+
+	/*
+	 * This must set opp table for cpu_dev in a similar way as done by
+	 * of_init_opp_table().
+	 */
+	int (*init_opp_table)(struct device *cpu_dev);
+};
+
+int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
+void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops);
+
+#endif /* CPUFREQ_ARM_BIG_LITTLE_H */
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
new file mode 100644
index 0000000..452ff46
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -0,0 +1,92 @@
+/*
+ * Generic big.LITTLE CPUFreq Interface driver
+ *
+ * It provides necessary ops to arm_big_little cpufreq driver and gets
+ * Frequency information from Device Tree. Freq table in DT must be in KHz.
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "arm_big_little.h"
+
+static int dt_init_opp_table(struct device *cpu_dev)
+{
+	struct device_node *np = NULL;
+	int count = 0, ret;
+
+	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+		if (count++ != cpu_dev->id)
+			continue;
+		if (!of_get_property(np, "operating-points", NULL))
+			return -ENODATA;
+
+		cpu_dev->of_node = np;
+
+		ret = of_init_opp_table(cpu_dev);
+		if (ret)
+			return ret;
+
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static int dt_get_transition_latency(struct device *cpu_dev)
+{
+	struct device_node *np = NULL;
+	u32 transition_latency = CPUFREQ_ETERNAL;
+	int count = 0;
+
+	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+		if (count++ != cpu_dev->id)
+			continue;
+
+		of_property_read_u32(np, "clock-latency", &transition_latency);
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static struct cpufreq_arm_bL_ops dt_bL_ops = {
+	.name	= "dt-bl",
+	.get_transition_latency = dt_get_transition_latency,
+	.init_opp_table = dt_init_opp_table,
+};
+
+static int generic_bL_init(void)
+{
+	return bL_cpufreq_register(&dt_bL_ops);
+}
+module_init(generic_bL_init);
+
+static void generic_bL_exit(void)
+{
+	return bL_cpufreq_unregister(&dt_bL_ops);
+}
+module_exit(generic_bL_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
+MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver via DT");
+MODULE_LICENSE("GPL");
-- 
1.7.12.rc2.18.g61b472e



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

* [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue
@ 2013-03-26  9:51 ` Viresh Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Viresh Kumar @ 2013-03-26  9:51 UTC (permalink / raw)
  To: linux-arm-kernel

big LITTLE is ARM's new Architecture focussing power/performance needs of modern
world. More information about big LITTLE can be found here:

http://www.arm.com/products/processors/technologies/biglittleprocessing.php
http://lwn.net/Articles/481055/

In order to keep cpufreq support for all big LITTLE platforms simple/generic,
this patch tries to add a generic cpufreq driver layer for all big LITTLE
platforms.

The driver is divided into two parts:
- Core driver: Generic and shared across all big LITTLE SoC's
- Glue drivers: Per platform drivers providing ops to the core driver

This patch adds in a generic glue driver which would extract information from
Device Tree.

Future SoC's can either reuse the DT glue or write their own depending on the
need.

Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
V1->V2:
- It was reviewed here earlier: https://lkml.org/lkml/2013/3/4/614
- It supports OPP library now and doesn't create a new binding for cpufreq table
- It doesn't add any dependency on cluster node in DT, rather we work with
  existing cpu nodes, Documentation updated.
- cpu_dev used because of OPP library and hence dev_err/dbg/info used at
  multiple places.
- Interface with glue driver updated a bit
- IS_ERR_OR_NULL replaced with IS_ERR for clk_get
- clk_get_sys used instead of clk_get and name of clk is also updated
- Few more minor cleanups done.

It is pushed here:

http://git.linaro.org/gitweb?p=people/vireshk/linux.git;a=shortlog;h=refs/heads/cpufreq-biglittle

 .../bindings/cpufreq/arm_big_little_dt.txt         |  65 +++++
 MAINTAINERS                                        |  11 +
 drivers/cpufreq/Kconfig.arm                        |  12 +
 drivers/cpufreq/Makefile                           |   4 +
 drivers/cpufreq/arm_big_little.c                   | 282 +++++++++++++++++++++
 drivers/cpufreq/arm_big_little.h                   |  40 +++
 drivers/cpufreq/arm_big_little_dt.c                |  92 +++++++
 7 files changed, 506 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
 create mode 100644 drivers/cpufreq/arm_big_little.c
 create mode 100644 drivers/cpufreq/arm_big_little.h
 create mode 100644 drivers/cpufreq/arm_big_little_dt.c

diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
new file mode 100644
index 0000000..34a460d
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
@@ -0,0 +1,65 @@
+Generic ARM big LITTLE cpufreq driver's DT glue
+-----------------------------------------------
+
+This is DT specific glue layer for generic cpufreq driver for big LITTLE
+systems.
+
+Both required and optional properties listed below must be defined
+under node /cpus/cpu at x. Where x is the first cpu inside a cluster.
+
+NOTE: Cpus should boot in the order specified in DT and all cpus for a cluster
+must be present contiguously. Generic DT driver will check only node 'x' for
+cpu:x.
+
+Required properties:
+- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+  for details
+
+Optional properties:
+- clock-latency: Specify the possible maximum transition latency for clock,
+  in unit of nanoseconds.
+
+Examples:
+
+cpus {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	cpu at 0 {
+		compatible = "arm,cortex-a15";
+		reg = <0>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz    uV */
+			792000  1100000
+			396000  950000
+			198000  850000
+		>;
+		clock-latency = <61036>; /* two CLK32 periods */
+	};
+
+	cpu at 1 {
+		compatible = "arm,cortex-a15";
+		reg = <1>;
+		next-level-cache = <&L2>;
+	};
+
+	cpu at 100 {
+		compatible = "arm,cortex-a7";
+		reg = <100>;
+		next-level-cache = <&L2>;
+		operating-points = <
+			/* kHz    uV */
+			792000  950000
+			396000  750000
+			198000  450000
+		>;
+		clock-latency = <61036>; /* two CLK32 periods */
+	};
+
+	cpu at 101 {
+		compatible = "arm,cortex-a7";
+		reg = <101>;
+		next-level-cache = <&L2>;
+	};
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index 4cf5fd3..4071b71 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2206,6 +2206,17 @@ S:	Maintained
 F:	drivers/cpufreq/
 F:	include/linux/cpufreq.h
 
+CPU FREQUENCY DRIVERS - ARM BIG LITTLE
+M:	Viresh Kumar <viresh.kumar@linaro.org>
+M:	Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+L:	cpufreq at vger.kernel.org
+L:	linux-pm at vger.kernel.org
+W:	http://www.arm.com/products/processors/technologies/biglittleprocessing.php
+S:	Maintained
+F:	drivers/cpufreq/arm_big_little.h
+F:	drivers/cpufreq/arm_big_little.c
+F:	drivers/cpufreq/arm_big_little_dt.c
+
 CPUID/MSR DRIVER
 M:	"H. Peter Anvin" <hpa@zytor.com>
 S:	Maintained
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 030ddf6..87b7e48 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -2,6 +2,18 @@
 # ARM CPU Frequency scaling drivers
 #
 
+config ARM_BIG_LITTLE_CPUFREQ
+	tristate
+	depends on ARM_CPU_TOPOLOGY
+
+config ARM_DT_BL_CPUFREQ
+	tristate "Generic ARM big LITTLE CPUfreq driver probed via DT"
+	select ARM_BIG_LITTLE_CPUFREQ
+	depends on OF && HAVE_CLK
+	help
+	  This enables the Generic CPUfreq driver for ARM big.LITTLE platform.
+	  This gets frequency tables from DT.
+
 config ARM_OMAP2PLUS_CPUFREQ
 	bool "TI OMAP2+"
 	depends on ARCH_OMAP2PLUS
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 863fd18..d1b0832 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -44,6 +44,10 @@ obj-$(CONFIG_X86_INTEL_PSTATE)		+= intel_pstate.o
 
 ##################################################################################
 # ARM SoC drivers
+obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ)	+= arm_big_little.o
+# big LITTLE per platform glues. Keep DT_BL_CPUFREQ as the last entry in all big
+# LITTLE drivers, so that it is probed last.
+obj-$(CONFIG_ARM_DT_BL_CPUFREQ)	+= arm_big_little_dt.o
 obj-$(CONFIG_UX500_SOC_DB8500)		+= dbx500-cpufreq.o
 obj-$(CONFIG_ARM_S3C2416_CPUFREQ)	+= s3c2416-cpufreq.o
 obj-$(CONFIG_ARM_S3C64XX_CPUFREQ)	+= s3c64xx-cpufreq.o
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
new file mode 100644
index 0000000..1d29d1a
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little.c
@@ -0,0 +1,282 @@
+/*
+ * ARM big.LITTLE Platforms CPUFreq support
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
+#include <linux/export.h>
+#include <linux/of_platform.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <linux/topology.h>
+#include <linux/types.h>
+
+#include "arm_big_little.h"
+
+/* Currently we support only two clusters */
+#define MAX_CLUSTERS	2
+
+static struct cpufreq_arm_bL_ops *arm_bL_ops;
+static struct clk *clk[MAX_CLUSTERS];
+static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
+static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)};
+
+static int cpu_to_cluster(int cpu)
+{
+	return topology_physical_package_id(cpu);
+}
+
+static unsigned int bL_cpufreq_get(unsigned int cpu)
+{
+	u32 cur_cluster = cpu_to_cluster(cpu);
+
+	return clk_get_rate(clk[cur_cluster]) / 1000;
+}
+
+/* Validate policy frequency range */
+static int bL_cpufreq_verify_policy(struct cpufreq_policy *policy)
+{
+	u32 cur_cluster = cpu_to_cluster(policy->cpu);
+
+	return cpufreq_frequency_table_verify(policy, freq_table[cur_cluster]);
+}
+
+/* Set clock frequency */
+static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
+		unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	u32 cpu = policy->cpu, freq_tab_idx, cur_cluster;
+	int ret = 0;
+
+	cur_cluster = cpu_to_cluster(policy->cpu);
+
+	freqs.old = bL_cpufreq_get(policy->cpu);
+
+	/* Determine valid target frequency using freq_table */
+	cpufreq_frequency_table_target(policy, freq_table[cur_cluster],
+			target_freq, relation, &freq_tab_idx);
+	freqs.new = freq_table[cur_cluster][freq_tab_idx].frequency;
+
+	freqs.cpu = policy->cpu;
+
+	pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n",
+			__func__, cpu, cur_cluster, freqs.old, target_freq,
+			freqs.new);
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_cpu(freqs.cpu, policy->cpus)
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000);
+	if (ret) {
+		pr_err("clk_set_rate failed: %d\n", ret);
+		return ret;
+	}
+
+	policy->cur = freqs.new;
+
+	for_each_cpu(freqs.cpu, policy->cpus)
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return ret;
+}
+
+static void put_cluster_clk_and_freq_table(struct device *cpu_dev)
+{
+	u32 cluster = cpu_to_cluster(cpu_dev->id);
+
+	if (!atomic_dec_return(&cluster_usage[cluster])) {
+		clk_put(clk[cluster]);
+		opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
+		dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster);
+	}
+}
+
+static int get_cluster_clk_and_freq_table(struct device *cpu_dev)
+{
+	u32 cluster = cpu_to_cluster(cpu_dev->id);
+	char name[14] = "cpu-cluster.";
+	int ret;
+
+	if (atomic_inc_return(&cluster_usage[cluster]) != 1)
+		return 0;
+
+	ret = arm_bL_ops->init_opp_table(cpu_dev);
+	if (ret) {
+		dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n",
+				__func__, cpu_dev->id, ret);
+		goto atomic_dec;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]);
+	if (ret) {
+		dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n",
+				__func__, cpu_dev->id, ret);
+		goto atomic_dec;
+	}
+
+	name[12] = cluster + '0';
+	clk[cluster] = clk_get_sys(name, NULL);
+	if (!IS_ERR(clk[cluster])) {
+		dev_dbg(cpu_dev, "%s: clk: %p & freq table: %p, cluster: %d\n",
+				__func__, clk[cluster], freq_table[cluster],
+				cluster);
+		return 0;
+	}
+
+	dev_err(cpu_dev, "%s: Failed to get clk for cpu: %d, cluster: %d\n",
+			__func__, cpu_dev->id, cluster);
+	ret = PTR_ERR(clk[cluster]);
+	opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
+
+atomic_dec:
+	atomic_dec(&cluster_usage[cluster]);
+	dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__,
+			cluster);
+	return ret;
+}
+
+/* Per-CPU initialization */
+static int bL_cpufreq_init(struct cpufreq_policy *policy)
+{
+	u32 cur_cluster = cpu_to_cluster(policy->cpu);
+	struct device *cpu_dev;
+	int ret;
+
+	cpu_dev = get_cpu_device(policy->cpu);
+	if (!cpu_dev) {
+		pr_err("%s: failed to get cpu%d device\n", __func__,
+				policy->cpu);
+		return -ENODEV;
+	}
+
+	ret = get_cluster_clk_and_freq_table(cpu_dev);
+	if (ret)
+		return ret;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table[cur_cluster]);
+	if (ret) {
+		dev_err(cpu_dev, "CPU %d, cluster: %d invalid freq table\n",
+				policy->cpu, cur_cluster);
+		put_cluster_clk_and_freq_table(cpu_dev);
+		return ret;
+	}
+
+	cpufreq_frequency_table_get_attr(freq_table[cur_cluster], policy->cpu);
+
+	if (arm_bL_ops->get_transition_latency)
+		policy->cpuinfo.transition_latency =
+			arm_bL_ops->get_transition_latency(cpu_dev);
+	else
+		policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+
+	policy->cur = bL_cpufreq_get(policy->cpu);
+
+	cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
+
+	dev_info(cpu_dev, "CPU %d initialized\n", policy->cpu);
+	return 0;
+}
+
+static int bL_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	struct device *cpu_dev;
+
+	cpu_dev = get_cpu_device(policy->cpu);
+	if (!cpu_dev) {
+		pr_err("%s: failed to get cpu%d device\n", __func__,
+				policy->cpu);
+		return -ENODEV;
+	}
+
+	put_cluster_clk_and_freq_table(cpu_dev);
+	dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu);
+
+	return 0;
+}
+
+/* Export freq_table to sysfs */
+static struct freq_attr *bL_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver bL_cpufreq_driver = {
+	.name			= "arm-big-little",
+	.flags			= CPUFREQ_STICKY,
+	.verify			= bL_cpufreq_verify_policy,
+	.target			= bL_cpufreq_set_target,
+	.get			= bL_cpufreq_get,
+	.init			= bL_cpufreq_init,
+	.exit			= bL_cpufreq_exit,
+	.have_multiple_policies	= true,
+	.attr			= bL_cpufreq_attr,
+};
+
+int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
+{
+	int ret;
+
+	if (arm_bL_ops) {
+		pr_debug("%s: Already registered: %s, exiting\n", __func__,
+				arm_bL_ops->name);
+		return -EBUSY;
+	}
+
+	if (!ops || !strlen(ops->name) || !ops->init_opp_table) {
+		pr_err("%s: Invalid arm_bL_ops, exiting\n", __func__);
+		return -ENODEV;
+	}
+
+	arm_bL_ops = ops;
+
+	ret = cpufreq_register_driver(&bL_cpufreq_driver);
+	if (ret) {
+		pr_info("%s: Failed registering platform driver: %s, err: %d\n",
+				__func__, ops->name, ret);
+		arm_bL_ops = NULL;
+	} else {
+		pr_info("%s: Registered platform driver: %s\n", __func__,
+				ops->name);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(bL_cpufreq_register);
+
+void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
+{
+	if (arm_bL_ops != ops) {
+		pr_err("%s: Registered with: %s, can't unregister, exiting\n",
+				__func__, arm_bL_ops->name);
+		return;
+	}
+
+	cpufreq_unregister_driver(&bL_cpufreq_driver);
+	pr_info("%s: Un-registered platform driver: %s\n", __func__,
+			arm_bL_ops->name);
+	arm_bL_ops = NULL;
+}
+EXPORT_SYMBOL_GPL(bL_cpufreq_unregister);
diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h
new file mode 100644
index 0000000..70f18fc
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little.h
@@ -0,0 +1,40 @@
+/*
+ * ARM big.LITTLE platform's CPUFreq header file
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef CPUFREQ_ARM_BIG_LITTLE_H
+#define CPUFREQ_ARM_BIG_LITTLE_H
+
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/types.h>
+
+struct cpufreq_arm_bL_ops {
+	char name[CPUFREQ_NAME_LEN];
+	int (*get_transition_latency)(struct device *cpu_dev);
+
+	/*
+	 * This must set opp table for cpu_dev in a similar way as done by
+	 * of_init_opp_table().
+	 */
+	int (*init_opp_table)(struct device *cpu_dev);
+};
+
+int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
+void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops);
+
+#endif /* CPUFREQ_ARM_BIG_LITTLE_H */
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
new file mode 100644
index 0000000..452ff46
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -0,0 +1,92 @@
+/*
+ * Generic big.LITTLE CPUFreq Interface driver
+ *
+ * It provides necessary ops to arm_big_little cpufreq driver and gets
+ * Frequency information from Device Tree. Freq table in DT must be in KHz.
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * 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 program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "arm_big_little.h"
+
+static int dt_init_opp_table(struct device *cpu_dev)
+{
+	struct device_node *np = NULL;
+	int count = 0, ret;
+
+	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+		if (count++ != cpu_dev->id)
+			continue;
+		if (!of_get_property(np, "operating-points", NULL))
+			return -ENODATA;
+
+		cpu_dev->of_node = np;
+
+		ret = of_init_opp_table(cpu_dev);
+		if (ret)
+			return ret;
+
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static int dt_get_transition_latency(struct device *cpu_dev)
+{
+	struct device_node *np = NULL;
+	u32 transition_latency = CPUFREQ_ETERNAL;
+	int count = 0;
+
+	for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+		if (count++ != cpu_dev->id)
+			continue;
+
+		of_property_read_u32(np, "clock-latency", &transition_latency);
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static struct cpufreq_arm_bL_ops dt_bL_ops = {
+	.name	= "dt-bl",
+	.get_transition_latency = dt_get_transition_latency,
+	.init_opp_table = dt_init_opp_table,
+};
+
+static int generic_bL_init(void)
+{
+	return bL_cpufreq_register(&dt_bL_ops);
+}
+module_init(generic_bL_init);
+
+static void generic_bL_exit(void)
+{
+	return bL_cpufreq_unregister(&dt_bL_ops);
+}
+module_exit(generic_bL_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
+MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver via DT");
+MODULE_LICENSE("GPL");
-- 
1.7.12.rc2.18.g61b472e

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

end of thread, other threads:[~2013-04-15  7:03 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-07 17:14 [PATCH V2] cpufreq: ARM big LITTLE: Add generic cpufreq driver and its DT glue Viresh Kumar
2013-03-07 17:14 ` Viresh Kumar
2013-03-07 21:56 ` Guennadi Liakhovetski
2013-03-07 21:56   ` Guennadi Liakhovetski
2013-03-08  4:20   ` Viresh Kumar
2013-03-08  4:20     ` Viresh Kumar
2013-03-08  6:11     ` Guennadi Liakhovetski
2013-03-08  6:11       ` Guennadi Liakhovetski
2013-03-09  3:06       ` Viresh Kumar
2013-03-09  3:06         ` Viresh Kumar
2013-03-10 15:58 ` Francesco Lavra
2013-03-10 15:58   ` Francesco Lavra
2013-03-11  0:57   ` Viresh Kumar
2013-03-11  0:57     ` Viresh Kumar
2013-03-11  0:57     ` Viresh Kumar
2013-03-21 23:50     ` Rafael J. Wysocki
2013-03-21 23:50       ` Rafael J. Wysocki
2013-03-22  2:21       ` Viresh Kumar
2013-03-22  2:21         ` Viresh Kumar
2013-03-26  9:51 Viresh Kumar
2013-03-26  9:51 ` Viresh Kumar
2013-03-26 13:17 ` Rob Herring
2013-03-26 13:17   ` Rob Herring
2013-03-26 14:30   ` Viresh Kumar
2013-03-26 14:30     ` Viresh Kumar
2013-04-13 20:13 ` Francesco Lavra
2013-04-13 20:13   ` Francesco Lavra
2013-04-15  7:02   ` Viresh Kumar
2013-04-15  7:02     ` Viresh Kumar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.