2013-09-12 11:25:20

by Bill Huang

[permalink] [raw]
Subject: [PATCH v2 0/4] Remodel Tegra cpufreq driver to support Tegra series SoCs

This patch series remodel Tegra cpufreq driver to make it more easy to
add new SoC support, in addition to that, adding probe function in the
driver to let probe defer can be used to control init sequence when we
going to support DVFS.

Changes since v1:

- Split up patches.
- Split configuration-time data out of structure "tegra_cpufreq_data".
- Bug fixes.

Bill Huang (4):
cpufreq: tegra: Call tegra_cpufreq_init() specifically in machine
code
cpufreq: tegra: Remove not used header files and clean up codes
cpufreq: tegra: Re-model Tegra cpufreq driver
ARM: tegra: defconfig updates

arch/arm/configs/tegra_defconfig | 1 +
arch/arm/mach-tegra/common.c | 2 +
drivers/cpufreq/Kconfig.arm | 8 +-
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/tegra-cpufreq.c | 194 +++++++++++++++++--------------------
drivers/cpufreq/tegra-cpufreq.h | 42 ++++++++
drivers/cpufreq/tegra20-cpufreq.c | 138 ++++++++++++++++++++++++++
include/linux/tegra-soc.h | 11 ++-
8 files changed, 290 insertions(+), 107 deletions(-)
create mode 100644 drivers/cpufreq/tegra-cpufreq.h
create mode 100644 drivers/cpufreq/tegra20-cpufreq.c

--
1.7.9.5


2013-09-12 11:25:27

by Bill Huang

[permalink] [raw]
Subject: [PATCH v2 1/4] cpufreq: tegra: Call tegra_cpufreq_init() specifically in machine code

Move the call from module_init to Tegra machine codes so it won't be
called in a multi-platform kernel running on non-Tegra SoCs.

Signed-off-by: Bill Huang <[email protected]>
---
arch/arm/mach-tegra/common.c | 2 ++
drivers/cpufreq/tegra-cpufreq.c | 13 ++-----------
include/linux/tegra-soc.h | 11 ++++++++++-
3 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 94a119a..db4414e 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -25,6 +25,7 @@
#include <linux/reboot.h>
#include <linux/irqchip.h>
#include <linux/clk-provider.h>
+#include <linux/tegra-soc.h>

#include <asm/hardware/cache-l2x0.h>

@@ -109,6 +110,7 @@ void __init tegra_init_early(void)

void __init tegra_init_late(void)
{
+ tegra_cpufreq_init();
tegra_init_suspend();
tegra_cpuidle_init();
tegra_powergate_debugfs_init();
diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c
index a7b876f..09c5af0 100644
--- a/drivers/cpufreq/tegra-cpufreq.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -253,7 +253,7 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
.attr = tegra_cpufreq_attr,
};

-static int __init tegra_cpufreq_init(void)
+int __init tegra_cpufreq_init(void)
{
cpu_clk = clk_get_sys(NULL, "cclk");
if (IS_ERR(cpu_clk))
@@ -275,17 +275,8 @@ static int __init tegra_cpufreq_init(void)

return cpufreq_register_driver(&tegra_cpufreq_driver);
}
-
-static void __exit tegra_cpufreq_exit(void)
-{
- cpufreq_unregister_driver(&tegra_cpufreq_driver);
- clk_put(emc_clk);
- clk_put(cpu_clk);
-}
-
+EXPORT_SYMBOL(tegra_cpufreq_init);

MODULE_AUTHOR("Colin Cross <[email protected]>");
MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2");
MODULE_LICENSE("GPL");
-module_init(tegra_cpufreq_init);
-module_exit(tegra_cpufreq_exit);
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index 95f611d..d86d081 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2012,2013, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -19,4 +19,13 @@

u32 tegra_read_chipid(void);

+#ifdef CONFIG_ARM_TEGRA_CPUFREQ
+int tegra_cpufreq_init(void);
+#else
+static inline int tegra_cpufreq_init(void)
+{
+ return -EINVAL;
+}
+#endif
+
#endif /* __LINUX_TEGRA_SOC_H_ */
--
1.7.9.5

2013-09-12 11:25:29

by Bill Huang

[permalink] [raw]
Subject: [PATCH v2 2/4] cpufreq: tegra: Remove not used header files and clean up codes

Remove the inclustion of the not needed header files and remove the
logic to check the CPU ID to not exceeding the maximum supported CPUs.

Signed-off-by: Bill Huang <[email protected]>
---
drivers/cpufreq/tegra-cpufreq.c | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c
index 09c5af0..c2d2910 100644
--- a/drivers/cpufreq/tegra-cpufreq.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -18,14 +18,9 @@

#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/cpufreq.h>
-#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/err.h>
#include <linux/clk.h>
-#include <linux/io.h>
#include <linux/suspend.h>

static struct cpufreq_frequency_table freq_table[] = {
@@ -40,14 +35,14 @@ static struct cpufreq_frequency_table freq_table[] = {
{ .frequency = CPUFREQ_TABLE_END },
};

-#define NUM_CPUS 2
+#define MAX_CPUS 4

static struct clk *cpu_clk;
static struct clk *pll_x_clk;
static struct clk *pll_p_clk;
static struct clk *emc_clk;

-static unsigned long target_cpu_speed[NUM_CPUS];
+static unsigned long target_cpu_speed[MAX_CPUS];
static DEFINE_MUTEX(tegra_cpu_lock);
static bool is_suspended;

@@ -60,9 +55,6 @@ static unsigned int tegra_getspeed(unsigned int cpu)
{
unsigned long rate;

- if (cpu >= NUM_CPUS)
- return 0;
-
rate = clk_get_rate(cpu_clk) / 1000;
return rate;
}
@@ -209,9 +201,6 @@ static struct notifier_block tegra_cpu_pm_notifier = {

static int tegra_cpu_init(struct cpufreq_policy *policy)
{
- if (policy->cpu >= NUM_CPUS)
- return -EINVAL;
-
clk_prepare_enable(emc_clk);
clk_prepare_enable(cpu_clk);

--
1.7.9.5

2013-09-12 11:25:34

by Bill Huang

[permalink] [raw]
Subject: [PATCH v2 3/4] cpufreq: tegra: Re-model Tegra cpufreq driver

Re-model Tegra cpufreq driver to support all Tegra series of SoCs.

* Make tegra-cpufreq.c a generic Tegra cpufreq driver.
* Move Tegra20 specific codes into tegra20-cpufreq.c.
* Bind Tegra cpufreq dirver with a fake device so defer probe would work
when we're going to get regulator in the driver to support voltage
scaling (DVFS).

Signed-off-by: Bill Huang <[email protected]>
---
drivers/cpufreq/Kconfig.arm | 8 +-
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/tegra-cpufreq.c | 176 +++++++++++++++++++------------------
drivers/cpufreq/tegra-cpufreq.h | 42 +++++++++
drivers/cpufreq/tegra20-cpufreq.c | 138 +++++++++++++++++++++++++++++
5 files changed, 278 insertions(+), 87 deletions(-)
create mode 100644 drivers/cpufreq/tegra-cpufreq.h
create mode 100644 drivers/cpufreq/tegra20-cpufreq.c

diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 0fa204b..09a80a4 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -232,6 +232,12 @@ config ARM_TEGRA_CPUFREQ
bool "TEGRA CPUFreq support"
depends on ARCH_TEGRA
select CPU_FREQ_TABLE
+
+config ARM_TEGRA20_CPUFREQ
+ bool "NVIDIA TEGRA20"
+ depends on ARM_TEGRA_CPUFREQ && ARCH_TEGRA_2x_SOC
default y
help
- This adds the CPUFreq driver support for TEGRA SOCs.
+ This adds the CPUFreq driver for NVIDIA TEGRA20 SoC.
+
+ If in doubt, say N.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index ad5866c..22a85f0 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o
+obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o

##################################################################################
# PowerPC platform drivers
diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c
index c2d2910..8616f6f 100644
--- a/drivers/cpufreq/tegra-cpufreq.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2013, NVIDIA Corporation.
* Copyright (C) 2010 Google, Inc.
*
* Author:
@@ -22,25 +23,16 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/suspend.h>
+#include <linux/cpu.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>

-static struct cpufreq_frequency_table freq_table[] = {
- { .frequency = 216000 },
- { .frequency = 312000 },
- { .frequency = 456000 },
- { .frequency = 608000 },
- { .frequency = 760000 },
- { .frequency = 816000 },
- { .frequency = 912000 },
- { .frequency = 1000000 },
- { .frequency = CPUFREQ_TABLE_END },
-};
+#include "tegra-cpufreq.h"

#define MAX_CPUS 4

-static struct clk *cpu_clk;
-static struct clk *pll_x_clk;
-static struct clk *pll_p_clk;
-static struct clk *emc_clk;
+static struct tegra_cpufreq_data *tegra_data;
+static const struct tegra_cpufreq_config *soc_config;

static unsigned long target_cpu_speed[MAX_CPUS];
static DEFINE_MUTEX(tegra_cpu_lock);
@@ -48,53 +40,17 @@ static bool is_suspended;

static int tegra_verify_speed(struct cpufreq_policy *policy)
{
- return cpufreq_frequency_table_verify(policy, freq_table);
+ return cpufreq_frequency_table_verify(policy, tegra_data->freq_table);
}

static unsigned int tegra_getspeed(unsigned int cpu)
{
unsigned long rate;

- rate = clk_get_rate(cpu_clk) / 1000;
+ rate = clk_get_rate(tegra_data->cpu_clk) / 1000;
return rate;
}

-static int tegra_cpu_clk_set_rate(unsigned long rate)
-{
- int ret;
-
- /*
- * Take an extra reference to the main pll so it doesn't turn
- * off when we move the cpu off of it
- */
- clk_prepare_enable(pll_x_clk);
-
- ret = clk_set_parent(cpu_clk, pll_p_clk);
- if (ret) {
- pr_err("Failed to switch cpu to clock pll_p\n");
- goto out;
- }
-
- if (rate == clk_get_rate(pll_p_clk))
- goto out;
-
- ret = clk_set_rate(pll_x_clk, rate);
- if (ret) {
- pr_err("Failed to change pll_x to %lu\n", rate);
- goto out;
- }
-
- ret = clk_set_parent(cpu_clk, pll_x_clk);
- if (ret) {
- pr_err("Failed to switch cpu to clock pll_x\n");
- goto out;
- }
-
-out:
- clk_disable_unprepare(pll_x_clk);
- return ret;
-}
-
static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
unsigned long rate)
{
@@ -111,12 +67,8 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
* Vote on memory bus frequency based on cpu frequency
* This sets the minimum frequency, display or avp may request higher
*/
- if (rate >= 816000)
- clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */
- else if (rate >= 456000)
- clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */
- else
- clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
+ if (soc_config->vote_emc_on_cpu_rate)
+ soc_config->vote_emc_on_cpu_rate(rate);

cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);

@@ -125,7 +77,7 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
freqs.old, freqs.new);
#endif

- ret = tegra_cpu_clk_set_rate(freqs.new * 1000);
+ ret = soc_config->cpu_clk_set_rate(freqs.new * 1000);
if (ret) {
pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
freqs.new);
@@ -151,6 +103,7 @@ static int tegra_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
+ struct cpufreq_frequency_table *freq_table = tegra_data->freq_table;
unsigned int idx;
unsigned int freq;
int ret = 0;
@@ -162,8 +115,8 @@ static int tegra_target(struct cpufreq_policy *policy,
goto out;
}

- cpufreq_frequency_table_target(policy, freq_table, target_freq,
- relation, &idx);
+ cpufreq_frequency_table_target(policy, freq_table,
+ target_freq, relation, &idx);

freq = freq_table[idx].frequency;

@@ -179,6 +132,8 @@ out:
static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
void *dummy)
{
+ struct cpufreq_frequency_table *freq_table = tegra_data->freq_table;
+
mutex_lock(&tegra_cpu_lock);
if (event == PM_SUSPEND_PREPARE) {
struct cpufreq_policy *policy = cpufreq_cpu_get(0);
@@ -201,11 +156,11 @@ static struct notifier_block tegra_cpu_pm_notifier = {

static int tegra_cpu_init(struct cpufreq_policy *policy)
{
- clk_prepare_enable(emc_clk);
- clk_prepare_enable(cpu_clk);
+ if (soc_config->cpufreq_clk_init)
+ soc_config->cpufreq_clk_init();

- cpufreq_frequency_table_cpuinfo(policy, freq_table);
- cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+ cpufreq_frequency_table_cpuinfo(policy, tegra_data->freq_table);
+ cpufreq_frequency_table_get_attr(tegra_data->freq_table, policy->cpu);
policy->cur = tegra_getspeed(policy->cpu);
target_cpu_speed[policy->cpu] = policy->cur;

@@ -222,8 +177,9 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)

static int tegra_cpu_exit(struct cpufreq_policy *policy)
{
- cpufreq_frequency_table_cpuinfo(policy, freq_table);
- clk_disable_unprepare(emc_clk);
+ cpufreq_frequency_table_cpuinfo(policy, tegra_data->freq_table);
+ if (soc_config->cpufreq_clk_exit)
+ soc_config->cpufreq_clk_exit();
return 0;
}

@@ -242,27 +198,75 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
.attr = tegra_cpufreq_attr,
};

-int __init tegra_cpufreq_init(void)
+static struct {
+ char *compat;
+ int (*init)(struct tegra_cpufreq_data *,
+ const struct tegra_cpufreq_config **);
+} tegra_init_funcs[] = {
+ { "nvidia,tegra20", tegra20_cpufreq_init },
+};
+
+static int tegra_cpufreq_probe(struct platform_device *pdev)
{
- cpu_clk = clk_get_sys(NULL, "cclk");
- if (IS_ERR(cpu_clk))
- return PTR_ERR(cpu_clk);
-
- pll_x_clk = clk_get_sys(NULL, "pll_x");
- if (IS_ERR(pll_x_clk))
- return PTR_ERR(pll_x_clk);
-
- pll_p_clk = clk_get_sys(NULL, "pll_p");
- if (IS_ERR(pll_p_clk))
- return PTR_ERR(pll_p_clk);
-
- emc_clk = clk_get_sys("cpu", "emc");
- if (IS_ERR(emc_clk)) {
- clk_put(cpu_clk);
- return PTR_ERR(emc_clk);
+ int i;
+ int ret = -EINVAL;
+
+ tegra_data = devm_kzalloc(&pdev->dev,
+ sizeof(*tegra_data), GFP_KERNEL);
+ if (!tegra_data) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ tegra_data->dev = &pdev->dev;
+
+ for (i = 0; i < ARRAY_SIZE(tegra_init_funcs); i++) {
+ if (of_machine_is_compatible(tegra_init_funcs[i].compat)) {
+ ret = tegra_init_funcs[i].init(tegra_data, &soc_config);
+ if (!ret)
+ break;
+ else
+ goto out;
+ }
+ }
+ if (i == ARRAY_SIZE(tegra_init_funcs))
+ goto out;
+
+ ret = cpufreq_register_driver(&tegra_cpufreq_driver);
+ if (ret) {
+ dev_err(tegra_data->dev,
+ "%s: failed to register cpufreq driver\n", __func__);
+ goto out;
}

- return cpufreq_register_driver(&tegra_cpufreq_driver);
+ return 0;
+out:
+ return ret;
+}
+
+static int tegra_cpufreq_remove(struct platform_device *pdev)
+{
+ cpufreq_unregister_driver(&tegra_cpufreq_driver);
+ return 0;
+}
+
+static struct platform_driver tegra_cpufreq_platdrv = {
+ .driver = {
+ .name = "tegra-cpufreq",
+ .owner = THIS_MODULE,
+ },
+ .probe = tegra_cpufreq_probe,
+ .remove = tegra_cpufreq_remove,
+};
+module_platform_driver(tegra_cpufreq_platdrv);
+
+int __init tegra_cpufreq_init(void)
+{
+ struct platform_device_info devinfo = { .name = "tegra-cpufreq", };
+
+ platform_device_register_full(&devinfo);
+
+ return 0;
}
EXPORT_SYMBOL(tegra_cpufreq_init);

diff --git a/drivers/cpufreq/tegra-cpufreq.h b/drivers/cpufreq/tegra-cpufreq.h
new file mode 100644
index 0000000..820d5b1
--- /dev/null
+++ b/drivers/cpufreq/tegra-cpufreq.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LINUX_TEGRA_CPUFREQ_H
+#define __LINUX_TEGRA_CPUFREQ_H
+
+struct tegra_cpufreq_config {
+ void (*vote_emc_on_cpu_rate)(unsigned long);
+ int (*cpu_clk_set_rate)(unsigned long);
+ void (*cpufreq_clk_init)(void);
+ void (*cpufreq_clk_exit)(void);
+};
+
+struct tegra_cpufreq_data {
+ struct device *dev;
+ struct clk *cpu_clk;
+ struct cpufreq_frequency_table *freq_table;
+};
+
+#ifdef CONFIG_ARM_TEGRA20_CPUFREQ
+int tegra20_cpufreq_init(struct tegra_cpufreq_data *data,
+ const struct tegra_cpufreq_config **config);
+#else
+static inline int tegra20_cpufreq_init(struct tegra_cpufreq_data *data,
+ const struct tegra_cpufreq_config **config)
+{ return -EINVAL; }
+#endif
+
+#endif /* __LINUX_TEGRA_CPUFREQ_H_ */
diff --git a/drivers/cpufreq/tegra20-cpufreq.c b/drivers/cpufreq/tegra20-cpufreq.c
new file mode 100644
index 0000000..9cf75a2
--- /dev/null
+++ b/drivers/cpufreq/tegra20-cpufreq.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/suspend.h>
+#include <linux/cpu.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#include "tegra-cpufreq.h"
+
+static struct cpufreq_frequency_table freq_table[] = {
+ { .frequency = 216000 },
+ { .frequency = 312000 },
+ { .frequency = 456000 },
+ { .frequency = 608000 },
+ { .frequency = 760000 },
+ { .frequency = 816000 },
+ { .frequency = 912000 },
+ { .frequency = 1000000 },
+ { .frequency = CPUFREQ_TABLE_END },
+};
+
+static struct clk *cpu_clk;
+static struct clk *pll_x_clk;
+static struct clk *pll_p_clk;
+static struct clk *emc_clk;
+
+static void tegra20_vote_emc_on_cpu_rate(unsigned long rate)
+{
+ if (rate >= 816000)
+ clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */
+ else if (rate >= 456000)
+ clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */
+ else
+ clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
+}
+
+static int tegra20_cpu_clk_set_rate(unsigned long rate)
+{
+ int ret;
+
+ /*
+ * Take an extra reference to the main pll so it doesn't turn
+ * off when we move the cpu off of it
+ */
+ clk_prepare_enable(pll_x_clk);
+
+ ret = clk_set_parent(cpu_clk, pll_p_clk);
+ if (ret) {
+ pr_err("Failed to switch cpu to clock pll_p\n");
+ goto out;
+ }
+
+ if (rate == clk_get_rate(pll_p_clk))
+ goto out;
+
+ ret = clk_set_rate(pll_x_clk, rate);
+ if (ret) {
+ pr_err("Failed to change pll_x to %lu\n", rate);
+ goto out;
+ }
+
+ ret = clk_set_parent(cpu_clk, pll_x_clk);
+ if (ret) {
+ pr_err("Failed to switch cpu to clock pll_x\n");
+ goto out;
+ }
+
+out:
+ clk_disable_unprepare(pll_x_clk);
+ return ret;
+}
+
+static void tegra20_cpufreq_clk_init(void)
+{
+ clk_prepare_enable(emc_clk);
+ clk_prepare_enable(cpu_clk);
+}
+
+static void tegra20_cpufreq_clk_exit(void)
+{
+ clk_disable_unprepare(cpu_clk);
+ clk_disable_unprepare(emc_clk);
+}
+
+static const struct tegra_cpufreq_config tegra20_cpufreq_config = {
+ .vote_emc_on_cpu_rate = tegra20_vote_emc_on_cpu_rate,
+ .cpu_clk_set_rate = tegra20_cpu_clk_set_rate,
+ .cpufreq_clk_init = tegra20_cpufreq_clk_init,
+ .cpufreq_clk_exit = tegra20_cpufreq_clk_exit,
+};
+
+int tegra20_cpufreq_init(struct tegra_cpufreq_data *data,
+ const struct tegra_cpufreq_config **soc_config)
+{
+ cpu_clk = clk_get_sys(NULL, "cclk");
+ if (IS_ERR(cpu_clk))
+ return PTR_ERR(cpu_clk);
+
+ pll_x_clk = clk_get_sys(NULL, "pll_x");
+ if (IS_ERR(pll_x_clk))
+ return PTR_ERR(pll_x_clk);
+
+ pll_p_clk = clk_get_sys(NULL, "pll_p");
+ if (IS_ERR(pll_p_clk))
+ return PTR_ERR(pll_p_clk);
+
+ emc_clk = clk_get_sys("cpu", "emc");
+ if (IS_ERR(emc_clk)) {
+ clk_put(cpu_clk);
+ return PTR_ERR(emc_clk);
+ }
+
+ data->cpu_clk = cpu_clk;
+ data->freq_table = freq_table;
+ *soc_config = &tegra20_cpufreq_config;
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra20_cpufreq_init);
--
1.7.9.5

2013-09-12 11:25:40

by Bill Huang

[permalink] [raw]
Subject: [PATCH v2 4/4] ARM: tegra: defconfig updates

Enable:
* Tegra CPUFreq driver.

Signed-off-by: Bill Huang <[email protected]>
---
arch/arm/configs/tegra_defconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index ea042e8..64bc8bd 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -42,6 +42,7 @@ CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_KEXEC=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_ARM_TEGRA_CPUFREQ=y
CONFIG_CPU_IDLE=y
CONFIG_VFP=y
CONFIG_PM_RUNTIME=y
--
1.7.9.5

2013-09-12 11:27:31

by Viresh Kumar

[permalink] [raw]
Subject: Re: [PATCH v2 0/4] Remodel Tegra cpufreq driver to support Tegra series SoCs

On 12 September 2013 16:54, Bill Huang <[email protected]> wrote:
> This patch series remodel Tegra cpufreq driver to make it more easy to
> add new SoC support, in addition to that, adding probe function in the
> driver to let probe defer can be used to control init sequence when we
> going to support DVFS.
>
> Changes since v1:
>
> - Split up patches.
> - Split configuration-time data out of structure "tegra_cpufreq_data".
> - Bug fixes.
>
> Bill Huang (4):
> cpufreq: tegra: Call tegra_cpufreq_init() specifically in machine
> code
> cpufreq: tegra: Remove not used header files and clean up codes
> cpufreq: tegra: Re-model Tegra cpufreq driver
> ARM: tegra: defconfig updates
>
> arch/arm/configs/tegra_defconfig | 1 +
> arch/arm/mach-tegra/common.c | 2 +
> drivers/cpufreq/Kconfig.arm | 8 +-
> drivers/cpufreq/Makefile | 1 +
> drivers/cpufreq/tegra-cpufreq.c | 194 +++++++++++++++++--------------------
> drivers/cpufreq/tegra-cpufreq.h | 42 ++++++++
> drivers/cpufreq/tegra20-cpufreq.c | 138 ++++++++++++++++++++++++++
> include/linux/tegra-soc.h | 11 ++-
> 8 files changed, 290 insertions(+), 107 deletions(-)
> create mode 100644 drivers/cpufreq/tegra-cpufreq.h
> create mode 100644 drivers/cpufreq/tegra20-cpufreq.c

I haven't gone deeper into these yet, but there are some cleaup
patches that I have prepared/posted earlier, which will be queued
by Rafael soon.. And after that you would be required to rebase
your stuff on top of it.. As there would be many conflicts..

--
viresh

2013-09-13 22:26:20

by Stephen Warren

[permalink] [raw]
Subject: Re: [PATCH v2 3/4] cpufreq: tegra: Re-model Tegra cpufreq driver

On 09/12/2013 05:24 AM, Bill Huang wrote:
> Re-model Tegra cpufreq driver to support all Tegra series of SoCs.
>
> * Make tegra-cpufreq.c a generic Tegra cpufreq driver.
> * Move Tegra20 specific codes into tegra20-cpufreq.c.
> * Bind Tegra cpufreq dirver with a fake device so defer probe would work
> when we're going to get regulator in the driver to support voltage
> scaling (DVFS).

> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm

> @@ -232,6 +232,12 @@ config ARM_TEGRA_CPUFREQ
> bool "TEGRA CPUFreq support"
> depends on ARCH_TEGRA
> select CPU_FREQ_TABLE
> +
> +config ARM_TEGRA20_CPUFREQ
> + bool "NVIDIA TEGRA20"
> + depends on ARM_TEGRA_CPUFREQ && ARCH_TEGRA_2x_SOC
> default y
> help
> - This adds the CPUFreq driver support for TEGRA SOCs.
> + This adds the CPUFreq driver for NVIDIA TEGRA20 SoC.
> +
> + If in doubt, say N.

This patch removes the following from "config ARM_TEGRA_CPUFREQ":

default y
help
This adds the CPUFreq driver support for TEGRA SOCs.

I think that option should be left unchanged, such that this patch
*just* adds the new option without changing the existing one. If you do
that, then you can completely drop patch 4/4.

Other than that, this series looks fine.

2013-09-14 02:00:52

by Bill Huang

[permalink] [raw]
Subject: Re: [PATCH v2 3/4] cpufreq: tegra: Re-model Tegra cpufreq driver

On Sat, 2013-09-14 at 06:26 +0800, Stephen Warren wrote:
> On 09/12/2013 05:24 AM, Bill Huang wrote:
> > Re-model Tegra cpufreq driver to support all Tegra series of SoCs.
> >
> > * Make tegra-cpufreq.c a generic Tegra cpufreq driver.
> > * Move Tegra20 specific codes into tegra20-cpufreq.c.
> > * Bind Tegra cpufreq dirver with a fake device so defer probe would work
> > when we're going to get regulator in the driver to support voltage
> > scaling (DVFS).
>
> > diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
>
> > @@ -232,6 +232,12 @@ config ARM_TEGRA_CPUFREQ
> > bool "TEGRA CPUFreq support"
> > depends on ARCH_TEGRA
> > select CPU_FREQ_TABLE
> > +
> > +config ARM_TEGRA20_CPUFREQ
> > + bool "NVIDIA TEGRA20"
> > + depends on ARM_TEGRA_CPUFREQ && ARCH_TEGRA_2x_SOC
> > default y
> > help
> > - This adds the CPUFreq driver support for TEGRA SOCs.
> > + This adds the CPUFreq driver for NVIDIA TEGRA20 SoC.
> > +
> > + If in doubt, say N.
>
> This patch removes the following from "config ARM_TEGRA_CPUFREQ":
>
> default y
> help
> This adds the CPUFreq driver support for TEGRA SOCs.
>
> I think that option should be left unchanged, such that this patch
> *just* adds the new option without changing the existing one. If you do
> that, then you can completely drop patch 4/4.

Thanks, I'll change and rebase in next version after Viresh's cleanup
patch series is merged.
>
> Other than that, this series looks fine.