diff options
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap/dvfs')
20 files changed, 2222 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0001-OMAP3-PM-Adding-T2-enabling-of-smartreflex.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0001-OMAP3-PM-Adding-T2-enabling-of-smartreflex.patch new file mode 100644 index 00000000..eafc4d30 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0001-OMAP3-PM-Adding-T2-enabling-of-smartreflex.patch @@ -0,0 +1,60 @@ +From 8548db6d3cf115b29142f803d701122dc4cbb775 Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Fri, 31 Dec 2010 13:35:02 +0530 +Subject: [PATCH 01/20] OMAP3: PM: Adding T2 enabling of smartreflex + +The smartreflex bit on twl4030 needs to be enabled by default irrespective +of whether smartreflex module is enabled on the OMAP side or not. +This is because without this bit enabled the voltage scaling through +vp forceupdate does not function properly on OMAP3. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/mach-omap2/omap_twl.c | 16 ++++++++++++++++ + 1 files changed, 16 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c +index 15f8c6c..a59f36b 100644 +--- a/arch/arm/mach-omap2/omap_twl.c ++++ b/arch/arm/mach-omap2/omap_twl.c +@@ -58,7 +58,9 @@ + static bool is_offset_valid; + static u8 smps_offset; + ++#define TWL4030_DCDC_GLOBAL_CFG 0x06 + #define REG_SMPS_OFFSET 0xE0 ++#define SMARTREFLEX_ENABLE BIT(3) + + unsigned long twl4030_vsel_to_uv(const u8 vsel) + { +@@ -256,6 +258,7 @@ int __init omap4_twl_init(void) + int __init omap3_twl_init(void) + { + struct voltagedomain *voltdm; ++ u8 temp; + + if (!cpu_is_omap34xx()) + return -ENODEV; +@@ -267,6 +270,19 @@ int __init omap3_twl_init(void) + omap3_core_volt_info.vp_vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX; + } + ++ /* ++ * The smartreflex bit on twl4030 needs to be enabled by ++ * default irrespective of whether smartreflex module is ++ * enabled on the OMAP side or not. This is because without ++ * this bit enabled the voltage scaling through ++ * vp forceupdate does not function properly on OMAP3. ++ */ ++ twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &temp, ++ TWL4030_DCDC_GLOBAL_CFG); ++ temp |= SMARTREFLEX_ENABLE; ++ twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, temp, ++ TWL4030_DCDC_GLOBAL_CFG); ++ + voltdm = omap_voltage_domain_lookup("mpu"); + omap_voltage_register_pmic(voltdm, &omap3_mpu_volt_info); + +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0002-OMAP-CPUfreq-ensure-driver-initializes-after-cpufreq.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0002-OMAP-CPUfreq-ensure-driver-initializes-after-cpufreq.patch new file mode 100644 index 00000000..b6512a5e --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0002-OMAP-CPUfreq-ensure-driver-initializes-after-cpufreq.patch @@ -0,0 +1,27 @@ +From e446cbf4aa8359d58180a81282df70045b8a41c1 Mon Sep 17 00:00:00 2001 +From: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> +Date: Wed, 11 Aug 2010 17:02:43 -0700 +Subject: [PATCH 02/20] OMAP: CPUfreq: ensure driver initializes after cpufreq framework and governors + +Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> +--- + arch/arm/plat-omap/cpu-omap.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c +index 11c54ec..79d2155 100644 +--- a/arch/arm/plat-omap/cpu-omap.c ++++ b/arch/arm/plat-omap/cpu-omap.c +@@ -160,7 +160,7 @@ static int __init omap_cpufreq_init(void) + return cpufreq_register_driver(&omap_driver); + } + +-arch_initcall(omap_cpufreq_init); ++late_initcall(omap_cpufreq_init); + + /* + * if ever we want to remove this, upon cleanup call: +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0003-OMAP-CPUfreq-ensure-policy-is-fully-initialized.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0003-OMAP-CPUfreq-ensure-policy-is-fully-initialized.patch new file mode 100644 index 00000000..c6826e3c --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0003-OMAP-CPUfreq-ensure-policy-is-fully-initialized.patch @@ -0,0 +1,31 @@ +From 647691beb64312327646a84dc161faf35935e7f7 Mon Sep 17 00:00:00 2001 +From: Kevin Hilman <khilman@deeprootsystems.com> +Date: Wed, 11 Aug 2010 17:05:38 -0700 +Subject: [PATCH 03/20] OMAP: CPUfreq: ensure policy is fully initialized + +Ensure policy min/max/cur values are initialized when OMAP +CPUfreq driver starts. + +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> +--- + arch/arm/plat-omap/cpu-omap.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c +index 79d2155..bfa063b 100644 +--- a/arch/arm/plat-omap/cpu-omap.c ++++ b/arch/arm/plat-omap/cpu-omap.c +@@ -126,6 +126,10 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy) + VERY_HI_RATE) / 1000; + } + ++ policy->min = policy->cpuinfo.min_freq; ++ policy->max = policy->cpuinfo.max_freq; ++ policy->cur = omap_getspeed(0); ++ + /* FIXME: what's the actual transition time? */ + policy->cpuinfo.transition_latency = 300 * 1000; + +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0004-OMAP3-PM-CPUFreq-driver-for-OMAP3.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0004-OMAP3-PM-CPUFreq-driver-for-OMAP3.patch new file mode 100644 index 00000000..0371bc3a --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0004-OMAP3-PM-CPUFreq-driver-for-OMAP3.patch @@ -0,0 +1,269 @@ +From f6b96e3b9e31da193189d92320b3dd9fac7c9ba9 Mon Sep 17 00:00:00 2001 +From: Rajendra Nayak <rnayak@ti.com> +Date: Mon, 10 Nov 2008 17:00:25 +0530 +Subject: [PATCH 04/20] OMAP3 PM: CPUFreq driver for OMAP3 + +CPUFreq driver for OMAP3 + +With additional fixes and cleanups from Tero Kristo: +- Fix rate calculation bug in omap3_select_table_rate +- Refreshed DVFS VDD1 control against latest clock fw + +Signed-off-by: Tero Kristo <tero.kristo@nokia.com> +Signed-off-by: Rajendra Nayak <rnayak@ti.com> + +OMAP3: PM: CPUFreq: Fix omap_getspeed. + +Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> + +Make sure omap cpufreq driver initializes after cpufreq framework and governors + +Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> + +merge: CPUFreq: remove obsolete funcs + +OMAP3 clock: Update cpufreq driver + +This patch removes all refrences to virtual clock +nodes in CPUFreq driver. + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +Signed-off-by: Tero Kristo <tero.kristo@nokia.com> +Signed-off-by: Jean Pihet <jpihet@mvista.com> + +PM: Prevent direct cpufreq scaling during initialization + +It is seen that the OMAP specific cpufreq initialization code tries to +scale the MPU frequency to the highest possible without taking care of +the voltage level. On power on reset the power IC does not provide the +necessary voltage for the highest available MPU frequency (that would +satisfy all Si families). This potentially is an window of opportunity +for things to go wrong. + +Signed-off-by: Romit Dasgupta <romit@ti.com> +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> + +OMAP3: PM: enable 600MHz (overdrive) OPP + +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> + +omap3: introduce cpufreq + +OMAP OPP layer functions now have dependencies of CONFIG_CPU_FREQ only. + +With this patch, omap opp layer now has its compilation flags +bound to CONFIG_CPU_FREQ. Also its code has been removed from pm34xx.c. + +A new file has been created to contain cpu freq code related to +OMAP3: cpufreq34xx.c + +OMAP34xx and OMAP36xx family OPPs are made available + +Signed-off-by: Eduardo Valentin <eduardo.valentin@nokia.com> +Signed-off-by: Paul Walmsley <paul@pwsan.com> +Signed-off-by: Nishanth Menon <nm@ti.com> +Signed-off-by: Vishwanath BS <vishwanath.bs@ti.com> +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> +Signed-off-by: Romit Dasgupta <romit@ti.com> +Signed-off-by: Rajendra Nayak <rnayak@ti.com> + +omap3: cpufreq: allow default opp table init + +For board files which choose to override the defaults, the existing +mechanism will work, for boards that would like to work with defaults, +allow init_common_hw to call init_opp_table to initialize if not +already initialized. this will allow all omap boards which have opp +tables predefined for a silicon to use the same. + +Originally reported for overo: +http://marc.info/?t=127265269400004&r=1&w=2 + +Signed-off-by: Nishanth Menon <nm@ti.com> +Reported-by: Peter Tseng <tsenpet09@gmail.com> +Cc: Cliff Brake <cliff.brake@gmail.com> +Cc: Kevin Hilman <khilman@deeprootsystems.com> + +OMAP2: update OPP data to be device based + +Cc: Nishanth Menon <nm@ti.com> +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> + +OMAP3: CPUfreq: update to device-based OPP API + +Update usage of OPP API to use new device-based API. This requires +getting the 'struct device' for the MPU and using that with the OPP +API. + +Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com> + +omap3: opp: make independent of cpufreq + +Make opp3xx data which is registered with the opp layer +dependent purely on CONFIG_PM as opp layer and pm.c users +are CONFIG_PM dependent not cpufreq dependent. +so we rename the data definition to opp3xxx_data.c (inline with what +we have for omap2), also move the build definition to be under +the existing CONFIG_PM build instead of CPUFREQ. + +Cc: Eduardo Valentin <eduardo.valentin@nokia.com> +Cc: Kevin Hilman <khilman@deeprootsystems.com> +Cc: Paul Walmsley <paul@pwsan.com> +Cc: Rajendra Nayak <rnayak@ti.com> +Cc: Sanjeev Premi <premi@ti.com> +Cc: Thara Gopinath <thara@ti.com> +Cc: Tony Lindgren <tony@atomide.com> + +Signed-off-by: Nishanth Menon <nm@ti.com> +--- + arch/arm/mach-omap2/clock.h | 14 +++++++++++++- + arch/arm/mach-omap2/clock34xx.c | 2 ++ + arch/arm/plat-omap/cpu-omap.c | 35 ++++++++++++++++++++++++++++++++--- + 3 files changed, 47 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h +index 896584e..29b5cf0 100644 +--- a/arch/arm/mach-omap2/clock.h ++++ b/arch/arm/mach-omap2/clock.h +@@ -137,7 +137,9 @@ extern const struct clksel_rate gpt_32k_rates[]; + extern const struct clksel_rate gpt_sys_rates[]; + extern const struct clksel_rate gfx_l3_rates[]; + +-#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_CPU_FREQ) ++#ifdef CONFIG_CPU_FREQ ++ ++#ifdef CONFIG_ARCH_OMAP2 + extern void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table); + extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); + #else +@@ -145,6 +147,16 @@ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) + #define omap2_clk_exit_cpufreq_table 0 + #endif + ++#ifdef CONFIG_ARCH_OMAP3 ++extern void omap3_clk_init_cpufreq_table(struct cpufreq_frequency_table **table); ++extern void omap3_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); ++#else ++#define omap3_clk_init_cpufreq_table 0 ++#define omap3_clk_exit_cpufreq_table 0 ++#endif ++ ++#endif /* CONFIG_CPU_FREQ */ ++ + extern const struct clkops clkops_omap3_noncore_dpll_ops; + + #endif +diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c +index 287abc4..85d3877 100644 +--- a/arch/arm/mach-omap2/clock34xx.c ++++ b/arch/arm/mach-omap2/clock34xx.c +@@ -20,6 +20,8 @@ + #include <linux/kernel.h> + #include <linux/clk.h> + #include <linux/io.h> ++#include <linux/err.h> ++#include <linux/cpufreq.h> + + #include <plat/clock.h> + +diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c +index bfa063b..608216b 100644 +--- a/arch/arm/plat-omap/cpu-omap.c ++++ b/arch/arm/plat-omap/cpu-omap.c +@@ -8,6 +8,10 @@ + * + * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King + * ++ * Copyright (C) 2007-2008 Texas Instruments, Inc. ++ * Updated to support OMAP3 ++ * Rajendra Nayak <rnayak@ti.com> ++ * + * 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. +@@ -21,17 +25,25 @@ + #include <linux/err.h> + #include <linux/clk.h> + #include <linux/io.h> ++#include <linux/opp.h> + + #include <mach/hardware.h> + #include <plat/clock.h> ++#include <plat/common.h> + #include <asm/system.h> + ++#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++#include <plat/omap-pm.h> ++#endif ++ + #define VERY_HI_RATE 900000000 + + static struct cpufreq_frequency_table *freq_table; + + #ifdef CONFIG_ARCH_OMAP1 + #define MPU_CLK "mpu" ++#elif CONFIG_ARCH_OMAP3 ++#define MPU_CLK "arm_fck" + #else + #define MPU_CLK "virt_prcm_set" + #endif +@@ -73,7 +85,13 @@ static int omap_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) + { ++#ifdef CONFIG_ARCH_OMAP1 + struct cpufreq_freqs freqs; ++#endif ++#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++ unsigned long freq; ++ struct device *mpu_dev = omap2_get_mpuss_device(); ++#endif + int ret = 0; + + /* Ensure desired rate is within allowed range. Some govenors +@@ -83,13 +101,13 @@ static int omap_target(struct cpufreq_policy *policy, + if (target_freq > policy->max) + target_freq = policy->max; + ++#ifdef CONFIG_ARCH_OMAP1 + freqs.old = omap_getspeed(0); + freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; + freqs.cpu = 0; + + if (freqs.old == freqs.new) + return ret; +- + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + #ifdef CONFIG_CPU_FREQ_DEBUG + printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n", +@@ -97,7 +115,11 @@ static int omap_target(struct cpufreq_policy *policy, + #endif + ret = clk_set_rate(mpu_clk, freqs.new * 1000); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +- ++#elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++ freq = target_freq * 1000; ++ if (opp_find_freq_ceil(mpu_dev, &freq)) ++ omap_pm_cpu_set_freq(freq); ++#endif + return ret; + } + +@@ -114,7 +136,14 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy) + + policy->cur = policy->min = policy->max = omap_getspeed(0); + +- clk_init_cpufreq_table(&freq_table); ++ if (!cpu_is_omap34xx()) { ++ clk_init_cpufreq_table(&freq_table); ++ } else { ++ struct device *mpu_dev = omap2_get_mpuss_device(); ++ ++ opp_init_cpufreq_table(mpu_dev, &freq_table); ++ } ++ + if (freq_table) { + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (!result) +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0005-OMAP-PM-CPUFREQ-Fix-conditional-compilation.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0005-OMAP-PM-CPUFREQ-Fix-conditional-compilation.patch new file mode 100644 index 00000000..b843704e --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0005-OMAP-PM-CPUFREQ-Fix-conditional-compilation.patch @@ -0,0 +1,32 @@ +From 25ea605d0aaf1d60030b4df122a3384c7878d86e Mon Sep 17 00:00:00 2001 +From: Silesh C V <silesh@ti.com> +Date: Wed, 29 Sep 2010 14:52:54 +0530 +Subject: [PATCH 05/20] OMAP: PM: CPUFREQ: Fix conditional compilation + +Fix conditional compilation. A conditional expresiion +should follow "#elif", in this case #elif clause should +check whether CONFIG_ARCH_OMAP3 is defined or not +(ie. defined(CONFIG_ARCH_OMAP3)) rather than checking for +the value of the macro. + +Signed-off-by: Silesh C V <silesh@ti.com> +--- + arch/arm/plat-omap/cpu-omap.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c +index 608216b..671e4b9 100644 +--- a/arch/arm/plat-omap/cpu-omap.c ++++ b/arch/arm/plat-omap/cpu-omap.c +@@ -42,7 +42,7 @@ static struct cpufreq_frequency_table *freq_table; + + #ifdef CONFIG_ARCH_OMAP1 + #define MPU_CLK "mpu" +-#elif CONFIG_ARCH_OMAP3 ++#elif defined(CONFIG_ARCH_OMAP3) + #define MPU_CLK "arm_fck" + #else + #define MPU_CLK "virt_prcm_set" +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0006-OMAP-Introduce-a-user-list-for-each-voltage-domain-i.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0006-OMAP-Introduce-a-user-list-for-each-voltage-domain-i.patch new file mode 100644 index 00000000..516c7cb0 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0006-OMAP-Introduce-a-user-list-for-each-voltage-domain-i.patch @@ -0,0 +1,199 @@ +From a4107498616e8dafa2a0155a6d45a990766b161b Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Fri, 29 Oct 2010 20:43:07 +0530 +Subject: [PATCH 06/20] OMAP: Introduce a user list for each voltage domain instance in the voltage driver. + +This patch introduces a user list of devices associated with each +voltage domain instance. The user list is implemented using plist +structure with priority node populated with the voltage values. +This patch also adds an API which will take in a device and +requested voltage as parameters, adds the info to the user list +and returns back the maximum voltage requested by all the user +devices. This can be used anytime to get the voltage that the +voltage domain instance can be transitioned into. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/mach-omap2/voltage.c | 97 +++++++++++++++++++++++++++++ + arch/arm/plat-omap/include/plat/voltage.h | 8 +++ + 2 files changed, 105 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c +index ed6079c..76c98c6 100644 +--- a/arch/arm/mach-omap2/voltage.c ++++ b/arch/arm/mach-omap2/voltage.c +@@ -24,6 +24,9 @@ + #include <linux/err.h> + #include <linux/debugfs.h> + #include <linux/slab.h> ++#include <linux/spinlock.h> ++#include <linux/plist.h> ++#include <linux/slab.h> + + #include <plat/common.h> + #include <plat/voltage.h> +@@ -118,6 +121,20 @@ struct vc_reg_info { + }; + + /** ++ * struct omap_vdd_user_list - The per vdd user list ++ * ++ * @dev: The device asking for the vdd to be set at a particular ++ * voltage ++ * @node: The list head entry ++ * @volt: The voltage requested by the device <dev> ++ */ ++struct omap_vdd_user_list { ++ struct device *dev; ++ struct plist_node node; ++ u32 volt; ++}; ++ ++/** + * omap_vdd_info - Per Voltage Domain info + * + * @volt_data : voltage table having the distinct voltages supported +@@ -132,6 +149,10 @@ struct vc_reg_info { + * shifts, masks etc. + * @voltdm : pointer to the voltage domain structure + * @debug_dir : debug directory for this voltage domain. ++ * @user_lock : the lock to be used by the plist user_list ++ * @user_list : the list head maintaining the various users. ++ * @scaling_mutex : the dvfs muutex. ++ * of this vdd with the voltage requested by each user. + * @curr_volt : current voltage for this vdd. + * @ocp_mod : The prm module for accessing the prm irqstatus reg. + * @prm_irqst_reg : prm irqstatus register. +@@ -146,6 +167,9 @@ struct omap_vdd_info { + struct vc_reg_info vc_reg; + struct voltagedomain voltdm; + struct dentry *debug_dir; ++ spinlock_t user_lock; ++ struct plist_head user_list; ++ struct mutex scaling_mutex; + u32 curr_volt; + u16 ocp_mod; + u8 prm_irqst_reg; +@@ -869,6 +893,11 @@ static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd) + vdd->write_reg = omap3_voltage_write_reg; + vdd->volt_scale = vp_forceupdate_scale_voltage; + vdd->vp_enabled = false; ++ /* Init the plist */ ++ spin_lock_init(&vdd->user_lock); ++ plist_head_init(&vdd->user_list, &vdd->user_lock); ++ /* Init the DVFS mutex */ ++ mutex_init(&vdd->scaling_mutex); + + /* VC parameters */ + vdd->vc_reg.prm_mod = OMAP3430_GR_MOD; +@@ -1059,6 +1088,11 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd) + vdd->write_reg = omap4_voltage_write_reg; + vdd->volt_scale = vp_forceupdate_scale_voltage; + vdd->vp_enabled = false; ++ /* Init the plist */ ++ spin_lock_init(&vdd->user_lock); ++ plist_head_init(&vdd->user_list, &vdd->user_lock); ++ /* Init the DVFS mutex */ ++ mutex_init(&vdd->scaling_mutex); + + /* VC parameters */ + vdd->vc_reg.prm_mod = OMAP4430_PRM_DEVICE_INST; +@@ -1171,6 +1205,69 @@ unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm) + + return vdd->pmic_info->vsel_to_uv(curr_vsel); + } ++/** ++ * omap_voltage_add_request() - API to keep track of various requests to ++ * scale the VDD and returns the best possible ++ * voltage the VDD can be put to. ++ * @volt_domain: pointer to the voltage domain. ++ * @dev: the device pointer. ++ * @volt: the voltage which is requested by the device. ++ * ++ * This API is to be called before the actual voltage scaling is ++ * done to determine what is the best possible voltage the VDD can ++ * be put to. This API adds the device <dev> in the user list of the ++ * vdd <volt_domain> with <volt> as the requested voltage. The user list ++ * is a plist with the priority element absolute voltage values. ++ * The API then finds the maximum of all the requested voltages for ++ * the VDD and returns it back through <volt> pointer itself. ++ * Returns error value in case of any errors. ++ */ ++int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev, ++ unsigned long *volt) ++{ ++ struct omap_vdd_info *vdd; ++ struct omap_vdd_user_list *user; ++ struct plist_node *node; ++ int found = 0; ++ ++ if (!voltdm || IS_ERR(voltdm)) { ++ pr_warning("%s: VDD specified does not exist!\n", __func__); ++ return -EINVAL; ++ } ++ ++ vdd = container_of(voltdm, struct omap_vdd_info, voltdm); ++ ++ mutex_lock(&vdd->scaling_mutex); ++ ++ plist_for_each_entry(user, &vdd->user_list, node) { ++ if (user->dev == dev) { ++ found = 1; ++ break; ++ } ++ } ++ ++ if (!found) { ++ user = kzalloc(sizeof(struct omap_vdd_user_list), GFP_KERNEL); ++ if (!user) { ++ pr_err("%s: Unable to creat a new user for vdd_%s\n", ++ __func__, voltdm->name); ++ mutex_unlock(&vdd->scaling_mutex); ++ return -ENOMEM; ++ } ++ user->dev = dev; ++ } else { ++ plist_del(&user->node, &vdd->user_list); ++ } ++ ++ plist_node_init(&user->node, *volt); ++ plist_add(&user->node, &vdd->user_list); ++ node = plist_last(&vdd->user_list); ++ *volt = user->volt = node->prio; ++ ++ mutex_unlock(&vdd->scaling_mutex); ++ ++ return 0; ++} + + /** + * omap_vp_enable() - API to enable a particular VP +diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h +index 0ff1233..bd07eca 100644 +--- a/arch/arm/plat-omap/include/plat/voltage.h ++++ b/arch/arm/plat-omap/include/plat/voltage.h +@@ -132,6 +132,9 @@ int omap_voltage_register_pmic(struct voltagedomain *voltdm, + void omap_change_voltscale_method(struct voltagedomain *voltdm, + int voltscale_method); + int omap_voltage_late_init(void); ++int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev, ++ unsigned long *volt); ++ + #else + static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm, + struct omap_volt_pmic_info *pmic_info) {} +@@ -141,6 +144,11 @@ static inline int omap_voltage_late_init(void) + { + return -EINVAL; + } ++static inline int omap_voltage_add_request(struct voltagedomain *voltdm, ++ struct device *dev, unsigned long *volt) ++{ ++ return -EINVAL; ++} + #endif + + #endif +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0007-OMAP-Introduce-API-in-the-OPP-layer-to-find-the-opp-.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0007-OMAP-Introduce-API-in-the-OPP-layer-to-find-the-opp-.patch new file mode 100644 index 00000000..58842f25 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0007-OMAP-Introduce-API-in-the-OPP-layer-to-find-the-opp-.patch @@ -0,0 +1,82 @@ +From dac6c4c03140835b758e32c72eb004d379c35fec Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Fri, 29 Oct 2010 20:43:10 +0530 +Subject: [PATCH 07/20] OMAP: Introduce API in the OPP layer to find the opp entry corresponding to a voltage. + +This patch adds an API in the opp layer to get the opp table entry +corresponding to the voltage passed as the parameter. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + drivers/base/power/opp.c | 28 ++++++++++++++++++++++++++++ + include/linux/opp.h | 8 ++++++++ + 2 files changed, 36 insertions(+), 0 deletions(-) + +diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c +index 2bb9b4c..60b4478 100644 +--- a/drivers/base/power/opp.c ++++ b/drivers/base/power/opp.c +@@ -354,6 +354,34 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq) + } + + /** ++ * opp_find_voltage() - search for an exact voltage ++ * @dev: device pointer associated with the opp type ++ * @volt: voltage to search for ++ * ++ * Searches for exact match in the opp list and returns handle to the matching ++ * opp if found, else returns ERR_PTR in case of error and should be handled ++ * using IS_ERR. ++ */ ++struct opp *opp_find_voltage(struct device *dev, unsigned long volt) ++{ ++ struct device_opp *dev_opp; ++ struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); ++ ++ dev_opp = find_device_opp(dev); ++ if (IS_ERR(dev_opp)) ++ return opp; ++ ++ list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { ++ if (temp_opp->available && temp_opp->u_volt == volt) { ++ opp = temp_opp; ++ break; ++ } ++ } ++ ++ return opp; ++} ++ ++/** + * opp_add() - Add an OPP table from a table definitions + * @dev: device for which we do this operation + * @freq: Frequency in Hz for this OPP +diff --git a/include/linux/opp.h b/include/linux/opp.h +index 5449945..4977d5c 100644 +--- a/include/linux/opp.h ++++ b/include/linux/opp.h +@@ -34,6 +34,8 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq); + + struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq); + ++struct opp *opp_find_voltage(struct device *dev, unsigned long volt); ++ + int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt); + + int opp_enable(struct device *dev, unsigned long freq); +@@ -74,6 +76,12 @@ static inline struct opp *opp_find_freq_ceil(struct device *dev, + return ERR_PTR(-EINVAL); + } + ++static inline struct opp *opp_find_voltage(struct device *dev, ++ unsigned long volt) ++{ ++ return ERR_PTR(-EINVAL); ++} ++ + static inline int opp_add(struct device *dev, unsigned long freq, + unsigned long u_volt) + { +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0008-OMAP-Introduce-API-to-register-a-device-with-a-volta.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0008-OMAP-Introduce-API-to-register-a-device-with-a-volta.patch new file mode 100644 index 00000000..d00751d4 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0008-OMAP-Introduce-API-to-register-a-device-with-a-volta.patch @@ -0,0 +1,182 @@ +From 3fcad983e7df504ecb1d0db79e3fe2e3abc44850 Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Fri, 29 Oct 2010 20:43:24 +0530 +Subject: [PATCH 08/20] OMAP: Introduce API to register a device with a voltagedomain + +This patch adds an API in the voltage layer that +can be used during omap_device_build to register the built +device with the voltage domain. This API is to be typically called +only once per device during the device registeration. This approach +makes it easy during dvfs to scale all the devices associated with +a voltage domain and then scale the voltage domain. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/mach-omap2/voltage.c | 50 +++++++++++++++++++++++++++++ + arch/arm/plat-omap/include/plat/voltage.h | 7 +++- + arch/arm/plat-omap/omap_device.c | 12 +++++++ + 3 files changed, 68 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c +index 76c98c6..7381fa6 100644 +--- a/arch/arm/mach-omap2/voltage.c ++++ b/arch/arm/mach-omap2/voltage.c +@@ -134,6 +134,11 @@ struct omap_vdd_user_list { + u32 volt; + }; + ++struct omap_vdd_dev_list { ++ struct device *dev; ++ struct list_head node; ++}; ++ + /** + * omap_vdd_info - Per Voltage Domain info + * +@@ -153,6 +158,7 @@ struct omap_vdd_user_list { + * @user_list : the list head maintaining the various users. + * @scaling_mutex : the dvfs muutex. + * of this vdd with the voltage requested by each user. ++ * @dev_list : list of devices bwlonging to this voltage domain. + * @curr_volt : current voltage for this vdd. + * @ocp_mod : The prm module for accessing the prm irqstatus reg. + * @prm_irqst_reg : prm irqstatus register. +@@ -170,6 +176,7 @@ struct omap_vdd_info { + spinlock_t user_lock; + struct plist_head user_list; + struct mutex scaling_mutex; ++ struct list_head dev_list; + u32 curr_volt; + u16 ocp_mod; + u8 prm_irqst_reg; +@@ -1093,6 +1100,8 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd) + plist_head_init(&vdd->user_list, &vdd->user_lock); + /* Init the DVFS mutex */ + mutex_init(&vdd->scaling_mutex); ++ /* Init the device list */ ++ INIT_LIST_HEAD(&vdd->dev_list); + + /* VC parameters */ + vdd->vc_reg.prm_mod = OMAP4430_PRM_DEVICE_INST; +@@ -1269,6 +1278,40 @@ int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev, + return 0; + } + ++int omap_voltage_add_dev(struct voltagedomain *voltdm, struct device *dev) ++{ ++ struct omap_vdd_info *vdd; ++ struct omap_vdd_dev_list *temp_dev; ++ ++ if (!voltdm || IS_ERR(voltdm)) { ++ pr_warning("%s: VDD specified does not exist!\n", __func__); ++ return -EINVAL; ++ } ++ ++ vdd = container_of(voltdm, struct omap_vdd_info, voltdm); ++ ++ list_for_each_entry(temp_dev, &vdd->dev_list, node) { ++ if (temp_dev->dev == dev) { ++ dev_warn(dev, "%s: Device already added to vdee_%s\n", ++ __func__, voltdm->name); ++ return -EINVAL; ++ } ++ } ++ ++ temp_dev = kzalloc(sizeof(struct omap_vdd_dev_list), GFP_KERNEL); ++ if (!temp_dev) { ++ dev_err(dev, "%s: Unable to creat a new device for vdd_%s\n", ++ __func__, voltdm->name); ++ return -ENOMEM; ++ } ++ ++ temp_dev->dev = dev; ++ ++ list_add(&temp_dev->node, &vdd->dev_list); ++ ++ return 0; ++} ++ + /** + * omap_vp_enable() - API to enable a particular VP + * @voltdm: pointer to the VDD whose VP is to be enabled. +@@ -1649,6 +1692,8 @@ int __init omap_voltage_late_init(void) + */ + static int __init omap_voltage_early_init(void) + { ++ int i; ++ + if (cpu_is_omap34xx()) { + vdd_info = omap3_vdd_info; + nr_scalable_vdd = OMAP3_NR_SCALABLE_VDD; +@@ -1661,8 +1706,13 @@ static int __init omap_voltage_early_init(void) + vdd_data_configure = omap4_vdd_data_configure; + } else { + pr_warning("%s: voltage driver support not added\n", __func__); ++ return -EINVAL; + } + ++ /* Init the device list */ ++ for (i = 0; i < nr_scalable_vdd; i++) ++ INIT_LIST_HEAD(&(vdd_info[i].dev_list)); ++ + return 0; + } + core_initcall(omap_voltage_early_init); +diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h +index bd07eca..adbc6af 100644 +--- a/arch/arm/plat-omap/include/plat/voltage.h ++++ b/arch/arm/plat-omap/include/plat/voltage.h +@@ -134,7 +134,7 @@ void omap_change_voltscale_method(struct voltagedomain *voltdm, + int omap_voltage_late_init(void); + int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev, + unsigned long *volt); +- ++int omap_voltage_add_dev(struct voltagedomain *voltdm, struct device *dev); + #else + static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm, + struct omap_volt_pmic_info *pmic_info) {} +@@ -149,6 +149,11 @@ static inline int omap_voltage_add_request(struct voltagedomain *voltdm, + { + return -EINVAL; + } ++static inline int omap_voltage_add_dev(struct voltagedomain *voltdm, ++ struct device *dev) ++{ ++ return -EINVAL; ++} + #endif + + #endif +diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c +index 57adb27..2c95e61 100644 +--- a/arch/arm/plat-omap/omap_device.c ++++ b/arch/arm/plat-omap/omap_device.c +@@ -86,6 +86,7 @@ + + #include <plat/omap_device.h> + #include <plat/omap_hwmod.h> ++#include <plat/voltage.h> + + /* These parameters are passed to _omap_device_{de,}activate() */ + #define USE_WAKEUP_LAT 0 +@@ -481,6 +482,17 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id, + for (i = 0; i < oh_cnt; i++) { + hwmods[i]->od = od; + _add_optional_clock_alias(od, hwmods[i]); ++ if (hwmods[i]->vdd_name) { ++ struct omap_hwmod *oh = hwmods[i]; ++ struct voltagedomain *voltdm; ++ ++ if (is_early_device) ++ continue; ++ ++ voltdm = omap_voltage_domain_lookup(oh->vdd_name); ++ if (!omap_voltage_add_dev(voltdm, &od->pdev.dev)) ++ oh->voltdm = voltdm; ++ } + } + + if (ret) +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0009-OMAP-Introduce-device-specific-set-rate-and-get-rate.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0009-OMAP-Introduce-device-specific-set-rate-and-get-rate.patch new file mode 100644 index 00000000..f5914aa3 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0009-OMAP-Introduce-device-specific-set-rate-and-get-rate.patch @@ -0,0 +1,120 @@ +From 6ec7cf889c9a8ddf97fbbcbda4888b0f17930e04 Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Fri, 29 Oct 2010 20:43:29 +0530 +Subject: [PATCH 09/20] OMAP: Introduce device specific set rate and get rate in omap_device structure + +This patch extends the omap_device structure to contain +pointers to scale the operating rate of the +device and to retrieve the operating rate of the device. +This patch also adds the three new APIs in the omap device layer +namely omap_device_set_rate that can be called to set a new operating +rate for a device, omap_device_get_rate that can be called to retrieve +the operating frequency for a device and omap_device_populate_rate_fns +to populte the device specific set_rate and get_rate API's. +The omap_device_set_rate and omap_device_get_rate does some routine error +checks and finally calls into the device specific set_rate +and get_rate APIs populated through omap_device_populate_rate_fns. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/plat-omap/include/plat/omap_device.h | 9 +++++ + arch/arm/plat-omap/omap_device.c | 49 +++++++++++++++++++++++++ + 2 files changed, 58 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h +index e4c349f..1178b86 100644 +--- a/arch/arm/plat-omap/include/plat/omap_device.h ++++ b/arch/arm/plat-omap/include/plat/omap_device.h +@@ -50,6 +50,8 @@ extern struct device omap_device_parent; + * @hwmods: (one .. many per omap_device) + * @hwmods_cnt: ARRAY_SIZE() of @hwmods + * @pm_lats: ptr to an omap_device_pm_latency table ++ * @set_rate: fn ptr to change the operating rate. ++ * @get_rate: fn ptr to retrieve the current operating rate. + * @pm_lats_cnt: ARRAY_SIZE() of what is passed to @pm_lats + * @pm_lat_level: array index of the last odpl entry executed - -1 if never + * @dev_wakeup_lat: dev wakeup latency in nanoseconds +@@ -67,6 +69,8 @@ struct omap_device { + struct platform_device pdev; + struct omap_hwmod **hwmods; + struct omap_device_pm_latency *pm_lats; ++ int (*set_rate)(struct device *dev, unsigned long rate); ++ unsigned long (*get_rate) (struct device *dev); + u32 dev_wakeup_lat; + u32 _dev_wakeup_lat_limit; + u8 pm_lats_cnt; +@@ -108,6 +112,11 @@ int omap_device_align_pm_lat(struct platform_device *pdev, + u32 new_wakeup_lat_limit); + struct powerdomain *omap_device_get_pwrdm(struct omap_device *od); + u32 omap_device_get_context_loss_count(struct platform_device *pdev); ++int omap_device_set_rate(struct device *dev, unsigned long freq); ++unsigned long omap_device_get_rate(struct device *dev); ++void omap_device_populate_rate_fns(struct device *dev, ++ int (*set_rate)(struct device *dev, unsigned long rate), ++ unsigned long (*get_rate) (struct device *dev)); + + /* Other */ + +diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c +index 2c95e61..0d67af6 100644 +--- a/arch/arm/plat-omap/omap_device.c ++++ b/arch/arm/plat-omap/omap_device.c +@@ -813,6 +813,55 @@ int omap_device_enable_clocks(struct omap_device *od) + return 0; + } + ++int omap_device_set_rate(struct device *dev, unsigned long freq) ++{ ++ struct platform_device *pdev; ++ struct omap_device *od; ++ ++ pdev = container_of(dev, struct platform_device, dev); ++ od = _find_by_pdev(pdev); ++ ++ if (!od->set_rate) { ++ dev_err(dev, "%s: No set_rate API for scaling device\n", ++ __func__); ++ return -ENODATA; ++ } ++ ++ return od->set_rate(dev, freq); ++} ++ ++unsigned long omap_device_get_rate(struct device *dev) ++{ ++ struct platform_device *pdev; ++ struct omap_device *od; ++ ++ pdev = container_of(dev, struct platform_device, dev); ++ od = _find_by_pdev(pdev); ++ ++ ++ if (!od->get_rate) { ++ dev_err(dev, "%s: No get rate API for the device\n", ++ __func__); ++ return 0; ++ } ++ ++ return od->get_rate(dev); ++} ++ ++void omap_device_populate_rate_fns(struct device *dev, ++ int (*set_rate)(struct device *dev, unsigned long rate), ++ unsigned long (*get_rate) (struct device *dev)) ++{ ++ struct platform_device *pdev; ++ struct omap_device *od; ++ ++ pdev = container_of(dev, struct platform_device, dev); ++ od = _find_by_pdev(pdev); ++ ++ od->set_rate = set_rate; ++ od->get_rate = get_rate; ++} ++ + struct device omap_device_parent = { + .init_name = "omap", + .parent = &platform_bus, +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0010-OMAP-Voltage-layer-changes-to-support-DVFS.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0010-OMAP-Voltage-layer-changes-to-support-DVFS.patch new file mode 100644 index 00000000..ead9cbba --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0010-OMAP-Voltage-layer-changes-to-support-DVFS.patch @@ -0,0 +1,134 @@ +From 96ee5b07e3162056169689b363f4c0edae7d7303 Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Fri, 29 Oct 2010 20:43:34 +0530 +Subject: [PATCH 10/20] OMAP: Voltage layer changes to support DVFS. + +This patch introduces an API to take in the voltage domain and the +new voltage as parameter and to scale all the scalable devices +associated with the the voltage domain to the rate corresponding to the +new voltage and scale the voltage domain to the new voltage. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/mach-omap2/voltage.c | 69 +++++++++++++++++++++++++++++ + arch/arm/plat-omap/include/plat/voltage.h | 7 +++ + 2 files changed, 76 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c +index 7381fa6..9adf9d1 100644 +--- a/arch/arm/mach-omap2/voltage.c ++++ b/arch/arm/mach-omap2/voltage.c +@@ -27,9 +27,11 @@ + #include <linux/spinlock.h> + #include <linux/plist.h> + #include <linux/slab.h> ++#include <linux/opp.h> + + #include <plat/common.h> + #include <plat/voltage.h> ++#include <plat/omap_device.h> + + #include "prm-regbits-34xx.h" + #include "prm-regbits-44xx.h" +@@ -1656,6 +1658,73 @@ struct voltagedomain *omap_voltage_domain_lookup(char *name) + } + + /** ++ * omap_voltage_scale : API to scale the devices associated with a ++ * voltage domain vdd voltage. ++ * @volt_domain : the voltage domain to be scaled ++ * @volt : the new voltage for the voltage domain ++ * ++ * This API runs through the list of devices associated with the ++ * voltage domain and scales the device rates to those corresponding ++ * to the new voltage of the voltage domain. This API also scales ++ * the voltage domain voltage to the new value. Returns 0 on success ++ * else the error value. ++ */ ++int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt) ++{ ++ unsigned long curr_volt; ++ int is_volt_scaled = 0; ++ struct omap_vdd_info *vdd; ++ struct omap_vdd_dev_list *temp_dev; ++ ++ if (!voltdm || IS_ERR(voltdm)) { ++ pr_warning("%s: VDD specified does not exist!\n", __func__); ++ return -EINVAL; ++ } ++ ++ vdd = container_of(voltdm, struct omap_vdd_info, voltdm); ++ ++ mutex_lock(&vdd->scaling_mutex); ++ ++ curr_volt = omap_voltage_get_nom_volt(voltdm); ++ ++ if (curr_volt == volt) { ++ is_volt_scaled = 1; ++ } else if (curr_volt < volt) { ++ omap_voltage_scale_vdd(voltdm, volt); ++ is_volt_scaled = 1; ++ } ++ ++ list_for_each_entry(temp_dev, &vdd->dev_list, node) { ++ struct device *dev; ++ struct opp *opp; ++ unsigned long freq; ++ ++ dev = temp_dev->dev; ++ ++ opp = opp_find_voltage(dev, volt); ++ if (IS_ERR(opp)) ++ continue; ++ ++ freq = opp_get_freq(opp); ++ ++ if (freq == omap_device_get_rate(dev)) { ++ dev_warn(dev, "%s: Already at the requested" ++ "rate %ld\n", __func__, freq); ++ continue; ++ } ++ ++ omap_device_set_rate(dev, freq); ++ } ++ ++ if (!is_volt_scaled) ++ omap_voltage_scale_vdd(voltdm, volt); ++ ++ mutex_unlock(&vdd->scaling_mutex); ++ ++ return 0; ++} ++ ++/** + * omap_voltage_late_init() - Init the various voltage parameters + * + * This API is to be called in the later stages of the +diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h +index adbc6af..6782c5e 100644 +--- a/arch/arm/plat-omap/include/plat/voltage.h ++++ b/arch/arm/plat-omap/include/plat/voltage.h +@@ -135,6 +135,7 @@ int omap_voltage_late_init(void); + int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev, + unsigned long *volt); + int omap_voltage_add_dev(struct voltagedomain *voltdm, struct device *dev); ++int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt); + #else + static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm, + struct omap_volt_pmic_info *pmic_info) {} +@@ -154,6 +155,12 @@ static inline int omap_voltage_add_dev(struct voltagedomain *voltdm, + { + return -EINVAL; + } ++ ++static inline int omap_voltage_scale(struct voltagedomain *voltdm, ++ unsigned long volt) ++{ ++ return -EINVAL; ++} + #endif + + #endif +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0011-OMAP-Introduce-dependent-voltage-domain-support.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0011-OMAP-Introduce-dependent-voltage-domain-support.patch new file mode 100644 index 00000000..6c4ca2ab --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0011-OMAP-Introduce-dependent-voltage-domain-support.patch @@ -0,0 +1,195 @@ +From b1b41c78d5a19260605fcb259a51ca7cd71c097a Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Fri, 2 Jul 2010 13:06:57 +0530 +Subject: [PATCH 11/20] OMAP: Introduce dependent voltage domain support. + +There could be dependencies between various voltage domains for +maintaining system performance or hardware limitation reasons +like VDD<X> should be at voltage v1 when VDD<Y> is at voltage v2. +This patch introduce dependent vdd information structures in the +voltage layer which can be used to populate these dependencies +for a voltage domain. This patch also adds support to scale +the dependent vdd and the scalable devices belonging to it +during the scaling of a main vdd through omap_voltage_scale. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/mach-omap2/voltage.c | 122 +++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 122 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c +index 9adf9d1..c83d968 100644 +--- a/arch/arm/mach-omap2/voltage.c ++++ b/arch/arm/mach-omap2/voltage.c +@@ -123,6 +123,36 @@ struct vc_reg_info { + }; + + /** ++ * omap_vdd_dep_volt - Table containing the parent vdd voltage and the ++ * dependent vdd voltage corresponding to it. ++ * ++ * @main_vdd_volt : The main vdd voltage ++ * @dep_vdd_volt : The voltage at which the dependent vdd should be ++ * when the main vdd is at <main_vdd_volt> voltage ++ */ ++struct omap_vdd_dep_volt { ++ u32 main_vdd_volt; ++ u32 dep_vdd_volt; ++}; ++ ++/** ++ * omap_vdd_dep_info - Dependent vdd info ++ * ++ * @name : Dependent vdd name ++ * @voltdm : Dependent vdd pointer ++ * @dep_table : Table containing the dependent vdd voltage ++ * corresponding to every main vdd voltage. ++ * @cur_dep_volt : The voltage to which dependent vdd should be put ++ * to for the current main vdd voltage. ++ */ ++struct omap_vdd_dep_info { ++ char *name; ++ struct voltagedomain *voltdm; ++ struct omap_vdd_dep_volt *dep_table; ++ unsigned long cur_dep_volt; ++}; ++ ++/** + * struct omap_vdd_user_list - The per vdd user list + * + * @dev: The device asking for the vdd to be set at a particular +@@ -174,11 +204,13 @@ struct omap_vdd_info { + struct vp_reg_val vp_reg; + struct vc_reg_info vc_reg; + struct voltagedomain voltdm; ++ struct omap_vdd_dep_info *dep_vdd_info; + struct dentry *debug_dir; + spinlock_t user_lock; + struct plist_head user_list; + struct mutex scaling_mutex; + struct list_head dev_list; ++ int nr_dep_vdd; + u32 curr_volt; + u16 ocp_mod; + u8 prm_irqst_reg; +@@ -1160,6 +1192,80 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd) + return 0; + } + ++static int calc_dep_vdd_volt(struct device *dev, ++ struct omap_vdd_info *main_vdd, unsigned long main_volt) ++{ ++ struct omap_vdd_dep_info *dep_vdds; ++ int i, ret = 0; ++ ++ if (!main_vdd->dep_vdd_info) { ++ pr_debug("%s: No dependent VDD's for vdd_%s\n", ++ __func__, main_vdd->voltdm.name); ++ return 0; ++ } ++ ++ dep_vdds = main_vdd->dep_vdd_info; ++ ++ for (i = 0; i < main_vdd->nr_dep_vdd; i++) { ++ struct omap_vdd_dep_volt *volt_table = dep_vdds[i].dep_table; ++ int nr_volt = 0; ++ unsigned long dep_volt = 0, act_volt = 0; ++ ++ while (volt_table[nr_volt].main_vdd_volt != 0) { ++ if (volt_table[nr_volt].main_vdd_volt == main_volt) { ++ dep_volt = volt_table[nr_volt].dep_vdd_volt; ++ break; ++ } ++ nr_volt++; ++ } ++ if (!dep_volt) { ++ pr_warning("%s: Not able to find a matching volt for" ++ "vdd_%s corresponding to vdd_%s %ld volt\n", ++ __func__, dep_vdds[i].name, ++ main_vdd->voltdm.name, main_volt); ++ ret = -EINVAL; ++ continue; ++ } ++ ++ if (!dep_vdds[i].voltdm) ++ dep_vdds[i].voltdm = ++ omap_voltage_domain_lookup(dep_vdds[i].name); ++ ++ act_volt = dep_volt; ++ ++ /* See if dep_volt is possible for the vdd*/ ++ ret = omap_voltage_add_request(dep_vdds[i].voltdm, dev, ++ &act_volt); ++ ++ /* ++ * Currently we do not bother if the dep volt and act volt are ++ * different. We could add a check if needed. ++ */ ++ dep_vdds[i].cur_dep_volt = act_volt; ++ } ++ ++ return ret; ++} ++ ++static int scale_dep_vdd(struct omap_vdd_info *main_vdd) ++{ ++ struct omap_vdd_dep_info *dep_vdds; ++ int i; ++ ++ if (!main_vdd->dep_vdd_info) { ++ pr_debug("%s: No dependent VDD's for vdd_%s\n", ++ __func__, main_vdd->voltdm.name); ++ return 0; ++ } ++ ++ dep_vdds = main_vdd->dep_vdd_info; ++ ++ for (i = 0; i < main_vdd->nr_dep_vdd; i++) ++ omap_voltage_scale(dep_vdds[i].voltdm, ++ dep_vdds[i].cur_dep_volt); ++ return 0; ++} ++ + /* Public functions */ + /** + * omap_voltage_get_nom_volt() - Gets the current non-auto-compensated voltage +@@ -1675,6 +1781,8 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt) + int is_volt_scaled = 0; + struct omap_vdd_info *vdd; + struct omap_vdd_dev_list *temp_dev; ++ struct plist_node *node; ++ struct omap_vdd_user_list *user; + + if (!voltdm || IS_ERR(voltdm)) { + pr_warning("%s: VDD specified does not exist!\n", __func__); +@@ -1687,6 +1795,17 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt) + + curr_volt = omap_voltage_get_nom_volt(voltdm); + ++ /* Find the device requesting the voltage scaling */ ++ node = plist_first(&vdd->user_list); ++ user = container_of(node, struct omap_vdd_user_list, node); ++ ++ /* calculate the voltages for dependent vdd's */ ++ if (calc_dep_vdd_volt(user->dev, vdd, volt)) { ++ pr_warning("%s: Error in calculating dependent vdd voltages" ++ "for vdd_%s\n", __func__, voltdm->name); ++ return -EINVAL; ++ } ++ + if (curr_volt == volt) { + is_volt_scaled = 1; + } else if (curr_volt < volt) { +@@ -1721,6 +1840,9 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt) + + mutex_unlock(&vdd->scaling_mutex); + ++ /* Scale dependent vdds */ ++ scale_dep_vdd(vdd); ++ + return 0; + } + +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0012-OMAP-Introduce-device-scale.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0012-OMAP-Introduce-device-scale.patch new file mode 100644 index 00000000..a6d35bd6 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0012-OMAP-Introduce-device-scale.patch @@ -0,0 +1,134 @@ +From b461bd17384c73bbb243c54bf1d6466c94e594c3 Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Fri, 2 Jul 2010 13:07:35 +0530 +Subject: [PATCH 12/20] OMAP: Introduce device scale + +This patch adds omap_device_scale API which can be used to generic +device rate scaling. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/plat-omap/include/plat/omap_device.h | 3 +- + arch/arm/plat-omap/omap_device.c | 78 +++++++++++++++++++++++++ + 2 files changed, 80 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h +index 1178b86..e44a0f7 100644 +--- a/arch/arm/plat-omap/include/plat/omap_device.h ++++ b/arch/arm/plat-omap/include/plat/omap_device.h +@@ -117,6 +117,8 @@ unsigned long omap_device_get_rate(struct device *dev); + void omap_device_populate_rate_fns(struct device *dev, + int (*set_rate)(struct device *dev, unsigned long rate), + unsigned long (*get_rate) (struct device *dev)); ++int omap_device_scale(struct device *req_dev, struct device *dev, ++ unsigned long rate); + + /* Other */ + +@@ -126,7 +128,6 @@ int omap_device_enable_hwmods(struct omap_device *od); + int omap_device_disable_clocks(struct omap_device *od); + int omap_device_enable_clocks(struct omap_device *od); + +- + /* + * Entries should be kept in latency order ascending + * +diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c +index 0d67af6..458d648 100644 +--- a/arch/arm/plat-omap/omap_device.c ++++ b/arch/arm/plat-omap/omap_device.c +@@ -83,6 +83,7 @@ + #include <linux/err.h> + #include <linux/io.h> + #include <linux/clk.h> ++#include <linux/opp.h> + + #include <plat/omap_device.h> + #include <plat/omap_hwmod.h> +@@ -862,6 +863,83 @@ void omap_device_populate_rate_fns(struct device *dev, + od->get_rate = get_rate; + } + ++/** ++ * omap_device_scale() - Set a new rate at which the device is to operate ++ * @req_dev: pointer to the device requesting the scaling. ++ * @dev: pointer to the device that is to be scaled ++ * @rate: the rnew rate for the device. ++ * ++ * This API gets the device opp table associated with this device and ++ * tries putting the device to the requested rate and the voltage domain ++ * associated with the device to the voltage corresponding to the ++ * requested rate. Since multiple devices can be assocciated with a ++ * voltage domain this API finds out the possible voltage the ++ * voltage domain can enter and then decides on the final device ++ * rate. Return 0 on success else the error value ++ */ ++int omap_device_scale(struct device *req_dev, struct device *dev, ++ unsigned long rate) ++{ ++ struct opp *opp; ++ unsigned long volt, freq, min_freq, max_freq; ++ struct voltagedomain *voltdm; ++ struct platform_device *pdev; ++ struct omap_device *od; ++ int ret; ++ ++ pdev = container_of(dev, struct platform_device, dev); ++ od = _find_by_pdev(pdev); ++ ++ /* ++ * Figure out if the desired frquency lies between the ++ * maximum and minimum possible for the particular device ++ */ ++ min_freq = 0; ++ if (IS_ERR(opp_find_freq_ceil(dev, &min_freq))) { ++ dev_err(dev, "%s: Unable to find lowest opp\n", __func__); ++ return -ENODEV; ++ } ++ ++ max_freq = ULONG_MAX; ++ if (IS_ERR(opp_find_freq_floor(dev, &max_freq))) { ++ dev_err(dev, "%s: Unable to find highest opp\n", __func__); ++ return -ENODEV; ++ } ++ ++ if (rate < min_freq) ++ freq = min_freq; ++ else if (rate > max_freq) ++ freq = max_freq; ++ else ++ freq = rate; ++ ++ opp = opp_find_freq_ceil(dev, &freq); ++ if (IS_ERR(opp)) { ++ dev_err(dev, "%s: Unable to find OPP for freq%ld\n", ++ __func__, rate); ++ return -ENODEV; ++ } ++ ++ /* Get the voltage corresponding to the requested frequency */ ++ volt = opp_get_voltage(opp); ++ ++ /* ++ * Call into the voltage layer to get the final voltage possible ++ * for the voltage domain associated with the device. ++ */ ++ voltdm = od->hwmods[0]->voltdm; ++ ret = omap_voltage_add_request(voltdm, req_dev, &volt); ++ if (ret) { ++ dev_err(dev, "%s: Unable to get the final volt for scaling\n", ++ __func__); ++ return ret; ++ } ++ ++ /* Do the actual scaling */ ++ return omap_voltage_scale(voltdm, volt); ++} ++EXPORT_SYMBOL(omap_device_scale); ++ + struct device omap_device_parent = { + .init_name = "omap", + .parent = &platform_bus, +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0013-OMAP-Disable-smartreflex-across-DVFS.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0013-OMAP-Disable-smartreflex-across-DVFS.patch new file mode 100644 index 00000000..89384a8e --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0013-OMAP-Disable-smartreflex-across-DVFS.patch @@ -0,0 +1,50 @@ +From 4c68660aa69a5eaeaff7fda7e2297e2d31de0333 Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Fri, 2 Jul 2010 13:06:57 +0530 +Subject: [PATCH 13/20] OMAP: Disable smartreflex across DVFS + +This patch disables smartreflex for a particular voltage +domain when the the voltage domain and the devices belonging +to it is being scaled and re-enables it back once the scaling +is done. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/mach-omap2/voltage.c | 7 +++++++ + 1 files changed, 7 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c +index c83d968..2f331de 100644 +--- a/arch/arm/mach-omap2/voltage.c ++++ b/arch/arm/mach-omap2/voltage.c +@@ -32,6 +32,7 @@ + #include <plat/common.h> + #include <plat/voltage.h> + #include <plat/omap_device.h> ++#include <plat/smartreflex.h> + + #include "prm-regbits-34xx.h" + #include "prm-regbits-44xx.h" +@@ -1806,6 +1807,9 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt) + return -EINVAL; + } + ++ /* Disable smartreflex module across voltage and frequency scaling */ ++ omap_sr_disable(voltdm); ++ + if (curr_volt == volt) { + is_volt_scaled = 1; + } else if (curr_volt < volt) { +@@ -1840,6 +1844,9 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt) + + mutex_unlock(&vdd->scaling_mutex); + ++ /* Enable Smartreflex module */ ++ omap_sr_enable(voltdm); ++ + /* Scale dependent vdds */ + scale_dep_vdd(vdd); + +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0014-OMAP3-Introduce-custom-set-rate-and-get-rate-APIs-fo.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0014-OMAP3-Introduce-custom-set-rate-and-get-rate-APIs-fo.patch new file mode 100644 index 00000000..16335ccb --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0014-OMAP3-Introduce-custom-set-rate-and-get-rate-APIs-fo.patch @@ -0,0 +1,176 @@ +From 6fb7bd2b3da02e6e799d3c7661a1acb6572f9add Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Wed, 18 Aug 2010 16:22:32 +0530 +Subject: [PATCH 14/20] OMAP3: Introduce custom set rate and get rate APIs for scalable devices + +This patch also introduces omap3_mpu_set_rate, omap3_iva_set_rate, +omap3_l3_set_rate, omap3_mpu_get_rate, omap3_iva_get_rate, +omap3_l3_get_rate as device specific set rate and get rate +APIs for OMAP3 mpu, iva and l3_main devices. This patch also +calls into omap_device_populate_rate_fns during system init to register +various set_rate and get_rate APIs with the omap device layer + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/mach-omap2/pm.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 110 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c +index d5a102c..94ab0dd 100644 +--- a/arch/arm/mach-omap2/pm.c ++++ b/arch/arm/mach-omap2/pm.c +@@ -14,6 +14,7 @@ + #include <linux/io.h> + #include <linux/err.h> + #include <linux/opp.h> ++#include <linux/delay.h> + + #include <plat/omap-pm.h> + #include <plat/omap_device.h> +@@ -22,6 +23,8 @@ + + #include "powerdomain.h" + #include "clockdomain.h" ++#include "cm-regbits-34xx.h" ++#include "cm2xxx_3xxx.h" + #include "pm.h" + + static struct omap_device_pm_latency *pm_lats; +@@ -31,6 +34,8 @@ static struct device *iva_dev; + static struct device *l3_dev; + static struct device *dsp_dev; + ++static struct clk *dpll1_clk, *dpll2_clk, *dpll3_clk; ++ + struct device *omap2_get_mpuss_device(void) + { + WARN_ON_ONCE(!mpu_dev); +@@ -56,6 +61,26 @@ struct device *omap4_get_dsp_device(void) + } + EXPORT_SYMBOL(omap4_get_dsp_device); + ++static unsigned long compute_lpj(unsigned long ref, u_int div, u_int mult) ++{ ++ unsigned long new_jiffy_l, new_jiffy_h; ++ ++ /* ++ * Recalculate loops_per_jiffy. We do it this way to ++ * avoid math overflow on 32-bit machines. Maybe we ++ * should make this architecture dependent? If you have ++ * a better way of doing this, please replace! ++ * ++ * new = old * mult / div ++ */ ++ new_jiffy_h = ref / div; ++ new_jiffy_l = (ref % div) / 100; ++ new_jiffy_h *= mult; ++ new_jiffy_l = new_jiffy_l * mult / div; ++ ++ return new_jiffy_h + new_jiffy_l * 100; ++} ++ + /* static int _init_omap_device(struct omap_hwmod *oh, void *user) */ + static int _init_omap_device(char *name, struct device **new_dev) + { +@@ -77,6 +102,74 @@ static int _init_omap_device(char *name, struct device **new_dev) + return 0; + } + ++static unsigned long omap3_mpu_get_rate(struct device *dev) ++{ ++ return dpll1_clk->rate; ++} ++ ++static int omap3_mpu_set_rate(struct device *dev, unsigned long rate) ++{ ++ unsigned long cur_rate = omap3_mpu_get_rate(dev); ++ int ret; ++ ++#ifdef CONFIG_CPU_FREQ ++ struct cpufreq_freqs freqs_notify; ++ ++ freqs_notify.old = cur_rate / 1000; ++ freqs_notify.new = rate / 1000; ++ freqs_notify.cpu = 0; ++ /* Send pre notification to CPUFreq */ ++ cpufreq_notify_transition(&freqs_notify, CPUFREQ_PRECHANGE); ++#endif ++ ret = clk_set_rate(dpll1_clk, rate); ++ if (ret) { ++ dev_warn(dev, "%s: Unable to set rate to %ld\n", ++ __func__, rate); ++ return ret; ++ } ++ ++#ifdef CONFIG_CPU_FREQ ++ /* Send a post notification to CPUFreq */ ++ cpufreq_notify_transition(&freqs_notify, CPUFREQ_POSTCHANGE); ++#endif ++ ++#ifndef CONFIG_CPU_FREQ ++ /*Update loops_per_jiffy if processor speed is being changed*/ ++ loops_per_jiffy = compute_lpj(loops_per_jiffy, ++ cur_rate / 1000, rate / 1000); ++#endif ++ return 0; ++} ++ ++static int omap3_iva_set_rate(struct device *dev, unsigned long rate) ++{ ++ return clk_set_rate(dpll2_clk, rate); ++} ++ ++static unsigned long omap3_iva_get_rate(struct device *dev) ++{ ++ return dpll2_clk->rate; ++} ++ ++static int omap3_l3_set_rate(struct device *dev, unsigned long rate) ++{ ++ int l3_div; ++ ++ l3_div = omap2_cm_read_mod_reg(CORE_MOD, CM_CLKSEL) & ++ OMAP3430_CLKSEL_L3_MASK; ++ ++ return clk_set_rate(dpll3_clk, rate * l3_div); ++} ++ ++static unsigned long omap3_l3_get_rate(struct device *dev) ++{ ++ int l3_div; ++ ++ l3_div = omap2_cm_read_mod_reg(CORE_MOD, CM_CLKSEL) & ++ OMAP3430_CLKSEL_L3_MASK; ++ return dpll3_clk->rate / l3_div; ++} ++ + /* + * Build omap_devices for processors and bus. + */ +@@ -90,6 +183,23 @@ static void omap2_init_processor_devices(void) + } else { + _init_omap_device("l3_main", &l3_dev); + } ++ ++ if (cpu_is_omap34xx()) { ++ dpll1_clk = clk_get(NULL, "dpll1_ck"); ++ dpll2_clk = clk_get(NULL, "dpll2_ck"); ++ dpll3_clk = clk_get(NULL, "dpll3_m2_ck"); ++ ++ if (mpu_dev) ++ omap_device_populate_rate_fns(mpu_dev, ++ omap3_mpu_set_rate, omap3_mpu_get_rate); ++ if (iva_dev) ++ omap_device_populate_rate_fns(iva_dev, ++ omap3_iva_set_rate, omap3_iva_get_rate); ++ if (l3_dev) ++ omap_device_populate_rate_fns(l3_dev, ++ omap3_l3_set_rate, omap3_l3_get_rate); ++ ++ } + } + + /* Types of sleep_switch used in omap_set_pwrdm_state */ +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0015-OMAP3-Update-cpufreq-driver-to-use-the-new-set_rate-.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0015-OMAP3-Update-cpufreq-driver-to-use-the-new-set_rate-.patch new file mode 100644 index 00000000..4b9ff5d8 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0015-OMAP3-Update-cpufreq-driver-to-use-the-new-set_rate-.patch @@ -0,0 +1,54 @@ +From d8fae1dcedb636a37096ee92e6b81b112d5f32a5 Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Fri, 2 Jul 2010 13:07:49 +0530 +Subject: [PATCH 15/20] OMAP3: Update cpufreq driver to use the new set_rate API + +This patch updates the cpufreq driver to use the device +set rate API to scale the mpu frequency for OMAP3. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/plat-omap/cpu-omap.c | 11 ++++------- + 1 files changed, 4 insertions(+), 7 deletions(-) + +diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c +index 671e4b9..71777db 100644 +--- a/arch/arm/plat-omap/cpu-omap.c ++++ b/arch/arm/plat-omap/cpu-omap.c +@@ -31,10 +31,7 @@ + #include <plat/clock.h> + #include <plat/common.h> + #include <asm/system.h> +- +-#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) +-#include <plat/omap-pm.h> +-#endif ++#include <plat/omap_device.h> + + #define VERY_HI_RATE 900000000 + +@@ -88,7 +85,7 @@ static int omap_target(struct cpufreq_policy *policy, + #ifdef CONFIG_ARCH_OMAP1 + struct cpufreq_freqs freqs; + #endif +-#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++#if defined(CONFIG_ARCH_OMAP3) + unsigned long freq; + struct device *mpu_dev = omap2_get_mpuss_device(); + #endif +@@ -115,10 +112,10 @@ static int omap_target(struct cpufreq_policy *policy, + #endif + ret = clk_set_rate(mpu_clk, freqs.new * 1000); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +-#elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++#elif defined(CONFIG_ARCH_OMAP3) + freq = target_freq * 1000; + if (opp_find_freq_ceil(mpu_dev, &freq)) +- omap_pm_cpu_set_freq(freq); ++ omap_device_scale(mpu_dev, mpu_dev, freq); + #endif + return ret; + } +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0016-OMAP3-Introduce-voltage-domain-info-in-the-hwmod-str.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0016-OMAP3-Introduce-voltage-domain-info-in-the-hwmod-str.patch new file mode 100644 index 00000000..fe856527 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0016-OMAP3-Introduce-voltage-domain-info-in-the-hwmod-str.patch @@ -0,0 +1,45 @@ +From b54b316174e1d59a820e68c45c4abfc1336d8e09 Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Wed, 18 Aug 2010 16:22:43 +0530 +Subject: [PATCH 16/20] OMAP3: Introduce voltage domain info in the hwmod structures. + +This patch adds voltage domain info in the relevant +device hwmod structures so as to enable OMAP3 DVFS +support. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +index 8d81813..c57f34d 100644 +--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c ++++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +@@ -94,6 +94,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_l3_main_masters[] = { + static struct omap_hwmod omap3xxx_l3_main_hwmod = { + .name = "l3_main", + .class = &l3_hwmod_class, ++ .vdd_name = "core", + .masters = omap3xxx_l3_main_masters, + .masters_cnt = ARRAY_SIZE(omap3xxx_l3_main_masters), + .slaves = omap3xxx_l3_main_slaves, +@@ -384,6 +385,7 @@ static struct omap_hwmod omap3xxx_mpu_hwmod = { + .name = "mpu", + .class = &mpu_hwmod_class, + .main_clk = "arm_fck", ++ .vdd_name = "mpu", + .masters = omap3xxx_mpu_masters, + .masters_cnt = ARRAY_SIZE(omap3xxx_mpu_masters), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), +@@ -412,6 +414,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_iva_masters[] = { + static struct omap_hwmod omap3xxx_iva_hwmod = { + .name = "iva", + .class = &iva_hwmod_class, ++ .vdd_name = "mpu", + .masters = omap3xxx_iva_masters, + .masters_cnt = ARRAY_SIZE(omap3xxx_iva_masters), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0017-OMAP3-Add-voltage-dependency-table-for-VDD1.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0017-OMAP3-Add-voltage-dependency-table-for-VDD1.patch new file mode 100644 index 00000000..68999391 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0017-OMAP3-Add-voltage-dependency-table-for-VDD1.patch @@ -0,0 +1,61 @@ +From c196a4ac3941fb9af4654d5d028ad21f4b91d721 Mon Sep 17 00:00:00 2001 +From: Thara Gopinath <thara@ti.com> +Date: Wed, 18 Aug 2010 16:22:49 +0530 +Subject: [PATCH 17/20] OMAP3: Add voltage dependency table for VDD1. + +In OMAP3, for perfomrance reasons when VDD1 is at voltage above +1.075V, VDD2 should be at 1.15V for perfomrance reasons. This +patch introduce this cross VDD dependency for OMAP3 VDD1. + +Signed-off-by: Thara Gopinath <thara@ti.com> +--- + arch/arm/mach-omap2/voltage.c | 24 ++++++++++++++++++++++-- + 1 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c +index 2f331de..d10cb1b 100644 +--- a/arch/arm/mach-omap2/voltage.c ++++ b/arch/arm/mach-omap2/voltage.c +@@ -374,6 +374,23 @@ static struct omap_volt_data omap44xx_vdd_core_volt_data[] = { + VOLT_DATA_DEFINE(0, 0, 0, 0), + }; + ++/* OMAP 3430 MPU Core VDD dependency table */ ++static struct omap_vdd_dep_volt omap34xx_vdd1_vdd2_data[] = { ++ {.main_vdd_volt = 975000, .dep_vdd_volt = 1050000}, ++ {.main_vdd_volt = 1075000, .dep_vdd_volt = 1050000}, ++ {.main_vdd_volt = 1200000, .dep_vdd_volt = 1150000}, ++ {.main_vdd_volt = 1270000, .dep_vdd_volt = 1150000}, ++ {.main_vdd_volt = 1350000, .dep_vdd_volt = 1150000}, ++ {.main_vdd_volt = 0, .dep_vdd_volt = 0}, ++}; ++ ++static struct omap_vdd_dep_info omap34xx_vdd1_dep_info[] = { ++ { ++ .name = "core", ++ .dep_table = omap34xx_vdd1_vdd2_data, ++ }, ++}; ++ + static struct dentry *voltage_dir; + + /* Init function pointers */ +@@ -879,10 +896,13 @@ static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd) + } + + if (!strcmp(vdd->voltdm.name, "mpu")) { +- if (cpu_is_omap3630()) ++ if (cpu_is_omap3630()) { + vdd->volt_data = omap36xx_vddmpu_volt_data; +- else ++ } else { + vdd->volt_data = omap34xx_vddmpu_volt_data; ++ vdd->dep_vdd_info = omap34xx_vdd1_dep_info; ++ vdd->nr_dep_vdd = ARRAY_SIZE(omap34xx_vdd1_dep_info); ++ } + + vdd->vp_reg.tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK; + vdd->vc_reg.cmdval_reg = OMAP3_PRM_VC_CMD_VAL_0_OFFSET; +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0018-omap3-4-opp-make-omapx_opp_init-non-static.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0018-omap3-4-opp-make-omapx_opp_init-non-static.patch new file mode 100644 index 00000000..e21fe964 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0018-omap3-4-opp-make-omapx_opp_init-non-static.patch @@ -0,0 +1,62 @@ +From 16c7667d2908631149ef38b7b6dd7b08d6d5502e Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Wed, 5 Jan 2011 14:14:55 -0600 +Subject: [PATCH 18/20] omap3|4: opp: make omapx_opp_init non-static + +omap3 and omap4 opp_init should be made non-static to allow +for platform specific opp table tweaking. making these static +conflicts with the definition in pm.h(global) as well. +we include pm.h as well to ensure that there are no such prototype +conflicts with actual implementation in the future. + +Signed-off-by: Nishanth Menon <nm@ti.com> +--- + arch/arm/mach-omap2/opp3xxx_data.c | 3 ++- + arch/arm/mach-omap2/opp4xxx_data.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c +index 0486fce..fd3a1af 100644 +--- a/arch/arm/mach-omap2/opp3xxx_data.c ++++ b/arch/arm/mach-omap2/opp3xxx_data.c +@@ -21,6 +21,7 @@ + #include <plat/cpu.h> + + #include "omap_opp_data.h" ++#include "pm.h" + + static struct omap_opp_def __initdata omap34xx_opp_def_list[] = { + /* MPU OPP1 */ +@@ -88,7 +89,7 @@ static struct omap_opp_def __initdata omap36xx_opp_def_list[] = { + /** + * omap3_opp_init() - initialize omap3 opp table + */ +-static int __init omap3_opp_init(void) ++int __init omap3_opp_init(void) + { + int r = -ENODEV; + +diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c +index a11fa56..f0e9939 100644 +--- a/arch/arm/mach-omap2/opp4xxx_data.c ++++ b/arch/arm/mach-omap2/opp4xxx_data.c +@@ -22,6 +22,7 @@ + #include <plat/cpu.h> + + #include "omap_opp_data.h" ++#include "pm.h" + + static struct omap_opp_def __initdata omap44xx_opp_def_list[] = { + /* MPU OPP1 - OPP50 */ +@@ -42,7 +43,7 @@ static struct omap_opp_def __initdata omap44xx_opp_def_list[] = { + /** + * omap4_opp_init() - initialize omap4 opp table + */ +-static int __init omap4_opp_init(void) ++int __init omap4_opp_init(void) + { + int r = -ENODEV; + +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0019-OMAP3-beagle-xm-enable-upto-1GHz-OPP.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0019-OMAP3-beagle-xm-enable-upto-1GHz-OPP.patch new file mode 100644 index 00000000..9d1fa917 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0019-OMAP3-beagle-xm-enable-upto-1GHz-OPP.patch @@ -0,0 +1,107 @@ +From 897e90138695dccac0dca1601542fd5f4c85b657 Mon Sep 17 00:00:00 2001 +From: Nishanth Menon <nm@ti.com> +Date: Wed, 5 Jan 2011 14:16:59 -0600 +Subject: [PATCH 19/20] OMAP3: beagle xm: enable upto 1GHz OPP + +Beagle XM uses 3730 and the board design allows enabling 800MHz and 1GHz +OPPs. tweak the default table to allow for higher OPP tables + +Reported-by: Koen Kooi <koen@beagleboard.org> +Signed-off-by: Nishanth Menon <nm@ti.com> +--- + arch/arm/mach-omap2/board-omap3beagle.c | 54 +++++++++++++++++++++++++++++++ + 1 files changed, 54 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c +index ad0c1d8..1e0870e 100644 +--- a/arch/arm/mach-omap2/board-omap3beagle.c ++++ b/arch/arm/mach-omap2/board-omap3beagle.c +@@ -24,6 +24,7 @@ + #include <linux/irq.h> + #include <linux/input.h> + #include <linux/gpio_keys.h> ++#include <linux/opp.h> + + #include <linux/mtd/mtd.h> + #include <linux/mtd/partitions.h> +@@ -45,10 +46,12 @@ + #include <plat/gpmc.h> + #include <plat/nand.h> + #include <plat/usb.h> ++#include <plat/omap_device.h> + + #include "mux.h" + #include "hsmmc.h" + #include "timer-gp.h" ++#include "pm.h" + + #define NAND_BLOCK_SIZE SZ_128K + +@@ -804,6 +807,56 @@ static int __init expansionboard_setup(char *str) + return 0; + } + ++static void __init beagle_opp_init(void) ++{ ++ int r = 0; ++ ++ /* Initialize the omap3 opp table */ ++ if (omap3_opp_init()) { ++ pr_err("%s: opp default init failed\n", __func__); ++ return; ++ } ++ ++ /* Custom OPP enabled for XM */ ++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) { ++ struct omap_hwmod *mh = omap_hwmod_lookup("mpu"); ++ struct omap_hwmod *dh = omap_hwmod_lookup("iva"); ++ struct device *dev; ++ ++ if (!mh || !dh) { ++ pr_err("%s: Aiee.. no mpu/dsp devices? %p %p\n", ++ __func__, mh, dh); ++ r = -EINVAL; ++ } else { ++ /* Enable MPU 1GHz and lower opps */ ++ dev = &mh->od->pdev.dev; ++ r = opp_enable(dev, 800000000); ++ r |= opp_enable(dev, 1000000000); ++ ++ /* Enable IVA 800MHz and lower opps */ ++ dev = &dh->od->pdev.dev; ++ r |= opp_enable(dev, 660000000); ++ r |= opp_enable(dev, 800000000); ++ } ++ if (r) { ++ pr_err("%s: failed to enable higher opp %d\n", ++ __func__, r); ++ /* ++ * Cleanup - disable the higher freqs - we dont care ++ * about the results ++ */ ++ dev = &mh->od->pdev.dev; ++ opp_disable(dev, 800000000); ++ opp_disable(dev, 1000000000); ++ dev = &dh->od->pdev.dev; ++ opp_disable(dev, 660000000); ++ opp_disable(dev, 800000000); ++ } else { ++ pr_err("%s: turbo OPPs enabled!\n", __func__); ++ } ++ } ++} ++ + static void __init omap3_beagle_init(void) + { + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); +@@ -876,6 +929,7 @@ static void __init omap3_beagle_init(void) + omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT); + + beagle_display_init(); ++ beagle_opp_init(); + } + + early_param("buddy", expansionboard_setup); +-- +1.6.6.1 + diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0020-omap3-Add-basic-support-for-720MHz-part.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0020-omap3-Add-basic-support-for-720MHz-part.patch new file mode 100644 index 00000000..107e1162 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0020-omap3-Add-basic-support-for-720MHz-part.patch @@ -0,0 +1,202 @@ +From bb655c594a2f77b17d0747116795f46e00d5ffcb Mon Sep 17 00:00:00 2001 +From: Sanjeev Premi <premi@ti.com> +Date: Tue, 18 Jan 2011 13:19:55 +0530 +Subject: [PATCH 20/20] omap3: Add basic support for 720MHz part + +This patch adds support for new speed enhanced parts with ARM +and IVA running at 720MHz and 520MHz respectively. These parts +can be probed at run-time by reading PRODID.SKUID[3:0] at +0x4830A20C [1]. + +This patch specifically does following: + * Detect devices capable of 720MHz. + * Add new OPP + * Ensure that OPP is conditionally enabled. + * Check for presence of IVA before attempting to enable + the corresponding OPP. + + [1] http://focus.ti.com/lit/ug/spruff1d/spruff1d.pdf + +Signed-off-by: Sanjeev Premi <premi@ti.com> +--- + arch/arm/mach-omap2/control.h | 7 ++++ + arch/arm/mach-omap2/id.c | 10 +++++ + arch/arm/mach-omap2/opp3xxx_data.c | 63 ++++++++++++++++++++++++++++++++- + arch/arm/plat-omap/include/plat/cpu.h | 2 + + 4 files changed, 81 insertions(+), 1 deletions(-) + +diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h +index f0629ae..eebc045 100644 +--- a/arch/arm/mach-omap2/control.h ++++ b/arch/arm/mach-omap2/control.h +@@ -365,6 +365,13 @@ + #define FEAT_NEON 0 + #define FEAT_NEON_NONE 1 + ++/* ++ * Product ID register ++ */ ++#define OMAP3_PRODID 0x020C ++ ++#define OMAP3_SKUID_MASK 0x0f ++#define OMAP3_SKUID_720MHZ 0x08 + + #ifndef __ASSEMBLY__ + #ifdef CONFIG_ARCH_OMAP2PLUS +diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c +index 5f9086c..53fbe01 100644 +--- a/arch/arm/mach-omap2/id.c ++++ b/arch/arm/mach-omap2/id.c +@@ -195,6 +195,15 @@ static void __init omap3_check_features(void) + * TODO: Get additional info (where applicable) + * e.g. Size of L2 cache. + */ ++ ++ /* ++ * Does it support 720MHz? ++ */ ++ status = (OMAP3_SKUID_MASK & read_tap_reg(OMAP3_PRODID)); ++ ++ if (status & OMAP3_SKUID_720MHZ) { ++ omap3_features |= OMAP3_HAS_720MHZ; ++ } + } + + static void __init omap3_check_revision(void) +@@ -445,6 +454,7 @@ static void __init omap3_cpuinfo(void) + OMAP3_SHOW_FEATURE(neon); + OMAP3_SHOW_FEATURE(isp); + OMAP3_SHOW_FEATURE(192mhz_clk); ++ OMAP3_SHOW_FEATURE(720mhz); + + printk(")\n"); + } +diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c +index fd3a1af..76d26c7 100644 +--- a/arch/arm/mach-omap2/opp3xxx_data.c ++++ b/arch/arm/mach-omap2/opp3xxx_data.c +@@ -17,8 +17,10 @@ + * GNU General Public License for more details. + */ + #include <linux/module.h> ++#include <linux/opp.h> + + #include <plat/cpu.h> ++#include <plat/omap_device.h> + + #include "omap_opp_data.h" + #include "pm.h" +@@ -34,6 +36,8 @@ static struct omap_opp_def __initdata omap34xx_opp_def_list[] = { + OPP_INITIALIZER("mpu", true, 550000000, 1270000), + /* MPU OPP5 */ + OPP_INITIALIZER("mpu", true, 600000000, 1350000), ++ /* MPU OPP6 */ ++ OPP_INITIALIZER("mpu", false, 720000000, 1350000), + + /* + * L3 OPP1 - 41.5 MHz is disabled because: The voltage for that OPP is +@@ -59,6 +63,8 @@ static struct omap_opp_def __initdata omap34xx_opp_def_list[] = { + OPP_INITIALIZER("iva", true, 400000000, 1270000), + /* DSP OPP5 */ + OPP_INITIALIZER("iva", true, 430000000, 1350000), ++ /* DSP OPP6 */ ++ OPP_INITIALIZER("iva", false, 520000000, 1350000), + }; + + static struct omap_opp_def __initdata omap36xx_opp_def_list[] = { +@@ -86,6 +92,57 @@ static struct omap_opp_def __initdata omap36xx_opp_def_list[] = { + OPP_INITIALIZER("iva", false, 800000000, 1375000), + }; + ++ ++/** ++ * omap3_opp_enable_720Mhz() - Enable the OPP corresponding to 720MHz ++ * ++ * This function would be executed only if the silicon is capable of ++ * running at the 720MHz. ++ */ ++static int __init omap3_opp_enable_720Mhz(void) ++{ ++ int r = -ENODEV; ++ struct omap_hwmod *oh_mpu = omap_hwmod_lookup("mpu"); ++ struct omap_hwmod *oh_iva; ++ struct platform_device *pdev; ++ ++ if (!oh_mpu || !oh_mpu->od) { ++ goto err; ++ } else { ++ pdev = &oh_mpu->od->pdev; ++ ++ r = opp_enable(&pdev->dev, 720000000); ++ if (r < 0) { ++ dev_err(&pdev->dev, ++ "opp_enable() failed for mpu@720MHz"); ++ goto err; ++ } ++ } ++ ++ if (omap3_has_iva()) { ++ oh_iva = omap_hwmod_lookup("iva"); ++ ++ if (!oh_iva || !oh_iva->od) { ++ r = -ENODEV; ++ goto err; ++ } else { ++ pdev = &oh_iva->od->pdev; ++ ++ r = opp_enable(&pdev->dev, 520000000); ++ if (r < 0) { ++ dev_err(&pdev->dev, ++ "opp_enable() failed for iva@520MHz"); ++ goto err; ++ } ++ } ++ } ++ ++ dev_info(&pdev->dev, "Enabled OPP corresponding to 720MHz\n"); ++ ++err: ++ return r; ++} ++ + /** + * omap3_opp_init() - initialize omap3 opp table + */ +@@ -99,10 +156,14 @@ int __init omap3_opp_init(void) + if (cpu_is_omap3630()) + r = omap_init_opp_table(omap36xx_opp_def_list, + ARRAY_SIZE(omap36xx_opp_def_list)); +- else ++ else { + r = omap_init_opp_table(omap34xx_opp_def_list, + ARRAY_SIZE(omap34xx_opp_def_list)); + ++ if (omap3_has_720mhz()) ++ r = omap3_opp_enable_720Mhz(); ++ } ++ + return r; + } + device_initcall(omap3_opp_init); +diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h +index 1a8c347..7d24faa 100644 +--- a/arch/arm/plat-omap/include/plat/cpu.h ++++ b/arch/arm/plat-omap/include/plat/cpu.h +@@ -510,6 +510,7 @@ extern u32 omap3_features; + #define OMAP3_HAS_ISP BIT(4) + #define OMAP3_HAS_192MHZ_CLK BIT(5) + #define OMAP3_HAS_IO_WAKEUP BIT(6) ++#define OMAP3_HAS_720MHZ BIT(7) + + #define OMAP3_HAS_FEATURE(feat,flag) \ + static inline unsigned int omap3_has_ ##feat(void) \ +@@ -524,5 +525,6 @@ OMAP3_HAS_FEATURE(neon, NEON) + OMAP3_HAS_FEATURE(isp, ISP) + OMAP3_HAS_FEATURE(192mhz_clk, 192MHZ_CLK) + OMAP3_HAS_FEATURE(io_wakeup, IO_WAKEUP) ++OMAP3_HAS_FEATURE(720mhz, 720MHZ) + + #endif +-- +1.6.6.1 + |