* [PATCH 0/9] OMAP3: PM: introduce support for 3630 OPPs @ 2009-11-12 5:45 Nishanth Menon 2009-11-12 5:45 ` [PATCH 1/9] omap3: pm: introduce enabled flag to omap_opp Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-12 5:45 UTC (permalink / raw) To: linux-omap; +Cc: Nishanth Menon Hi, This patch series is based on previous discussions: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg17632.html I have modified the initial patch From Sanjeev: http://patchwork.kernel.org/patch/50998/ Other than these, we cannot use the old VDDx_MAX based usage anymore as 3630 OPPs are now different and runtime handling is a must-have, hence introducing these accessor functions is not avoidable. The changes are incremental and tries to avoid intrusive change as much as possible. 3630 testing can only happen once the clock tree relevant changes are also pushed in.. but most of the relevant APIs have been exercised on 3430 itself as just the size of the OPP table varies b/w 3630 and 3430. The OPP accessor functions introduced in this series is hopefully a start for us to optimize this heavily used path. Finally, I have only done limited testing of SR, as it is still in my TODO list to revamp SR in the form of a v5 patch next time I get some bandwidth. An alternate approach for detecting 3630 OPP is using FEATURES instead of detecting the cpu_type as I have implemented in this series. Nishanth Menon (9): omap3: pm: introduce enabled flag to omap_opp omap3: pm: introduce opp accessor functions omap3: pm: srf: introduce accessor function omap3: pm: use opp accessor functions for omap-target omap3: pm: sr: replace get_opp with freq_to_opp omap3: clk: use pm accessor functions for cpufreq table omap3: pm: remove VDDx_MIN/MAX macros omap3: pm: introduce dynamic OPP omap3: pm: introduce 3630 opps arch/arm/mach-omap2/board-3430sdp.c | 1 + arch/arm/mach-omap2/board-omap3beagle.c | 1 + arch/arm/mach-omap2/board-omap3evm.c | 1 + arch/arm/mach-omap2/board-rx51.c | 2 + arch/arm/mach-omap2/board-zoom2.c | 2 + arch/arm/mach-omap2/clock34xx.c | 46 +++++--- arch/arm/mach-omap2/omap3-opp.h | 49 ++------ arch/arm/mach-omap2/pm.c | 160 +++++++++++++++++++++++++ arch/arm/mach-omap2/pm.h | 8 ++ arch/arm/mach-omap2/pm34xx.c | 122 +++++++++++++++++++ arch/arm/mach-omap2/resource34xx.c | 174 +++++++++++++++++---------- arch/arm/mach-omap2/smartreflex.c | 36 ++----- arch/arm/plat-omap/cpu-omap.c | 12 +-- arch/arm/plat-omap/include/plat/omap-pm.h | 111 ++++++++++++++++++ arch/arm/plat-omap/include/plat/omap34xx.h | 5 - 15 files changed, 573 insertions(+), 157 deletions(-) Regards, Nishanth Menon ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/9] omap3: pm: introduce enabled flag to omap_opp 2009-11-12 5:45 [PATCH 0/9] OMAP3: PM: introduce support for 3630 OPPs Nishanth Menon @ 2009-11-12 5:45 ` Nishanth Menon 2009-11-12 5:45 ` [PATCH 2/9] omap3: pm: introduce opp accessor functions Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-12 5:45 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, Thara Gopinath, Vishwanath Sripathy We used to enable and disable OPPs based on rate being set to 0, this has been confusing in general. So, we now allow specific OPPs to be now enabled/disabled by an explicit enabled flag instead of re-using rate flag itself. Tested on: SDP3430 Cc: Benoit Cousson <b-cousson@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/omap3-opp.h | 32 ++++++++++++++-------------- arch/arm/mach-omap2/resource34xx.c | 4 +++ arch/arm/plat-omap/include/plat/omap-pm.h | 2 + 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-omap2/omap3-opp.h b/arch/arm/mach-omap2/omap3-opp.h index c773ea7..42557e1 100644 --- a/arch/arm/mach-omap2/omap3-opp.h +++ b/arch/arm/mach-omap2/omap3-opp.h @@ -22,41 +22,41 @@ #define S166M 166000000 static struct omap_opp omap3_mpu_rate_table[] = { - {0, 0, 0}, + {0, 0, 0, 0}, /*OPP1*/ - {S125M, VDD1_OPP1, 0x1E}, + {true, S125M, VDD1_OPP1, 0x1E}, /*OPP2*/ - {S250M, VDD1_OPP2, 0x26}, + {true, S250M, VDD1_OPP2, 0x26}, /*OPP3*/ - {S500M, VDD1_OPP3, 0x30}, + {true, S500M, VDD1_OPP3, 0x30}, /*OPP4*/ - {S550M, VDD1_OPP4, 0x36}, + {true, S550M, VDD1_OPP4, 0x36}, /*OPP5*/ - {S600M, VDD1_OPP5, 0x3C}, + {true, S600M, VDD1_OPP5, 0x3C}, }; static struct omap_opp omap3_l3_rate_table[] = { - {0, 0, 0}, + {0, 0, 0, 0}, /*OPP1*/ - {0, VDD2_OPP1, 0x1E}, + {false, 0, VDD2_OPP1, 0x1E}, /*OPP2*/ - {S83M, VDD2_OPP2, 0x24}, + {true, S83M, VDD2_OPP2, 0x24}, /*OPP3*/ - {S166M, VDD2_OPP3, 0x2C}, + {true, S166M, VDD2_OPP3, 0x2C}, }; static struct omap_opp omap3_dsp_rate_table[] = { - {0, 0, 0}, + {0, 0, 0, 0}, /*OPP1*/ - {S90M, VDD1_OPP1, 0x1E}, + {true, S90M, VDD1_OPP1, 0x1E}, /*OPP2*/ - {S180M, VDD1_OPP2, 0x26}, + {true, S180M, VDD1_OPP2, 0x26}, /*OPP3*/ - {S360M, VDD1_OPP3, 0x30}, + {true, S360M, VDD1_OPP3, 0x30}, /*OPP4*/ - {S400M, VDD1_OPP4, 0x36}, + {true, S400M, VDD1_OPP4, 0x36}, /*OPP5*/ - {S430M, VDD1_OPP5, 0x3C}, + {true, S430M, VDD1_OPP5, 0x3C}, }; #endif diff --git a/arch/arm/mach-omap2/resource34xx.c b/arch/arm/mach-omap2/resource34xx.c index 04be4d2..af6b3c1 100644 --- a/arch/arm/mach-omap2/resource34xx.c +++ b/arch/arm/mach-omap2/resource34xx.c @@ -285,6 +285,10 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, c_opp = ID_VDD(res) | ID_OPP_NO(opp[current_level].opp_id); #endif + /* Only allow enabled OPPs */ + if (!opp[target_level].enabled) + return -EINVAL; + /* Sanity check of the OPP params before attempting to set */ if (!opp[target_level].rate || !opp[target_level].vsel) return -EINVAL; diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h index 583e540..5dc2048 100644 --- a/arch/arm/plat-omap/include/plat/omap-pm.h +++ b/arch/arm/plat-omap/include/plat/omap-pm.h @@ -21,6 +21,7 @@ /** * struct omap_opp - clock frequency-to-OPP ID table for DSP, MPU + * @enabled: enabled if true, disabled if false * @rate: target clock rate * @opp_id: OPP ID * @min_vdd: minimum VDD1 voltage (in millivolts) for this OPP @@ -28,6 +29,7 @@ * Operating performance point data. Can vary by OMAP chip and board. */ struct omap_opp { + bool enabled; unsigned long rate; u8 opp_id; u16 vsel; -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/9] omap3: pm: introduce opp accessor functions 2009-11-12 5:45 ` [PATCH 1/9] omap3: pm: introduce enabled flag to omap_opp Nishanth Menon @ 2009-11-12 5:45 ` Nishanth Menon 2009-11-12 5:45 ` [PATCH 3/9] omap3: pm: srf: introduce accessor function Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-12 5:45 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, Thara Gopinath, Vishwanath Sripathy, Sanjeev Premi Modifies the initial patch From Sanjeev: http://patchwork.kernel.org/patch/50998/ NOTE: The original opp_table introduced by Sanjeev is not needed anymore as we can use enabled flag to have better granularity in enable/disable of OPPs. This introduces the following accessor functions: freq_to_opp and opp_to_freq: Matching functions to convert OPP to freq and viceversa. freq_to_vsel: Converts a frequency to corresponding voltage. opp_onoff: To enable/disable a specific OPP in a OPP table this allows granular runtime disable/enable of specific OPPs, esp when used in conjunction with search and mapping functions get_next_freq: A search function to get next matching frequency. This could possibly provide the basis for more complex OPP transition algos of the future. get_limit_freq: A search function to get the least or maximum frequency based on search criteria. Allows for independence from OPP_IDs in the future. Since the accessor functions hide the details of the table implementation, the opp table is now moved away from omap3-opp.h to pm34xx.c. The terminator entry is needed at the start and end of the table as it is still needed for reverse and forward search as the length of the table is unknown. Tests done: Accessor functions standalone tested on a PC host with dummy OPP table to simulate boundary, invalid and valid conditions, SDP3430 for system stability. Cc: Benoit Cousson <b-cousson@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Sanjeev Premi <premi@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/omap3-opp.h | 40 +------- arch/arm/mach-omap2/pm.c | 160 +++++++++++++++++++++++++++++ arch/arm/mach-omap2/pm34xx.c | 42 ++++++++ arch/arm/plat-omap/include/plat/omap-pm.h | 109 ++++++++++++++++++++ 4 files changed, 314 insertions(+), 37 deletions(-) diff --git a/arch/arm/mach-omap2/omap3-opp.h b/arch/arm/mach-omap2/omap3-opp.h index 42557e1..27e2ca5 100644 --- a/arch/arm/mach-omap2/omap3-opp.h +++ b/arch/arm/mach-omap2/omap3-opp.h @@ -21,42 +21,8 @@ #define S83M 83000000 #define S166M 166000000 -static struct omap_opp omap3_mpu_rate_table[] = { - {0, 0, 0, 0}, - /*OPP1*/ - {true, S125M, VDD1_OPP1, 0x1E}, - /*OPP2*/ - {true, S250M, VDD1_OPP2, 0x26}, - /*OPP3*/ - {true, S500M, VDD1_OPP3, 0x30}, - /*OPP4*/ - {true, S550M, VDD1_OPP4, 0x36}, - /*OPP5*/ - {true, S600M, VDD1_OPP5, 0x3C}, -}; - -static struct omap_opp omap3_l3_rate_table[] = { - {0, 0, 0, 0}, - /*OPP1*/ - {false, 0, VDD2_OPP1, 0x1E}, - /*OPP2*/ - {true, S83M, VDD2_OPP2, 0x24}, - /*OPP3*/ - {true, S166M, VDD2_OPP3, 0x2C}, -}; - -static struct omap_opp omap3_dsp_rate_table[] = { - {0, 0, 0, 0}, - /*OPP1*/ - {true, S90M, VDD1_OPP1, 0x1E}, - /*OPP2*/ - {true, S180M, VDD1_OPP2, 0x26}, - /*OPP3*/ - {true, S360M, VDD1_OPP3, 0x30}, - /*OPP4*/ - {true, S400M, VDD1_OPP4, 0x36}, - /*OPP5*/ - {true, S430M, VDD1_OPP5, 0x3C}, -}; +extern struct omap_opp omap3_mpu_rate_table[]; +extern struct omap_opp omap3_dsp_rate_table[]; +extern struct omap_opp omap3_l3_rate_table[]; #endif diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index f50e93d..9dcb5c7 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -33,6 +33,7 @@ #include <plat/powerdomain.h> #include <plat/resource.h> #include <plat/omap34xx.h> +#include <plat/omap-pm.h> #include "prm-regbits-34xx.h" #include "pm.h" @@ -203,3 +204,162 @@ static int __init omap_pm_init(void) return error; } late_initcall(omap_pm_init); + +int opp_to_freq(unsigned long *freq, const struct omap_opp *opps, u8 opp_id) +{ + int i = 1; + + BUG_ON(!freq || !opps); + + /* The first entry is a dummy one, loop till we hit terminator */ + while (!IS_OPP_TERMINATOR(opps, i)) { + if (opps[i].enabled && (opps[i].opp_id == opp_id)) { + *freq = opps[i].rate; + return 0; + } + i++; + } + + return -EINVAL; +} +EXPORT_SYMBOL(opp_to_freq); + +int freq_to_vsel(u8 *vsel, const struct omap_opp *opps, unsigned long freq) +{ + int i = 1; + + BUG_ON(!vsel || !opps); + + /* The first entry is a dummy one, loop till we hit terminator */ + while (!IS_OPP_TERMINATOR(opps, i)) { + if (opps[i].enabled && (opps[i].rate == freq)) { + *vsel = opps[i].vsel; + return 0; + } + i++; + } + + return -EINVAL; +} +EXPORT_SYMBOL(freq_to_vsel); + +int freq_to_opp(u8 *opp_id, const struct omap_opp *opps, unsigned long freq) +{ + int i = 1; + + BUG_ON(!opp_id || !opps); + + /* The first entry is a dummy one, loop till we hit terminator */ + while (!IS_OPP_TERMINATOR(opps, i)) { + if (opps[i].enabled && (opps[i].rate == freq)) { + *opp_id = opps[i].opp_id; + return 0; + } + i++; + } + + return -EINVAL; +} +EXPORT_SYMBOL(freq_to_opp); + +int opp_onoff(struct omap_opp *opps, unsigned long freq, bool enable) +{ + int i = 1; + + BUG_ON(!opps); + + /* The first entry is a dummy one, loop till we hit terminator */ + while (!IS_OPP_TERMINATOR(opps, i)) { + if (opps[i].rate == freq) { + opps[i].enabled = enable; + return 0; + } + i++; + } + + return -EINVAL; +} +EXPORT_SYMBOL(opp_onoff); + +int get_next_freq(unsigned long *freq, const struct omap_opp *opps, + bool search_higher, bool search_enabled_only, bool exact_search) +{ + int i = 1, inc = 1; + bool found = false; + + BUG_ON(!opps || !freq || !(*freq)); + + /* The first entry is a dummy one, loop till we hit terminator + * XXX: The following algorithm works only on a presorted + * list of OPPs + */ + while (!IS_OPP_TERMINATOR(opps, i)) { + /* if we found the original freq, then + * case 1: enabled search ONLY, check opp is enabled or not + * case 2: the next available freq if enabled is not searched + */ + if ((found && search_enabled_only && opps[i].enabled) || + (found && !search_enabled_only)) { + *freq = opps[i].rate; + return 0; + } + + /* Find the baseline freq first.. */ + if (!found && ((exact_search && opps[i].rate == *freq) || + (!exact_search && opps[i].rate >= *freq))) { + /* found.. next decide direction */ + inc = search_higher ? 1 : -1; + found = true; + /* handle an exception case for exact search.. */ + if (exact_search || !search_higher) + i += inc; + /* fall thru to search for the right match */ + } else { + i += inc; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL(get_next_freq); + +int get_limit_freq(unsigned long *freq, const struct omap_opp *opps, + bool search_highest, bool search_enabled_only) +{ + int i = 1; + unsigned long cur_freq_match = search_highest ? 0 : -1; + bool found = false; + + BUG_ON(!opps || !freq); + + /* The first entry is a dummy one, loop till we hit terminator + * XXX: The following algorithm works only on a presorted + * list of OPPs + * We could use get_next_freq to search, but that will tend + * to be inefficient + */ + while (!IS_OPP_TERMINATOR(opps, i)) { + /* match condition: + * check if the enabled cases match (only invalid case is: + * search_enabled=1,enabled=0) + * then we look for comparison condition, based on direction + */ + if (!(search_enabled_only && !opps[i].enabled) && + ((search_highest && (opps[i].rate > cur_freq_match)) || + (!search_highest && (opps[i].rate < cur_freq_match)))) { + cur_freq_match = opps[i].rate; + found = true; + /* if we are searching for least, the first match + * is the right one, look no further. + */ + if (!search_highest) + break; + } + i++; + } + if (!found) + return -EINVAL; + *freq = cur_freq_match; + return 0; +} +EXPORT_SYMBOL(get_limit_freq); diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 3a2dc2b..92f11d7 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -50,6 +50,7 @@ #include "prm.h" #include "pm.h" #include "sdrc.h" +#include "omap3-opp.h" static int regset_save_on_suspend; @@ -98,6 +99,47 @@ static struct prm_setup_vc prm_setup = { .vdd1_off = 0x00, /* 0.6v */ }; +struct omap_opp omap3_mpu_rate_table[] = { + {0, 0, 0, 0}, + /*OPP1*/ + {true, S125M, VDD1_OPP1, 0x1E}, + /*OPP2*/ + {true, S250M, VDD1_OPP2, 0x26}, + /*OPP3*/ + {true, S500M, VDD1_OPP3, 0x30}, + /*OPP4*/ + {true, S550M, VDD1_OPP4, 0x36}, + /*OPP5*/ + {true, S600M, VDD1_OPP5, 0x3C}, + {0, 0, 0, 0}, +}; + +struct omap_opp omap3_l3_rate_table[] = { + {0, 0, 0, 0}, + /*OPP1*/ + {false, 0, VDD2_OPP1, 0x1E}, + /*OPP2*/ + {true, S83M, VDD2_OPP2, 0x24}, + /*OPP3*/ + {true, S166M, VDD2_OPP3, 0x2C}, + {0, 0, 0, 0}, +}; + +struct omap_opp omap3_dsp_rate_table[] = { + {0, 0, 0, 0}, + /*OPP1*/ + {true, S90M, VDD1_OPP1, 0x1E}, + /*OPP2*/ + {true, S180M, VDD1_OPP2, 0x26}, + /*OPP3*/ + {true, S360M, VDD1_OPP3, 0x30}, + /*OPP4*/ + {true, S400M, VDD1_OPP4, 0x36}, + /*OPP5*/ + {true, S430M, VDD1_OPP5, 0x3C}, + {0, 0, 0, 0}, +}; + static inline void omap3_per_save_context(void) { omap_gpio_save_context(); diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h index 5dc2048..693b8c1 100644 --- a/arch/arm/plat-omap/include/plat/omap-pm.h +++ b/arch/arm/plat-omap/include/plat/omap-pm.h @@ -35,6 +35,10 @@ struct omap_opp { u16 vsel; }; +/* Identify a OPP terminator */ +#define IS_OPP_TERMINATOR(opps, i) (!opps[i].enabled && (opps[i].rate == 0) &&\ + (opps[i].vsel == 0)) + extern struct omap_opp *mpu_opps; extern struct omap_opp *dsp_opps; extern struct omap_opp *l3_opps; @@ -324,5 +328,110 @@ unsigned long omap_pm_cpu_get_freq(void); */ int omap_pm_get_dev_context_loss_count(struct device *dev); +/** + * freq_to_opp - Get opp_id corresponding to a frequency if enabled + * This function can also be used to check if a certain frequency is enabled + * in the opp list. + * + * @opp_id: the ID to return + * @opps: the opps table to search through + * @freq: the frequency to search for + * + * returns 0 if *opp_id is populated, else returns EINVAL + */ +int freq_to_opp(u8 *opp_id, const struct omap_opp *opps, unsigned long freq); +/** + * freq_to_vsel - Get voltage corresponding to a frequency if enabled + * This function can also be used to check if a certain frequency is enabled + * in the opp list. + * + * @vsel: voltage corresponding to return + * @opps: the opps table to search through + * @freq: the frequency to search for + * + * returns 0 if *vsel is populated, else returns EINVAL + */ +int freq_to_vsel(u8 *vsel, const struct omap_opp *opps, unsigned long freq); + +/** + * opp_to_freq - Get frequency corresponding to an OPP if enabled + * This function can also be used to check if a certain opp_id is enabled + * in the opp list. + * + * @freq: return the frequency on this + * @opps: the opps table to search through + * @opp_id: the ID to search for + * + * returns 0 if *freq is populated, else returns EINVAL + */ +int opp_to_freq(unsigned long *freq, const struct omap_opp *opps, u8 opp_id); + +/** + * opp_onoff - Disable or enable an OPP in the supported OPPs if available + * + * @opps: the opps table to search through + * @freq: the frequency to search for + * @enable: true to enable the OPP, false to disable it + * + * returns 0 if the OPP is found, else returns EINVAL. if the opp is found + * NOTE: Even if it was in the same state as requested, the functions returns 0. + */ +int opp_onoff(struct omap_opp *opps, unsigned long freq, bool enable); + +/** + * get_next_freq - search for next matching frequency, given a starting + * frequency. This can be combined to create a search logic etc without + * knowing OPP IDs. + * Example usages: + * a) I have an approximate frequency, get enabled opp freq at least freq + * if a match is achieved, result_freq >= requested_freq + * res = get_next_freq(&freq, opps, true, true, false) + * b) I have an approximate frequency, get enabled opp freq less than freq + * if a match is achieved, result_freq < requested_freq + * res = get_next_freq(&freq, opps, false, true, false) + * c) I have exact OPP freq I want to check -> search for higher enabled + * frequency + * res = get_next_freq(&freq, opps, true, true, true) + * d) I have exact OPP freq I want to check -> search for lower enabled + * frequency + * res = get_next_freq(&freq, opps, false, true, true) + * + * Then we can create all sorts of search combinations -> including searching + * for an OPP freq we would like to enable by controlling search_enabled_only + * + * @freq: Which frequency to start from- should be a valid frequency, + * even if not enabled. + * if a match is found, this will contain the matched frequency + * @opps: the opp table to search through + * @search_higher: should the search go up the list (search for higher freq) + * if true, searches for next highest freq, else searches for the next + * lowest frequency + * @search_enabled_only: Should the search only for enabled frequencies. + * if true, searches for only enabled OPP frequencies, else does not + * care for enabled status of the OPP (useful to enable OPPs) + * @exact_search: start search iff start *freq gets an exact match + * + * If a match is found, returns the matched frequency in *freq and returns 0, + * else, returns EINVAL, *freq is unchanged + */ +int get_next_freq(unsigned long *freq, const struct omap_opp *opps, + bool search_higher, bool search_enabled_only, bool exact_search); + +/** + * get_limit_freq: Get the max or min frequency for an opp table + * we can search for just the enabled opps, or the max or least in + * the table + * + * @freq: returns the max or min opp if a match was found + * @opps: opp table to search + * @search_highest: search for the highest if true, else search for lowest + * frequency + * @search_enabled_only: search only for enabled OPPs + * + * returns 0 if a match is found and *freq contains the matched frequency + * else, returns EINVAL, *freq is unchanged + */ +int get_limit_freq(unsigned long *freq, const struct omap_opp *opps, + bool search_highest, bool search_enabled_only); #endif -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/9] omap3: pm: srf: introduce accessor function 2009-11-12 5:45 ` [PATCH 2/9] omap3: pm: introduce opp accessor functions Nishanth Menon @ 2009-11-12 5:45 ` Nishanth Menon 2009-11-12 5:45 ` [PATCH 4/9] omap3: pm: use opp accessor functions for omap-target Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-12 5:45 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, Thara Gopinath, Vishwanath Sripathy With the accessor functions, many of the direct accesses are redundant. Cleanup of SRF to: a) Remove get_opp as it redundant as freq_to_opp does exactly the samething. b) Remove any direct dereference of opp tables except thru accessor functions. NOTE: the implementation is just a start and leaves scope for further performance and robustness improvements which can be added on top. Cc: Benoit Cousson <b-cousson@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/resource34xx.c | 178 ++++++++++++++++++++++-------------- 1 files changed, 109 insertions(+), 69 deletions(-) diff --git a/arch/arm/mach-omap2/resource34xx.c b/arch/arm/mach-omap2/resource34xx.c index af6b3c1..15b5cb6 100644 --- a/arch/arm/mach-omap2/resource34xx.c +++ b/arch/arm/mach-omap2/resource34xx.c @@ -155,29 +155,14 @@ static int curr_vdd1_opp; static int curr_vdd2_opp; static DEFINE_MUTEX(dvfs_mutex); -static unsigned short get_opp(struct omap_opp *opp_freq_table, - unsigned long freq) -{ - struct omap_opp *prcm_config; - prcm_config = opp_freq_table; - - if (prcm_config->rate <= freq) - return prcm_config->opp_id; /* Return the Highest OPP */ - for (; prcm_config->rate; prcm_config--) - if (prcm_config->rate < freq) - return (prcm_config+1)->opp_id; - else if (prcm_config->rate == freq) - return prcm_config->opp_id; - /* Return the least OPP */ - return (prcm_config+1)->opp_id; -} - /** * init_opp - Initialize the OPP resource */ void init_opp(struct shared_resource *resp) { struct clk *l3_clk; + int ret; + u8 opp_id; resp->no_of_users = 0; if (!mpu_opps || !dsp_opps || !l3_opps) @@ -190,17 +175,18 @@ void init_opp(struct shared_resource *resp) vdd1_resp = resp; dpll1_clk = clk_get(NULL, "dpll1_ck"); dpll2_clk = clk_get(NULL, "dpll2_ck"); - resp->curr_level = get_opp(mpu_opps + MAX_VDD1_OPP, - dpll1_clk->rate); - curr_vdd1_opp = resp->curr_level; + ret = freq_to_opp(&opp_id, mpu_opps, dpll1_clk->rate); + BUG_ON(ret); /* TBD Cleanup handling */ + curr_vdd1_opp = opp_id; } else if (strcmp(resp->name, "vdd2_opp") == 0) { vdd2_resp = resp; dpll3_clk = clk_get(NULL, "dpll3_m2_ck"); l3_clk = clk_get(NULL, "l3_ick"); - resp->curr_level = get_opp(l3_opps + MAX_VDD2_OPP, - l3_clk->rate); - curr_vdd2_opp = resp->curr_level; + ret = freq_to_opp(&opp_id, l3_opps, l3_clk->rate); + BUG_ON(ret); /* TBD Cleanup handling */ + curr_vdd2_opp = opp_id; } + resp->curr_level = opp_id; return; } @@ -242,24 +228,40 @@ static int program_opp_freq(int res, int target_level, int current_level) { int ret = 0, l3_div; int *curr_opp; + unsigned long mpu_freq, dsp_freq, l3_freq; +#ifndef CONFIG_CPU_FREQ + unsigned long mpu_cur_freq +#endif + + /* Check if I can actually switch or not */ + if (res == VDD1_OPP) { + ret = opp_to_freq(&mpu_freq, mpu_opps, target_level); + ret |= opp_to_freq(&dsp_freq, dsp_opps, target_level); +#ifndef CONFIG_CPU_FREQ + ret |= opp_to_freq(&mpu_cur_freq, mpu_opps, current_level); +#endif + } else { + ret = opp_to_freq(&l3_freq, l3_opps, target_level); + } + /* we would have caught all bad levels earlier.. */ + if (unlikely(ret)) + return ret; lock_scratchpad_sem(); if (res == VDD1_OPP) { curr_opp = &curr_vdd1_opp; - clk_set_rate(dpll1_clk, mpu_opps[target_level].rate); - clk_set_rate(dpll2_clk, dsp_opps[target_level].rate); + clk_set_rate(dpll1_clk, mpu_freq); + clk_set_rate(dpll2_clk, dsp_freq); #ifndef CONFIG_CPU_FREQ /*Update loops_per_jiffy if processor speed is being changed*/ loops_per_jiffy = compute_lpj(loops_per_jiffy, - mpu_opps[current_level].rate/1000, - mpu_opps[target_level].rate/1000); + mpu_cur_freq / 1000, mpu_freq / 1000); #endif } else { curr_opp = &curr_vdd2_opp; l3_div = cm_read_mod_reg(CORE_MOD, CM_CLKSEL) & OMAP3430_CLKSEL_L3_MASK; - ret = clk_set_rate(dpll3_clk, - l3_opps[target_level].rate * l3_div); + ret = clk_set_rate(dpll3_clk, l3_freq * l3_div); } if (ret) { unlock_scratchpad_sem(); @@ -278,6 +280,7 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, int current_level) { int i, ret = 0, raise; + unsigned long freq; #ifdef CONFIG_OMAP_SMARTREFLEX unsigned long t_opp, c_opp; @@ -285,13 +288,10 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, c_opp = ID_VDD(res) | ID_OPP_NO(opp[current_level].opp_id); #endif - /* Only allow enabled OPPs */ - if (!opp[target_level].enabled) - return -EINVAL; - - /* Sanity check of the OPP params before attempting to set */ - if (!opp[target_level].rate || !opp[target_level].vsel) - return -EINVAL; + /* See if have a freq associated, if not, invalid opp */ + ret = opp_to_freq(&freq, opp, target_level); + if (unlikely(ret)) + return ret; if (target_level > current_level) raise = 1; @@ -303,10 +303,16 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, ret = program_opp_freq(res, target_level, current_level); #ifdef CONFIG_OMAP_SMARTREFLEX - else + else { + u8 v_current, v_target; + /* none of the following should fail.. */ + BUG_ON(freq_to_vsel(&v_target, opp, freq)); + BUG_ON(opp_to_freq(&freq, opp, current_level)); + BUG_ON(freq_to_vsel(&v_current, opp, freq)); + /* ok to scale.. */ sr_voltagescale_vcbypass(t_opp, c_opp, - opp[target_level].vsel, - opp[current_level].vsel); + v_target, v_current); + } #endif } @@ -315,7 +321,8 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, int resource_set_opp_level(int res, u32 target_level, int flags) { - unsigned long mpu_freq, mpu_old_freq; + unsigned long mpu_freq, mpu_old_freq, l3_freq; + int ret; #ifdef CONFIG_CPU_FREQ struct cpufreq_freqs freqs_notify; #endif @@ -334,6 +341,16 @@ int resource_set_opp_level(int res, u32 target_level, int flags) if (!mpu_opps || !dsp_opps || !l3_opps) return 0; + /* Check if I can actually switch or not */ + if (res == VDD1_OPP) { + ret = opp_to_freq(&mpu_freq, mpu_opps, target_level); + ret |= opp_to_freq(&mpu_old_freq, mpu_opps, resp->curr_level); + } else { + ret = opp_to_freq(&l3_freq, l3_opps, target_level); + } + if (ret) + return ret; + mutex_lock(&dvfs_mutex); if (res == VDD1_OPP) { @@ -341,9 +358,6 @@ int resource_set_opp_level(int res, u32 target_level, int flags) mutex_unlock(&dvfs_mutex); return 0; } - mpu_old_freq = mpu_opps[resp->curr_level].rate; - mpu_freq = mpu_opps[target_level].rate; - #ifdef CONFIG_CPU_FREQ freqs_notify.old = mpu_old_freq/1000; freqs_notify.new = mpu_freq/1000; @@ -371,15 +385,13 @@ int resource_set_opp_level(int res, u32 target_level, int flags) int set_opp(struct shared_resource *resp, u32 target_level) { - unsigned long tput; - unsigned long req_l3_freq; - int ind; + int ret = -EINVAL; if (resp == vdd1_resp) { if (target_level < 3) resource_release("vdd2_opp", &vdd2_dev); - resource_set_opp_level(VDD1_OPP, target_level, 0); + ret = resource_set_opp_level(VDD1_OPP, target_level, 0); /* * For VDD1 OPP3 and above, make sure the interconnect * is at 100Mhz or above. @@ -389,21 +401,28 @@ int set_opp(struct shared_resource *resp, u32 target_level) resource_request("vdd2_opp", &vdd2_dev, 400000); } else if (resp == vdd2_resp) { - tput = target_level; + unsigned long req_l3_freq; /* Convert the tput in KiB/s to Bus frequency in MHz */ - req_l3_freq = (tput * 1000)/4; - - for (ind = 2; ind <= MAX_VDD2_OPP; ind++) - if ((l3_opps + ind)->rate >= req_l3_freq) { - target_level = ind; - break; - } - - /* Set the highest OPP possible */ - if (ind > MAX_VDD2_OPP) - target_level = ind-1; - resource_set_opp_level(VDD2_OPP, target_level, 0); + req_l3_freq = (target_level * 1000)/4; + + /* Get the best freq around */ + ret = get_next_freq(&req_l3_freq, l3_opps, true, true, false); + + /* If we dont find a good freq, then use the highest + * possible freq + */ + if (ret) + ret = get_limit_freq(&req_l3_freq, l3_opps, true, true); + + /* uh uh.. no OPPs?? */ + BUG_ON(ret); + + ret = freq_to_opp((u8 *)&target_level, l3_opps, req_l3_freq); + /* we dont expect this to fail */ + BUG_ON(ret); + + ret = resource_set_opp_level(VDD2_OPP, target_level, 0); } return 0; } @@ -416,6 +435,11 @@ int set_opp(struct shared_resource *resp, u32 target_level) */ int validate_opp(struct shared_resource *resp, u32 target_level) { + unsigned long x; + if (strcmp(resp->name, "mpu_freq") == 0) + return opp_to_freq(&x, mpu_opps, target_level); + else if (strcmp(resp->name, "dsp_freq") == 0) + return opp_to_freq(&x, dsp_opps, target_level); return 0; } @@ -425,6 +449,8 @@ int validate_opp(struct shared_resource *resp, u32 target_level) void init_freq(struct shared_resource *resp) { char *linked_res_name; + int ret = -EINVAL; + unsigned long freq; resp->no_of_users = 0; if (!mpu_opps || !dsp_opps) @@ -436,32 +462,46 @@ void init_freq(struct shared_resource *resp) */ if (strcmp(resp->name, "mpu_freq") == 0) /* MPU freq in Mhz */ - resp->curr_level = mpu_opps[curr_vdd1_opp].rate; + ret = opp_to_freq(&freq, mpu_opps, curr_vdd1_opp); else if (strcmp(resp->name, "dsp_freq") == 0) /* DSP freq in Mhz */ - resp->curr_level = dsp_opps[curr_vdd1_opp].rate; + ret = opp_to_freq(&freq, dsp_opps, curr_vdd1_opp); + BUG_ON(ret); + + resp->curr_level = freq; return; } int set_freq(struct shared_resource *resp, u32 target_level) { - unsigned int vdd1_opp; + u8 vdd1_opp; + int ret = -EINVAL; if (!mpu_opps || !dsp_opps) return 0; if (strcmp(resp->name, "mpu_freq") == 0) { - vdd1_opp = get_opp(mpu_opps + MAX_VDD1_OPP, target_level); - resource_request("vdd1_opp", &dummy_mpu_dev, vdd1_opp); + ret = freq_to_opp(&vdd1_opp, mpu_opps, target_level); + if (!ret) + ret = resource_request("vdd1_opp", &dummy_mpu_dev, + vdd1_opp); } else if (strcmp(resp->name, "dsp_freq") == 0) { - vdd1_opp = get_opp(dsp_opps + MAX_VDD1_OPP, target_level); - resource_request("vdd1_opp", &dummy_dsp_dev, vdd1_opp); + ret = freq_to_opp(&vdd1_opp, dsp_opps, target_level); + if (!ret) + ret = resource_request("vdd1_opp", &dummy_dsp_dev, + vdd1_opp); } - resp->curr_level = target_level; - return 0; + if (!ret) + resp->curr_level = target_level; + return ret; } int validate_freq(struct shared_resource *resp, u32 target_level) { + u8 x; + if (strcmp(resp->name, "mpu_freq") == 0) + return freq_to_opp(&x, mpu_opps, target_level); + else if (strcmp(resp->name, "dsp_freq") == 0) + return freq_to_opp(&x, dsp_opps, target_level); return 0; } -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 4/9] omap3: pm: use opp accessor functions for omap-target 2009-11-12 5:45 ` [PATCH 3/9] omap3: pm: srf: introduce accessor function Nishanth Menon @ 2009-11-12 5:45 ` Nishanth Menon 2009-11-12 5:45 ` [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-12 5:45 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, Thara Gopinath, Vishwanath Sripathy The logic in omap-target can now be improved with the accessor functions. Dont scan through the list manually, instead use get_next_freq to do the scanning. Cc: Benoit Cousson <b-cousson@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/plat-omap/cpu-omap.c | 12 ++++-------- 1 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c index f9b480d..dac1eab 100644 --- a/arch/arm/plat-omap/cpu-omap.c +++ b/arch/arm/plat-omap/cpu-omap.c @@ -111,14 +111,10 @@ static int omap_target(struct cpufreq_policy *policy, cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); #elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) if (mpu_opps) { - int ind; - for (ind = 1; ind <= MAX_VDD1_OPP; ind++) { - if (mpu_opps[ind].rate/1000 >= target_freq) { - omap_pm_cpu_set_freq - (mpu_opps[ind].rate); - break; - } - } + unsigned long freq = target_freq * 1000; + int res = get_next_freq(&freq, mpu_opps, true, true, false); + if (!res) + omap_pm_cpu_set_freq(freq); } #endif return ret; -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2009-11-12 5:45 ` [PATCH 4/9] omap3: pm: use opp accessor functions for omap-target Nishanth Menon @ 2009-11-12 5:45 ` Nishanth Menon 2009-11-12 5:45 ` [PATCH 6/9] omap3: clk: use pm accessor functions for cpufreq table Nishanth Menon 2009-12-18 23:12 ` [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp Kevin Hilman 0 siblings, 2 replies; 22+ messages in thread From: Nishanth Menon @ 2009-11-12 5:45 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, Thara Gopinath, Vishwanath Sripathy SmartReflex implements a get_opp to search through the opp table, replace it with the accessor function as it is a duplicate of freq_to_opp Cc: Benoit Cousson <b-cousson@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/smartreflex.c | 36 ++++++++---------------------------- 1 files changed, 8 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index be3a1da..d34224d 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -146,49 +146,29 @@ static u32 cal_test_nvalue(u32 sennval, u32 senpval) (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT); } -/* determine the current OPP from the frequency - * we need to give this function last element of OPP rate table - * and the frequency - */ -static u16 get_opp(struct omap_opp *opp_freq_table, - unsigned long freq) -{ - struct omap_opp *prcm_config; - - prcm_config = opp_freq_table; - - if (prcm_config->rate <= freq) - return prcm_config->opp_id; /* Return the Highest OPP */ - for (; prcm_config->rate; prcm_config--) - if (prcm_config->rate < freq) - return (prcm_config+1)->opp_id; - else if (prcm_config->rate == freq) - return prcm_config->opp_id; - /* Return the least OPP */ - return (prcm_config+1)->opp_id; -} - -static u16 get_vdd1_opp(void) +static u8 get_vdd1_opp(void) { - u16 opp; + u8 opp; if (sr1.vdd_opp_clk == NULL || IS_ERR(sr1.vdd_opp_clk) || mpu_opps == NULL) return 0; - opp = get_opp(mpu_opps + MAX_VDD1_OPP, sr1.vdd_opp_clk->rate); + /* Not expected to fail.. */ + BUG_ON(freq_to_opp(&opp, mpu_opps, sr1.vdd_opp_clk->rate)); return opp; } -static u16 get_vdd2_opp(void) +static u8 get_vdd2_opp(void) { - u16 opp; + u8 opp; if (sr2.vdd_opp_clk == NULL || IS_ERR(sr2.vdd_opp_clk) || l3_opps == NULL) return 0; - opp = get_opp(l3_opps + MAX_VDD2_OPP, sr2.vdd_opp_clk->rate); + /* Not expected to fail.. */ + BUG_ON(freq_to_opp(&opp, l3_opps, sr2.vdd_opp_clk->rate)); return opp; } -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 6/9] omap3: clk: use pm accessor functions for cpufreq table 2009-11-12 5:45 ` [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp Nishanth Menon @ 2009-11-12 5:45 ` Nishanth Menon 2009-11-12 5:45 ` [PATCH 7/9] omap3: pm: remove VDDx_MIN/MAX macros Nishanth Menon 2009-12-18 23:12 ` [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp Kevin Hilman 1 sibling, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-12 5:45 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, Thara Gopinath, Vishwanath Sripathy omap2_clk_init_cpufreq_table currently directly accesses the opp table, making it unscalable to various OMAPs. Instead use the accessor functions to populate the cpufreq table Cc: Benoit Cousson <b-cousson@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/clock34xx.c | 46 +++++++++++++++++++++++++++----------- 1 files changed, 32 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index da5bc1f..daec6ea 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -1042,28 +1042,46 @@ static unsigned long omap3_clkoutx2_recalc(struct clk *clk) #if defined(CONFIG_ARCH_OMAP3) #ifdef CONFIG_CPU_FREQ -static struct cpufreq_frequency_table freq_table[MAX_VDD1_OPP+1]; + +/* Use a dummy table with no entries to start with */ +static struct cpufreq_frequency_table dummy_freq_table = { + .frequency = CPUFREQ_TABLE_END, +}; +static struct cpufreq_frequency_table *freq_table = &dummy_freq_table; void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table) { - struct omap_opp *prcm; - int i = 0; + int i; + int ret; + u8 opp_id; + unsigned long freq; if (!mpu_opps) return; - - prcm = mpu_opps + MAX_VDD1_OPP; - for (; prcm->rate; prcm--) { - freq_table[i].index = i; - freq_table[i].frequency = prcm->rate / 1000; - i++; + ret = get_limit_freq(&freq, mpu_opps, true, true); + if (ret) { + pr_warning("%s: failed to initialize frequency" + "table\n", __func__); + return; } + /* The following should'nt fail */ + BUG_ON(freq_to_opp(&opp_id, mpu_opps, freq)); - if (i == 0) { - printk(KERN_WARNING "%s: failed to initialize frequency \ - table\n", - __func__); - return; + /* There is a risk of overallocating if the lower/intermediate + * OPPs are disabled, but the amount is not expected to be high + * in comparison to reallocating to exactly available opps + */ + freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * + (opp_id + 1), GFP_KERNEL); + + /* Populate the first index.. we already found the freq */ + freq_table[0].index = 0; + freq_table[0].frequency = freq / 1000; + + /* Populate the table highest to lowest */ + for (i = 1; !get_next_freq(&freq, mpu_opps, false, true, true); i++) { + freq_table[i].index = i; + freq_table[i].frequency = freq / 1000; } freq_table[i].index = i; -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 7/9] omap3: pm: remove VDDx_MIN/MAX macros 2009-11-12 5:45 ` [PATCH 6/9] omap3: clk: use pm accessor functions for cpufreq table Nishanth Menon @ 2009-11-12 5:45 ` Nishanth Menon 2009-11-12 5:45 ` [PATCH 8/9] omap3: pm: introduce dynamic OPP Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-12 5:45 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, Thara Gopinath, Vishwanath Sripathy Since accessor functions are used through out, we dont depend on the predefined macros to know the limits of the opp table. Hence, remove these. Cc: Benoit Cousson <b-cousson@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/plat-omap/include/plat/omap34xx.h | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/arch/arm/plat-omap/include/plat/omap34xx.h b/arch/arm/plat-omap/include/plat/omap34xx.h index 868e238..cc7cfae 100644 --- a/arch/arm/plat-omap/include/plat/omap34xx.h +++ b/arch/arm/plat-omap/include/plat/omap34xx.h @@ -104,10 +104,5 @@ #define VDD2_OPP2 0x2 #define VDD2_OPP3 0x3 -#define MIN_VDD1_OPP VDD1_OPP1 -#define MAX_VDD1_OPP VDD1_OPP5 -#define MIN_VDD2_OPP VDD2_OPP1 -#define MAX_VDD2_OPP VDD2_OPP3 - #endif /* __ASM_ARCH_OMAP34XX_H */ -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 8/9] omap3: pm: introduce dynamic OPP 2009-11-12 5:45 ` [PATCH 7/9] omap3: pm: remove VDDx_MIN/MAX macros Nishanth Menon @ 2009-11-12 5:45 ` Nishanth Menon 2009-11-12 5:45 ` [PATCH 9/9] omap3: pm: introduce 3630 opps Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-12 5:45 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, Thara Gopinath, Vishwanath Sripathy OPP tables have been used as static arrays till now this causes limitations in terms of ability to dynamically making decisions for cpu types and populating it with the right values. This implementation is based on the discussions in the thread: http://marc.info/?l=linux-omap&m=125482970102327&w=2 inputs from Romit, Benoit, Kevin, Sanjeev, Santosh acked. omap3_pm_init_opp_table is introduced here, and the default omap3 tables have been renamed to omap34xx_ tables, original omap3_xx tables are now dynamically allocated and populated. Corresponding board files calling omap2_init_common_hw with the active opp table params have been updated with this patch. This now paves way to introduce 3630 OPP tables. Tested on: SDP3430 Cc: Benoit Cousson <b-cousson@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/board-3430sdp.c | 1 + arch/arm/mach-omap2/board-omap3beagle.c | 1 + arch/arm/mach-omap2/board-omap3evm.c | 1 + arch/arm/mach-omap2/board-rx51.c | 2 ++ arch/arm/mach-omap2/board-zoom2.c | 2 ++ arch/arm/mach-omap2/omap3-opp.h | 6 +++--- arch/arm/mach-omap2/pm.h | 8 ++++++++ arch/arm/mach-omap2/pm34xx.c | 31 ++++++++++++++++++++++++++++--- 8 files changed, 46 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index 11f0dc5..de1b632 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -222,6 +222,7 @@ static void __init omap_3430sdp_init_irq(void) omap_board_config_size = ARRAY_SIZE(sdp3430_config); omap3_pm_init_vc(&omap3_setuptime_table); omap3_pm_init_cpuidle(omap3_cpuidle_params_table); + omap3_pm_init_opp_table(); omap2_init_common_hw(hyb18m512160af6_sdrc_params, NULL, omap3_mpu_rate_table, omap3_dsp_rate_table, omap3_l3_rate_table); omap_init_irq(); diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index d0a95ea..65bab97 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -351,6 +351,7 @@ static void __init omap3_beagle_init_irq(void) { omap_board_config = omap3_beagle_config; omap_board_config_size = ARRAY_SIZE(omap3_beagle_config); + omap3_pm_init_opp_table(); omap2_init_common_hw(mt46h32m32lf6_sdrc_params, mt46h32m32lf6_sdrc_params, omap3_mpu_rate_table, omap3_dsp_rate_table, omap3_l3_rate_table); diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 2c63002..d8318cd 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -336,6 +336,7 @@ static void __init omap3_evm_init_irq(void) { omap_board_config = omap3_evm_config; omap_board_config_size = ARRAY_SIZE(omap3_evm_config); + omap3_pm_init_opp_table(); omap2_init_common_hw(mt46h32m32lf6_sdrc_params, NULL, omap3_mpu_rate_table, omap3_dsp_rate_table, omap3_l3_rate_table); omap_init_irq(); diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c index 527f0c6..1f24933 100644 --- a/arch/arm/mach-omap2/board-rx51.c +++ b/arch/arm/mach-omap2/board-rx51.c @@ -31,6 +31,7 @@ #include <plat/gpmc.h> #include <plat/usb.h> +#include "pm.h" #include "omap3-opp.h" #define RX51_GPIO_SLEEP_IND 162 @@ -84,6 +85,7 @@ static void __init rx51_init_irq(void) { omap_board_config = rx51_config; omap_board_config_size = ARRAY_SIZE(rx51_config); + omap3_pm_init_opp_table(); omap2_init_common_hw(rx51_get_sdram_timings(), rx51_get_sdram_timings(), omap3_mpu_rate_table, omap3_dsp_rate_table, omap3_l3_rate_table); diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c index b6801a7..a7e1fee 100644 --- a/arch/arm/mach-omap2/board-zoom2.c +++ b/arch/arm/mach-omap2/board-zoom2.c @@ -25,6 +25,7 @@ #include <plat/usb.h> #include "mmc-twl4030.h" +#include "pm.h" #include "sdram-micron-mt46h32m32lf-6.h" #include "omap3-opp.h" @@ -215,6 +216,7 @@ static void __init omap_zoom2_init_irq(void) { omap_board_config = zoom2_config; omap_board_config_size = ARRAY_SIZE(zoom2_config); + omap3_pm_init_opp_table(); omap2_init_common_hw(mt46h32m32lf6_sdrc_params, mt46h32m32lf6_sdrc_params, omap3_mpu_rate_table, omap3_dsp_rate_table, omap3_l3_rate_table); diff --git a/arch/arm/mach-omap2/omap3-opp.h b/arch/arm/mach-omap2/omap3-opp.h index 27e2ca5..7f27f44 100644 --- a/arch/arm/mach-omap2/omap3-opp.h +++ b/arch/arm/mach-omap2/omap3-opp.h @@ -21,8 +21,8 @@ #define S83M 83000000 #define S166M 166000000 -extern struct omap_opp omap3_mpu_rate_table[]; -extern struct omap_opp omap3_dsp_rate_table[]; -extern struct omap_opp omap3_l3_rate_table[]; +extern struct omap_opp *omap3_mpu_rate_table; +extern struct omap_opp *omap3_dsp_rate_table; +extern struct omap_opp *omap3_l3_rate_table; #endif diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index b576424..1aabf74 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -51,6 +51,14 @@ struct cpuidle_params { extern void omap3_pm_init_vc(struct prm_setup_vc *setup_vc); extern void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params); +/** + * omap3_pm_init_opp_table - OMAP opp table lookup called after + * cpu is detected. + * Initialize the basic opp table here, board files + * could choose to modify opp table after the basic initialization + */ +extern void omap3_pm_init_opp_table(void); + extern int resource_set_opp_level(int res, u32 target_level, int flags); extern int resource_access_opp_lock(int res, int delta); #define resource_lock_opp(res) resource_access_opp_lock(res, 1) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 92f11d7..511137c 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -99,7 +99,7 @@ static struct prm_setup_vc prm_setup = { .vdd1_off = 0x00, /* 0.6v */ }; -struct omap_opp omap3_mpu_rate_table[] = { +static __initdata struct omap_opp omap34xx_mpu_rate_table[] = { {0, 0, 0, 0}, /*OPP1*/ {true, S125M, VDD1_OPP1, 0x1E}, @@ -114,7 +114,7 @@ struct omap_opp omap3_mpu_rate_table[] = { {0, 0, 0, 0}, }; -struct omap_opp omap3_l3_rate_table[] = { +static __initdata struct omap_opp omap34xx_l3_rate_table[] = { {0, 0, 0, 0}, /*OPP1*/ {false, 0, VDD2_OPP1, 0x1E}, @@ -125,7 +125,7 @@ struct omap_opp omap3_l3_rate_table[] = { {0, 0, 0, 0}, }; -struct omap_opp omap3_dsp_rate_table[] = { +static __initdata struct omap_opp omap34xx_dsp_rate_table[] = { {0, 0, 0, 0}, /*OPP1*/ {true, S90M, VDD1_OPP1, 0x1E}, @@ -140,6 +140,10 @@ struct omap_opp omap3_dsp_rate_table[] = { {0, 0, 0, 0}, }; +struct omap_opp *omap3_mpu_rate_table; +struct omap_opp *omap3_dsp_rate_table; +struct omap_opp *omap3_l3_rate_table; + static inline void omap3_per_save_context(void) { omap_gpio_save_context(); @@ -1276,6 +1280,27 @@ static void __init configure_vc(void) pm_dbg_regset_init(2); } +void __init omap3_pm_init_opp_table(void) +{ + /* Populate the base CPU rate tables here */ + omap3_mpu_rate_table = kmalloc(sizeof(omap34xx_mpu_rate_table), + GFP_KERNEL); + omap3_dsp_rate_table = kmalloc(sizeof(omap34xx_dsp_rate_table), + GFP_KERNEL); + omap3_l3_rate_table = kmalloc(sizeof(omap34xx_l3_rate_table), + GFP_KERNEL); + + BUG_ON(!omap3_mpu_rate_table || !omap3_dsp_rate_table || + !omap3_l3_rate_table); + + memcpy(omap3_mpu_rate_table, omap34xx_mpu_rate_table, + sizeof(omap34xx_mpu_rate_table)); + memcpy(omap3_dsp_rate_table, omap34xx_dsp_rate_table, + sizeof(omap34xx_dsp_rate_table)); + memcpy(omap3_l3_rate_table, omap34xx_l3_rate_table, + sizeof(omap34xx_l3_rate_table)); +} + static int __init omap3_pm_early_init(void) { prm_clear_mod_reg_bits(OMAP3430_OFFMODE_POL, OMAP3430_GR_MOD, -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 9/9] omap3: pm: introduce 3630 opps 2009-11-12 5:45 ` [PATCH 8/9] omap3: pm: introduce dynamic OPP Nishanth Menon @ 2009-11-12 5:45 ` Nishanth Menon 0 siblings, 0 replies; 22+ messages in thread From: Nishanth Menon @ 2009-11-12 5:45 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, Thara Gopinath, Vishwanath Sripathy Introduce the OMAP3630 OPPs including the defined OPP tuples. Further information on OMAP3630 can be found here: http://focus.ti.com/general/docs/wtbu/wtbuproductcontent.tsp?templateId=6123&navigationId=12836&contentId=52606 OMAP36xx family introduces: VDD1 with 4 OPPs, of which OPP3 & 4 are available only on devices yet to be introduced in 36xx family. Meanwhile, VDD2 has 2 opps. Device Support of OPPs-> |<-3630-600->| (default) |<- 3630-800 ->| (device: TBD) |<- 3630-1000 ->| (device: TBD) H/w OPP-> OPP50 OPP100 OPP-Turbo OPP1G-SB VDD1 OPP1 OPP2 OPP3 OPP4 VDD2 OPP1 OPP2 OPP2 OPP2 Note: a) TI h/w naming for OPPs are now standardized in terms of OPP50, 100, Turbo and SB. This maps as shown above to the opp IDs (s/w term). b) For boards which need custom VDD1/2 OPPs, the opp table can be updated by the board file on a need basis after the omap3_pm_init_opp_table call. The OPPs introduced here are the official OPP table at this point in time. Cc: Benoit Cousson <b-cousson@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/omap3-opp.h | 9 ++++ arch/arm/mach-omap2/pm34xx.c | 87 +++++++++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-omap2/omap3-opp.h b/arch/arm/mach-omap2/omap3-opp.h index 7f27f44..a5880b8 100644 --- a/arch/arm/mach-omap2/omap3-opp.h +++ b/arch/arm/mach-omap2/omap3-opp.h @@ -4,22 +4,31 @@ #include <plat/omap-pm.h> /* MPU speeds */ +#define S1000M 1000000000 +#define S800M 800000000 #define S600M 600000000 #define S550M 550000000 #define S500M 500000000 +#define S300M 300000000 #define S250M 250000000 #define S125M 125000000 /* DSP speeds */ +#define S875M 875000000 +#define S660M 660000000 +#define S520M 520000000 #define S430M 430000000 #define S400M 400000000 #define S360M 360000000 +#define S260M 260000000 #define S180M 180000000 #define S90M 90000000 /* L3 speeds */ #define S83M 83000000 +#define S100M 100000000 #define S166M 166000000 +#define S200M 200000000 extern struct omap_opp *omap3_mpu_rate_table; extern struct omap_opp *omap3_dsp_rate_table; diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 511137c..ffed70f 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -140,6 +140,41 @@ static __initdata struct omap_opp omap34xx_dsp_rate_table[] = { {0, 0, 0, 0}, }; +static __initdata struct omap_opp omap36xx_mpu_rate_table[] = { + {0, 0, 0, 0}, + /*OPP1 - 930mV - OPP50*/ + {true, S300M, VDD1_OPP1, 0x1A}, + /*OPP2 - 1.100V - OPP100*/ + {true, S600M, VDD1_OPP2, 0x28}, + /*OPP3 - 1.260V - OPP-Turbo*/ + {true, S800M, VDD1_OPP3, 0x34}, + /*OPP4 - 1.310V - OPP-SB*/ + {false, S1000M, VDD1_OPP4, 0x38}, + {0, 0, 0, 0}, +}; + +static __initdata struct omap_opp omap36xx_l3_rate_table[] = { + {0, 0, 0, 0}, + /*OPP1 - 930mV - OPP50 */ + {true, S100M, VDD2_OPP1, 0x1A}, + /*OPP2 - 1.375V - OPP100, OPP-Turbo, OPP-SB*/ + {true, S200M, VDD2_OPP2, 0x3E}, + {0, 0, 0, 0}, +}; + +static __initdata struct omap_opp omap36xx_dsp_rate_table[] = { + {0, 0, 0, 0}, + /*OPP1 - OPP50*/ + {true, S260M, VDD1_OPP1, 0x1A}, + /*OPP2 - OPP100*/ + {true, S520M, VDD1_OPP2, 0x28}, + /*OPP3 - OPP-Turbo*/ + {false, S660M, VDD1_OPP3, 0x34}, + /*OPP4 - OPP-SB*/ + {false, S875M, VDD1_OPP4, 0x38}, + {0, 0, 0, 0}, +}; + struct omap_opp *omap3_mpu_rate_table; struct omap_opp *omap3_dsp_rate_table; struct omap_opp *omap3_l3_rate_table; @@ -1283,22 +1318,42 @@ static void __init configure_vc(void) void __init omap3_pm_init_opp_table(void) { /* Populate the base CPU rate tables here */ - omap3_mpu_rate_table = kmalloc(sizeof(omap34xx_mpu_rate_table), - GFP_KERNEL); - omap3_dsp_rate_table = kmalloc(sizeof(omap34xx_dsp_rate_table), - GFP_KERNEL); - omap3_l3_rate_table = kmalloc(sizeof(omap34xx_l3_rate_table), - GFP_KERNEL); - - BUG_ON(!omap3_mpu_rate_table || !omap3_dsp_rate_table || - !omap3_l3_rate_table); - - memcpy(omap3_mpu_rate_table, omap34xx_mpu_rate_table, - sizeof(omap34xx_mpu_rate_table)); - memcpy(omap3_dsp_rate_table, omap34xx_dsp_rate_table, - sizeof(omap34xx_dsp_rate_table)); - memcpy(omap3_l3_rate_table, omap34xx_l3_rate_table, - sizeof(omap34xx_l3_rate_table)); + if (cpu_is_omap3630()) { + omap3_mpu_rate_table = kmalloc(sizeof(omap36xx_mpu_rate_table), + GFP_KERNEL); + omap3_dsp_rate_table = kmalloc(sizeof(omap36xx_dsp_rate_table), + GFP_KERNEL); + omap3_l3_rate_table = kmalloc(sizeof(omap36xx_l3_rate_table), + GFP_KERNEL); + + BUG_ON(!omap3_mpu_rate_table || !omap3_dsp_rate_table || + !omap3_l3_rate_table); + + memcpy(omap3_mpu_rate_table, omap36xx_mpu_rate_table, + sizeof(omap36xx_mpu_rate_table)); + memcpy(omap3_dsp_rate_table, omap36xx_dsp_rate_table, + sizeof(omap36xx_dsp_rate_table)); + memcpy(omap3_l3_rate_table, omap36xx_l3_rate_table, + sizeof(omap36xx_l3_rate_table)); + } else { + /* Default to 34xx devices */ + omap3_mpu_rate_table = kmalloc(sizeof(omap34xx_mpu_rate_table), + GFP_KERNEL); + omap3_dsp_rate_table = kmalloc(sizeof(omap34xx_dsp_rate_table), + GFP_KERNEL); + omap3_l3_rate_table = kmalloc(sizeof(omap34xx_l3_rate_table), + GFP_KERNEL); + + BUG_ON(!omap3_mpu_rate_table || !omap3_dsp_rate_table || + !omap3_l3_rate_table); + + memcpy(omap3_mpu_rate_table, omap34xx_mpu_rate_table, + sizeof(omap34xx_mpu_rate_table)); + memcpy(omap3_dsp_rate_table, omap34xx_dsp_rate_table, + sizeof(omap34xx_dsp_rate_table)); + memcpy(omap3_l3_rate_table, omap34xx_l3_rate_table, + sizeof(omap34xx_l3_rate_table)); + } } static int __init omap3_pm_early_init(void) -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2009-11-12 5:45 ` [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp Nishanth Menon 2009-11-12 5:45 ` [PATCH 6/9] omap3: clk: use pm accessor functions for cpufreq table Nishanth Menon @ 2009-12-18 23:12 ` Kevin Hilman 2009-12-19 11:35 ` Menon, Nishanth 2009-12-21 6:58 ` Romit Dasgupta 1 sibling, 2 replies; 22+ messages in thread From: Kevin Hilman @ 2009-12-18 23:12 UTC (permalink / raw) To: Nishanth Menon Cc: linux-omap, Benoit Cousson, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, Thara Gopinath, Vishwanath Sripathy Nishanth Menon <nm@ti.com> writes: > SmartReflex implements a get_opp to search through the opp table, > replace it with the accessor function as it is a duplicate of > freq_to_opp SmartReflex is not quite working with this version which is in pm-wip-opp. My (untested) theory below... [...] > --- a/arch/arm/mach-omap2/smartreflex.c > +++ b/arch/arm/mach-omap2/smartreflex.c > @@ -146,49 +146,29 @@ static u32 cal_test_nvalue(u32 sennval, u32 senpval) > (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT); > } > > -/* determine the current OPP from the frequency > - * we need to give this function last element of OPP rate table > - * and the frequency > - */ > -static u16 get_opp(struct omap_opp *opp_freq_table, > - unsigned long freq) > -{ > - struct omap_opp *prcm_config; > - > - prcm_config = opp_freq_table; > - > - if (prcm_config->rate <= freq) > - return prcm_config->opp_id; /* Return the Highest OPP */ > - for (; prcm_config->rate; prcm_config--) > - if (prcm_config->rate < freq) > - return (prcm_config+1)->opp_id; > - else if (prcm_config->rate == freq) > - return prcm_config->opp_id; > - /* Return the least OPP */ > - return (prcm_config+1)->opp_id; > -} The function you removed here is doing the equivalent of opp_find_freq_ceil() > -static u16 get_vdd1_opp(void) > +static u8 get_vdd1_opp(void) > { > - u16 opp; > + u8 opp; > > if (sr1.vdd_opp_clk == NULL || IS_ERR(sr1.vdd_opp_clk) || > mpu_opps == NULL) > return 0; > > - opp = get_opp(mpu_opps + MAX_VDD1_OPP, sr1.vdd_opp_clk->rate); > + /* Not expected to fail.. */ > + BUG_ON(freq_to_opp(&opp, mpu_opps, sr1.vdd_opp_clk->rate)); > return opp; > } Ih this version you use freq_to_opp(), but in the V5 tarball you sent, you replace get_opp with: opp = opp_find_freq_exact(mpu_opps, sr1.vdd_opp_clk->rate, true); This results in never finding an OPP, and SR never scaling. This should probably be opp_find_freq_ceil(), right? Kevin ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2009-12-18 23:12 ` [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp Kevin Hilman @ 2009-12-19 11:35 ` Menon, Nishanth 2009-12-22 16:45 ` Kevin Hilman 2009-12-21 6:58 ` Romit Dasgupta 1 sibling, 1 reply; 22+ messages in thread From: Menon, Nishanth @ 2009-12-19 11:35 UTC (permalink / raw) To: Kevin Hilman Cc: linux-omap, Cousson, Benoit, Chikkature Rajashekar, Madhusudhan, Paul Walmsley, Dasgupta, Romit, Premi, Sanjeev, Shilimkar, Santosh, Aguirre, Sergio, Gopinath, Thara, Sripathy, Vishwanath, K, Ambresh Kevin Hilman said the following on 12/19/2009 04:42 AM: > Nishanth Menon <nm@ti.com> writes: > > >> SmartReflex implements a get_opp to search through the opp table, >> replace it with the accessor function as it is a duplicate of >> freq_to_opp >> > > SmartReflex is not quite working with this version which is in > pm-wip-opp. My (untested) theory below... > > [...] > Ambresh and I just tested the very latest of the pm-wip-opp branch and checked. Voltage transitions and SR adjustments are happily happening on SDP3430 ES3.1 at the very least (verified with a scope on vdd1). and if you look closely in the code, sr2.vdd_opp_clk->rate and sr1.vdd_opp_clk->rate are based on sr1.vdd_opp_clk = clk_get(NULL, "dpll1_ck") sr2.vdd_opp_clk = clk_get(NULL, "l3_ick"); now, if the dpll1_ck ->rate and l3_ick->rate are not exact frequencies as the opp tables, I think we have a clockframework bug and the code here is correct. we should fix the clockframework/find the rootcause elsewhere. Now is the clockframework wrong? we added a patch to print the frequencies and checked if IS_ERR(opp) is true -> not a single call while using cpu_freq transitions resulted in an error value and all the frequencies we printed were from the OPP table Might be good to hear your rationale for saying this result.. Regards, Nishanth Menon ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2009-12-19 11:35 ` Menon, Nishanth @ 2009-12-22 16:45 ` Kevin Hilman 2010-01-06 23:46 ` Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Kevin Hilman @ 2009-12-22 16:45 UTC (permalink / raw) To: nm Cc: linux-omap, Cousson, Benoit, Chikkature Rajashekar, Madhusudhan, Paul Walmsley, Dasgupta, Romit, Premi, Sanjeev, Shilimkar, Santosh, Aguirre, Sergio, Gopinath, Thara, Sripathy, Vishwanath, K, Ambresh "Menon, Nishanth" <nm@ti.com> writes: > Kevin Hilman said the following on 12/19/2009 04:42 AM: >> Nishanth Menon <nm@ti.com> writes: >> >> >>> SmartReflex implements a get_opp to search through the opp table, >>> replace it with the accessor function as it is a duplicate of >>> freq_to_opp >>> >> >> SmartReflex is not quite working with this version which is in >> pm-wip-opp. My (untested) theory below... >> >> [...] >> > Ambresh and I just tested the very latest of the pm-wip-opp branch > and checked. Voltage transitions and SR adjustments are happily > happening on SDP3430 ES3.1 at the very least (verified with a scope on > vdd1). > > and if you look closely in the code, sr2.vdd_opp_clk->rate and > sr1.vdd_opp_clk->rate are based on > sr1.vdd_opp_clk = clk_get(NULL, "dpll1_ck") > sr2.vdd_opp_clk = clk_get(NULL, "l3_ick"); > > now, if the dpll1_ck ->rate and l3_ick->rate are not exact frequencies > as the opp tables, I think we have a clockframework bug and the code > here is correct. we should fix the clockframework/find the rootcause > elsewhere. > > Now is the clockframework wrong? we added a patch to print the > frequencies and checked if IS_ERR(opp) is true -> not a single call > while using cpu_freq transitions resulted in an error value and all > the frequencies we printed were from the OPP table > > Might be good to hear your rationale for saying this result.. Part of my rationale was that the PM branch version get_vdd1_opp() does an approximate match (actually the equivalent of opp_find_freq_ceil() via get_opp.) So you replaced an approximate match with an exact match. That may be the right solution and point to a bug elsewhere, but it was not an equivalent replacement, and probably should've been done in a separate patch with justification/rationale. I didn't catch it during initial review. But the primary reason I noticed it in the first place was that I was seeing DVFS errors on n900, which is the only platform I have that actually can do SmartReflex. Specifically, sr_reset_voltage() is failing for VDD1. Dumping out the clock rates used in get_vdd1_opp() show that the clocks rates are close, but not the exact value used in the OPP table. Here is the patch I used to add some debugging, and I see that for the 250MHz OPP, the clock framework rate is 249600000 and for the 125MHz OPP, the clock rate is 124800000. As I said, close, but clearly an find with exact match is going to fail. Below the patch, is the console dump and backtrace of how get_vdd1_opp() was called so you can see the call chain. Kevin diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index d341857..01a3dbd 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -155,6 +155,8 @@ static u8 get_vdd1_opp(void) mpu_opps == NULL) return 0; + printk("%s: sr1.vdd_opp_clk->rate = %d\n", __func__, + sr1.vdd_opp_clk->rate); opp = opp_find_freq_exact(mpu_opps, sr1.vdd_opp_clk->rate, true); if (IS_ERR(opp)) return 0; @@ -451,6 +453,7 @@ static int sr_reset_voltage(int srid) target_opp_no = get_vdd1_opp(); if (!target_opp_no) { pr_info("Current OPP unknown: Cannot reset voltage\n"); + __backtrace(); return 1; } /sys/devices/system/cpu/cpu0/cpufreq # echo 250000 > scaling_setspeed get_vdd1_opp: sr1.vdd_opp_clk->rate = 249600000 Current OPP unknown: Cannot reset voltage [<c0042c98>] (sr_reset_voltage+0x0/0x190) from [<c0043094>] (sr_stop_vddautocomap+0x12c/0x148) r7:00000001 r6:00000001 r5:c03ac878 r4:00000000 [<c0042f68>] (sr_stop_vddautocomap+0x0/0x148) from [<c0043388>] (sr_voltagescale_vcbypass+0x2c/0x170) r7:00000001 r6:00000001 r5:00000030 r4:00000026 [<c004335c>] (sr_voltagescale_vcbypass+0x0/0x170) from [<c0043e00>] (program_opp+0x1e4/0x210) [<c0043c1c>] (program_opp+0x0/0x210) from [<c0043f64>] (resource_set_opp_level+0x138/0x1b0) [<c0043e2c>] (resource_set_opp_level+0x0/0x1b0) from [<c0044024>] (set_opp+0x48/0x120) [<c0043fdc>] (set_opp+0x0/0x120) from [<c004bb48>] (update_resource_level+0xb0/0xd4) r5:c03b365c r4:00000002 [<c004ba98>] (update_resource_level+0x0/0xd4) from [<c004be34>] (resource_request+0x154/0x184) r7:00000002 r6:c03db5a0 r5:c03b365c r4:00000000 [<c004bce0>] (resource_request+0x0/0x184) from [<c0043a50>] (set_freq+0xb4/0xe8) r7:0ee6b280 r6:cf801080 r5:cf801000 r4:c0359347 [<c004399c>] (set_freq+0x0/0xe8) from [<c004bb48>] (update_resource_level+0xb0/0xd4) r8:c03d52f8 r7:0ee6b280 r6:c03dbf70 r5:c03b36a4 r4:0ee6b280 [<c004ba98>] (update_resource_level+0x0/0xd4) from [<c004be34>] (resource_request+0x154/0x184) r7:0ee6b280 r6:c03dbf70 r5:c03b36a4 r4:00000000 [<c004bce0>] (resource_request+0x0/0x184) from [<c004b7a4>] (omap_pm_cpu_set_freq+0x34/0x44) r7:00000007 r6:cfae7000 r5:cf96c100 r4:0003d090 [<c004b770>] (omap_pm_cpu_set_freq+0x0/0x44) from [<c004ac44>] (omap_target+0x64/0x74) [<c004abe0>] (omap_target+0x0/0x74) from [<c02318c4>] (__cpufreq_driver_target+0x30/0x40) [<c0231894>] (__cpufreq_driver_target+0x0/0x40) from [<c02339e8>] (cpufreq_set+0x58/0x74) [<c0233990>] (cpufreq_set+0x0/0x74) from [<c0231b9c>] (store_scaling_setspeed+0x64/0x7c) r5:00000007 r4:cf96c100 [<c0231b38>] (store_scaling_setspeed+0x0/0x7c) from [<c0232ae0>] (store+0x60/0x7c) r5:cf96c100 r4:c03d53f8 [<c0232a80>] (store+0x0/0x7c) from [<c010c684>] (sysfs_write_file+0x110/0x144) r7:cf96c150 r6:cfb10bc0 r5:cf8fc000 r4:00000007 [<c010c574>] (sysfs_write_file+0x0/0x144) from [<c00bbdcc>] (vfs_write+0xb8/0x164) [<c00bbd14>] (vfs_write+0x0/0x164) from [<c00bbf3c>] (sys_write+0x44/0x70) r8:40001000 r7:00000007 r6:cfafa280 r5:00000000 r4:00000000 [<c00bbef8>] (sys_write+0x0/0x70) from [<c0030fc0>] (ret_fast_syscall+0x0/0x2c) r8:c0031144 r7:00000004 r6:41149600 r5:40001000 r4:00000007 /sys/devices/system/cpu/cpu0/cpufreq # echo 125000 > scaling_setspeed get_vdd1_opp: sr1.vdd_opp_clk->rate = 124800000 Current OPP unknown: Cannot reset voltage [<c0042c98>] (sr_reset_voltage+0x0/0x190) from [<c0043094>] (sr_stop_vddautocomap+0x12c/0x148) r7:00000001 r6:00000001 r5:c03ac878 r4:00000000 [<c0042f68>] (sr_stop_vddautocomap+0x0/0x148) from [<c0043388>] (sr_voltagescale_vcbypass+0x2c/0x170) r7:00000001 r6:00000001 r5:00000026 r4:0000001e [<c004335c>] (sr_voltagescale_vcbypass+0x0/0x170) from [<c0043e00>] (program_opp+0x1e4/0x210) [<c0043c1c>] (program_opp+0x0/0x210) from [<c0043f64>] (resource_set_opp_level+0x138/0x1b0) [<c0043e2c>] (resource_set_opp_level+0x0/0x1b0) from [<c0044024>] (set_opp+0x48/0x120) [<c0043fdc>] (set_opp+0x0/0x120) from [<c004bb48>] (update_resource_level+0xb0/0xd4) r5:c03b365c r4:00000001 [<c004ba98>] (update_resource_level+0x0/0xd4) from [<c004be34>] (resource_request+0x154/0x184) r7:00000001 r6:c03db5a0 r5:c03b365c r4:00000000 [<c004bce0>] (resource_request+0x0/0x184) from [<c0043a50>] (set_freq+0xb4/0xe8) r7:07735940 r6:cf801080 r5:cf801000 r4:c0359347 [<c004399c>] (set_freq+0x0/0xe8) from [<c004bb48>] (update_resource_level+0xb0/0xd4) r8:c03d52f8 r7:07735940 r6:c03dbf70 r5:c03b36a4 r4:07735940 [<c004ba98>] (update_resource_level+0x0/0xd4) from [<c004be34>] (resource_request+0x154/0x184) r7:07735940 r6:c03dbf70 r5:c03b36a4 r4:00000000 [<c004bce0>] (resource_request+0x0/0x184) from [<c004b7a4>] (omap_pm_cpu_set_freq+0x34/0x44) r7:00000007 r6:cfae7000 r5:cf96c100 r4:0001e848 [<c004b770>] (omap_pm_cpu_set_freq+0x0/0x44) from [<c004ac44>] (omap_target+0x64/0x74) [<c004abe0>] (omap_target+0x0/0x74) from [<c02318c4>] (__cpufreq_driver_target+0x30/0x40) [<c0231894>] (__cpufreq_driver_target+0x0/0x40) from [<c02339e8>] (cpufreq_set+0x58/0x74) [<c0233990>] (cpufreq_set+0x0/0x74) from [<c0231b9c>] (store_scaling_setspeed+0x64/0x7c) r5:00000007 r4:cf96c100 [<c0231b38>] (store_scaling_setspeed+0x0/0x7c) from [<c0232ae0>] (store+0x60/0x7c) r5:cf96c100 r4:c03d53f8 [<c0232a80>] (store+0x0/0x7c) from [<c010c684>] (sysfs_write_file+0x110/0x144) r7:cf96c150 r6:cfb10bc0 r5:cf8fc000 r4:00000007 [<c010c574>] (sysfs_write_file+0x0/0x144) from [<c00bbdcc>] (vfs_write+0xb8/0x164) [<c00bbd14>] (vfs_write+0x0/0x164) from [<c00bbf3c>] (sys_write+0x44/0x70) r8:40001000 r7:00000007 r6:cfafa700 r5:00000000 r4:00000000 [<c00bbef8>] (sys_write+0x0/0x70) from [<c0030fc0>] (ret_fast_syscall+0x0/0x2c) r8:c0031144 r7:00000004 r6:41149600 r5:40001000 r4:00000007 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2009-12-22 16:45 ` Kevin Hilman @ 2010-01-06 23:46 ` Nishanth Menon 2010-01-07 0:23 ` Kevin Hilman 2010-01-07 8:35 ` Sripathy, Vishwanath 0 siblings, 2 replies; 22+ messages in thread From: Nishanth Menon @ 2010-01-06 23:46 UTC (permalink / raw) To: Kevin Hilman Cc: linux-omap, Cousson, Benoit, Chikkature Rajashekar, Madhusudhan, Paul Walmsley, Dasgupta, Romit, Premi, Sanjeev, Shilimkar, Santosh, Aguirre, Sergio, Gopinath, Thara, Sripathy, Vishwanath, K, Ambresh Kevin Hilman had written, on 12/22/2009 10:45 AM, the following: > "Menon, Nishanth" <nm@ti.com> writes: > >> Kevin Hilman said the following on 12/19/2009 04:42 AM: >>> Nishanth Menon <nm@ti.com> writes: >>> >>> >>>> SmartReflex implements a get_opp to search through the opp table, >>>> replace it with the accessor function as it is a duplicate of >>>> freq_to_opp >>>> >>> SmartReflex is not quite working with this version which is in >>> pm-wip-opp. My (untested) theory below... >>> >>> [...] >>> >> Ambresh and I just tested the very latest of the pm-wip-opp branch >> and checked. Voltage transitions and SR adjustments are happily >> happening on SDP3430 ES3.1 at the very least (verified with a scope on >> vdd1). >> >> and if you look closely in the code, sr2.vdd_opp_clk->rate and >> sr1.vdd_opp_clk->rate are based on >> sr1.vdd_opp_clk = clk_get(NULL, "dpll1_ck") >> sr2.vdd_opp_clk = clk_get(NULL, "l3_ick"); >> >> now, if the dpll1_ck ->rate and l3_ick->rate are not exact frequencies >> as the opp tables, I think we have a clockframework bug and the code >> here is correct. we should fix the clockframework/find the rootcause >> elsewhere. >> >> Now is the clockframework wrong? we added a patch to print the >> frequencies and checked if IS_ERR(opp) is true -> not a single call >> while using cpu_freq transitions resulted in an error value and all >> the frequencies we printed were from the OPP table >> >> Might be good to hear your rationale for saying this result.. > > Part of my rationale was that the PM branch version get_vdd1_opp() > does an approximate match (actually the equivalent of > opp_find_freq_ceil() via get_opp.) So you replaced an approximate > match with an exact match. That may be the right solution and point > to a bug elsewhere, but it was not an equivalent replacement, and > probably should've been done in a separate patch with > justification/rationale. I didn't catch it during initial review. > > But the primary reason I noticed it in the first place was that I was > seeing DVFS errors on n900, which is the only platform I have that > actually can do SmartReflex. Specifically, sr_reset_voltage() is > failing for VDD1. Dumping out the clock rates used in get_vdd1_opp() > show that the clocks rates are close, but not the exact value used in > the OPP table. > > Here is the patch I used to add some debugging, and I see that for the > 250MHz OPP, the clock framework rate is 249600000 and for the 125MHz > OPP, the clock rate is 124800000. As I said, close, but clearly an > find with exact match is going to fail. > > Below the patch, is the console dump and backtrace of how get_vdd1_opp() > was called so you can see the call chain. > > Kevin > > diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c > index d341857..01a3dbd 100644 > --- a/arch/arm/mach-omap2/smartreflex.c > +++ b/arch/arm/mach-omap2/smartreflex.c > @@ -155,6 +155,8 @@ static u8 get_vdd1_opp(void) > mpu_opps == NULL) > return 0; > > + printk("%s: sr1.vdd_opp_clk->rate = %d\n", __func__, > + sr1.vdd_opp_clk->rate); > opp = opp_find_freq_exact(mpu_opps, sr1.vdd_opp_clk->rate, true); > if (IS_ERR(opp)) > return 0; > @@ -451,6 +453,7 @@ static int sr_reset_voltage(int srid) > target_opp_no = get_vdd1_opp(); > if (!target_opp_no) { > pr_info("Current OPP unknown: Cannot reset voltage\n"); > + __backtrace(); > return 1; > } > > > > /sys/devices/system/cpu/cpu0/cpufreq # echo 250000 > scaling_setspeed > get_vdd1_opp: sr1.vdd_opp_clk->rate = 249600000 > Current OPP unknown: Cannot reset voltage > [<c0042c98>] (sr_reset_voltage+0x0/0x190) from [<c0043094>] (sr_stop_vddautocomap+0x12c/0x148) > r7:00000001 r6:00000001 r5:c03ac878 r4:00000000 > [<c0042f68>] (sr_stop_vddautocomap+0x0/0x148) from [<c0043388>] (sr_voltagescale_vcbypass+0x2c/0x170) [...] Throws up my hands! 3430 on N900/SDP3430 should be essentially the same! Configuration: ============== kernel: git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm.git branch: pm-wip-opp 6e1276f omap3:pm: remove map3_[mpu|dsp|l3]_rate_tables Applied my bugfix: http://patchwork.kernel.org/patch/71457/ I have a 3430 ES3.1 SDP3430 where I did run the test: Log Patch: http://pastebin.mozilla.org/695225 Test script: http://pastebin.mozilla.org/695226 (I call this test-me.sh) Result log: http://pastebin.mozilla.org/695224 huh? no crash, all the frequencies and transitions are good, the rates of dpll1,2,3 look good! there is something definitely fishy about N900 configuration?? -- Regards, Nishanth Menon ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2010-01-06 23:46 ` Nishanth Menon @ 2010-01-07 0:23 ` Kevin Hilman 2010-01-07 8:35 ` Sripathy, Vishwanath 1 sibling, 0 replies; 22+ messages in thread From: Kevin Hilman @ 2010-01-07 0:23 UTC (permalink / raw) To: Nishanth Menon Cc: linux-omap, Cousson, Benoit, Chikkature Rajashekar, Madhusudhan, Paul Walmsley, Dasgupta, Romit, Premi, Sanjeev, Shilimkar, Santosh, Aguirre, Sergio, Gopinath, Thara, Sripathy, Vishwanath, K, Ambresh Nishanth Menon <nm@ti.com> writes: > Kevin Hilman had written, on 12/22/2009 10:45 AM, the following: >> "Menon, Nishanth" <nm@ti.com> writes: >> >>> Kevin Hilman said the following on 12/19/2009 04:42 AM: >>>> Nishanth Menon <nm@ti.com> writes: >>>> >>>> >>>>> SmartReflex implements a get_opp to search through the opp table, >>>>> replace it with the accessor function as it is a duplicate of >>>>> freq_to_opp >>>>> >>>> SmartReflex is not quite working with this version which is in >>>> pm-wip-opp. My (untested) theory below... >>>> >>>> [...] >>>> >>> Ambresh and I just tested the very latest of the pm-wip-opp branch >>> and checked. Voltage transitions and SR adjustments are happily >>> happening on SDP3430 ES3.1 at the very least (verified with a scope on >>> vdd1). >>> >>> and if you look closely in the code, sr2.vdd_opp_clk->rate and >>> sr1.vdd_opp_clk->rate are based on >>> sr1.vdd_opp_clk = clk_get(NULL, "dpll1_ck") >>> sr2.vdd_opp_clk = clk_get(NULL, "l3_ick"); >>> >>> now, if the dpll1_ck ->rate and l3_ick->rate are not exact frequencies >>> as the opp tables, I think we have a clockframework bug and the code >>> here is correct. we should fix the clockframework/find the rootcause >>> elsewhere. >>> >>> Now is the clockframework wrong? we added a patch to print the >>> frequencies and checked if IS_ERR(opp) is true -> not a single call >>> while using cpu_freq transitions resulted in an error value and all >>> the frequencies we printed were from the OPP table >>> >>> Might be good to hear your rationale for saying this result.. >> >> Part of my rationale was that the PM branch version get_vdd1_opp() >> does an approximate match (actually the equivalent of >> opp_find_freq_ceil() via get_opp.) So you replaced an approximate >> match with an exact match. That may be the right solution and point >> to a bug elsewhere, but it was not an equivalent replacement, and >> probably should've been done in a separate patch with >> justification/rationale. I didn't catch it during initial review. >> >> But the primary reason I noticed it in the first place was that I was >> seeing DVFS errors on n900, which is the only platform I have that >> actually can do SmartReflex. Specifically, sr_reset_voltage() is >> failing for VDD1. Dumping out the clock rates used in get_vdd1_opp() >> show that the clocks rates are close, but not the exact value used in >> the OPP table. >> >> Here is the patch I used to add some debugging, and I see that for the >> 250MHz OPP, the clock framework rate is 249600000 and for the 125MHz >> OPP, the clock rate is 124800000. As I said, close, but clearly an >> find with exact match is going to fail. >> >> Below the patch, is the console dump and backtrace of how get_vdd1_opp() >> was called so you can see the call chain. >> >> Kevin >> >> diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c >> index d341857..01a3dbd 100644 >> --- a/arch/arm/mach-omap2/smartreflex.c >> +++ b/arch/arm/mach-omap2/smartreflex.c >> @@ -155,6 +155,8 @@ static u8 get_vdd1_opp(void) >> mpu_opps == NULL) >> return 0; >> + printk("%s: sr1.vdd_opp_clk->rate = %d\n", __func__, >> + sr1.vdd_opp_clk->rate); >> opp = opp_find_freq_exact(mpu_opps, sr1.vdd_opp_clk->rate, true); >> if (IS_ERR(opp)) >> return 0; >> @@ -451,6 +453,7 @@ static int sr_reset_voltage(int srid) >> target_opp_no = get_vdd1_opp(); >> if (!target_opp_no) { >> pr_info("Current OPP unknown: Cannot reset voltage\n"); >> + __backtrace(); >> return 1; >> } >> >> >> >> /sys/devices/system/cpu/cpu0/cpufreq # echo 250000 > >> scaling_setspeed get_vdd1_opp: sr1.vdd_opp_clk->rate = 249600000 >> Current OPP unknown: Cannot reset voltage >> [<c0042c98>] (sr_reset_voltage+0x0/0x190) from [<c0043094>] (sr_stop_vddautocomap+0x12c/0x148) >> r7:00000001 r6:00000001 r5:c03ac878 r4:00000000 >> [<c0042f68>] (sr_stop_vddautocomap+0x0/0x148) from [<c0043388>] (sr_voltagescale_vcbypass+0x2c/0x170) > [...] > > Throws up my hands! 3430 on N900/SDP3430 should be essentially the same! > > Configuration: > ============== > kernel: > git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm.git > branch: > pm-wip-opp 6e1276f omap3:pm: remove map3_[mpu|dsp|l3]_rate_tables > Applied my bugfix: http://patchwork.kernel.org/patch/71457/ > > I have a 3430 ES3.1 SDP3430 where I did run the test: > > Log Patch: http://pastebin.mozilla.org/695225 > Test script: http://pastebin.mozilla.org/695226 (I call this test-me.sh) > Result log: http://pastebin.mozilla.org/695224 > > huh? no crash, all the frequencies and transitions are good, the rates > of dpll1,2,3 look good! there is something definitely fishy about N900 > configuration?? OK, so for now we need to at least replace the original approximate match with an equivalent approximate match. Then, use an additional patch to change it to an exact match when we find out what's happening on N900. Kevin ^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2010-01-06 23:46 ` Nishanth Menon 2010-01-07 0:23 ` Kevin Hilman @ 2010-01-07 8:35 ` Sripathy, Vishwanath 2010-01-07 8:53 ` Romit Dasgupta 2010-01-07 12:15 ` Nishanth Menon 1 sibling, 2 replies; 22+ messages in thread From: Sripathy, Vishwanath @ 2010-01-07 8:35 UTC (permalink / raw) To: Menon, Nishanth, Kevin Hilman Cc: linux-omap, Cousson, Benoit, Chikkature Rajashekar, Madhusudhan, Paul Walmsley, Dasgupta, Romit, Premi, Sanjeev, Shilimkar, Santosh, Aguirre, Sergio, Gopinath, Thara, K, Ambresh Nishant, Have you tested your opp patches on 3630? Apparently opp changes in wip branch does not even boot on ZOOM3 board. Vishwa > -----Original Message----- > From: Menon, Nishanth > Sent: Thursday, January 07, 2010 5:16 AM > To: Kevin Hilman > Cc: linux-omap; Cousson, Benoit; Chikkature Rajashekar, Madhusudhan; Paul > Walmsley; Dasgupta, Romit; Premi, Sanjeev; Shilimkar, Santosh; Aguirre, Sergio; > Gopinath, Thara; Sripathy, Vishwanath; K, Ambresh > Subject: Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp > > Kevin Hilman had written, on 12/22/2009 10:45 AM, the following: > > "Menon, Nishanth" <nm@ti.com> writes: > > > >> Kevin Hilman said the following on 12/19/2009 04:42 AM: > >>> Nishanth Menon <nm@ti.com> writes: > >>> > >>> > >>>> SmartReflex implements a get_opp to search through the opp table, > >>>> replace it with the accessor function as it is a duplicate of > >>>> freq_to_opp > >>>> > >>> SmartReflex is not quite working with this version which is in > >>> pm-wip-opp. My (untested) theory below... > >>> > >>> [...] > >>> > >> Ambresh and I just tested the very latest of the pm-wip-opp branch > >> and checked. Voltage transitions and SR adjustments are happily > >> happening on SDP3430 ES3.1 at the very least (verified with a scope on > >> vdd1). > >> > >> and if you look closely in the code, sr2.vdd_opp_clk->rate and > >> sr1.vdd_opp_clk->rate are based on > >> sr1.vdd_opp_clk = clk_get(NULL, "dpll1_ck") > >> sr2.vdd_opp_clk = clk_get(NULL, "l3_ick"); > >> > >> now, if the dpll1_ck ->rate and l3_ick->rate are not exact frequencies > >> as the opp tables, I think we have a clockframework bug and the code > >> here is correct. we should fix the clockframework/find the rootcause > >> elsewhere. > >> > >> Now is the clockframework wrong? we added a patch to print the > >> frequencies and checked if IS_ERR(opp) is true -> not a single call > >> while using cpu_freq transitions resulted in an error value and all > >> the frequencies we printed were from the OPP table > >> > >> Might be good to hear your rationale for saying this result.. > > > > Part of my rationale was that the PM branch version get_vdd1_opp() > > does an approximate match (actually the equivalent of > > opp_find_freq_ceil() via get_opp.) So you replaced an approximate > > match with an exact match. That may be the right solution and point > > to a bug elsewhere, but it was not an equivalent replacement, and > > probably should've been done in a separate patch with > > justification/rationale. I didn't catch it during initial review. > > > > But the primary reason I noticed it in the first place was that I was > > seeing DVFS errors on n900, which is the only platform I have that > > actually can do SmartReflex. Specifically, sr_reset_voltage() is > > failing for VDD1. Dumping out the clock rates used in get_vdd1_opp() > > show that the clocks rates are close, but not the exact value used in > > the OPP table. > > > > Here is the patch I used to add some debugging, and I see that for the > > 250MHz OPP, the clock framework rate is 249600000 and for the 125MHz > > OPP, the clock rate is 124800000. As I said, close, but clearly an > > find with exact match is going to fail. > > > > Below the patch, is the console dump and backtrace of how get_vdd1_opp() > > was called so you can see the call chain. > > > > Kevin > > > > diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach- > omap2/smartreflex.c > > index d341857..01a3dbd 100644 > > --- a/arch/arm/mach-omap2/smartreflex.c > > +++ b/arch/arm/mach-omap2/smartreflex.c > > @@ -155,6 +155,8 @@ static u8 get_vdd1_opp(void) > > mpu_opps == NULL) > > return 0; > > > > + printk("%s: sr1.vdd_opp_clk->rate = %d\n", __func__, > > + sr1.vdd_opp_clk->rate); > > opp = opp_find_freq_exact(mpu_opps, sr1.vdd_opp_clk->rate, true); > > if (IS_ERR(opp)) > > return 0; > > @@ -451,6 +453,7 @@ static int sr_reset_voltage(int srid) > > target_opp_no = get_vdd1_opp(); > > if (!target_opp_no) { > > pr_info("Current OPP unknown: Cannot reset voltage\n"); > > + __backtrace(); > > return 1; > > } > > > > > > > > /sys/devices/system/cpu/cpu0/cpufreq # echo 250000 > scaling_setspeed > > get_vdd1_opp: sr1.vdd_opp_clk->rate = 249600000 > > Current OPP unknown: Cannot reset voltage > > [<c0042c98>] (sr_reset_voltage+0x0/0x190) from [<c0043094>] > (sr_stop_vddautocomap+0x12c/0x148) > > r7:00000001 r6:00000001 r5:c03ac878 r4:00000000 > > [<c0042f68>] (sr_stop_vddautocomap+0x0/0x148) from [<c0043388>] > (sr_voltagescale_vcbypass+0x2c/0x170) > [...] > > Throws up my hands! 3430 on N900/SDP3430 should be essentially the same! > > Configuration: > ============== > kernel: > git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm.git > branch: > pm-wip-opp 6e1276f omap3:pm: remove map3_[mpu|dsp|l3]_rate_tables > Applied my bugfix: http://patchwork.kernel.org/patch/71457/ > > I have a 3430 ES3.1 SDP3430 where I did run the test: > > Log Patch: http://pastebin.mozilla.org/695225 > Test script: http://pastebin.mozilla.org/695226 (I call this test-me.sh) > Result log: http://pastebin.mozilla.org/695224 > > huh? no crash, all the frequencies and transitions are good, the rates > of dpll1,2,3 look good! there is something definitely fishy about N900 > configuration?? > > -- > Regards, > Nishanth Menon ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2010-01-07 8:35 ` Sripathy, Vishwanath @ 2010-01-07 8:53 ` Romit Dasgupta 2010-01-07 9:13 ` Sripathy, Vishwanath 2010-01-07 12:15 ` Nishanth Menon 1 sibling, 1 reply; 22+ messages in thread From: Romit Dasgupta @ 2010-01-07 8:53 UTC (permalink / raw) To: Sripathy, Vishwanath Cc: Menon, Nishanth, Kevin Hilman, linux-omap, Cousson, Benoit, Chikkature Rajashekar, Madhusudhan, Paul Walmsley, Premi, Sanjeev, Shilimkar, Santosh, Aguirre, Sergio, Gopinath, Thara, K, Ambresh Sripathy, Vishwanath wrote: > Nishant, > Have you tested your opp patches on 3630? Apparently opp changes in wip branch does not even boot on ZOOM3 board. > > Vishwa Vishwa, did you try on top of my OPP patches? Thanks, -Romit ^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2010-01-07 8:53 ` Romit Dasgupta @ 2010-01-07 9:13 ` Sripathy, Vishwanath 0 siblings, 0 replies; 22+ messages in thread From: Sripathy, Vishwanath @ 2010-01-07 9:13 UTC (permalink / raw) To: Dasgupta, Romit Cc: Menon, Nishanth, Kevin Hilman, linux-omap, Cousson, Benoit, Chikkature Rajashekar, Madhusudhan, Paul Walmsley, Premi, Sanjeev, Shilimkar, Santosh, Aguirre, Sergio, Gopinath, Thara, K, Ambresh Yes Vijay tried with your OPP patches on 3630 ZOOM3 and it seems to work. Vishwa > -----Original Message----- > From: Dasgupta, Romit > Sent: Thursday, January 07, 2010 2:23 PM > To: Sripathy, Vishwanath > Cc: Menon, Nishanth; Kevin Hilman; linux-omap; Cousson, Benoit; Chikkature > Rajashekar, Madhusudhan; Paul Walmsley; Premi, Sanjeev; Shilimkar, Santosh; > Aguirre, Sergio; Gopinath, Thara; K, Ambresh > Subject: Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp > > Sripathy, Vishwanath wrote: > > Nishant, > > Have you tested your opp patches on 3630? Apparently opp changes in wip branch > does not even boot on ZOOM3 board. > > > > Vishwa > Vishwa, > did you try on top of my OPP patches? > > Thanks, > -Romit ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2010-01-07 8:35 ` Sripathy, Vishwanath 2010-01-07 8:53 ` Romit Dasgupta @ 2010-01-07 12:15 ` Nishanth Menon 2010-01-07 14:18 ` Nishanth Menon 1 sibling, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2010-01-07 12:15 UTC (permalink / raw) To: Sripathy, Vishwanath Cc: Kevin Hilman, linux-omap, Cousson, Benoit, Chikkature Rajashekar, Madhusudhan, Paul Walmsley, Dasgupta, Romit, Premi, Sanjeev, Shilimkar, Santosh, Aguirre, Sergio, Gopinath, Thara, K, Ambresh Sripathy, Vishwanath said the following on 01/07/2010 02:35 AM: > Nishant, > Have you tested your opp patches on 3630? Apparently opp changes in wip branch does not even boot on ZOOM3 board. > The original series was tested and reported with results. I have'nt had a chance to try with the newer patch set. if there are patches, they are most welcome meanwhile. I will also try to do some on SDP3630 later today. > Vishwa > > >> -----Original Message----- >> From: Menon, Nishanth >> Sent: Thursday, January 07, 2010 5:16 AM >> To: Kevin Hilman >> Cc: linux-omap; Cousson, Benoit; Chikkature Rajashekar, Madhusudhan; Paul >> Walmsley; Dasgupta, Romit; Premi, Sanjeev; Shilimkar, Santosh; Aguirre, Sergio; >> Gopinath, Thara; Sripathy, Vishwanath; K, Ambresh >> Subject: Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp >> being a nitpick: could we avoid top-posting please? Regards, Nishanth Menon ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2010-01-07 12:15 ` Nishanth Menon @ 2010-01-07 14:18 ` Nishanth Menon 0 siblings, 0 replies; 22+ messages in thread From: Nishanth Menon @ 2010-01-07 14:18 UTC (permalink / raw) To: Nishanth Menon Cc: Sripathy, Vishwanath, Kevin Hilman, linux-omap, Cousson, Benoit, Chikkature Rajashekar, Madhusudhan, Paul Walmsley, Dasgupta, Romit, Premi, Sanjeev, Shilimkar, Santosh, Aguirre, Sergio, Gopinath, Thara, K, Ambresh Nishanth Menon had written, on 01/07/2010 06:15 AM, the following: > Sripathy, Vishwanath said the following on 01/07/2010 02:35 AM: >> Nishant, >> Have you tested your opp patches on 3630? Apparently opp changes in wip branch does not even boot on ZOOM3 board. >> > The original series was tested and reported with results. I have'nt had > a chance to try with the newer patch set. if there are patches, they are > most welcome meanwhile. I will also try to do some on SDP3630 later today. > [...] http://pastebin.mozilla.org/695411 has the boot log on SDP3630! as reported previously clock framework is crashing, that is probably because the clock framework changes for 3630 corresponding to 3630 OPPs are not available. the scripts and kernel details are part of http://marc.info/?l=linux-omap&m=126282159227739&w=2 -- Regards, Nishanth Menon ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2009-12-18 23:12 ` [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp Kevin Hilman 2009-12-19 11:35 ` Menon, Nishanth @ 2009-12-21 6:58 ` Romit Dasgupta 1 sibling, 0 replies; 22+ messages in thread From: Romit Dasgupta @ 2009-12-21 6:58 UTC (permalink / raw) To: Kevin Hilman Cc: Menon, Nishanth, linux-omap, Cousson, Benoit, Chikkature Rajashekar, Madhusudhan, Paul Walmsley, Premi, Sanjeev, Shilimkar, Santosh, Aguirre, Sergio, Gopinath, Thara, Sripathy, Vishwanath Kevin Hilman wrote: > Nishanth Menon <nm@ti.com> writes: > > > SmartReflex is not quite working with this version which is in > pm-wip-opp. My (untested) theory below... Mostly you have not included SR in the build. OTOH I raised this issue earlier that the omap cpufreq driver is not honoring CPUFREQ_RELATION_L and CPUFREQ_RELATION_H flags. I do not understand why do we need to do a opp_find_freq_ceil here? The validate function of the frequency resources would have already identified if we can get this exact frequency or not. ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 0/9 v2] omap3: pm: introduce support for 3630 OPPs @ 2009-11-13 6:05 Nishanth Menon 2009-11-13 6:05 ` [PATCH 1/9] omap3: pm: introduce enabled flag to omap_opp Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-13 6:05 UTC (permalink / raw) To: linux-omap; +Cc: Nishanth Menon Hi, V2 of the patch series. What changed in V2: * Rebased to latest pm branch as of today (with zoom3 and SDP3630 support -thanks kevin and Vikram in getting it done) 8/9 changed * Jon Hunter pointed me to errors in vdd2 opp2 voltage that I made a mistake-9/9 changed * Lam pointed me to an error in OPP enable for 3630OPP I made- vdd1 opp3 was disabled by default in DSP but I missed MPU :( - 9/9 changed * Accepted Kevin's recommendation that I rename opp_onoff to opp_enable 2/9 changed * I realized that macro paramaters usage in IS_OPP_TERMINATOR, so made them mess up safe (2/9 changed) * Few of the patch subjects got renamed from "introduce opp accessor functions" to "use accessor function" to better reflect what was being done. Finally, This series has been tested on SDP3430 and SDP3630 :) - though not stress tested for various drivers - basic OPP changes on VDD1 & VDD2, and cpufreq tests only. Requesting more thorough testing from as many folks as possible. (omap3_pm_defconfig used) NOTE: SDP3630 needs the patch for 8250 as discussed here: http://marc.info/?l=linux-omap&m=125795354108797&w=2 I am reposting the complete rebased set as v2 to maintain continuity on the new baseline ==== This patch series is based on previous discussions: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg17632.html I have modified the initial patch From Sanjeev: http://patchwork.kernel.org/patch/50998/ Other than these, we cannot use the old VDDx_MAX based usage anymore as 3630 OPPs are now different and runtime handling is a must-have, hence introducing these accessor functions is not avoidable. The changes are incremental and tries to avoid intrusive change as much as possible. The OPP accessor functions introduced in this series is hopefully a start for us to optimize this heavily used path. Finally, I have only done limited testing of SR, as it is still in my TODO list to revamp SR in the form of a v5 patch next time I get some bandwidth. An alternate approach for detecting 3630 OPP is using FEATURES instead of detecting the cpu_type as I have implemented in this series. Nishanth Menon (9): omap3: pm: introduce enabled flag to omap_opp omap3: pm: introduce opp accessor functions omap3: pm: srf: use opp accessor function omap3: pm: use opp accessor functions for omap-target omap3: pm: sr: replace get_opp with freq_to_opp omap3: clk: use pm accessor functions for cpufreq table omap3: pm: remove VDDx_MIN/MAX macros omap3: pm: introduce dynamic OPP omap3: pm: introduce 3630 opps arch/arm/mach-omap2/board-3430sdp.c | 1 + arch/arm/mach-omap2/board-3630sdp.c | 6 +- arch/arm/mach-omap2/board-omap3beagle.c | 1 + arch/arm/mach-omap2/board-omap3evm.c | 1 + arch/arm/mach-omap2/board-rx51.c | 1 + arch/arm/mach-omap2/board-zoom2.c | 7 +- arch/arm/mach-omap2/board-zoom3.c | 6 +- arch/arm/mach-omap2/clock34xx.c | 46 +++++--- arch/arm/mach-omap2/omap3-opp.h | 49 ++------ arch/arm/mach-omap2/pm.c | 160 +++++++++++++++++++++++++ arch/arm/mach-omap2/pm.h | 7 + arch/arm/mach-omap2/pm34xx.c | 122 +++++++++++++++++++ arch/arm/mach-omap2/resource34xx.c | 174 +++++++++++++++++---------- arch/arm/mach-omap2/smartreflex.c | 36 ++----- arch/arm/plat-omap/cpu-omap.c | 12 +-- arch/arm/plat-omap/include/plat/omap-pm.h | 111 ++++++++++++++++++ arch/arm/plat-omap/include/plat/omap34xx.h | 5 - 17 files changed, 584 insertions(+), 161 deletions(-) Regards, Nishanth Menon PS: Sample log from 3630SDP: 3630SDP cpufreq results: # head /sys/devices/system/cpu/cpu0/cpu /sys/devices/system/cpu/cpu0/cpufreq/ /sys/devices/system/cpu/cpu0/cpuidle/ /tests/pm-test-scripts # head /sys/devices/system/cpu/cpu0/cpufreq/* ==> /sys/devices/system/cpu/cpu0/cpufreq/affected_cpus <== 0 ==> /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq <== 300000 ==> /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq <== 600000 ==> /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq <== 300000 ==> /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_transition_latency <== 300000 ==> /sys/devices/system/cpu/cpu0/cpufreq/related_cpus <== 0 ==> /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies <== 600000 300000 ==> /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors <== userspace ==> /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq <== 300000 ==> /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver <== omap ==> /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor <== userspace ==> /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq <== 600000 ==> /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq <== 300000 ==> /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed <== 300000 # head /sys/devices/system/cpu/cpu0/cpufreq/stats/* ==> /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state <== 600000 9246 300000 159753 ==> /sys/devices/system/cpu/cpu0/cpufreq/stats/total_trans <== 13 [..] /dbg/pm_debug# cat voltage_off_while_idle 0 /dbg/pm_debug # cat enable_off_mode 0 /dbg/pm_debug # echo -n '1' >enable_off_mode Unable to Changelevel for resource dsp_freq to 0 Error: could not refresh resources /dbg/pm_debug # echo -n '1' >voltage_off_while_idle /dbg/pm_debug # cat enable_off_mode 1 /dbg/pm_debug # echo 'mem' >/sys/power/state PM: Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.00 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.00 seconds) done. Suspending console(s) (use no_console_suspend to debug) Successfully put all powerdomains to target state Restarting tasks ... done. /dbg/pm_debug # /dbg/pm_debug # echo 'mem' >/sys/power/state PM: Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.00 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.00 seconds) done. Suspending console(s) (use no_console_suspend to debug) Successfully put all powerdomains to target state Restarting tasks ... done. /dbg/pm_debug # /dbg/pm_debug # /dbg/pm_debug # ls cam_pwrdm iva2_pwrdm sleep_while_idle core_pwrdm mpu_pwrdm time count neon_pwrdm usbhost_pwrdm dss_pwrdm per_pwrdm voltage_off_while_idle emu_pwrdm registers wakeup_timer_seconds enable_off_mode sgx_pwrdm wkup_pwrdm /dbg/pm_debug # cat count time usbhost_pwrdm (OFF),OFF:1,RET:1,INA:0,ON:1 sgx_pwrdm (OFF),OFF:1,RET:0,INA:0,ON:1 per_pwrdm (ON),OFF:2,RET:143,INA:0,ON:146 dss_pwrdm (OFF),OFF:1,RET:1,INA:0,ON:1 cam_pwrdm (OFF),OFF:1,RET:1,INA:0,ON:1 core_pwrdm (ON),OFF:2,RET:1,INA:0,ON:4 neon_pwrdm (ON),OFF:2,RET:1,INA:190,ON:194 mpu_pwrdm (ON),OFF:2,RET:1,INA:190,ON:194 iva2_pwrdm (OFF),OFF:1,RET:1,INA:0,ON:1 per_clkdm->per_pwrdm (9) usbhost_clkdm->usbhost_pwrdm (0) cam_clkdm->cam_pwrdm (0) dss_clkdm->dss_pwrdm (0) core_l4_clkdm->core_pwrdm (5) core_l3_clkdm->core_pwrdm (4) d2d_clkdm->core_pwrdm (0) sgx_clkdm->sgx_pwrdm (0) iva2_clkdm->iva2_pwrdm (0) neon_clkdm->neon_pwrdm (0) mpu_clkdm->mpu_pwrdm (0) prm_clkdm->wkup_pwrdm (0) cm_clkdm->core_pwrdm (0) usbhost_pwrdm (OFF),OFF:47586242676,RET:150255279541,INA:0,ON:22111267089 sgx_pwrdm (OFF),OFF:197841491699,RET:0,INA:0,ON:22111297607 per_pwrdm (ON),OFF:4080291748,RET:5557220473,INA:0,ON:210315277085 dss_pwrdm (OFF),OFF:47586303711,RET:150255249024,INA:0,ON:22111267089 cam_pwrdm (OFF),OFF:47586303711,RET:150255249024,INA:0,ON:22111267089 core_pwrdm (ON),OFF:4080291748,RET:2764923095,INA:0,ON:213107604981 neon_pwrdm (ON),OFF:4080291748,RET:2764923095,INA:5508361840,ON:207599273658 mpu_pwrdm (ON),OFF:4080291748,RET:2764923095,INA:5508972194,ON:207598663304 iva2_pwrdm (OFF),OFF:47586364746,RET:150255187988,INA:0,ON:22111297607 /dbg/pm_debug # ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/9] omap3: pm: introduce enabled flag to omap_opp 2009-11-13 6:05 [PATCH 0/9 v2] omap3: pm: introduce support for 3630 OPPs Nishanth Menon @ 2009-11-13 6:05 ` Nishanth Menon 2009-11-13 6:05 ` [PATCH 2/9 v2] omap3: pm: introduce opp accessor functions Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-13 6:05 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Jon Hunter, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, SuiLun Lam, Thara Gopinath, Vishwanath Sripathy We used to enable and disable OPPs based on rate being set to 0, this has been confusing in general. So, we now allow specific OPPs to be now enabled/disabled by an explicit enabled flag instead of re-using rate flag itself. Tested on: SDP3430, SDP3630 Cc: Benoit Cousson <b-cousson@ti.com> Cc: Jon Hunter <jon-hunter@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: SuiLun Lam <s-lam@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/omap3-opp.h | 32 ++++++++++++++-------------- arch/arm/mach-omap2/resource34xx.c | 4 +++ arch/arm/plat-omap/include/plat/omap-pm.h | 2 + 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-omap2/omap3-opp.h b/arch/arm/mach-omap2/omap3-opp.h index c773ea7..42557e1 100644 --- a/arch/arm/mach-omap2/omap3-opp.h +++ b/arch/arm/mach-omap2/omap3-opp.h @@ -22,41 +22,41 @@ #define S166M 166000000 static struct omap_opp omap3_mpu_rate_table[] = { - {0, 0, 0}, + {0, 0, 0, 0}, /*OPP1*/ - {S125M, VDD1_OPP1, 0x1E}, + {true, S125M, VDD1_OPP1, 0x1E}, /*OPP2*/ - {S250M, VDD1_OPP2, 0x26}, + {true, S250M, VDD1_OPP2, 0x26}, /*OPP3*/ - {S500M, VDD1_OPP3, 0x30}, + {true, S500M, VDD1_OPP3, 0x30}, /*OPP4*/ - {S550M, VDD1_OPP4, 0x36}, + {true, S550M, VDD1_OPP4, 0x36}, /*OPP5*/ - {S600M, VDD1_OPP5, 0x3C}, + {true, S600M, VDD1_OPP5, 0x3C}, }; static struct omap_opp omap3_l3_rate_table[] = { - {0, 0, 0}, + {0, 0, 0, 0}, /*OPP1*/ - {0, VDD2_OPP1, 0x1E}, + {false, 0, VDD2_OPP1, 0x1E}, /*OPP2*/ - {S83M, VDD2_OPP2, 0x24}, + {true, S83M, VDD2_OPP2, 0x24}, /*OPP3*/ - {S166M, VDD2_OPP3, 0x2C}, + {true, S166M, VDD2_OPP3, 0x2C}, }; static struct omap_opp omap3_dsp_rate_table[] = { - {0, 0, 0}, + {0, 0, 0, 0}, /*OPP1*/ - {S90M, VDD1_OPP1, 0x1E}, + {true, S90M, VDD1_OPP1, 0x1E}, /*OPP2*/ - {S180M, VDD1_OPP2, 0x26}, + {true, S180M, VDD1_OPP2, 0x26}, /*OPP3*/ - {S360M, VDD1_OPP3, 0x30}, + {true, S360M, VDD1_OPP3, 0x30}, /*OPP4*/ - {S400M, VDD1_OPP4, 0x36}, + {true, S400M, VDD1_OPP4, 0x36}, /*OPP5*/ - {S430M, VDD1_OPP5, 0x3C}, + {true, S430M, VDD1_OPP5, 0x3C}, }; #endif diff --git a/arch/arm/mach-omap2/resource34xx.c b/arch/arm/mach-omap2/resource34xx.c index 04be4d2..af6b3c1 100644 --- a/arch/arm/mach-omap2/resource34xx.c +++ b/arch/arm/mach-omap2/resource34xx.c @@ -285,6 +285,10 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, c_opp = ID_VDD(res) | ID_OPP_NO(opp[current_level].opp_id); #endif + /* Only allow enabled OPPs */ + if (!opp[target_level].enabled) + return -EINVAL; + /* Sanity check of the OPP params before attempting to set */ if (!opp[target_level].rate || !opp[target_level].vsel) return -EINVAL; diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h index 583e540..5dc2048 100644 --- a/arch/arm/plat-omap/include/plat/omap-pm.h +++ b/arch/arm/plat-omap/include/plat/omap-pm.h @@ -21,6 +21,7 @@ /** * struct omap_opp - clock frequency-to-OPP ID table for DSP, MPU + * @enabled: enabled if true, disabled if false * @rate: target clock rate * @opp_id: OPP ID * @min_vdd: minimum VDD1 voltage (in millivolts) for this OPP @@ -28,6 +29,7 @@ * Operating performance point data. Can vary by OMAP chip and board. */ struct omap_opp { + bool enabled; unsigned long rate; u8 opp_id; u16 vsel; -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/9 v2] omap3: pm: introduce opp accessor functions 2009-11-13 6:05 ` [PATCH 1/9] omap3: pm: introduce enabled flag to omap_opp Nishanth Menon @ 2009-11-13 6:05 ` Nishanth Menon 2009-11-13 6:05 ` [PATCH 3/9] omap3: pm: srf: use opp accessor function Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-13 6:05 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Jon Hunter, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, SuiLun Lam, Thara Gopinath, Vishwanath Sripathy Modifies the initial patch From Sanjeev: http://patchwork.kernel.org/patch/50998/ NOTE: The original opp_table introduced by Sanjeev is not needed anymore as we can use enabled flag to have better granularity in enable/disable of OPPs. This introduces the following accessor functions: freq_to_opp and opp_to_freq: Matching functions to convert OPP to freq and viceversa. freq_to_vsel: Converts a frequency to corresponding voltage. opp_enable: To enable/disable a specific OPP in a OPP table this allows granular runtime disable/enable of specific OPPs, esp when used in conjunction with search and mapping functions get_next_freq: A search function to get next matching frequency. This could possibly provide the basis for more complex OPP transition algos of the future. get_limit_freq: A search function to get the least or maximum frequency based on search criteria. Allows for independence from OPP_IDs in the future. Since the accessor functions hide the details of the table implementation, the opp table is now moved away from omap3-opp.h to pm34xx.c. The terminator entry is needed at the start and end of the table as it is still needed for reverse and forward search as the length of the table is unknown. Tests done: Accessor functions standalone tested on a PC host with dummy OPP table to simulate boundary, invalid and valid conditions, SDP3430, SDP3630 for system stability. Cc: Benoit Cousson <b-cousson@ti.com> Cc: Jon Hunter <jon-hunter@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: SuiLun Lam <s-lam@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Sanjeev Premi <premi@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/omap3-opp.h | 40 +------- arch/arm/mach-omap2/pm.c | 160 +++++++++++++++++++++++++++++ arch/arm/mach-omap2/pm34xx.c | 42 ++++++++ arch/arm/plat-omap/include/plat/omap-pm.h | 109 ++++++++++++++++++++ 4 files changed, 314 insertions(+), 37 deletions(-) diff --git a/arch/arm/mach-omap2/omap3-opp.h b/arch/arm/mach-omap2/omap3-opp.h index 42557e1..27e2ca5 100644 --- a/arch/arm/mach-omap2/omap3-opp.h +++ b/arch/arm/mach-omap2/omap3-opp.h @@ -21,42 +21,8 @@ #define S83M 83000000 #define S166M 166000000 -static struct omap_opp omap3_mpu_rate_table[] = { - {0, 0, 0, 0}, - /*OPP1*/ - {true, S125M, VDD1_OPP1, 0x1E}, - /*OPP2*/ - {true, S250M, VDD1_OPP2, 0x26}, - /*OPP3*/ - {true, S500M, VDD1_OPP3, 0x30}, - /*OPP4*/ - {true, S550M, VDD1_OPP4, 0x36}, - /*OPP5*/ - {true, S600M, VDD1_OPP5, 0x3C}, -}; - -static struct omap_opp omap3_l3_rate_table[] = { - {0, 0, 0, 0}, - /*OPP1*/ - {false, 0, VDD2_OPP1, 0x1E}, - /*OPP2*/ - {true, S83M, VDD2_OPP2, 0x24}, - /*OPP3*/ - {true, S166M, VDD2_OPP3, 0x2C}, -}; - -static struct omap_opp omap3_dsp_rate_table[] = { - {0, 0, 0, 0}, - /*OPP1*/ - {true, S90M, VDD1_OPP1, 0x1E}, - /*OPP2*/ - {true, S180M, VDD1_OPP2, 0x26}, - /*OPP3*/ - {true, S360M, VDD1_OPP3, 0x30}, - /*OPP4*/ - {true, S400M, VDD1_OPP4, 0x36}, - /*OPP5*/ - {true, S430M, VDD1_OPP5, 0x3C}, -}; +extern struct omap_opp omap3_mpu_rate_table[]; +extern struct omap_opp omap3_dsp_rate_table[]; +extern struct omap_opp omap3_l3_rate_table[]; #endif diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index f50e93d..b2cd30c 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -33,6 +33,7 @@ #include <plat/powerdomain.h> #include <plat/resource.h> #include <plat/omap34xx.h> +#include <plat/omap-pm.h> #include "prm-regbits-34xx.h" #include "pm.h" @@ -203,3 +204,162 @@ static int __init omap_pm_init(void) return error; } late_initcall(omap_pm_init); + +int opp_to_freq(unsigned long *freq, const struct omap_opp *opps, u8 opp_id) +{ + int i = 1; + + BUG_ON(!freq || !opps); + + /* The first entry is a dummy one, loop till we hit terminator */ + while (!IS_OPP_TERMINATOR(opps, i)) { + if (opps[i].enabled && (opps[i].opp_id == opp_id)) { + *freq = opps[i].rate; + return 0; + } + i++; + } + + return -EINVAL; +} +EXPORT_SYMBOL(opp_to_freq); + +int freq_to_vsel(u8 *vsel, const struct omap_opp *opps, unsigned long freq) +{ + int i = 1; + + BUG_ON(!vsel || !opps); + + /* The first entry is a dummy one, loop till we hit terminator */ + while (!IS_OPP_TERMINATOR(opps, i)) { + if (opps[i].enabled && (opps[i].rate == freq)) { + *vsel = opps[i].vsel; + return 0; + } + i++; + } + + return -EINVAL; +} +EXPORT_SYMBOL(freq_to_vsel); + +int freq_to_opp(u8 *opp_id, const struct omap_opp *opps, unsigned long freq) +{ + int i = 1; + + BUG_ON(!opp_id || !opps); + + /* The first entry is a dummy one, loop till we hit terminator */ + while (!IS_OPP_TERMINATOR(opps, i)) { + if (opps[i].enabled && (opps[i].rate == freq)) { + *opp_id = opps[i].opp_id; + return 0; + } + i++; + } + + return -EINVAL; +} +EXPORT_SYMBOL(freq_to_opp); + +int opp_enable(struct omap_opp *opps, unsigned long freq, bool enable) +{ + int i = 1; + + BUG_ON(!opps); + + /* The first entry is a dummy one, loop till we hit terminator */ + while (!IS_OPP_TERMINATOR(opps, i)) { + if (opps[i].rate == freq) { + opps[i].enabled = enable; + return 0; + } + i++; + } + + return -EINVAL; +} +EXPORT_SYMBOL(opp_enable); + +int get_next_freq(unsigned long *freq, const struct omap_opp *opps, + bool search_higher, bool search_enabled_only, bool exact_search) +{ + int i = 1, inc = 1; + bool found = false; + + BUG_ON(!opps || !freq || !(*freq)); + + /* The first entry is a dummy one, loop till we hit terminator + * XXX: The following algorithm works only on a presorted + * list of OPPs + */ + while (!IS_OPP_TERMINATOR(opps, i)) { + /* if we found the original freq, then + * case 1: enabled search ONLY, check opp is enabled or not + * case 2: the next available freq if enabled is not searched + */ + if ((found && search_enabled_only && opps[i].enabled) || + (found && !search_enabled_only)) { + *freq = opps[i].rate; + return 0; + } + + /* Find the baseline freq first.. */ + if (!found && ((exact_search && opps[i].rate == *freq) || + (!exact_search && opps[i].rate >= *freq))) { + /* found.. next decide direction */ + inc = search_higher ? 1 : -1; + found = true; + /* handle an exception case for exact search.. */ + if (exact_search || !search_higher) + i += inc; + /* fall thru to search for the right match */ + } else { + i += inc; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL(get_next_freq); + +int get_limit_freq(unsigned long *freq, const struct omap_opp *opps, + bool search_highest, bool search_enabled_only) +{ + int i = 1; + unsigned long cur_freq_match = search_highest ? 0 : -1; + bool found = false; + + BUG_ON(!opps || !freq); + + /* The first entry is a dummy one, loop till we hit terminator + * XXX: The following algorithm works only on a presorted + * list of OPPs + * We could use get_next_freq to search, but that will tend + * to be inefficient + */ + while (!IS_OPP_TERMINATOR(opps, i)) { + /* match condition: + * check if the enabled cases match (only invalid case is: + * search_enabled=1,enabled=0) + * then we look for comparison condition, based on direction + */ + if (!(search_enabled_only && !opps[i].enabled) && + ((search_highest && (opps[i].rate > cur_freq_match)) || + (!search_highest && (opps[i].rate < cur_freq_match)))) { + cur_freq_match = opps[i].rate; + found = true; + /* if we are searching for least, the first match + * is the right one, look no further. + */ + if (!search_highest) + break; + } + i++; + } + if (!found) + return -EINVAL; + *freq = cur_freq_match; + return 0; +} +EXPORT_SYMBOL(get_limit_freq); diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 9e471f7..2f17a40 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -51,6 +51,7 @@ #include "prm.h" #include "pm.h" #include "sdrc.h" +#include "omap3-opp.h" static int regset_save_on_suspend; @@ -99,6 +100,47 @@ static struct prm_setup_vc prm_setup = { .vdd1_off = 0x00, /* 0.6v */ }; +struct omap_opp omap3_mpu_rate_table[] = { + {0, 0, 0, 0}, + /*OPP1*/ + {true, S125M, VDD1_OPP1, 0x1E}, + /*OPP2*/ + {true, S250M, VDD1_OPP2, 0x26}, + /*OPP3*/ + {true, S500M, VDD1_OPP3, 0x30}, + /*OPP4*/ + {true, S550M, VDD1_OPP4, 0x36}, + /*OPP5*/ + {true, S600M, VDD1_OPP5, 0x3C}, + {0, 0, 0, 0}, +}; + +struct omap_opp omap3_l3_rate_table[] = { + {0, 0, 0, 0}, + /*OPP1*/ + {false, 0, VDD2_OPP1, 0x1E}, + /*OPP2*/ + {true, S83M, VDD2_OPP2, 0x24}, + /*OPP3*/ + {true, S166M, VDD2_OPP3, 0x2C}, + {0, 0, 0, 0}, +}; + +struct omap_opp omap3_dsp_rate_table[] = { + {0, 0, 0, 0}, + /*OPP1*/ + {true, S90M, VDD1_OPP1, 0x1E}, + /*OPP2*/ + {true, S180M, VDD1_OPP2, 0x26}, + /*OPP3*/ + {true, S360M, VDD1_OPP3, 0x30}, + /*OPP4*/ + {true, S400M, VDD1_OPP4, 0x36}, + /*OPP5*/ + {true, S430M, VDD1_OPP5, 0x3C}, + {0, 0, 0, 0}, +}; + static inline void omap3_per_save_context(void) { omap_gpio_save_context(); diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h index 5dc2048..8316999 100644 --- a/arch/arm/plat-omap/include/plat/omap-pm.h +++ b/arch/arm/plat-omap/include/plat/omap-pm.h @@ -35,6 +35,10 @@ struct omap_opp { u16 vsel; }; +/* Identify a OPP terminator */ +#define IS_OPP_TERMINATOR(opps, i) (!(opps)[(i)].enabled &&\ + ((opps)[(i)].rate == 0) && ((opps)[(i)].vsel == 0)) + extern struct omap_opp *mpu_opps; extern struct omap_opp *dsp_opps; extern struct omap_opp *l3_opps; @@ -324,5 +328,110 @@ unsigned long omap_pm_cpu_get_freq(void); */ int omap_pm_get_dev_context_loss_count(struct device *dev); +/** + * freq_to_opp - Get opp_id corresponding to a frequency if enabled + * This function can also be used to check if a certain frequency is enabled + * in the opp list. + * + * @opp_id: the ID to return + * @opps: the opps table to search through + * @freq: the frequency to search for + * + * returns 0 if *opp_id is populated, else returns EINVAL + */ +int freq_to_opp(u8 *opp_id, const struct omap_opp *opps, unsigned long freq); +/** + * freq_to_vsel - Get voltage corresponding to a frequency if enabled + * This function can also be used to check if a certain frequency is enabled + * in the opp list. + * + * @vsel: voltage corresponding to return + * @opps: the opps table to search through + * @freq: the frequency to search for + * + * returns 0 if *vsel is populated, else returns EINVAL + */ +int freq_to_vsel(u8 *vsel, const struct omap_opp *opps, unsigned long freq); + +/** + * opp_to_freq - Get frequency corresponding to an OPP if enabled + * This function can also be used to check if a certain opp_id is enabled + * in the opp list. + * + * @freq: return the frequency on this + * @opps: the opps table to search through + * @opp_id: the ID to search for + * + * returns 0 if *freq is populated, else returns EINVAL + */ +int opp_to_freq(unsigned long *freq, const struct omap_opp *opps, u8 opp_id); + +/** + * opp_enable - Enable or Disable an OPP in the supported OPPs if available + * + * @opps: the opps table to search through + * @freq: the frequency to search for + * @enable: true to enable the OPP, false to disable it + * + * returns 0 if the OPP is found, else returns EINVAL. if the opp is found + * NOTE: Even if it was in the same state as requested, the functions returns 0. + */ +int opp_enable(struct omap_opp *opps, unsigned long freq, bool enable); + +/** + * get_next_freq - search for next matching frequency, given a starting + * frequency. This can be combined to create a search logic etc without + * knowing OPP IDs. + * Example usages: + * a) I have an approximate frequency, get enabled opp freq at least freq + * if a match is achieved, result_freq >= requested_freq + * res = get_next_freq(&freq, opps, true, true, false) + * b) I have an approximate frequency, get enabled opp freq less than freq + * if a match is achieved, result_freq < requested_freq + * res = get_next_freq(&freq, opps, false, true, false) + * c) I have exact OPP freq I want to check -> search for higher enabled + * frequency + * res = get_next_freq(&freq, opps, true, true, true) + * d) I have exact OPP freq I want to check -> search for lower enabled + * frequency + * res = get_next_freq(&freq, opps, false, true, true) + * + * Then we can create all sorts of search combinations -> including searching + * for an OPP freq we would like to enable by controlling search_enabled_only + * + * @freq: Which frequency to start from- should be a valid frequency, + * even if not enabled. + * if a match is found, this will contain the matched frequency + * @opps: the opp table to search through + * @search_higher: should the search go up the list (search for higher freq) + * if true, searches for next highest freq, else searches for the next + * lowest frequency + * @search_enabled_only: Should the search only for enabled frequencies. + * if true, searches for only enabled OPP frequencies, else does not + * care for enabled status of the OPP (useful to enable OPPs) + * @exact_search: start search iff start *freq gets an exact match + * + * If a match is found, returns the matched frequency in *freq and returns 0, + * else, returns EINVAL, *freq is unchanged + */ +int get_next_freq(unsigned long *freq, const struct omap_opp *opps, + bool search_higher, bool search_enabled_only, bool exact_search); + +/** + * get_limit_freq: Get the max or min frequency for an opp table + * we can search for just the enabled opps, or the max or least in + * the table + * + * @freq: returns the max or min opp if a match was found + * @opps: opp table to search + * @search_highest: search for the highest if true, else search for lowest + * frequency + * @search_enabled_only: search only for enabled OPPs + * + * returns 0 if a match is found and *freq contains the matched frequency + * else, returns EINVAL, *freq is unchanged + */ +int get_limit_freq(unsigned long *freq, const struct omap_opp *opps, + bool search_highest, bool search_enabled_only); #endif -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/9] omap3: pm: srf: use opp accessor function 2009-11-13 6:05 ` [PATCH 2/9 v2] omap3: pm: introduce opp accessor functions Nishanth Menon @ 2009-11-13 6:05 ` Nishanth Menon 2009-11-13 6:05 ` [PATCH 4/9] omap3: pm: use opp accessor functions for omap-target Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-13 6:05 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Jon Hunter, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, SuiLun Lam, Thara Gopinath, Vishwanath Sripathy With the accessor functions, many of the direct accesses are redundant. Cleanup of SRF to: a) Remove get_opp as it redundant as freq_to_opp does exactly the samething. b) Remove any direct dereference of opp tables except thru accessor functions. NOTE: the implementation is just a start and leaves scope for further performance and robustness improvements which can be added on top. Tested on: SDP3430, SDP3630 Cc: Benoit Cousson <b-cousson@ti.com> Cc: Jon Hunter <jon-hunter@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: SuiLun Lam <s-lam@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/resource34xx.c | 178 ++++++++++++++++++++++-------------- 1 files changed, 109 insertions(+), 69 deletions(-) diff --git a/arch/arm/mach-omap2/resource34xx.c b/arch/arm/mach-omap2/resource34xx.c index af6b3c1..15b5cb6 100644 --- a/arch/arm/mach-omap2/resource34xx.c +++ b/arch/arm/mach-omap2/resource34xx.c @@ -155,29 +155,14 @@ static int curr_vdd1_opp; static int curr_vdd2_opp; static DEFINE_MUTEX(dvfs_mutex); -static unsigned short get_opp(struct omap_opp *opp_freq_table, - unsigned long freq) -{ - struct omap_opp *prcm_config; - prcm_config = opp_freq_table; - - if (prcm_config->rate <= freq) - return prcm_config->opp_id; /* Return the Highest OPP */ - for (; prcm_config->rate; prcm_config--) - if (prcm_config->rate < freq) - return (prcm_config+1)->opp_id; - else if (prcm_config->rate == freq) - return prcm_config->opp_id; - /* Return the least OPP */ - return (prcm_config+1)->opp_id; -} - /** * init_opp - Initialize the OPP resource */ void init_opp(struct shared_resource *resp) { struct clk *l3_clk; + int ret; + u8 opp_id; resp->no_of_users = 0; if (!mpu_opps || !dsp_opps || !l3_opps) @@ -190,17 +175,18 @@ void init_opp(struct shared_resource *resp) vdd1_resp = resp; dpll1_clk = clk_get(NULL, "dpll1_ck"); dpll2_clk = clk_get(NULL, "dpll2_ck"); - resp->curr_level = get_opp(mpu_opps + MAX_VDD1_OPP, - dpll1_clk->rate); - curr_vdd1_opp = resp->curr_level; + ret = freq_to_opp(&opp_id, mpu_opps, dpll1_clk->rate); + BUG_ON(ret); /* TBD Cleanup handling */ + curr_vdd1_opp = opp_id; } else if (strcmp(resp->name, "vdd2_opp") == 0) { vdd2_resp = resp; dpll3_clk = clk_get(NULL, "dpll3_m2_ck"); l3_clk = clk_get(NULL, "l3_ick"); - resp->curr_level = get_opp(l3_opps + MAX_VDD2_OPP, - l3_clk->rate); - curr_vdd2_opp = resp->curr_level; + ret = freq_to_opp(&opp_id, l3_opps, l3_clk->rate); + BUG_ON(ret); /* TBD Cleanup handling */ + curr_vdd2_opp = opp_id; } + resp->curr_level = opp_id; return; } @@ -242,24 +228,40 @@ static int program_opp_freq(int res, int target_level, int current_level) { int ret = 0, l3_div; int *curr_opp; + unsigned long mpu_freq, dsp_freq, l3_freq; +#ifndef CONFIG_CPU_FREQ + unsigned long mpu_cur_freq +#endif + + /* Check if I can actually switch or not */ + if (res == VDD1_OPP) { + ret = opp_to_freq(&mpu_freq, mpu_opps, target_level); + ret |= opp_to_freq(&dsp_freq, dsp_opps, target_level); +#ifndef CONFIG_CPU_FREQ + ret |= opp_to_freq(&mpu_cur_freq, mpu_opps, current_level); +#endif + } else { + ret = opp_to_freq(&l3_freq, l3_opps, target_level); + } + /* we would have caught all bad levels earlier.. */ + if (unlikely(ret)) + return ret; lock_scratchpad_sem(); if (res == VDD1_OPP) { curr_opp = &curr_vdd1_opp; - clk_set_rate(dpll1_clk, mpu_opps[target_level].rate); - clk_set_rate(dpll2_clk, dsp_opps[target_level].rate); + clk_set_rate(dpll1_clk, mpu_freq); + clk_set_rate(dpll2_clk, dsp_freq); #ifndef CONFIG_CPU_FREQ /*Update loops_per_jiffy if processor speed is being changed*/ loops_per_jiffy = compute_lpj(loops_per_jiffy, - mpu_opps[current_level].rate/1000, - mpu_opps[target_level].rate/1000); + mpu_cur_freq / 1000, mpu_freq / 1000); #endif } else { curr_opp = &curr_vdd2_opp; l3_div = cm_read_mod_reg(CORE_MOD, CM_CLKSEL) & OMAP3430_CLKSEL_L3_MASK; - ret = clk_set_rate(dpll3_clk, - l3_opps[target_level].rate * l3_div); + ret = clk_set_rate(dpll3_clk, l3_freq * l3_div); } if (ret) { unlock_scratchpad_sem(); @@ -278,6 +280,7 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, int current_level) { int i, ret = 0, raise; + unsigned long freq; #ifdef CONFIG_OMAP_SMARTREFLEX unsigned long t_opp, c_opp; @@ -285,13 +288,10 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, c_opp = ID_VDD(res) | ID_OPP_NO(opp[current_level].opp_id); #endif - /* Only allow enabled OPPs */ - if (!opp[target_level].enabled) - return -EINVAL; - - /* Sanity check of the OPP params before attempting to set */ - if (!opp[target_level].rate || !opp[target_level].vsel) - return -EINVAL; + /* See if have a freq associated, if not, invalid opp */ + ret = opp_to_freq(&freq, opp, target_level); + if (unlikely(ret)) + return ret; if (target_level > current_level) raise = 1; @@ -303,10 +303,16 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, ret = program_opp_freq(res, target_level, current_level); #ifdef CONFIG_OMAP_SMARTREFLEX - else + else { + u8 v_current, v_target; + /* none of the following should fail.. */ + BUG_ON(freq_to_vsel(&v_target, opp, freq)); + BUG_ON(opp_to_freq(&freq, opp, current_level)); + BUG_ON(freq_to_vsel(&v_current, opp, freq)); + /* ok to scale.. */ sr_voltagescale_vcbypass(t_opp, c_opp, - opp[target_level].vsel, - opp[current_level].vsel); + v_target, v_current); + } #endif } @@ -315,7 +321,8 @@ static int program_opp(int res, struct omap_opp *opp, int target_level, int resource_set_opp_level(int res, u32 target_level, int flags) { - unsigned long mpu_freq, mpu_old_freq; + unsigned long mpu_freq, mpu_old_freq, l3_freq; + int ret; #ifdef CONFIG_CPU_FREQ struct cpufreq_freqs freqs_notify; #endif @@ -334,6 +341,16 @@ int resource_set_opp_level(int res, u32 target_level, int flags) if (!mpu_opps || !dsp_opps || !l3_opps) return 0; + /* Check if I can actually switch or not */ + if (res == VDD1_OPP) { + ret = opp_to_freq(&mpu_freq, mpu_opps, target_level); + ret |= opp_to_freq(&mpu_old_freq, mpu_opps, resp->curr_level); + } else { + ret = opp_to_freq(&l3_freq, l3_opps, target_level); + } + if (ret) + return ret; + mutex_lock(&dvfs_mutex); if (res == VDD1_OPP) { @@ -341,9 +358,6 @@ int resource_set_opp_level(int res, u32 target_level, int flags) mutex_unlock(&dvfs_mutex); return 0; } - mpu_old_freq = mpu_opps[resp->curr_level].rate; - mpu_freq = mpu_opps[target_level].rate; - #ifdef CONFIG_CPU_FREQ freqs_notify.old = mpu_old_freq/1000; freqs_notify.new = mpu_freq/1000; @@ -371,15 +385,13 @@ int resource_set_opp_level(int res, u32 target_level, int flags) int set_opp(struct shared_resource *resp, u32 target_level) { - unsigned long tput; - unsigned long req_l3_freq; - int ind; + int ret = -EINVAL; if (resp == vdd1_resp) { if (target_level < 3) resource_release("vdd2_opp", &vdd2_dev); - resource_set_opp_level(VDD1_OPP, target_level, 0); + ret = resource_set_opp_level(VDD1_OPP, target_level, 0); /* * For VDD1 OPP3 and above, make sure the interconnect * is at 100Mhz or above. @@ -389,21 +401,28 @@ int set_opp(struct shared_resource *resp, u32 target_level) resource_request("vdd2_opp", &vdd2_dev, 400000); } else if (resp == vdd2_resp) { - tput = target_level; + unsigned long req_l3_freq; /* Convert the tput in KiB/s to Bus frequency in MHz */ - req_l3_freq = (tput * 1000)/4; - - for (ind = 2; ind <= MAX_VDD2_OPP; ind++) - if ((l3_opps + ind)->rate >= req_l3_freq) { - target_level = ind; - break; - } - - /* Set the highest OPP possible */ - if (ind > MAX_VDD2_OPP) - target_level = ind-1; - resource_set_opp_level(VDD2_OPP, target_level, 0); + req_l3_freq = (target_level * 1000)/4; + + /* Get the best freq around */ + ret = get_next_freq(&req_l3_freq, l3_opps, true, true, false); + + /* If we dont find a good freq, then use the highest + * possible freq + */ + if (ret) + ret = get_limit_freq(&req_l3_freq, l3_opps, true, true); + + /* uh uh.. no OPPs?? */ + BUG_ON(ret); + + ret = freq_to_opp((u8 *)&target_level, l3_opps, req_l3_freq); + /* we dont expect this to fail */ + BUG_ON(ret); + + ret = resource_set_opp_level(VDD2_OPP, target_level, 0); } return 0; } @@ -416,6 +435,11 @@ int set_opp(struct shared_resource *resp, u32 target_level) */ int validate_opp(struct shared_resource *resp, u32 target_level) { + unsigned long x; + if (strcmp(resp->name, "mpu_freq") == 0) + return opp_to_freq(&x, mpu_opps, target_level); + else if (strcmp(resp->name, "dsp_freq") == 0) + return opp_to_freq(&x, dsp_opps, target_level); return 0; } @@ -425,6 +449,8 @@ int validate_opp(struct shared_resource *resp, u32 target_level) void init_freq(struct shared_resource *resp) { char *linked_res_name; + int ret = -EINVAL; + unsigned long freq; resp->no_of_users = 0; if (!mpu_opps || !dsp_opps) @@ -436,32 +462,46 @@ void init_freq(struct shared_resource *resp) */ if (strcmp(resp->name, "mpu_freq") == 0) /* MPU freq in Mhz */ - resp->curr_level = mpu_opps[curr_vdd1_opp].rate; + ret = opp_to_freq(&freq, mpu_opps, curr_vdd1_opp); else if (strcmp(resp->name, "dsp_freq") == 0) /* DSP freq in Mhz */ - resp->curr_level = dsp_opps[curr_vdd1_opp].rate; + ret = opp_to_freq(&freq, dsp_opps, curr_vdd1_opp); + BUG_ON(ret); + + resp->curr_level = freq; return; } int set_freq(struct shared_resource *resp, u32 target_level) { - unsigned int vdd1_opp; + u8 vdd1_opp; + int ret = -EINVAL; if (!mpu_opps || !dsp_opps) return 0; if (strcmp(resp->name, "mpu_freq") == 0) { - vdd1_opp = get_opp(mpu_opps + MAX_VDD1_OPP, target_level); - resource_request("vdd1_opp", &dummy_mpu_dev, vdd1_opp); + ret = freq_to_opp(&vdd1_opp, mpu_opps, target_level); + if (!ret) + ret = resource_request("vdd1_opp", &dummy_mpu_dev, + vdd1_opp); } else if (strcmp(resp->name, "dsp_freq") == 0) { - vdd1_opp = get_opp(dsp_opps + MAX_VDD1_OPP, target_level); - resource_request("vdd1_opp", &dummy_dsp_dev, vdd1_opp); + ret = freq_to_opp(&vdd1_opp, dsp_opps, target_level); + if (!ret) + ret = resource_request("vdd1_opp", &dummy_dsp_dev, + vdd1_opp); } - resp->curr_level = target_level; - return 0; + if (!ret) + resp->curr_level = target_level; + return ret; } int validate_freq(struct shared_resource *resp, u32 target_level) { + u8 x; + if (strcmp(resp->name, "mpu_freq") == 0) + return freq_to_opp(&x, mpu_opps, target_level); + else if (strcmp(resp->name, "dsp_freq") == 0) + return freq_to_opp(&x, dsp_opps, target_level); return 0; } -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 4/9] omap3: pm: use opp accessor functions for omap-target 2009-11-13 6:05 ` [PATCH 3/9] omap3: pm: srf: use opp accessor function Nishanth Menon @ 2009-11-13 6:05 ` Nishanth Menon 2009-11-13 6:05 ` [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp Nishanth Menon 0 siblings, 1 reply; 22+ messages in thread From: Nishanth Menon @ 2009-11-13 6:05 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Jon Hunter, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, SuiLun Lam, Thara Gopinath, Vishwanath Sripathy The logic in omap-target can now be improved with the accessor functions. Dont scan through the list manually, instead use get_next_freq to do the scanning. Tested on: SDP3430, SDP3630 Cc: Benoit Cousson <b-cousson@ti.com> Cc: Jon Hunter <jon-hunter@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: SuiLun Lam <s-lam@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/plat-omap/cpu-omap.c | 12 ++++-------- 1 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c index 449b6b6..16b5da2 100644 --- a/arch/arm/plat-omap/cpu-omap.c +++ b/arch/arm/plat-omap/cpu-omap.c @@ -111,14 +111,10 @@ static int omap_target(struct cpufreq_policy *policy, cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); #elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) if (mpu_opps) { - int ind; - for (ind = 1; ind <= MAX_VDD1_OPP; ind++) { - if (mpu_opps[ind].rate/1000 >= target_freq) { - omap_pm_cpu_set_freq - (mpu_opps[ind].rate); - break; - } - } + unsigned long freq = target_freq * 1000; + int res = get_next_freq(&freq, mpu_opps, true, true, false); + if (!res) + omap_pm_cpu_set_freq(freq); } #endif return ret; -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp 2009-11-13 6:05 ` [PATCH 4/9] omap3: pm: use opp accessor functions for omap-target Nishanth Menon @ 2009-11-13 6:05 ` Nishanth Menon 0 siblings, 0 replies; 22+ messages in thread From: Nishanth Menon @ 2009-11-13 6:05 UTC (permalink / raw) To: linux-omap Cc: Nishanth Menon, Benoit Cousson, Jon Hunter, Kevin Hilman, Madhusudhan Chikkature Rajashekar, Paul Walmsley, Romit Dasgupta, Sanjeev Premi, Santosh Shilimkar, Sergio Alberto Aguirre Rodriguez, SuiLun Lam, Thara Gopinath, Vishwanath Sripathy SmartReflex implements a get_opp to search through the opp table, replace it with the accessor function as it is a duplicate of freq_to_opp Tested on: SDP3430, SDP3630 Cc: Benoit Cousson <b-cousson@ti.com> Cc: Jon Hunter <jon-hunter@ti.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Madhusudhan Chikkature Rajashekar <madhu.cr@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Romit Dasgupta <romit@ti.com> Cc: Sanjeev Premi <premi@ti.com> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Sergio Alberto Aguirre Rodriguez <saaguirre@ti.com> Cc: SuiLun Lam <s-lam@ti.com> Cc: Thara Gopinath <thara@ti.com> Cc: Vishwanath Sripathy <vishwanath.bs@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com> --- arch/arm/mach-omap2/smartreflex.c | 36 ++++++++---------------------------- 1 files changed, 8 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index be3a1da..d34224d 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -146,49 +146,29 @@ static u32 cal_test_nvalue(u32 sennval, u32 senpval) (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT); } -/* determine the current OPP from the frequency - * we need to give this function last element of OPP rate table - * and the frequency - */ -static u16 get_opp(struct omap_opp *opp_freq_table, - unsigned long freq) -{ - struct omap_opp *prcm_config; - - prcm_config = opp_freq_table; - - if (prcm_config->rate <= freq) - return prcm_config->opp_id; /* Return the Highest OPP */ - for (; prcm_config->rate; prcm_config--) - if (prcm_config->rate < freq) - return (prcm_config+1)->opp_id; - else if (prcm_config->rate == freq) - return prcm_config->opp_id; - /* Return the least OPP */ - return (prcm_config+1)->opp_id; -} - -static u16 get_vdd1_opp(void) +static u8 get_vdd1_opp(void) { - u16 opp; + u8 opp; if (sr1.vdd_opp_clk == NULL || IS_ERR(sr1.vdd_opp_clk) || mpu_opps == NULL) return 0; - opp = get_opp(mpu_opps + MAX_VDD1_OPP, sr1.vdd_opp_clk->rate); + /* Not expected to fail.. */ + BUG_ON(freq_to_opp(&opp, mpu_opps, sr1.vdd_opp_clk->rate)); return opp; } -static u16 get_vdd2_opp(void) +static u8 get_vdd2_opp(void) { - u16 opp; + u8 opp; if (sr2.vdd_opp_clk == NULL || IS_ERR(sr2.vdd_opp_clk) || l3_opps == NULL) return 0; - opp = get_opp(l3_opps + MAX_VDD2_OPP, sr2.vdd_opp_clk->rate); + /* Not expected to fail.. */ + BUG_ON(freq_to_opp(&opp, l3_opps, sr2.vdd_opp_clk->rate)); return opp; } -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 22+ messages in thread
end of thread, other threads:[~2010-01-07 14:18 UTC | newest] Thread overview: 22+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-11-12 5:45 [PATCH 0/9] OMAP3: PM: introduce support for 3630 OPPs Nishanth Menon 2009-11-12 5:45 ` [PATCH 1/9] omap3: pm: introduce enabled flag to omap_opp Nishanth Menon 2009-11-12 5:45 ` [PATCH 2/9] omap3: pm: introduce opp accessor functions Nishanth Menon 2009-11-12 5:45 ` [PATCH 3/9] omap3: pm: srf: introduce accessor function Nishanth Menon 2009-11-12 5:45 ` [PATCH 4/9] omap3: pm: use opp accessor functions for omap-target Nishanth Menon 2009-11-12 5:45 ` [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp Nishanth Menon 2009-11-12 5:45 ` [PATCH 6/9] omap3: clk: use pm accessor functions for cpufreq table Nishanth Menon 2009-11-12 5:45 ` [PATCH 7/9] omap3: pm: remove VDDx_MIN/MAX macros Nishanth Menon 2009-11-12 5:45 ` [PATCH 8/9] omap3: pm: introduce dynamic OPP Nishanth Menon 2009-11-12 5:45 ` [PATCH 9/9] omap3: pm: introduce 3630 opps Nishanth Menon 2009-12-18 23:12 ` [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp Kevin Hilman 2009-12-19 11:35 ` Menon, Nishanth 2009-12-22 16:45 ` Kevin Hilman 2010-01-06 23:46 ` Nishanth Menon 2010-01-07 0:23 ` Kevin Hilman 2010-01-07 8:35 ` Sripathy, Vishwanath 2010-01-07 8:53 ` Romit Dasgupta 2010-01-07 9:13 ` Sripathy, Vishwanath 2010-01-07 12:15 ` Nishanth Menon 2010-01-07 14:18 ` Nishanth Menon 2009-12-21 6:58 ` Romit Dasgupta -- strict thread matches above, loose matches on Subject: below -- 2009-11-13 6:05 [PATCH 0/9 v2] omap3: pm: introduce support for 3630 OPPs Nishanth Menon 2009-11-13 6:05 ` [PATCH 1/9] omap3: pm: introduce enabled flag to omap_opp Nishanth Menon 2009-11-13 6:05 ` [PATCH 2/9 v2] omap3: pm: introduce opp accessor functions Nishanth Menon 2009-11-13 6:05 ` [PATCH 3/9] omap3: pm: srf: use opp accessor function Nishanth Menon 2009-11-13 6:05 ` [PATCH 4/9] omap3: pm: use opp accessor functions for omap-target Nishanth Menon 2009-11-13 6:05 ` [PATCH 5/9] omap3: pm: sr: replace get_opp with freq_to_opp Nishanth Menon
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox