diff options
author | Koen Kooi <koen@openembedded.org> | 2008-08-11 14:39:50 +0000 |
---|---|---|
committer | Koen Kooi <koen@openembedded.org> | 2008-08-11 14:39:50 +0000 |
commit | 5cf49c96a744508ff2dcbb49c86f709096a8f39e (patch) | |
tree | 850f3df66d7d20d364dc556fcb80460063bedc23 /packages/linux/linux-omap2-git/beagleboard | |
parent | 37ccaf6d05e4f962d4d7eab0e7b00179b409e64c (diff) |
linux-omap2 git: check in WIP cpufreq patches for beagleboard
Diffstat (limited to 'packages/linux/linux-omap2-git/beagleboard')
17 files changed, 4530 insertions, 7 deletions
diff --git a/packages/linux/linux-omap2-git/beagleboard/01-beagle-cpufreq.diff b/packages/linux/linux-omap2-git/beagleboard/01-beagle-cpufreq.diff new file mode 100644 index 0000000000..5343f3276b --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/01-beagle-cpufreq.diff @@ -0,0 +1,178 @@ +--- /tmp/board-omap3beagle.h 2008-08-11 15:40:17.000000000 +0200 ++++ git/include/asm-arm/arch-omap/board-omap3beagle.h 2008-08-11 15:41:32.433198000 +0200 +@@ -29,5 +29,41 @@ + #ifndef __ASM_ARCH_OMAP3_BEAGLE_H + #define __ASM_ARCH_OMAP3_BEAGLE_H + ++/* MPU speeds */ ++#define S600M 600000000 ++#define S550M 550000000 ++#define S500M 500000000 ++#define S250M 250000000 ++#define S125M 125000000 ++ ++/* IVA speeds */ ++#define S430M 430000000 ++#define S400M 400000000 ++#define S360M 360000000 ++#define S180M 180000000 ++#define S90M 90000000 ++ ++/* L3 speeds */ ++#define S83M 83000000 ++#define S166M 166000000 ++ ++/* VDD1 OPPS */ ++#define VDD1_OPP1 0x1 ++#define VDD1_OPP2 0x2 ++#define VDD1_OPP3 0x3 ++#define VDD1_OPP4 0x4 ++#define VDD1_OPP5 0x5 ++ ++/* VDD2 OPPS */ ++#define VDD2_OPP1 0x1 ++#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_OMAP3_BEAGLE_H */ + +--- /tmp/resource34xx.c 2008-08-11 16:11:28.000000000 +0200 ++++ git/arch/arm/mach-omap2/resource34xx.c 2008-08-11 16:20:18.803198000 +0200 +@@ -173,7 +173,7 @@ + + int set_opp(struct shared_resource *resp, u32 target_level) + { +-#ifdef CONFIG_MACH_OMAP_3430SDP ++#if defined(CONFIG_MACH_OMAP_3430SDP) || defined(CONFIG_MACH_OMAP3_BEAGLE) + unsigned long mpu_freq, l3_freq, tput; + int ind; + struct bus_throughput_db *tput_db; +@@ -248,7 +248,7 @@ + */ + void init_freq(struct shared_resource *resp) + { +-#ifdef CONFIG_MACH_OMAP_3430SDP ++#if defined(CONFIG_MACH_OMAP_3430SDP) || defined(CONFIG_MACH_OMAP3_BEAGLE) + char *linked_res_name; + resp->no_of_users = 0; + +@@ -269,7 +269,7 @@ + + int set_freq(struct shared_resource *resp, u32 target_level) + { +-#ifdef CONFIG_MACH_OMAP_3430SDP ++#if defined(CONFIG_MACH_OMAP_3430SDP) || defined(CONFIG_MACH_OMAP3_BEAGLE) + unsigned int vdd1_opp; + + if (strcmp(resp->name, "mpu_freq") == 0) +--- /tmp/clock34xx.c 2008-08-11 15:57:48.000000000 +0200 ++++ git/arch/arm/mach-omap2/clock34xx.c 2008-08-11 16:22:43.093198000 +0200 +@@ -773,7 +773,7 @@ + dpll2_clk = clk_get(NULL, "dpll2_ck"); + dpll3_clk = clk_get(NULL, "dpll3_ck"); + +-#ifdef CONFIG_MACH_OMAP_3430SDP ++#if defined(CONFIG_MACH_OMAP_3430SDP) || defined(CONFIG_MACH_OMAP3_BEAGLE) + mpu_speed = dpll1_clk->rate; + prcm_vdd = vdd1_rate_table + MAX_VDD1_OPP; + for (; prcm_vdd->speed; prcm_vdd--) { +@@ -836,7 +836,7 @@ + return (prcm_config+1)->opp; + } + +-#ifdef CONFIG_MACH_OMAP_3430SDP ++#if defined(CONFIG_MACH_OMAP_3430SDP) || defined(CONFIG_MACH_OMAP3_BEAGLE) + static void omap3_table_recalc(struct clk *clk) + { + if ((clk != &virt_vdd1_prcm_set) && (clk != &virt_vdd2_prcm_set)) +--- /tmp/board-omap3beagle.c 2008-08-11 15:54:04.000000000 +0200 ++++ git/arch/arm/mach-omap2/board-omap3beagle.c 2008-08-11 16:25:11.333198000 +0200 +@@ -39,9 +39,62 @@ + #include <asm/arch/gpmc.h> + #include <asm/arch/nand.h> + ++#include <asm/arch/clock.h> ++ + #define GPMC_CS0_BASE 0x60 + #define GPMC_CS_SIZE 0x30 + ++struct vdd_prcm_config vdd1_rate_table[] = { ++ {0, 0, 0}, ++ /*OPP1*/ ++ {S125M, VDD1_OPP1, 0}, ++ /*OPP2*/ ++ {S250M, VDD1_OPP2, 0}, ++ /*OPP3*/ ++ {S500M, VDD1_OPP3, 0}, ++ /*OPP4*/ ++ {S550M, VDD1_OPP4, 0}, ++ /*OPP5*/ ++ {S600M, VDD1_OPP5, 0}, ++}; ++ ++struct vdd_prcm_config vdd2_rate_table[] = { ++ {0, 0, 0}, ++ /*OPP1*/ ++ {0, VDD2_OPP1, 0}, ++ /*OPP2*/ ++ {S83M, VDD2_OPP2, 0}, ++ /*OPP3*/ ++ {S166M, VDD2_OPP3, 0}, ++}; ++ ++struct vdd_prcm_config iva2_rate_table[] = { ++ {0, 0, 0}, ++ /*OPP1*/ ++ {S90M, VDD1_OPP1, 0}, ++ /*OPP2*/ ++ {S180M, VDD1_OPP2, 0}, ++ /*OPP3*/ ++ {S360M, VDD1_OPP3, 0}, ++ /*OPP4*/ ++ {S400M, VDD1_OPP4, 0}, ++ /*OPP5*/ ++ {S430M, VDD1_OPP5, 0}, ++}; ++ ++u8 vdd1_volts[MAX_VDD1_OPP] = { ++ /* Vsel corresponding to 0.9V (OPP1), 1.00V (OPP2), ++ * 1.20V (OPP3), 1.27V (OPP4), 1.35 (OPP5) ++ */ ++ 0x18, 0x20, 0x30, 0x36, 0x3C ++}; ++ ++u8 vdd2_volts[MAX_VDD2_OPP] = { ++ /* Vsel corresponding to 0.9V (OPP1), 1.00V (OPP2), 1.15 (OPP3) */ ++ 0x18, 0x20, 0x2C ++}; ++ ++ + static struct mtd_partition omap3beagle_nand_partitions[] = { + /* All the partition sizes are listed in terms of NAND block size */ + { +--- /tmp/cpu-omap.c 2008-08-11 15:43:01.000000000 +0200 ++++ git/arch/arm/plat-omap/cpu-omap.c 2008-08-11 16:31:24.943198000 +0200 +@@ -47,7 +47,7 @@ + + static struct clk *mpu_clk; + +-#ifdef CONFIG_MACH_OMAP_3430SDP ++#if defined(CONFIG_MACH_OMAP_3430SDP) || defined(CONFIG_MACH_OMAP3_BEAGLE) + extern struct vdd_prcm_config vdd1_rate_table[]; + extern struct vdd_prcm_config vdd2_rate_table[]; + extern struct vdd_prcm_config iva2_rate_table[]; +@@ -127,7 +127,7 @@ + ret = clk_set_rate(mpu_clk, freqs.new * 1000); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + #elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)\ +- && defined(CONFIG_MACH_OMAP_3430SDP) ++ && (defined(CONFIG_MACH_OMAP_3430SDP) || defined(CONFIG_MACH_OMAP3_BEAGLE)) + { + int ind; + for (ind = 1; ind <= MAX_VDD1_OPP; ind++) { diff --git a/packages/linux/linux-omap2-git/beagleboard/01-omap3-cpufreq.eml b/packages/linux/linux-omap2-git/beagleboard/01-omap3-cpufreq.eml new file mode 100644 index 0000000000..b45a81edce --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/01-omap3-cpufreq.eml @@ -0,0 +1,319 @@ +CPUFreq driver for OMAP3 + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/configs/omap_3430sdp_defconfig | 19 +++++++ + arch/arm/mach-omap2/clock34xx.c | 42 ++++++++++++++++- + arch/arm/mach-omap2/resource34xx.c | 6 -- + arch/arm/plat-omap/cpu-omap.c | 78 ++++++++++++++++++++++++++++++-- + drivers/cpufreq/cpufreq.c | 2 + 5 files changed, 136 insertions(+), 11 deletions(-) + +Index: linux-omap-2.6/arch/arm/mach-omap2/clock34xx.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/clock34xx.c 2008-08-11 +17:21:57.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/clock34xx.c 2008-08-11 +17:36:53.000000000 +0530 +@@ -31,6 +31,7 @@ + #include <asm/arch/sram.h> + #include <asm/div64.h> + #include <asm/bitops.h> ++#include <linux/cpufreq.h> + + #include <asm/arch/sdrc.h> + #include "clock.h" +@@ -637,6 +638,35 @@ static void omap3_clkoutx2_recalc(struct + */ + #if defined(CONFIG_ARCH_OMAP3) + ++#ifdef CONFIG_CPU_FREQ ++static struct cpufreq_frequency_table freq_table[MAX_VDD1_OPP+1]; ++ ++void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table) ++{ ++ struct vdd_prcm_config *prcm; ++ int i = 0; ++ ++ prcm = vdd1_rate_table + MAX_VDD1_OPP; ++ for (; prcm->speed; prcm--) { ++ freq_table[i].index = i; ++ freq_table[i].frequency = prcm->speed / 1000; ++ i++; ++ } ++ ++ if (i == 0) { ++ printk(KERN_WARNING "%s: failed to initialize frequency \ ++ table\n", ++ __func__); ++ return; ++ } ++ ++ freq_table[i].index = i; ++ freq_table[i].frequency = CPUFREQ_TABLE_END; ++ ++ *table = &freq_table[0]; ++} ++#endif ++ + static struct clk_functions omap2_clk_functions = { + .clk_enable = omap2_clk_enable, + .clk_disable = omap2_clk_disable, +@@ -644,6 +674,9 @@ static struct clk_functions omap2_clk_fu + .clk_set_rate = omap2_clk_set_rate, + .clk_set_parent = omap2_clk_set_parent, + .clk_disable_unused = omap2_clk_disable_unused, ++#ifdef CONFIG_CPU_FREQ ++ .clk_init_cpufreq_table = omap2_clk_init_cpufreq_table, ++#endif + }; + + /* +@@ -793,12 +826,11 @@ inline unsigned int get_opp(struct vdd_p + + if (prcm_config->speed <= freq) + return prcm_config->opp; /* Return the Highest OPP */ +- for (; prcm_config->speed; prcm_config--) { ++ for (; prcm_config->speed; prcm_config--) + if (prcm_config->speed < freq) + return (prcm_config+1)->opp; + else if (prcm_config->speed == freq) + return prcm_config->opp; +- } + /* Return the least OPP */ + return (prcm_config+1)->opp; + } +@@ -878,6 +910,10 @@ static int omap3_select_table_rate(struc + clk_set_rate(dpll1_clk, prcm_vdd->speed); + clk_set_rate(dpll2_clk, iva2_rate_table[index].speed); + curr_vdd1_prcm_set = prcm_vdd; ++ omap2_clksel_recalc(&mpu_ck); ++ propagate_rate(&mpu_ck); ++ omap2_clksel_recalc(&iva2_ck); ++ propagate_rate(&iva2_ck); + #ifndef CONFIG_CPU_FREQ + /*Update loops_per_jiffy if processor speed is being changed*/ + loops_per_jiffy = compute_lpj(loops_per_jiffy, +@@ -886,6 +922,8 @@ static int omap3_select_table_rate(struc + } else { + clk_set_rate(dpll3_clk, prcm_vdd->speed); + curr_vdd2_prcm_set = prcm_vdd; ++ omap2_clksel_recalc(&core_ck); ++ propagate_rate(&core_ck); + } + return 0; + } +Index: linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/resource34xx.c 2008-08-11 +17:36:52.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c 2008-08-11 +17:36:53.000000000 +0530 +@@ -278,11 +278,7 @@ int set_freq(struct shared_resource *res + else if (strcmp(resp->name, "dsp_freq") == 0) + vdd1_opp = get_opp(iva2_rate_table + MAX_VDD1_OPP, + target_level); +- +- if (vdd1_opp == MIN_VDD1_OPP) +- resource_release("vdd1_opp", &dummy_srf_dev); +- else +- resource_request("vdd1_opp", &dummy_srf_dev, vdd1_opp); ++ resource_request("vdd1_opp", &dummy_srf_dev, vdd1_opp); + + resp->curr_level = target_level; + #endif +Index: linux-omap-2.6/arch/arm/plat-omap/cpu-omap.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/plat-omap/cpu-omap.c 2008-08-11 +17:21:57.000000000 +0530 ++++ linux-omap-2.6/arch/arm/plat-omap/cpu-omap.c 2008-08-11 17:36:53.000000000 ++0530 +@@ -8,6 +8,10 @@ + * + * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King + * ++ * Copyright (C) 2007-2008 Texas Instruments, Inc. ++ * Updated to support OMAP3 ++ * Rajendra Nayak <rnayak@ti.com> ++ * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +@@ -25,6 +29,9 @@ + #include <asm/io.h> + #include <asm/system.h> + #include <asm/arch/clock.h> ++#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++#include <asm/arch/omap-pm.h> ++#endif + + #define VERY_HI_RATE 900000000 + +@@ -32,12 +39,34 @@ static struct cpufreq_frequency_table *f + + #ifdef CONFIG_ARCH_OMAP1 + #define MPU_CLK "mpu" ++#elif CONFIG_ARCH_OMAP3 ++#define MPU_CLK "virt_vdd1_prcm_set" + #else + #define MPU_CLK "virt_prcm_set" + #endif + + static struct clk *mpu_clk; + ++#ifdef CONFIG_MACH_OMAP_3430SDP ++extern struct vdd_prcm_config vdd1_rate_table[]; ++extern struct vdd_prcm_config vdd2_rate_table[]; ++extern struct vdd_prcm_config iva2_rate_table[]; ++#endif ++ ++#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++int cpufreq_pre_func(struct notifier_block *n, unsigned long event, void *ptr); ++int cpufreq_post_func(struct notifier_block *n, unsigned long event, void *ptr); ++static struct notifier_block cpufreq_pre = { ++ cpufreq_pre_func, ++ NULL, ++}; ++ ++static struct notifier_block cpufreq_post = { ++ cpufreq_post_func, ++ NULL, ++}; ++#endif ++ + /* TODO: Add support for SDRAM timing changes */ + + int omap_verify_speed(struct cpufreq_policy *policy) +@@ -89,7 +118,7 @@ static int omap_target(struct cpufreq_po + + if (freqs.old == freqs.new) + return ret; +- ++#ifdef CONFIG_ARCH_OMAP1 + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + #ifdef CONFIG_CPU_FREQ_DEBUG + printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n", +@@ -97,10 +126,50 @@ static int omap_target(struct cpufreq_po + #endif + ret = clk_set_rate(mpu_clk, freqs.new * 1000); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +- ++#elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)\ ++ && defined(CONFIG_MACH_OMAP_3430SDP) ++ { ++ int ind; ++ for (ind = 1; ind <= MAX_VDD1_OPP; ind++) { ++ if (vdd1_rate_table[ind].speed/1000 >= freqs.new) { ++ omap_pm_cpu_set_freq ++ (vdd1_rate_table[ind].speed); ++ break; ++ } ++ } ++ } ++#endif + return ret; + } + ++#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++static struct cpufreq_freqs freqs_notify; ++int cpufreq_pre_func(struct notifier_block *n, unsigned long event, void *ptr) ++{ ++ struct clk_notifier_data *cnd; ++ ++ cnd = (struct clk_notifier_data *)ptr; ++ freqs_notify.old = cnd->old_rate/1000; ++ freqs_notify.new = cnd->new_rate/1000; ++ /* HACK: The clk_notify_post_rate_chg currently ++ * returns a zero for old_rate at bootup ++ */ ++ if (freqs_notify.old == 0) ++ freqs_notify.old = 500000; ++ cpufreq_notify_transition(&freqs_notify, CPUFREQ_PRECHANGE); ++ return 0; ++} ++ ++int cpufreq_post_func(struct notifier_block *n, unsigned long event, void *ptr) ++{ ++ struct clk_notifier_data *cnd; ++ ++ cnd = (struct clk_notifier_data *)ptr; ++ cpufreq_notify_transition(&freqs_notify, CPUFREQ_POSTCHANGE); ++ return 0; ++} ++#endif ++ + static int __init omap_cpu_init(struct cpufreq_policy *policy) + { + int result = 0; +@@ -128,7 +197,10 @@ static int __init omap_cpu_init(struct c + + /* FIXME: what's the actual transition time? */ + policy->cpuinfo.transition_latency = 10 * 1000 * 1000; +- ++#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++ clk_notifier_register(mpu_clk, &cpufreq_pre); ++ clk_notifier_register(mpu_clk, &cpufreq_post); ++#endif + return 0; + } + +Index: linux-omap-2.6/drivers/cpufreq/cpufreq.c +=================================================================== +--- linux-omap-2.6.orig/drivers/cpufreq/cpufreq.c 2008-08-11 17:21:57.000000000 ++0530 ++++ linux-omap-2.6/drivers/cpufreq/cpufreq.c 2008-08-11 17:36:53.000000000 +0530 +@@ -321,7 +321,9 @@ void cpufreq_notify_transition(struct cp + { + struct cpufreq_policy *policy; + ++#if 0 /*This causes an issue if clk_notify_post_rate_chg is used*/ + BUG_ON(irqs_disabled()); ++#endif + + freqs->flags = cpufreq_driver->flags; + dprintk("notification %u of frequency transition to %u kHz\n", +Index: linux-omap-2.6/arch/arm/configs/omap_3430sdp_defconfig +=================================================================== +--- linux-omap-2.6.orig/arch/arm/configs/omap_3430sdp_defconfig 2008-08-11 +17:36:43.000000000 +0530 ++++ linux-omap-2.6/arch/arm/configs/omap_3430sdp_defconfig 2008-08-11 +17:37:33.000000000 +0530 +@@ -193,6 +193,9 @@ CONFIG_OMAP_LL_DEBUG_UART1=y + # CONFIG_OMAP_LL_DEBUG_UART2 is not set + # CONFIG_OMAP_LL_DEBUG_UART3 is not set + CONFIG_OMAP_SERIAL_WAKE=y ++# CONFIG_OMAP_PM_NONE is not set ++# CONFIG_OMAP_PM_NOOP is not set ++CONFIG_OMAP_PM_SRF=y + CONFIG_ARCH_OMAP34XX=y + CONFIG_ARCH_OMAP3430=y + +@@ -288,7 +291,21 @@ CONFIG_CMDLINE="root=/dev/nfs nfsroot=19 + # + # CPU Frequency scaling + # +-# CONFIG_CPU_FREQ is not set ++CONFIG_CPU_FREQ=y ++CONFIG_CPU_FREQ_TABLE=y ++# CONFIG_CPU_FREQ_DEBUG is not set ++CONFIG_CPU_FREQ_STAT=y ++CONFIG_CPU_FREQ_STAT_DETAILS=y ++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y ++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set ++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set ++# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set ++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set ++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y ++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set ++# CONFIG_CPU_FREQ_GOV_USERSPACE is not set ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y ++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set + + # + # Floating point emulation + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/packages/linux/linux-omap2-git/beagleboard/01-omappm-srf.eml b/packages/linux/linux-omap2-git/beagleboard/01-omappm-srf.eml new file mode 100644 index 0000000000..8b8b183808 --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/01-omappm-srf.eml @@ -0,0 +1,513 @@ +Adds Generic Shared Resource Framework structures and API's + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/plat-omap/resource.c | 389 +++++++++++++++++++++++++++++++++++ + include/asm-arm/arch-omap/resource.h | 97 ++++++++ + 2 files changed, 486 insertions(+) + +Index: linux-omap-2.6/arch/arm/plat-omap/resource.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-omap-2.6/arch/arm/plat-omap/resource.c 2008-08-07 15:06:58.000000000 ++0530 +@@ -0,0 +1,389 @@ ++/* ++ * linux/arch/arm/plat-omap/resource.c ++ * Shared Resource Framework API implementation ++ * ++ * Copyright (C) 2007-2008 Texas Instruments, Inc. ++ * Written by Rajendra Nayak <rnayak@ti.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ++ * History: ++ * ++ */ ++ ++#include <linux/errno.h> ++#include <linux/err.h> ++#include <asm/arch/resource.h> ++#include <linux/slab.h> ++ ++/* res_list contains all registered struct shared_resource */ ++static LIST_HEAD(res_list); ++ ++/* res_mutex protects res_list add and del ops */ ++static DEFINE_MUTEX(res_mutex); ++ ++/* Static Pool of users for a resource */ ++/* used till kmalloc becomes availabel */ ++struct users_list usr_list[MAX_USERS]; ++ ++/* Private/Internal functions */ ++ ++/** ++ * resource_lookup - loop up a resource by its name, return a pointer ++ * @name: The name of the resource to lookup ++ * ++ * Looks for a registered resource by its name. Returns a pointer to ++ * the struct shared_resource if found, else returns NULL. ++ */ ++static struct shared_resource *resource_lookup(const char *name) ++{ ++ struct shared_resource *res, *tmp_res; ++ ++ if (!name) ++ return NULL; ++ ++ res = NULL; ++ ++ srf_mutex_lock(&res_mutex); ++ list_for_each_entry(tmp_res, &res_list, node) { ++ if (!strcmp(name, tmp_res->name)) { ++ res = tmp_res; ++ break; ++ } ++ } ++ srf_mutex_unlock(&res_mutex); ++ return res; ++} ++ ++/** ++ * update_resource_level - Regenerates and updates the curr_level of the res ++ * @resp: Pointer to the resource ++ * ++ * This function looks at all the users of the given resource and the levels ++ * requested by each of them, and recomputes a target level for the resource ++ * acceptable to all its current usres. It then calls platform specific ++ * change_level to change the level of the resource. ++ * Returns 0 on success, else a non-zero value returned by the platform ++ * specific change_level function. ++ **/ ++static int update_resource_level(struct shared_resource *resp) ++{ ++ struct users_list *user; ++ unsigned long target_level; ++ int ret; ++ ++ /* Regenerate the target_value for the resource */ ++ target_level = RES_DEFAULTLEVEL; ++ list_for_each_entry(user, &resp->users_list, node) ++ if (user->level > target_level) ++ target_level = user->level; ++ ++ pr_debug("SRF: Changing Level for resource %s to %ld\n", ++ resp->name, target_level); ++ ret = resp->ops->change_level(resp, target_level); ++ if (ret) { ++ printk(KERN_ERR "Unable to Change" ++ "level for resource %s to %ld\n", ++ resp->name, target_level); ++ return ret; ++ } ++ return ret; ++} ++ ++/** ++ * get_user - gets a new users_list struct from static pool or dynamically ++ * ++ * This function initally looks for availability in the static pool and ++ * tries to dynamcially allocate only once the static pool is empty. ++ * We hope that during bootup by the time we hit a case of dynamic allocation ++ * slab initialization would have happened. ++ * Returns a pointer users_list struct on success. On dynamic allocation failure ++ * returns a ERR_PTR(-ENOMEM). ++ */ ++static struct users_list *get_user(void) ++{ ++ int ind = 0; ++ struct users_list *user; ++ ++ /* See if something available in the static pool */ ++ while (ind < MAX_USERS) { ++ if (usr_list[ind].usage == UNUSED) ++ break; ++ else ++ ind++; ++ } ++ if (ind < MAX_USERS) { ++ /* Pick from the static pool */ ++ user = &usr_list[ind]; ++ user->usage = STATIC_ALLOC; ++ } else { ++ /* By this time we hope slab is initialized */ ++ if (slab_is_available()) { ++ user = kmalloc(sizeof(struct users_list), GFP_KERNEL); ++ if (!user) { ++ printk(KERN_ERR "SRF:FATAL ERROR: kmalloc" ++ "failed\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ user->usage = DYNAMIC_ALLOC; ++ } else { ++ /* Dynamic alloc not available yet */ ++ printk(KERN_ERR "SRF: FATAL ERROR: users_list" ++ "initial POOL EMPTY before slab init\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ return user; ++} ++ ++/** ++ * free_user - frees the dynamic users_list and marks the static one unused ++ * @user: The struct users_list to be freed ++ * ++ * Looks at the usage flag and either frees the users_list if it was ++ * dynamically allocated, and if its from the static pool, marks it unused. ++ * No return value. ++ */ ++void free_user(struct users_list *user) ++{ ++ if (user->usage == DYNAMIC_ALLOC) ++ kfree(user); ++ else { ++ user->usage = UNUSED; ++ user->level = RES_DEFAULTLEVEL; ++ user->dev = NULL; ++ } ++} ++ ++/** ++ * resource_init - Initializes the Shared resource framework. ++ * @resources: List of all the resources modelled ++ * ++ * Loops through the list of resources and registers all that ++ * are available for the current CPU. ++ * No return value ++ */ ++void resource_init(struct shared_resource **resources) ++{ ++ struct shared_resource **resp; ++ int ind; ++ ++ pr_debug("Initializing Shared Resource Framework\n"); ++ ++ if (!cpu_is_omap343x()) { ++ /* This CPU is not supported */ ++ printk(KERN_WARNING "Shared Resource Framework does not" ++ "support this CPU type.\n"); ++ WARN_ON(1); ++ } ++ ++ /* Init the users_list POOL */ ++ for (ind = 0; ind < MAX_USERS; ind++) { ++ usr_list[ind].usage = UNUSED; ++ usr_list[ind].dev = NULL; ++ usr_list[ind].level = RES_DEFAULTLEVEL; ++ } ++ ++ if (resources) ++ for (resp = resources; *resp; resp++) ++ resource_register(*resp); ++} ++ ++/** ++ * resource_register - registers and initializes a resource ++ * @res: struct shared_resource * to register ++ * ++ * Initializes the given resource and adds it to the resource list ++ * for the current CPU. ++ * Returns 0 on success, -EINVAL if given a NULL pointer, -EEXIST if the ++ * resource is already registered. ++ */ ++int resource_register(struct shared_resource *resp) ++{ ++ if (!resp) ++ return -EINVAL; ++ ++ if (!omap_chip_is(resp->omap_chip)) ++ return -EINVAL; ++ ++ /* Verify that the resource is not already registered */ ++ if (resource_lookup(resp->name)) ++ return -EEXIST; ++ ++ INIT_LIST_HEAD(&resp->users_list); ++ mutex_init(&resp->res_mutex); ++ ++ srf_mutex_lock(&res_mutex); ++ /* Add the resource to the resource list */ ++ list_add(&resp->node, &res_list); ++ srf_mutex_unlock(&res_mutex); ++ ++ /* Call the resource specific init*/ ++ if (resp->ops->init) ++ resp->ops->init(resp); ++ ++ pr_debug("resource: registered %s\n", resp->name); ++ ++ return 0; ++} ++EXPORT_SYMBOL(resource_register); ++ ++/** ++ * resource_unregister - unregister a resource ++ * @res: struct shared_resource * to unregister ++ * ++ * Removes a resource from the resource list. ++ * Returns 0 on success, -EINVAL if passed a NULL pointer. ++ */ ++int resource_unregister(struct shared_resource *resp) ++{ ++ if (!resp) ++ return -EINVAL; ++ ++ srf_mutex_lock(&res_mutex); ++ /* delete the resource from the resource list */ ++ list_del(&resp->node); ++ srf_mutex_unlock(&res_mutex); ++ ++ pr_debug("resource: unregistered %s\n", resp->name); ++ ++ return 0; ++} ++EXPORT_SYMBOL(resource_unregister); ++ ++/** ++ * resource_request - Request for a required level of a resource ++ * @name: The name of the resource requested ++ * @dev: Uniquely identifes the caller ++ * @level: The requested level for the resource ++ * ++ * This function recomputes the target level of the resource based on ++ * the level requested by the user. The level of the resource is ++ * changed to the target level, if it is not the same as the existing level ++ * of the resource. Multiple calls to this function by the same device will ++ * replace the previous level requested ++ * Returns 0 on success, -EINVAL if the resource name passed in invalid. ++ * -ENOMEM if no static pool available or dynamic allocations fails. ++ * Else returns a non-zero error value returned by one of the failing ++ * shared_resource_ops. ++ */ ++int resource_request(const char *name, struct device *dev, ++ unsigned long level) ++{ ++ struct shared_resource *resp; ++ struct users_list *user; ++ int found = 0, ret = 0; ++ ++ resp = resource_lookup(name); ++ if (!resp) { ++ printk(KERN_ERR "resource_request: Invalid resource name\n"); ++ return -EINVAL; ++ } ++ ++ /* Call the resource specific validate function */ ++ if (resp->ops->validate_level) ++ ret = resp->ops->validate_level(resp, level); ++ if (ret) ++ return ret; ++ ++ srf_mutex_lock(&resp->res_mutex); ++ list_for_each_entry(user, &(resp->users_list), node) ++ if (user->dev == dev) { ++ found = 1; ++ break; ++ } ++ if (!found) { ++ /* First time user */ ++ user = get_user(); ++ if (IS_ERR(user)) { ++ srf_mutex_unlock(&resp->res_mutex); ++ return -ENOMEM; ++ } ++ user->dev = dev; ++ list_add(&user->node, &resp->users_list); ++ resp->no_of_users++; ++ } ++ user->level = level; ++ srf_mutex_unlock(&resp->res_mutex); ++ ++ /* Recompute and set the current level for the resource */ ++ return update_resource_level(resp); ++} ++EXPORT_SYMBOL(resource_request); ++ ++/** ++ * resource_release - Release a previously requested level of a resource ++ * @name: The name of the resource to be released ++ * @dev: Uniquely identifes the caller ++ * ++ * This function recomputes the target level of the resource after removing ++ * the level requested by the user. The level of the resource is ++ * changed to the target level, if it is not the same as the existing level ++ * of the resource. ++ * Returns 0 on success, -EINVAL if the resource name or dev structure ++ * is invalid. ++ */ ++int resource_release(const char *name, struct device *dev) ++{ ++ struct shared_resource *resp; ++ struct users_list *user; ++ int found = 0; ++ ++ resp = resource_lookup(name); ++ if (!resp) { ++ printk(KERN_ERR "resource_release: Invalid resource name\n"); ++ return -EINVAL; ++ } ++ ++ srf_mutex_lock(&resp->res_mutex); ++ list_for_each_entry(user, &(resp->users_list), node) ++ if (user->dev == dev) { ++ found = 1; ++ break; ++ } ++ ++ if (!found) { ++ srf_mutex_unlock(&resp->res_mutex); ++ /* No such user exists */ ++ return -EINVAL; ++ } ++ ++ resp->no_of_users--; ++ list_del(&user->node); ++ free_user(user); ++ srf_mutex_unlock(&resp->res_mutex); ++ ++ /* Recompute and set the current level for the resource */ ++ return update_resource_level(resp); ++} ++EXPORT_SYMBOL(resource_release); ++ ++/** ++ * resource_get_level - Returns the current level of the resource ++ * @name: Name of the resource ++ * ++ * Returns the current level of the resource if found, else returns ++ * -EINVAL if the resource name is invalid. ++ */ ++int resource_get_level(const char *name) ++{ ++ struct shared_resource *resp; ++ u32 ret; ++ ++ resp = resource_lookup(name); ++ if (!resp) { ++ printk(KERN_ERR "resource_release: Invalid resource name\n"); ++ return -EINVAL; ++ } ++ ++ srf_mutex_lock(&resp->res_mutex); ++ ret = resp->curr_level; ++ srf_mutex_unlock(&resp->res_mutex); ++ return ret; ++} ++EXPORT_SYMBOL(resource_get_level); +Index: linux-omap-2.6/include/asm-arm/arch-omap/resource.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-omap-2.6/include/asm-arm/arch-omap/resource.h 2008-08-07 +15:06:58.000000000 +0530 +@@ -0,0 +1,97 @@ ++/* ++ * linux/include/asm-arm/arch-omap/resource.h ++ * Structure definitions for Shared resource Framework ++ * ++ * Copyright (C) 2007-2008 Texas Instruments, Inc. ++ * Written by Rajendra Nayak <rnayak@ti.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * History: ++ * ++ */ ++ ++#ifndef __ARCH_ARM_OMAP_RESOURCE_H ++#define __ARCH_ARM_OMAP_RESOURCE_H ++ ++#include <linux/list.h> ++#include <linux/mutex.h> ++#include <linux/device.h> ++#include <asm/arch/cpu.h> ++ ++#define srf_mutex_lock(x) { \ ++ if (!(in_atomic() || irqs_disabled())) \ ++ mutex_lock(x); \ ++ } ++#define srf_mutex_unlock(x) { \ ++ if (!(in_atomic() || irqs_disabled())) \ ++ mutex_unlock(x); \ ++ } ++ ++#define RES_DEFAULTLEVEL 0x0 ++ ++struct shared_resource_ops; /* forward declaration */ ++ ++/* Used to model a Shared Multilevel Resource */ ++struct shared_resource { ++ /* Resource name */ ++ const char *name; ++ /* Used to represent the OMAP chip types containing this res */ ++ const struct omap_chip_id omap_chip; ++ /* Total no of users at any point of this resource */ ++ u8 no_of_users; ++ /* Current level of this resource */ ++ u32 curr_level; ++ /* Used to store any resource specific data */ ++ void *resource_data; ++ /* List of all the current users for this resource */ ++ struct list_head users_list; ++ /* Used to guard the resource */ ++ struct mutex res_mutex; ++ /* Shared resource operations */ ++ struct shared_resource_ops *ops; ++ struct list_head node; ++}; ++ ++struct shared_resource_ops { ++ /* Init function for the resource */ ++ void (*init)(struct shared_resource *res); ++ /* Function to change the level of the resource */ ++ int (*change_level)(struct shared_resource *res, u32 target_level); ++ /* Function to validate the requested level of the resource */ ++ int (*validate_level)(struct shared_resource *res, u32 target_level); ++}; ++ ++/* This is to statically defining the users pool */ ++/* This static pool is used till kmalloc becomes available */ ++#define MAX_USERS 10 ++#define UNUSED 0x0 ++#define DYNAMIC_ALLOC 0x1 ++#define STATIC_ALLOC 0x2 ++ ++/* Used to represent a user of a shared resource */ ++struct users_list { ++ /* Device pointer used to uniquely identify the user */ ++ struct device *dev; ++ /* Current level as requested for the resource by the user */ ++ u32 level; ++ struct list_head node; ++ u8 usage; ++}; ++ ++/* Shared resource Framework API's */ ++void resource_init(struct shared_resource **resources); ++int resource_register(struct shared_resource *res); ++int resource_unregister(struct shared_resource *res); ++int resource_request(const char *name, struct device *dev, ++ unsigned long level); ++int resource_release(const char *name, struct device *dev); ++int resource_get_level(const char *name); ++ ++#endif /* __ARCH_ARM_OMAP_RESOURCE_H */ + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + diff --git a/packages/linux/linux-omap2-git/beagleboard/01-postrate-notifier.eml b/packages/linux/linux-omap2-git/beagleboard/01-postrate-notifier.eml new file mode 100644 index 0000000000..8e72afeb3f --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/01-postrate-notifier.eml @@ -0,0 +1,392 @@ +Add the infrastructure necessary to support clock post-rate-change notifiers +in the OMAP clock framework. This includes: + +- adding the clk_notify_post_rate_chg() function, which will trigger a + notifier call chain when a clock rate is changed (but which currently + does nothing); and + +- adding calls to clk_notify_post_rate_chg() everywhere clk->rate is + assigned (mostly *_recalc() functions). + +This patch has no functional effect by itself; the actual notifier +implementation follows in a separate patch. + +One item to note is that the post-rate-change notifier is called even +if the new clock rate is identical to the old rate. This is because +the process of changing the rate may have temporarily disabled or +glitched the clock or one of its parents, and some devices may be +sensitive to such changes. + +Signed-off-by: Paul Walmsley <paul@pwsan.com> +--- + + arch/arm/mach-omap2/clock.c | 37 +++++++++++++++++++++++++++------ + arch/arm/mach-omap2/clock24xx.c | 42 +++++++++++++++++++++++++++++++++++-- + arch/arm/mach-omap2/clock34xx.c | 10 +++++++++ + arch/arm/plat-omap/clock.c | 32 ++++++++++++++++++++++++++++ + include/asm-arm/arch-omap/clock.h | 21 +++++++++++++++++++ + 5 files changed, 134 insertions(+), 8 deletions(-) + +diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c +index ed15868..bd3c1f8 100644 +--- a/arch/arm/mach-omap2/clock.c ++++ b/arch/arm/mach-omap2/clock.c +@@ -165,10 +165,15 @@ u32 omap2_get_dpll_rate(struct clk *clk) + */ + void omap2_fixed_divisor_recalc(struct clk *clk) + { ++ unsigned long orig_rate; ++ + WARN_ON(!clk->fixed_div); + ++ orig_rate = clk->rate; + clk->rate = clk->parent->rate / clk->fixed_div; + ++ clk_notify_post_rate_chg(clk, orig_rate, clk->rate); ++ + if (clk->flags & RATE_PROPAGATES) + propagate_rate(clk); + } +@@ -376,6 +381,7 @@ int omap2_clk_enable(struct clk *clk) + void omap2_clksel_recalc(struct clk *clk) + { + u32 div = 0; ++ unsigned long orig_rate; + + pr_debug("clock: recalc'ing clksel clk %s\n", clk->name); + +@@ -385,10 +391,13 @@ void omap2_clksel_recalc(struct clk *clk) + + if (clk->rate == (clk->parent->rate / div)) + return; ++ orig_rate = clk->rate; + clk->rate = clk->parent->rate / div; + + pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div); + ++ clk_notify_post_rate_chg(clk, orig_rate, clk->rate); ++ + if (clk->flags & RATE_PROPAGATES) + propagate_rate(clk); + } +@@ -662,6 +671,8 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) + wmb(); + } + ++ /* post-rate-change notifier will be called by omap2_clk_set_rate() */ ++ + return 0; + } + +@@ -670,20 +681,30 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) + int omap2_clk_set_rate(struct clk *clk, unsigned long rate) + { + int ret = -EINVAL; +- +- pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate); ++ unsigned long orig_rate; + + /* CONFIG_PARTICIPANT clocks are changed only in sets via the + rate table mechanism, driven by mpu_speed */ + if (clk->flags & CONFIG_PARTICIPANT) + return -EINVAL; + ++ if (!clk->set_rate) ++ return -EINVAL; ++ ++ orig_rate = clk->rate; ++ ++ pr_debug("clock: set_rate for clock %s from %ld Hz to %ld Hz\n", ++ clk->name, orig_rate, rate); ++ + /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */ +- if (clk->set_rate) +- ret = clk->set_rate(clk, rate); ++ ret = clk->set_rate(clk, rate); + +- if (ret == 0 && (clk->flags & RATE_PROPAGATES)) +- propagate_rate(clk); ++ if (ret == 0) { ++ clk_notify_post_rate_chg(clk, orig_rate, rate); ++ ++ if (clk->flags & RATE_PROPAGATES) ++ propagate_rate(clk); ++ } + + return ret; + } +@@ -732,6 +753,7 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) + { + void __iomem *src_addr; + u32 field_val, field_mask, reg_val, parent_div; ++ unsigned long orig_rate; + + if (clk->flags & CONFIG_PARTICIPANT) + return -EINVAL; +@@ -765,11 +787,14 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) + clk->parent = new_parent; + + /* CLKSEL clocks follow their parents' rates, divided by a divisor */ ++ orig_rate = clk->rate; + clk->rate = new_parent->rate; + + if (parent_div > 0) + clk->rate /= parent_div; + ++ clk_notify_post_rate_chg(clk, orig_rate, clk->rate); ++ + pr_debug("clock: set parent of %s to %s (new rate %ld)\n", + clk->name, clk->parent->name, clk->rate); + +diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c +index 54cc6e1..e001549 100644 +--- a/arch/arm/mach-omap2/clock24xx.c ++++ b/arch/arm/mach-omap2/clock24xx.c +@@ -172,11 +172,22 @@ static long omap2_dpllcore_round_rate(unsigned long target_rate) + + static void omap2_dpllcore_recalc(struct clk *clk) + { ++ unsigned long orig_rate; ++ ++ orig_rate = clk->rate; + clk->rate = omap2_get_dpll_rate_24xx(clk); + ++ clk_notify_post_rate_chg(clk, orig_rate, clk->rate); ++ + propagate_rate(clk); + } + ++/* ++ * XXX REVISIT: This code needs to keep track of the underlying struct ++ * clocks that it is changing, so it can call post-rate-change notifiers ++ * on them. This function probably should be rewritten to use the clock ++ * fw. ++ */ + static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate) + { + u32 cur_rate, low, mult, div, valid_rate, done_rate; +@@ -259,7 +270,14 @@ dpll_exit: + */ + static void omap2_table_mpu_recalc(struct clk *clk) + { ++ unsigned long orig_rate; ++ ++ orig_rate = clk->rate; + clk->rate = curr_prcm_set->mpu_speed; ++ ++ clk_notify_post_rate_chg(clk, orig_rate, clk->rate); ++ ++ /* No rate propagation since table clocks have no children */ + } + + /* +@@ -294,7 +312,14 @@ static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate) + return highest_rate; + } + +-/* Sets basic clocks based on the specified rate */ ++/* ++ * Sets basic clocks based on the specified rate ++ * ++ * XXX REVISIT: This code needs to keep track of the underlying struct ++ * clocks that it is changing, so it can call post-rate-change notifiers ++ * on them. This function probably should be rewritten to use the clock ++ * fw. ++ */ + static int omap2_select_table_rate(struct clk *clk, unsigned long rate) + { + u32 cur_rate, done_rate, bypass = 0, tmp; +@@ -353,7 +378,8 @@ static int omap2_select_table_rate(struct clk *clk, unsigned long rate) + cm_write_mod_reg(prcm->cm_clksel_gfx, GFX_MOD, CM_CLKSEL); + + /* Major subsystem dividers */ +- tmp = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & OMAP24XX_CLKSEL_DSS2_MASK; ++ tmp = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & ++ OMAP24XX_CLKSEL_DSS2_MASK; + cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD, + CM_CLKSEL1); + +@@ -460,13 +486,25 @@ static u32 omap2_get_sysclkdiv(void) + + static void omap2_osc_clk_recalc(struct clk *clk) + { ++ unsigned long orig_rate; ++ ++ orig_rate = clk->rate; + clk->rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv(); ++ ++ clk_notify_post_rate_chg(clk, orig_rate, clk->rate); ++ + propagate_rate(clk); + } + + static void omap2_sys_clk_recalc(struct clk *clk) + { ++ unsigned long orig_rate; ++ ++ orig_rate = clk->rate; + clk->rate = clk->parent->rate / omap2_get_sysclkdiv(); ++ ++ clk_notify_post_rate_chg(clk, orig_rate, clk->rate); ++ + propagate_rate(clk); + } + +diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c +index 408b51a..7b89b61 100644 +--- a/arch/arm/mach-omap2/clock34xx.c ++++ b/arch/arm/mach-omap2/clock34xx.c +@@ -53,8 +53,13 @@ + */ + static void omap3_dpll_recalc(struct clk *clk) + { ++ unsigned long orig_rate; ++ ++ orig_rate = clk->rate; + clk->rate = omap2_get_dpll_rate(clk); + ++ clk_notify_post_rate_chg(clk, orig_rate, clk->rate); ++ + propagate_rate(clk); + } + +@@ -500,6 +505,7 @@ static void omap3_clkoutx2_recalc(struct clk *clk) + const struct dpll_data *dd; + u32 v; + struct clk *pclk; ++ unsigned long orig_rate; + + /* Walk up the parents of clk, looking for a DPLL */ + pclk = clk->parent; +@@ -513,6 +519,8 @@ static void omap3_clkoutx2_recalc(struct clk *clk) + + WARN_ON(!dd->control_reg || !dd->enable_mask); + ++ orig_rate = clk->rate; ++ + v = __raw_readl(dd->control_reg) & dd->enable_mask; + v >>= __ffs(dd->enable_mask); + if (v != DPLL_LOCKED) +@@ -520,6 +528,8 @@ static void omap3_clkoutx2_recalc(struct clk *clk) + else + clk->rate = clk->parent->rate * 2; + ++ clk_notify_post_rate_chg(clk, orig_rate, clk->rate); ++ + if (clk->flags & RATE_PROPAGATES) + propagate_rate(clk); + } +diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c +index c2e741d..421d076 100644 +--- a/arch/arm/plat-omap/clock.c ++++ b/arch/arm/plat-omap/clock.c +@@ -254,10 +254,16 @@ __setup("mpurate=", omap_clk_setup); + /* Used for clocks that always have same value as the parent clock */ + void followparent_recalc(struct clk *clk) + { ++ unsigned long orig_rate; ++ + if (clk == NULL || IS_ERR(clk)) + return; + ++ orig_rate = clk->rate; + clk->rate = clk->parent->rate; ++ ++ clk_notify_post_rate_chg(clk, orig_rate, clk->rate); ++ + if (unlikely(clk->flags & RATE_PROPAGATES)) + propagate_rate(clk); + } +@@ -373,6 +379,32 @@ void clk_init_cpufreq_table(struct cpufreq_frequency_table **table) + EXPORT_SYMBOL(clk_init_cpufreq_table); + #endif + ++/** ++ * clk_notify_post_rate_chg - call post-clk-rate-change notifier chain ++ * @clk: struct clk * that is changing rate ++ * @old_rate: old rate ++ * @new_rate: new rate ++ * ++ * Triggers a notifier call chain on the post-clk-rate-change notifier ++ * for clock 'clk'. Passes a pointer to the struct clk and the ++ * previous and current rates to the notifier callback. Intended to be ++ * called by internal clock code only. No return value. ++ */ ++void clk_notify_post_rate_chg(struct clk *clk, unsigned long old_rate, ++ unsigned long new_rate) ++{ ++ struct clk_notifier *cn; ++ struct clk_notifier_data cnd; ++ ++ cnd.clk = clk; ++ cnd.old_rate = old_rate; ++ cnd.new_rate = new_rate; ++ ++ /* XXX Call notifier here */ ++ ++} ++ ++ + /*-------------------------------------------------------------------------*/ + + #ifdef CONFIG_OMAP_RESET_CLOCKS +diff --git a/include/asm-arm/arch-omap/clock.h b/include/asm-arm/arch-omap/clock.h +index bfaf7b6..e3c9aeb 100644 +--- a/include/asm-arm/arch-omap/clock.h ++++ b/include/asm-arm/arch-omap/clock.h +@@ -10,6 +10,8 @@ + * published by the Free Software Foundation. + */ + ++#include <linux/notifier.h> ++ + #ifndef __ARCH_ARM_OMAP_CLOCK_H + #define __ARCH_ARM_OMAP_CLOCK_H + +@@ -58,6 +60,19 @@ struct dpll_data { + + #endif + ++struct clk_notifier { ++ struct clk *clk; ++ struct atomic_notifier_head notifier_head; ++ struct list_head node; ++}; ++ ++struct clk_notifier_data { ++ struct clk *clk; ++ unsigned long old_rate; ++ unsigned long new_rate; ++}; ++ ++ + struct clk { + struct list_head node; + struct module *owner; +@@ -121,6 +136,10 @@ extern void clk_allow_idle(struct clk *clk); + extern void clk_deny_idle(struct clk *clk); + extern int clk_get_usecount(struct clk *clk); + extern void clk_enable_init_clocks(void); ++extern int clk_notifier_register(struct clk *clk, struct notifier_block *nb); ++extern int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); ++extern void clk_notify_post_rate_chg(struct clk *clk, unsigned long old_rate, ++ unsigned long new_rate); + #ifdef CONFIG_CPU_FREQ + extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table); + #endif +@@ -161,6 +180,8 @@ extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table); + + #define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X) + ++/* Clk rate change notifier callback type */ ++#define CLK_POST_RATE_CHANGE 1 + + /* CM_CLKSEL2_PLL.CORE_CLK_SRC options (24XX) */ + #define CORE_CLK_SRC_32K 0 + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + diff --git a/packages/linux/linux-omap2-git/beagleboard/02-beagle_use_gptimer12 b/packages/linux/linux-omap2-git/beagleboard/02-beagle_use_gptimer12 new file mode 100644 index 0000000000..51d2c8cff0 --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/02-beagle_use_gptimer12 @@ -0,0 +1,38 @@ +BeagleBoard: make Beagle use GPTIMER12 for system ticks + +From: Paul Walmsley <paul@pwsan.com> + +There is suspicion that the 32kHz input clock to the OMAP may be noisy +on BeagleBoards. On OMAP2/3 GPTIMER1, this can cause the timer +counter register to warp to unknown values or miss interrupt +conditions. So, use GPTIMER12 instead, which apparently has its own +secure 32kHz oscillator and will hopefully not be prone to the 32kHz +glitches. +--- + + arch/arm/configs/omap3_beagle_defconfig | 5 +++-- + 1 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/configs/omap3_beagle_defconfig b/arch/arm/configs/omap3_beagle_defconfig +index e1b16d0..7805995 100644 +--- a/arch/arm/configs/omap3_beagle_defconfig ++++ defconfig +@@ -182,8 +182,8 @@ CONFIG_OMAP_BOOT_REASON=y + # CONFIG_OMAP_MCBSP is not set + # CONFIG_OMAP_MMU_FWK is not set + # CONFIG_OMAP_MBOX_FWK is not set +-CONFIG_OMAP_MPU_TIMER=y +-# CONFIG_OMAP_32K_TIMER is not set ++# CONFIG_OMAP_MPU_TIMER is not set ++CONFIG_OMAP_32K_TIMER=y + CONFIG_OMAP_DM_TIMER=y + # CONFIG_OMAP_LL_DEBUG_UART1 is not set + # CONFIG_OMAP_LL_DEBUG_UART2 is not set +@@ -198,6 +198,7 @@ CONFIG_ARCH_OMAP3430=y + # CONFIG_MACH_OMAP_3430SDP is not set + # CONFIG_MACH_OMAP3EVM is not set + CONFIG_MACH_OMAP3_BEAGLE=y ++CONFIG_OMAP_TICK_GPTIMER=12 + + # + # Boot options diff --git a/packages/linux/linux-omap2-git/beagleboard/02-omappm-mpu-latency-modeling.eml b/packages/linux/linux-omap2-git/beagleboard/02-omappm-mpu-latency-modeling.eml new file mode 100644 index 0000000000..35ef87bdf0 --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/02-omappm-mpu-latency-modeling.eml @@ -0,0 +1,245 @@ +Adds resource def's for mpu/core/powerdomain latencies for OMAP3 + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/resource34xx.h | 226 +++++++++++++++++++++++++++++++++++++ + 1 files changed, 226 insertions(+) + +Index: linux-omap-2.6/arch/arm/mach-omap2/resource34xx.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-omap-2.6/arch/arm/mach-omap2/resource34xx.h 2008-08-07 +15:07:02.000000000 +0530 +@@ -0,0 +1,226 @@ ++/* ++ * linux/arch/arm/mach-omap2/resource34xx.h ++ * ++ * OMAP3 resource definitions ++ * ++ * Copyright (C) 2007-2008 Texas Instruments, Inc. ++ * Written by Rajendra Nayak <rnayak@ti.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * History: ++ * ++ */ ++ ++#ifndef __ARCH_ARM_MACH_OMAP2_RESOURCE_H ++#define __ARCH_ARM_MACH_OMAP2_RESOURCE_H ++ ++#include <asm/arch/resource.h> ++#include <asm/arch/powerdomain.h> ++ ++/** ++ * mpu_latency/core_latency are used to control the cpuidle C state. ++ */ ++void init_latency(struct shared_resource *resp); ++int set_latency(struct shared_resource *resp, u32 target_level); ++ ++static u8 mpu_qos_req_added; ++static u8 core_qos_req_added; ++ ++static struct shared_resource_ops lat_res_ops = { ++ .init = init_latency, ++ .change_level = set_latency, ++}; ++ ++static struct shared_resource mpu_latency = { ++ .name = "mpu_latency", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .resource_data = &mpu_qos_req_added, ++ .ops = &lat_res_ops, ++}; ++ ++static struct shared_resource core_latency = { ++ .name = "core_latency", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .resource_data = &core_qos_req_added, ++ .ops = &lat_res_ops, ++}; ++ ++/** ++ * Power domain Latencies are used to control the target Power ++ * domain state once all clocks for the power domain ++ * are released. ++ */ ++void init_pd_latency(struct shared_resource *resp); ++int set_pd_latency(struct shared_resource *resp, u32 target_level); ++ ++/* Power Domain Latency levels */ ++#define PD_LATENCY_OFF 0x0 ++#define PD_LATENCY_RET 0x1 ++#define PD_LATENCY_INACT 0x2 ++#define PD_LATENCY_ON 0x3 ++ ++#define PD_LATENCY_MAXLEVEL 0x4 ++ ++struct pd_latency_db { ++ char *pwrdm_name; ++ struct powerdomain *pd; ++ /* Latencies for each state transition, stored in us */ ++ unsigned long latency[PD_LATENCY_MAXLEVEL]; ++}; ++ ++static struct shared_resource_ops pd_lat_res_ops = { ++ .init = init_pd_latency, ++ .change_level = set_pd_latency, ++}; ++ ++static struct pd_latency_db iva2_pwrdm_lat_db = { ++ .pwrdm_name = "iva2_pwrdm", ++ .latency[PD_LATENCY_OFF] = 1000, ++ .latency[PD_LATENCY_RET] = 100, ++ .latency[PD_LATENCY_INACT] = 0, ++ .latency[PD_LATENCY_ON] = 0 ++}; ++ ++static struct shared_resource iva2_pwrdm_latency = { ++ .name = "iva2_pwrdm_latency", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .resource_data = &iva2_pwrdm_lat_db, ++ .ops = &pd_lat_res_ops, ++}; ++ ++static struct pd_latency_db gfx_pwrdm_lat_db = { ++ .pwrdm_name = "gfx_pwrdm", ++ .latency[PD_LATENCY_OFF] = 1000, ++ .latency[PD_LATENCY_RET] = 100, ++ .latency[PD_LATENCY_INACT] = 0, ++ .latency[PD_LATENCY_ON] = 0 ++}; ++ ++static struct shared_resource gfx_pwrdm_latency = { ++ .name = "gfx_pwrdm_latency", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1), ++ .resource_data = &gfx_pwrdm_lat_db, ++ .ops = &pd_lat_res_ops, ++}; ++ ++static struct shared_resource sgx_pwrdm_latency = { ++ .name = "sgx_pwrdm_latency", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2), ++ .resource_data = &gfx_pwrdm_lat_db, ++ .ops = &pd_lat_res_ops, ++}; ++ ++static struct pd_latency_db dss_pwrdm_lat_db = { ++ .pwrdm_name = "dss_pwrdm", ++ .latency[PD_LATENCY_OFF] = 70, ++ .latency[PD_LATENCY_RET] = 20, ++ .latency[PD_LATENCY_INACT] = 0, ++ .latency[PD_LATENCY_ON] = 0 ++}; ++ ++static struct shared_resource dss_pwrdm_latency = { ++ .name = "dss_pwrdm_latency", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .resource_data = &dss_pwrdm_lat_db, ++ .ops = &pd_lat_res_ops, ++}; ++ ++static struct pd_latency_db cam_pwrdm_lat_db = { ++ .pwrdm_name = "cam_pwrdm", ++ .latency[PD_LATENCY_OFF] = 850, ++ .latency[PD_LATENCY_RET] = 35, ++ .latency[PD_LATENCY_INACT] = 0, ++ .latency[PD_LATENCY_ON] = 0 ++}; ++ ++static struct shared_resource cam_pwrdm_latency = { ++ .name = "cam_pwrdm_latency", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .resource_data = &cam_pwrdm_lat_db, ++ .ops = &pd_lat_res_ops, ++}; ++ ++static struct pd_latency_db per_pwrdm_lat_db = { ++ .pwrdm_name = "per_pwrdm", ++ .latency[PD_LATENCY_OFF] = 200, ++ .latency[PD_LATENCY_RET] = 110, ++ .latency[PD_LATENCY_INACT] = 0, ++ .latency[PD_LATENCY_ON] = 0 ++}; ++ ++static struct shared_resource per_pwrdm_latency = { ++ .name = "per_pwrdm_latency", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .resource_data = &per_pwrdm_lat_db, ++ .ops = &pd_lat_res_ops, ++}; ++ ++static struct pd_latency_db neon_pwrdm_lat_db = { ++ .pwrdm_name = "neon_pwrdm", ++ .latency[PD_LATENCY_OFF] = 1000, ++ .latency[PD_LATENCY_RET] = 100, ++ .latency[PD_LATENCY_INACT] = 0, ++ .latency[PD_LATENCY_ON] = 0 ++}; ++ ++static struct shared_resource neon_pwrdm_latency = { ++ .name = "neon_pwrdm_latency", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .resource_data = &neon_pwrdm_lat_db, ++ .ops = &pd_lat_res_ops, ++}; ++ ++static struct pd_latency_db usbhost_pwrdm_lat_db = { ++ .pwrdm_name = "usbhost_pwrdm", ++ .latency[PD_LATENCY_OFF] = 1000, ++ .latency[PD_LATENCY_RET] = 100, ++ .latency[PD_LATENCY_INACT] = 0, ++ .latency[PD_LATENCY_ON] = 0 ++}; ++ ++static struct shared_resource usbhost_pwrdm_latency = { ++ .name = "usbhost_pwrdm_latency", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2), ++ .resource_data = &usbhost_pwrdm_lat_db, ++ .ops = &pd_lat_res_ops, ++}; ++ ++static struct pd_latency_db emu_pwrdm_lat_db = { ++ .pwrdm_name = "emu_pwrdm", ++ .latency[PD_LATENCY_OFF] = 1000, ++ .latency[PD_LATENCY_RET] = 100, ++ .latency[PD_LATENCY_INACT] = 0, ++ .latency[PD_LATENCY_ON] = 0 ++}; ++ ++static struct shared_resource emu_pwrdm_latency = { ++ .name = "emu_pwrdm", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .resource_data = &emu_pwrdm_lat_db, ++ .ops = &pd_lat_res_ops, ++}; ++ ++struct shared_resource *resources_omap[] __initdata = { ++ &mpu_latency, ++ &core_latency, ++ /* Power Domain Latency resources */ ++ &iva2_pwrdm_latency, ++ &gfx_pwrdm_latency, ++ &sgx_pwrdm_latency, ++ &dss_pwrdm_latency, ++ &cam_pwrdm_latency, ++ &per_pwrdm_latency, ++ &neon_pwrdm_latency, ++ &usbhost_pwrdm_latency, ++ &emu_pwrdm_latency, ++ NULL ++}; ++ ++#endif /* __ARCH_ARM_MACH_OMAP2_RESOURCE_H */ + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/packages/linux/linux-omap2-git/beagleboard/02-postrate-notifier.eml b/packages/linux/linux-omap2-git/beagleboard/02-postrate-notifier.eml new file mode 100644 index 0000000000..97058f99e1 --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/02-postrate-notifier.eml @@ -0,0 +1,186 @@ +This patch implements the remaining code for notification of clock +rate changes via the clock framework: + +- a notifier registration function, clk_notifier_register() + +- a notifier unregistration function, clk_notifier_unregister() + +- the clk_notify_post_rate_chg() call-chain function, has been fleshed out + +The implementation is via an atomic notifier, called with the clockfw +spinlock held. Callback functions must not sleep and must not re-enter +the clock framework, and should execute quickly. + +In the medium-term future, there are likely to be few users of these +notifiers. So, rather than storing one notifier per struct clk, +notifiers are stored in a separate, dynamically allocated list, +effectively trading execution speed (in terms of a sequential scan of +the notifier list) for memory savings. The implementation is +completely hidden from the callbacks and is easily changed if +necessary. + +Signed-off-by: Paul Walmsley <paul@pwsan.com> +--- + + arch/arm/plat-omap/clock.c | 118 +++++++++++++++++++++++++++++++++++++++++++- + 1 files changed, 115 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c +index 421d076..354f45f 100644 +--- a/arch/arm/plat-omap/clock.c ++++ b/arch/arm/plat-omap/clock.c +@@ -22,6 +22,7 @@ + #include <linux/mutex.h> + #include <linux/platform_device.h> + #include <linux/cpufreq.h> ++#include <linux/notifier.h> + #include <linux/debugfs.h> + + #include <asm/io.h> +@@ -34,6 +35,8 @@ static DEFINE_SPINLOCK(clockfw_lock); + + static struct clk_functions *arch_clock; + ++static LIST_HEAD(clk_notifier_list); ++ + /*------------------------------------------------------------------------- + * Standard clock functions defined in include/linux/clk.h + *-------------------------------------------------------------------------*/ +@@ -380,6 +383,110 @@ EXPORT_SYMBOL(clk_init_cpufreq_table); + #endif + + /** ++<<<<<<< current:arch/arm/plat-omap/clock.c ++======= ++ * clk_notifier_register - add a clock rate change notifier ++ * @clk: struct clk * to watch for rate echanges ++ * @nb: struct notifier_block * with callback info ++ * ++ * Request notification after a frequency change on clock 'clk'. This ++ * uses an atomic notifier. The callback will be called with ++ * interrupts disabled; therefore callback code should be very ++ * lightweight. Callback code must not call back into the clock ++ * framework. Callback code will be passed the previous and new rate ++ * of the clock. ++ * ++ * clk_notifier_register() must be called from process ++ * context. Returns -EINVAL if called with null arguments, -ENOMEM ++ * upon allocation failure; otherwise, passes along the return value ++ * of atomic_notifier_chain_register(). ++ */ ++int clk_notifier_register(struct clk *clk, struct notifier_block *nb) ++{ ++ struct clk_notifier *cn = NULL, *cn_new = NULL; ++ int r; ++ unsigned long flags; ++ ++ if (!clk || !nb) ++ return -EINVAL; ++ ++ /* Allocate this here speculatively so we can avoid GFP_ATOMIC */ ++ cn_new = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL); ++ if (!cn_new) ++ return -ENOMEM; ++ ++ spin_lock_irqsave(&clockfw_lock, flags); ++ ++ list_for_each_entry(cn, &clk_notifier_list, node) { ++ if (cn->clk == clk) ++ break; ++ } ++ ++ if (cn->clk != clk) { ++ cn_new->clk = clk; ++ ATOMIC_INIT_NOTIFIER_HEAD(&cn_new->notifier_head); ++ ++ list_add(&cn_new->node, &clk_notifier_list); ++ cn = cn_new; ++ } else { ++ kfree(cn_new); /* didn't need it after all */ ++ } ++ ++ r = atomic_notifier_chain_register(&cn->notifier_head, nb); ++ ++ spin_unlock_irqrestore(&clockfw_lock, flags); ++ ++ return r; ++} ++ ++/** ++ * clk_notifier_unregister - remove a clock rate change notifier ++ * @clk: struct clk * ++ * @nb: struct notifier_block * with callback info ++ * ++ * Request no further notification for frequency changes on clock ++ * 'clk'. This function presently does not release memory allocated ++ * by its corresponding _register function; see inline comments for ++ * more informations. Returns -EINVAL if called with null arguments; ++ * otherwise, passes along the return value of ++ * atomic_notifier_chain_unregister(). ++ */ ++int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb) ++{ ++ struct clk_notifier *cn = NULL; ++ int r = -EINVAL; ++ unsigned long flags; ++ ++ if (!clk || !nb) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&clockfw_lock, flags); ++ ++ list_for_each_entry(cn, &clk_notifier_list, node) { ++ if (cn->clk == clk) ++ break; ++ } ++ ++ if (cn->clk == clk) { ++ r = atomic_notifier_chain_unregister(&cn->notifier_head, nb); ++ ++ /* ++ * XXX unfortunately it seems that there is no polite ++ * way to test if a notifier has zero users. So once ++ * a post-notifier has been registered on a clock, ++ * that struct clk_notifier will not be freed, even if ++ * all of its users unregister. ++ */ ++ } else { ++ r = -ENOENT; ++ } ++ ++ spin_unlock_irqrestore(&clockfw_lock, flags); ++ ++ return r; ++} ++ ++/** + * clk_notify_post_rate_chg - call post-clk-rate-change notifier chain + * @clk: struct clk * that is changing rate + * @old_rate: old rate +@@ -400,11 +507,16 @@ void clk_notify_post_rate_chg(struct clk *clk, unsigned long old_rate, + cnd.old_rate = old_rate; + cnd.new_rate = new_rate; + +- /* XXX Call notifier here */ +- ++ list_for_each_entry(cn, &clk_notifier_list, node) { ++ if (cn->clk == clk) { ++ atomic_notifier_call_chain(&cn->notifier_head, ++ CLK_POST_RATE_CHANGE, ++ &cnd); ++ break; ++ } ++ } + } + +- + /*-------------------------------------------------------------------------*/ + + #ifdef CONFIG_OMAP_RESET_CLOCKS + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + diff --git a/packages/linux/linux-omap2-git/beagleboard/03-omappm-omap3srf.eml b/packages/linux/linux-omap2-git/beagleboard/03-omappm-omap3srf.eml new file mode 100644 index 0000000000..d052023f12 --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/03-omappm-omap3srf.eml @@ -0,0 +1,167 @@ +Adds init/change_level/validate_level calls for OMAP3 resources + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/resource34xx.c | 148 +++++++++++++++++++++++++++++++++++++ + 1 files changed, 148 insertions(+) + +Index: linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c 2008-08-07 +15:07:04.000000000 +0530 +@@ -0,0 +1,148 @@ ++/* ++ * linux/arch/arm/mach-omap2/resource34xx.c ++ * OMAP3 resource init/change_level/validate_level functions ++ * ++ * Copyright (C) 2007-2008 Texas Instruments, Inc. ++ * Written by Rajendra Nayak <rnayak@ti.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ++ * History: ++ * ++ */ ++ ++#include <linux/pm_qos_params.h> ++#include <asm/arch/powerdomain.h> ++#include <asm/arch/clockdomain.h> ++#include "resource34xx.h" ++ ++/** ++ * init_latency - Initializes the mpu/core latency resource. ++ * @resp: Latency resource to be initalized ++ * ++ * No return value. ++ */ ++void init_latency(struct shared_resource *resp) ++{ ++ resp->no_of_users = 0; ++ resp->curr_level = RES_DEFAULTLEVEL; ++ *((u8 *)resp->resource_data) = 0; ++ return; ++} ++ ++/** ++ * set_latency - Adds/Updates and removes the CPU_DMA_LATENCY in *pm_qos_params. ++ * @resp: resource pointer ++ * @latency: target latency to be set ++ * ++ * Returns 0 on success, or error values as returned by ++ * pm_qos_update_requirement/pm_qos_add_requirement. ++ */ ++int set_latency(struct shared_resource *resp, u32 latency) ++{ ++ u8 *pm_qos_req_added; ++ ++ if (resp->curr_level == latency) ++ return 0; ++ else ++ /* Update the resources current level */ ++ resp->curr_level = latency; ++ ++ pm_qos_req_added = resp->resource_data; ++ if (latency == RES_DEFAULTLEVEL) ++ /* No more users left, remove the pm_qos_req if present */ ++ if (*pm_qos_req_added) { ++ pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, ++ resp->name); ++ *pm_qos_req_added = 0; ++ return 0; ++ } ++ ++ if (*pm_qos_req_added) { ++ return pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, ++ resp->name, latency); ++ } else { ++ *pm_qos_req_added = 1; ++ return pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, ++ resp->name, latency); ++ } ++} ++ ++/** ++ * init_pd_latency - Initializes the power domain latency resource. ++ * @resp: Power Domain Latency resource to be initialized. ++ * ++ * No return value. ++ */ ++void init_pd_latency(struct shared_resource *resp) ++{ ++ struct pd_latency_db *pd_lat_db; ++ ++ resp->no_of_users = 0; ++ resp->curr_level = PD_LATENCY_OFF; ++ pd_lat_db = resp->resource_data; ++ /* Populate the power domain associated with the latency resource */ ++ pd_lat_db->pd = pwrdm_lookup(pd_lat_db->pwrdm_name); ++ return; ++} ++ ++/** ++ * set_pd_latency - Updates the curr_level of the power domain resource. ++ * @resp: Power domain latency resource. ++ * @latency: New latency value acceptable. ++ * ++ * This function maps the latency in microsecs to the acceptable ++ * Power domain state using the latency DB. ++ * It then programs the power domain to enter the target state. ++ * Always returns 0. ++ */ ++int set_pd_latency(struct shared_resource *resp, u32 latency) ++{ ++ u32 pd_lat_level, ind, i; ++ struct pd_latency_db *pd_lat_db; ++ struct powerdomain *pwrdm; ++ ++ pd_lat_db = resp->resource_data; ++ pwrdm = pd_lat_db->pd; ++ pd_lat_level = PD_LATENCY_OFF; ++ /* using the latency db map to the appropriate PD state */ ++ for (ind = 0; ind < PD_LATENCY_MAXLEVEL; ind++) ++ if (pd_lat_db->latency[ind] < latency) ++ pd_lat_level = ind; ++ ++ resp->curr_level = pd_lat_level; ++ switch (pd_lat_level) { ++ case PWRDM_POWER_OFF: ++ case PWRDM_POWER_RET: ++ /* Errata 1.29: No transitions from INACTIVE to RET/OFF ++ * possible. ++ * Need to be taken care of here. ++ */ ++ if (pwrdm_read_pwrst(pwrdm) != PWRDM_POWER_ON) { ++ /* Force the clock domains to ON */ ++ for (i = 0; pwrdm->pwrdm_clkdms[i]; i++) { ++ omap2_clkdm_deny_idle(pwrdm->pwrdm_clkdms[i]); ++ omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[i]); ++ } ++ pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_ON); ++ pwrdm_set_next_pwrst(pwrdm, pd_lat_level); ++ for (i = 0; pwrdm->pwrdm_clkdms[i]; i++) { ++ omap2_clkdm_sleep(pwrdm->pwrdm_clkdms[i]); ++ omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[i]); ++ } ++ } else ++ pwrdm_set_next_pwrst(pwrdm, pd_lat_level); ++ break; ++ case PWRDM_POWER_ON: ++ pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_ON); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/packages/linux/linux-omap2-git/beagleboard/04-omappm-srf-noop.eml b/packages/linux/linux-omap2-git/beagleboard/04-omappm-srf-noop.eml new file mode 100644 index 0000000000..32d767a342 --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/04-omappm-srf-noop.eml @@ -0,0 +1,497 @@ +Adds SRF calls into OMAP PM skeleton layer developed by Paul W. + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/Makefile | 1 + arch/arm/mach-omap2/clockdomain.c | 7 + arch/arm/plat-omap/Kconfig | 3 + arch/arm/plat-omap/Makefile | 4 + arch/arm/plat-omap/omap-pm-srf.c | 367 ++++++++++++++++++++++++++++++++ + include/asm-arm/arch-omap/powerdomain.h | 1 + include/asm-arm/arch-omap/resource.h | 1 + 7 files changed, 383 insertions(+), 1 deletion(-) + +Index: linux-omap-2.6/arch/arm/plat-omap/omap-pm-srf.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-omap-2.6/arch/arm/plat-omap/omap-pm-srf.c 2008-08-11 +17:38:37.000000000 +0530 +@@ -0,0 +1,367 @@ ++/* ++ * omap-pm-srf.c - OMAP power management interface implemented ++ * using Shared resource framework ++ * ++ * This code implements the OMAP power management interface to ++ * drivers, CPUIdle, CPUFreq, and DSP Bridge. It is strictly for ++ * debug/demonstration use, as it does nothing but printk() whenever a ++ * function is called (when DEBUG is defined, below) ++ * ++ * Copyright (C) 2008 Texas Instruments, Inc. ++ * Copyright (C) 2008 Nokia Corporation ++ * Paul Walmsley ++ * ++ * Interface developed by (in alphabetical order): ++ * Karthik Dasu, Amish Lakhani, Tony Lindgren, Rajendra Nayak, Sakari ++ * Poussa, Veeramanikandan Raju, Igor Stoppa, Paul Walmsley, Richard ++ * Woodruff ++ * ++ * Interfaces defined by Paul Walmsley ++ * Updated with SRF calls by Rajendra Nayak ++ */ ++ ++#undef DEBUG ++ ++#include <linux/init.h> ++#include <linux/cpufreq.h> ++#include <linux/device.h> ++ ++/* Interface documentation is in asm/arch/omap-pm.h */ ++#include <asm/arch/omap-pm.h> ++ ++#include <asm/arch/powerdomain.h> ++#include <asm/arch/resource.h> ++/* ++#include <asm/arch/tiocp.h> ++*/ ++ ++#define LAT_RES_POSTAMBLE "_latency" ++char latency_res_name[30]; ++/* lat_name_mutex protects latency_res_name*/ ++static DEFINE_MUTEX(lat_name_mutex); ++ ++ ++/** ++ * get_lat_res_name - gets the latency resource name given a power domain name ++ * @pwrdm_name: Name of the power domain. ++ * ++ * Returns a pointer to the latency resource name. ++ */ ++static char *get_lat_res_name(const char *pwrdm_name) ++{ ++ strcpy(latency_res_name, ""); ++ if (!(in_atomic() || irqs_disabled())) ++ mutex_lock(&lat_name_mutex); ++ WARN_ON(strlen(pwrdm_name) + strlen(LAT_RES_POSTAMBLE) > ++ sizeof(latency_res_name)); ++ strcpy(latency_res_name, pwrdm_name); ++ strcat(latency_res_name, LAT_RES_POSTAMBLE); ++ if (!(in_atomic() || irqs_disabled())) ++ mutex_unlock(&lat_name_mutex); ++ return latency_res_name; ++} ++ ++static struct omap_opp *dsp_opps; ++static struct omap_opp *mpu_opps; ++ ++/* ++ * Device-driver-originated constraints (via board-*.c files) ++ */ ++ ++void omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t) ++{ ++ if (!dev || t < -1) { ++ WARN_ON(1); ++ return; ++ }; ++ ++ if (t == -1) { ++ pr_debug("OMAP PM: remove max MPU wakeup latency constraint: " ++ "dev %s\n", dev_name(dev)); ++ resource_release("mpu_latency", dev); ++ } else { ++ pr_debug("OMAP PM: add max MPU wakeup latency constraint: " ++ "dev %s, t = %ld usec\n", dev_name(dev), t); ++ resource_request("mpu_latency", dev, t); ++ } ++} ++ ++void omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r) ++{ ++ if (!dev || agent_id != OCP_INITIATOR_AGENT || ++ agent_id != OCP_TARGET_AGENT) { ++ WARN_ON(1); ++ return; ++ }; ++ ++ if (r == 0) ++ pr_debug("OMAP PM: remove min bus tput constraint: " ++ "dev %s for agent_id %d\n", dev_name(dev), agent_id); ++ else ++ pr_debug("OMAP PM: add min bus tput constraint: " ++ "dev %s for agent_id %d: rate %ld KiB\n", ++ dev_name(dev), agent_id, r); ++ ++ /* ++ * This code should model the interconnect and compute the ++ * required clock frequency, convert that to a VDD2 OPP ID, then ++ * set the VDD2 OPP appropriately. ++ * ++ * TI CDP code can call constraint_set here on the VDD2 OPP. ++ */ ++} ++ ++void omap_pm_set_max_dev_wakeup_lat(struct device *dev, long t) ++{ ++ /* struct tiocp *tiocp_dev; */ ++ struct powerdomain *pwrdm_dev; ++ char *res_name; ++ ++ if (!dev || t < -1) { ++ WARN_ON(1); ++ return; ++ }; ++ /* Look for the devices Power Domain */ ++ /* TODO: Put this back in once tiocp layer is available ++ tiocp_dev = container_of(dev, struct tiocp, dev); ++ pwrdm_dev = tiocp_dev->pwrdm; ++ */ ++ ++ if (t == -1) { ++ pr_debug("OMAP PM: remove max device latency constraint: " ++ "dev %s\n", dev_name(dev)); ++ res_name = get_lat_res_name(pwrdm_dev->name); ++ resource_release(res_name, dev); ++ } else { ++ pr_debug("OMAP PM: add max device latency constraint: " ++ "dev %s, t = %ld usec\n", dev_name(dev), t); ++ res_name = get_lat_res_name(pwrdm_dev->name); ++ resource_request(res_name, dev, t); ++ } ++ ++ /* ++ * For current Linux, this needs to map the device to a ++ * powerdomain, then go through the list of current max lat ++ * constraints on that powerdomain and find the smallest. If ++ * the latency constraint has changed, the code should ++ * recompute the state to enter for the next powerdomain ++ * state. Conceivably, this code should also determine ++ * whether to actually disable the device clocks or not, ++ * depending on how long it takes to re-enable the clocks. ++ * ++ * TI CDP code can call constraint_set here. ++ */ ++} ++ ++void omap_pm_set_max_sdma_lat(struct device *dev, long t) ++{ ++ if (!dev || t < -1) { ++ WARN_ON(1); ++ return; ++ }; ++ ++ if (t == -1) { ++ pr_debug("OMAP PM: remove max DMA latency constraint: " ++ "dev %s\n", dev_name(dev)); ++ resource_release("core_latency", dev); ++ } else { ++ pr_debug("OMAP PM: add max DMA latency constraint: " ++ "dev %s, t = %ld usec\n", dev_name(dev), t); ++ resource_request("core_latency", dev, t); ++ } ++ ++ /* ++ * For current Linux PM QOS params, this code should scan the ++ * list of maximum CPU and DMA latencies and select the ++ * smallest, then set cpu_dma_latency pm_qos_param ++ * accordingly. ++ * ++ * For future Linux PM QOS params, with separate CPU and DMA ++ * latency params, this code should just set the dma_latency param. ++ * ++ * TI CDP code can call constraint_set here. ++ */ ++ ++} ++ ++ ++/* ++ * DSP Bridge-specific constraints ++ */ ++ ++const struct omap_opp *omap_pm_dsp_get_opp_table(void) ++{ ++ pr_debug("OMAP PM: DSP request for OPP table\n"); ++ ++ /* ++ * Return DSP frequency table here: The final item in the ++ * array should have .rate = .opp_id = 0. ++ */ ++ ++ return NULL; ++} ++ ++void omap_pm_dsp_set_min_opp(u8 opp_id) ++{ ++ if (opp_id == 0) { ++ WARN_ON(1); ++ return; ++ } ++ ++ pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id); ++ ++ /* ++ * ++ * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we ++ * can just test to see which is higher, the CPU's desired OPP ++ * ID or the DSP's desired OPP ID, and use whichever is ++ * highest. ++ * ++ * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP ++ * rate is keyed on MPU speed, not the OPP ID. So we need to ++ * map the OPP ID to the MPU speed for use with clk_set_rate() ++ * if it is higher than the current OPP clock rate. ++ * ++ */ ++} ++ ++ ++u8 omap_pm_dsp_get_opp(void) ++{ ++ pr_debug("OMAP PM: DSP requests current DSP OPP ID\n"); ++ ++ /* ++ * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock ++ * ++ * CDP12.14+: ++ * Call clk_get_rate() on the OPP custom clock, map that to an ++ * OPP ID using the tables defined in board-*.c/chip-*.c files. ++ */ ++ ++ return 0; ++} ++ ++/* ++ * CPUFreq-originated constraint ++ * ++ * In the future, this should be handled by custom OPP clocktype ++ * functions. ++ */ ++ ++struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void) ++{ ++ pr_debug("OMAP PM: CPUFreq request for frequency table\n"); ++ ++ /* ++ * Return CPUFreq frequency table here: loop over ++ * all VDD1 clkrates, pull out the mpu_ck frequencies, build ++ * table ++ */ ++ ++ return NULL; ++} ++ ++void omap_pm_cpu_set_freq(unsigned long f) ++{ ++ if (f == 0) { ++ WARN_ON(1); ++ return; ++ } ++ ++ pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n", ++ f); ++ ++ /* ++ * For l-o dev tree, determine whether MPU freq or DSP OPP id ++ * freq is higher. Find the OPP ID corresponding to the ++ * higher frequency. Call clk_round_rate() and clk_set_rate() ++ * on the OPP custom clock. ++ * ++ * CDP should just be able to set the VDD1 OPP clock rate here. ++ */ ++} ++ ++unsigned long omap_pm_cpu_get_freq(void) ++{ ++ pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n"); ++ ++ /* ++ * Call clk_get_rate() on the mpu_ck. ++ */ ++ ++ return 0; ++} ++ ++struct device omap_pm_dev; ++ ++/* ++ * Powerdomain usecounting hooks ++ */ ++ ++void omap_pm_pwrdm_active(struct powerdomain *pwrdm) ++{ ++ char *res_name; ++ ++ if (!pwrdm) { ++ WARN_ON(1); ++ return; ++ }; ++ ++ if (!strcmp(pwrdm->name, "wkup_pwrdm") || ++ !strcmp(pwrdm->name, "core_pwrdm")) ++ return; ++ ++ pr_debug("OMAP PM: powerdomain %s is becoming active\n", pwrdm->name); ++ ++ res_name = get_lat_res_name(pwrdm->name); ++ /* Request for a zero latency which puts the Power Domain in ON state*/ ++ resource_request(res_name, &omap_pm_dev, 0); ++ return; ++} ++ ++void omap_pm_pwrdm_inactive(struct powerdomain *pwrdm) ++{ ++ char *res_name; ++ ++ if (!pwrdm) { ++ WARN_ON(1); ++ return; ++ }; ++ ++ if (!strcmp(pwrdm->name, "wkup_pwrdm") || ++ !strcmp(pwrdm->name, "core_pwrdm")) ++ return; ++ ++ pr_debug("OMAP PM: powerdomain %s is becoming inactive\n", ++ pwrdm->name); ++ ++ res_name = get_lat_res_name(pwrdm->name); ++ /* Release the latency requested */ ++ resource_release(res_name, &omap_pm_dev); ++ return; ++} ++ ++/* ++ * Should be called before clk framework since clk fw will call ++ * omap_pm_pwrdm_{in,}active() ++ */ ++int __init omap_pm_if_early_init(void) ++{ ++ return 0; ++} ++ ++/* Must be called after clock framework is initialized */ ++int __init omap_pm_if_init(struct omap_opp *mpu_opp_table, ++ struct omap_opp *dsp_opp_table) ++{ ++ mpu_opps = mpu_opp_table; ++ dsp_opps = dsp_opp_table; ++ resource_init(resources_omap); ++ return 0; ++} ++ ++void omap_pm_if_exit(void) ++{ ++ /* Deallocate CPUFreq frequency table here */ ++} ++ +Index: linux-omap-2.6/arch/arm/mach-omap2/clockdomain.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/clockdomain.c 2008-08-11 +17:12:19.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/clockdomain.c 2008-08-11 +17:14:31.000000000 +0530 +@@ -35,6 +35,7 @@ + + #include <asm/arch/powerdomain.h> + #include <asm/arch/clockdomain.h> ++#include <asm/arch/omap-pm.h> + + /* clkdm_list contains all registered struct clockdomains */ + static LIST_HEAD(clkdm_list); +@@ -561,6 +562,9 @@ int omap2_clkdm_clk_enable(struct clockd + else + omap2_clkdm_wakeup(clkdm); + ++ /*Hook to inform the OMAP PM layer that the pwrdm has become active */ ++ omap_pm_pwrdm_active(clkdm->pwrdm.ptr); ++ + return 0; + } + +@@ -612,6 +616,9 @@ int omap2_clkdm_clk_disable(struct clock + else + omap2_clkdm_sleep(clkdm); + ++ /*Hook to inform the OMAP PM layer that the pwrdm has become inactive */ ++ omap_pm_pwrdm_inactive(clkdm->pwrdm.ptr); ++ + return 0; + } + +Index: linux-omap-2.6/include/asm-arm/arch-omap/powerdomain.h +=================================================================== +--- linux-omap-2.6.orig/include/asm-arm/arch-omap/powerdomain.h 2008-08-11 +17:12:19.000000000 +0530 ++++ linux-omap-2.6/include/asm-arm/arch-omap/powerdomain.h 2008-08-11 +17:14:31.000000000 +0530 +@@ -148,6 +148,7 @@ int pwrdm_read_next_pwrst(struct powerdo + int pwrdm_read_pwrst(struct powerdomain *pwrdm); + int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm); + int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm); ++int pwrdm_read_pwrst(struct powerdomain *pwrdm); + + int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst); + int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst); +Index: linux-omap-2.6/arch/arm/mach-omap2/Makefile +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/Makefile 2008-08-11 +17:12:19.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/Makefile 2008-08-11 17:14:31.000000000 ++0530 +@@ -34,6 +34,7 @@ obj-$(CONFIG_OMAP_SMARTREFLEX) += smart + # Clock framework + obj-$(CONFIG_ARCH_OMAP2) += clock24xx.o + obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o ++obj-$(CONFIG_OMAP_PM_SRF) += resource34xx.o + + # DSP + obj-$(CONFIG_OMAP_MMU_FWK) += mmu_mach.o +Index: linux-omap-2.6/arch/arm/plat-omap/Kconfig +=================================================================== +--- linux-omap-2.6.orig/arch/arm/plat-omap/Kconfig 2008-08-11 +17:12:25.000000000 +0530 ++++ linux-omap-2.6/arch/arm/plat-omap/Kconfig 2008-08-11 17:14:31.000000000 +0530 +@@ -258,6 +258,9 @@ config OMAP_PM_NONE + config OMAP_PM_NOOP + bool "No-op/debug PM layer" + ++config OMAP_PM_SRF ++ bool "PM layer implemented using SRF" ++ + endchoice + + endif +Index: linux-omap-2.6/arch/arm/plat-omap/Makefile +=================================================================== +--- linux-omap-2.6.orig/arch/arm/plat-omap/Makefile 2008-08-11 +17:12:25.000000000 +0530 ++++ linux-omap-2.6/arch/arm/plat-omap/Makefile 2008-08-11 17:14:31.000000000 +0530 +@@ -29,4 +29,6 @@ obj-$(CONFIG_OMAP_MMU_FWK) += mmu.o + # OMAP mailbox framework + obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o + +-obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o +\ No newline at end of file ++obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o ++obj-$(CONFIG_OMAP_PM_SRF) += omap-pm-srf.o \ ++ resource.o +Index: linux-omap-2.6/include/asm-arm/arch-omap/resource.h +=================================================================== +--- linux-omap-2.6.orig/include/asm-arm/arch-omap/resource.h 2008-08-11 +17:12:30.000000000 +0530 ++++ linux-omap-2.6/include/asm-arm/arch-omap/resource.h 2008-08-11 +17:14:31.000000000 +0530 +@@ -85,6 +85,7 @@ struct users_list { + u8 usage; + }; + ++extern struct shared_resource *resources_omap[]; + /* Shared resource Framework API's */ + void resource_init(struct shared_resource **resources); + int resource_register(struct shared_resource *res); + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/packages/linux/linux-omap2-git/beagleboard/05-omappm-virtualclocks.eml b/packages/linux/linux-omap2-git/beagleboard/05-omappm-virtualclocks.eml new file mode 100644 index 0000000000..0aaed7b91c --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/05-omappm-virtualclocks.eml @@ -0,0 +1,456 @@ +The patch defines virtual nodes for VDD1 and VDD2 + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/board-3430sdp.c | 38 +++++ + arch/arm/mach-omap2/clock34xx.c | 206 +++++++++++++++++++++++++----- + arch/arm/mach-omap2/clock34xx.h | 29 ++++ + include/asm-arm/arch-omap/board-3430sdp.h | 35 +++++ + include/asm-arm/arch-omap/clock.h | 8 + + 5 files changed, 287 insertions(+), 29 deletions(-) + +Index: linux-omap-2.6/arch/arm/mach-omap2/clock34xx.h +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/clock34xx.h 2008-08-06 +14:55:12.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/clock34xx.h 2008-08-07 +15:07:19.000000000 +0530 +@@ -36,6 +36,14 @@ static int omap3_noncore_dpll_enable(str + static void omap3_noncore_dpll_disable(struct clk *clk); + static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate); + static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate); ++static void omap3_table_recalc(struct clk *clk); ++static long omap3_round_to_table_rate(struct clk *clk, unsigned long rate); ++static int omap3_select_table_rate(struct clk *clk, unsigned long rate); ++ ++extern struct vdd_prcm_config vdd1_rate_table[]; ++extern struct vdd_prcm_config vdd2_rate_table[]; ++extern struct vdd_prcm_config iva2_rate_table[]; ++ + + /* Maximum DPLL multiplier, divider values for OMAP3 */ + #define OMAP3_MAX_DPLL_MULT 2048 +@@ -3064,6 +3072,24 @@ static struct clk wdt1_fck = { + .recalc = &followparent_recalc, + }; + ++static struct clk virt_vdd1_prcm_set = { ++ .name = "virt_vdd1_prcm_set", ++ .flags = CLOCK_IN_OMAP343X | VIRTUAL_CLOCK | ALWAYS_ENABLED, ++ .parent = &mpu_ck, /* Indexed by mpu speed, no parent */ ++ .recalc = &omap3_table_recalc, /*sets are keyed on mpu rate */ ++ .set_rate = &omap3_select_table_rate, ++ .round_rate = &omap3_round_to_table_rate, ++}; ++ ++static struct clk virt_vdd2_prcm_set = { ++ .name = "virt_vdd2_prcm_set", ++ .flags = CLOCK_IN_OMAP343X | VIRTUAL_CLOCK | ALWAYS_ENABLED, ++ .parent = &core_ck, ++ .recalc = &omap3_table_recalc, ++ .set_rate = &omap3_select_table_rate, ++ .round_rate = &omap3_round_to_table_rate, ++}; ++ + static struct clk *onchip_34xx_clks[] __initdata = { + &omap_32k_fck, + &virt_12m_ck, +@@ -3276,6 +3302,9 @@ static struct clk *onchip_34xx_clks[] __ + &secure_32k_fck, + &gpt12_fck, + &wdt1_fck, ++ /* virtual group clock */ ++ &virt_vdd1_prcm_set, ++ &virt_vdd2_prcm_set, + }; + + #endif +Index: linux-omap-2.6/arch/arm/mach-omap2/clock34xx.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/clock34xx.c 2008-08-07 +14:34:23.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/clock34xx.c 2008-08-07 +15:07:19.000000000 +0530 +@@ -25,6 +25,7 @@ + #include <linux/clk.h> + #include <linux/io.h> + #include <linux/limits.h> ++#include <linux/err.h> + + #include <asm/arch/clock.h> + #include <asm/arch/sram.h> +@@ -45,6 +46,32 @@ + + #define MAX_DPLL_WAIT_TRIES 1000000 + ++struct vdd_prcm_config *curr_vdd1_prcm_set; ++struct vdd_prcm_config *curr_vdd2_prcm_set; ++static struct clk *dpll1_clk, *dpll2_clk, *dpll3_clk; ++ ++#ifndef CONFIG_CPU_FREQ ++static unsigned long compute_lpj(unsigned long ref, u_int div, u_int mult) ++{ ++ unsigned long new_jiffy_l, new_jiffy_h; ++ ++ /* ++ * Recalculate loops_per_jiffy. We do it this way to ++ * avoid math overflow on 32-bit machines. Maybe we ++ * should make this architecture dependent? If you have ++ * a better way of doing this, please replace! ++ * ++ * new = old * mult / div ++ */ ++ new_jiffy_h = ref / div; ++ new_jiffy_l = (ref % div) / 100; ++ new_jiffy_h *= mult; ++ new_jiffy_l = new_jiffy_l * mult / div; ++ ++ return new_jiffy_h + new_jiffy_l * 100; ++} ++#endif ++ + /** + * omap3_dpll_recalc - recalculate DPLL rate + * @clk: DPLL struct clk +@@ -644,15 +671,6 @@ void omap2_clk_prepare_for_reboot(void) + */ + static int __init omap2_clk_arch_init(void) + { +- if (!mpurate) +- return -EINVAL; +- +- /* REVISIT: not yet ready for 343x */ +-#if 0 +- if (omap2_select_table_rate(&virt_prcm_set, mpurate)) +- printk(KERN_ERR "Could not find matching MPU rate\n"); +-#endif +- + recalculate_root_clocks(); + + printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL3/MPU): " +@@ -670,6 +688,9 @@ int __init omap2_clk_init(void) + struct clk **clkp; + /* u32 clkrate; */ + u32 cpu_clkflg; ++ unsigned long mpu_speed, core_speed; ++ struct vdd_prcm_config *prcm_vdd; ++ + + /* REVISIT: Ultimately this will be used for multiboot */ + #if 0 +@@ -712,22 +733,31 @@ int __init omap2_clk_init(void) + } + } + +- /* REVISIT: Not yet ready for OMAP3 */ +-#if 0 +- /* Check the MPU rate set by bootloader */ +- clkrate = omap2_get_dpll_rate_24xx(&dpll_ck); +- for (prcm = rate_table; prcm->mpu_speed; prcm++) { +- if (!(prcm->flags & cpu_mask)) +- continue; +- if (prcm->xtal_speed != sys_ck.rate) +- continue; +- if (prcm->dpll_speed <= clkrate) +- break; ++ recalculate_root_clocks(); ++ ++ dpll1_clk = clk_get(NULL, "dpll1_ck"); ++ dpll2_clk = clk_get(NULL, "dpll2_ck"); ++ dpll3_clk = clk_get(NULL, "dpll3_ck"); ++ ++#ifdef CONFIG_MACH_OMAP_3430SDP ++ mpu_speed = dpll1_clk->rate; ++ prcm_vdd = vdd1_rate_table + MAX_VDD1_OPP; ++ for (; prcm_vdd->speed; prcm_vdd--) { ++ if (prcm_vdd->speed <= mpu_speed) { ++ curr_vdd1_prcm_set = prcm_vdd; ++ break; ++ } + } +- curr_prcm_set = prcm; +-#endif + +- recalculate_root_clocks(); ++ core_speed = dpll3_clk->rate; ++ prcm_vdd = vdd2_rate_table + MAX_VDD2_OPP; ++ for (; prcm_vdd->speed; prcm_vdd--) { ++ if (prcm_vdd->speed <= core_speed) { ++ curr_vdd2_prcm_set = prcm_vdd; ++ break; ++ } ++ } ++#endif + + printk(KERN_INFO "Clocking rate (Crystal/DPLL/ARM core): " + "%ld.%01ld/%ld/%ld MHz\n", +@@ -740,13 +770,131 @@ int __init omap2_clk_init(void) + */ + clk_enable_init_clocks(); + +- /* Avoid sleeping during omap2_clk_prepare_for_reboot() */ +- /* REVISIT: not yet ready for 343x */ +-#if 0 +- vclk = clk_get(NULL, "virt_prcm_set"); +- sclk = clk_get(NULL, "sys_ck"); +-#endif + return 0; + } + ++inline unsigned int get_freq(struct vdd_prcm_config *opp_freq_table, ++ unsigned long opp) ++{ ++ struct vdd_prcm_config *prcm_config; ++ prcm_config = opp_freq_table; ++ ++ for (; prcm_config->opp; prcm_config--) ++ if (prcm_config->opp == opp) ++ return prcm_config->speed; ++ return 0; ++} ++ ++inline unsigned int get_opp(struct vdd_prcm_config *opp_freq_table, ++ unsigned long freq) ++{ ++ struct vdd_prcm_config *prcm_config; ++ prcm_config = opp_freq_table; ++ ++ if (prcm_config->speed <= freq) ++ return prcm_config->opp; /* Return the Highest OPP */ ++ for (; prcm_config->speed; prcm_config--) { ++ if (prcm_config->speed < freq) ++ return (prcm_config+1)->opp; ++ else if (prcm_config->speed == freq) ++ return prcm_config->opp; ++ } ++ /* Return the least OPP */ ++ return (prcm_config+1)->opp; ++} ++ ++#ifdef CONFIG_MACH_OMAP_3430SDP ++static void omap3_table_recalc(struct clk *clk) ++{ ++ if ((clk != &virt_vdd1_prcm_set) && (clk != &virt_vdd2_prcm_set)) ++ return; ++ ++ if ((curr_vdd1_prcm_set) && (clk == &virt_vdd1_prcm_set)) ++ clk->rate = curr_vdd1_prcm_set->speed; ++ else if ((curr_vdd2_prcm_set) && (clk == &virt_vdd2_prcm_set)) ++ clk->rate = curr_vdd2_prcm_set->speed; ++ pr_debug("CLK RATE:%lu\n", clk->rate); ++} ++ ++static long omap3_round_to_table_rate(struct clk *clk, unsigned long rate) ++{ ++ struct vdd_prcm_config *ptr; ++ long highest_rate; ++ ++ if ((clk != &virt_vdd1_prcm_set) && (clk != &virt_vdd2_prcm_set)) ++ return -EINVAL; ++ ++ highest_rate = -EINVAL; ++ ++ if (clk == &virt_vdd1_prcm_set) ++ ptr = vdd1_rate_table + MAX_VDD1_OPP; ++ else ++ ptr = vdd2_rate_table + MAX_VDD2_OPP; ++ ++ for (; ptr->speed; ptr--) { ++ highest_rate = ptr->speed; ++ pr_debug("Highest speed : %lu, rate: %lu\n", highest_rate, ++ rate); ++ if (ptr->speed <= rate) ++ break; ++ } ++ return highest_rate; ++} ++ ++static int omap3_select_table_rate(struct clk *clk, unsigned long rate) ++{ ++ struct vdd_prcm_config *prcm_vdd; ++ unsigned long found_speed = 0, curr_mpu_speed; ++ int index; ++ ++ if ((clk != &virt_vdd1_prcm_set) && (clk != &virt_vdd2_prcm_set)) ++ return -EINVAL; ++ ++ if (clk == &virt_vdd1_prcm_set) { ++ prcm_vdd = vdd1_rate_table + MAX_VDD1_OPP; ++ index = MAX_VDD1_OPP; ++ } else if (clk == &virt_vdd2_prcm_set) { ++ prcm_vdd = vdd2_rate_table + MAX_VDD2_OPP; ++ index = MAX_VDD2_OPP; ++ } ++ ++ for (; prcm_vdd->speed; prcm_vdd--, index--) { ++ if (prcm_vdd->speed <= rate) { ++ found_speed = prcm_vdd->speed; ++ pr_debug("Found speed = %lu\n", found_speed); ++ break; ++ } ++ } ++ ++ if (!found_speed) { ++ printk(KERN_INFO "Could not set table rate to %luMHz\n", ++ rate / 1000000); ++ return -EINVAL; ++ } ++ ++ ++ if (clk == &virt_vdd1_prcm_set) { ++ curr_mpu_speed = curr_vdd1_prcm_set->speed; ++ clk_set_rate(dpll1_clk, prcm_vdd->speed); ++ clk_set_rate(dpll2_clk, iva2_rate_table[index].speed); ++ curr_vdd1_prcm_set = prcm_vdd; ++#ifndef CONFIG_CPU_FREQ ++ /*Update loops_per_jiffy if processor speed is being changed*/ ++ loops_per_jiffy = compute_lpj(loops_per_jiffy, ++ curr_mpu_speed/1000, found_speed/1000); + #endif ++ } else { ++ clk_set_rate(dpll3_clk, prcm_vdd->speed); ++ curr_vdd2_prcm_set = prcm_vdd; ++ } ++ return 0; ++} ++#else /* CONFIG_MACH_OMAP_3430SDP */ ++static void omap3_table_recalc(struct clk *clk) {} ++static long omap3_round_to_table_rate(struct clk *clk, unsigned long rate) ++{ return 0; } ++static int omap3_select_table_rate(struct clk *clk, unsigned long rate) ++{ return 0; } ++#endif /* CONFIG_MACH_OMAP_3430SDP */ ++ ++#endif /* CONFIG_ARCH_OMAP3 */ +Index: linux-omap-2.6/include/asm-arm/arch-omap/clock.h +=================================================================== +--- linux-omap-2.6.orig/include/asm-arm/arch-omap/clock.h 2008-08-07 +14:34:23.000000000 +0530 ++++ linux-omap-2.6/include/asm-arm/arch-omap/clock.h 2008-08-07 +15:07:19.000000000 +0530 +@@ -126,6 +126,14 @@ struct clk_functions { + #endif + }; + ++#ifdef CONFIG_ARCH_OMAP3 ++struct vdd_prcm_config { ++ unsigned long speed; ++ unsigned long opp; ++ unsigned long flags; ++}; ++#endif ++ + extern unsigned int mpurate; + + extern int clk_init(struct clk_functions *custom_clocks); +Index: linux-omap-2.6/arch/arm/mach-omap2/board-3430sdp.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/board-3430sdp.c 2008-08-06 +14:55:12.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/board-3430sdp.c 2008-08-07 +15:07:50.000000000 +0530 +@@ -40,6 +40,7 @@ + #include <asm/arch/keypad.h> + #include <asm/arch/dma.h> + #include <asm/arch/gpmc.h> ++#include <asm/arch/clock.h> + #include <linux/i2c/twl4030-rtc.h> + + #include <asm/io.h> +@@ -53,6 +54,43 @@ + #define ENABLE_VAUX3_DEDICATED 0x03 + #define ENABLE_VAUX3_DEV_GRP 0x20 + ++struct vdd_prcm_config vdd1_rate_table[] = { ++ {0, 0, 0}, ++ /*OPP1*/ ++ {S125M, VDD1_OPP1, 0}, ++ /*OPP2*/ ++ {S250M, VDD1_OPP2, 0}, ++ /*OPP3*/ ++ {S500M, VDD1_OPP3, 0}, ++ /*OPP4*/ ++ {S550M, VDD1_OPP4, 0}, ++ /*OPP5*/ ++ {S600M, VDD1_OPP5, 0}, ++}; ++ ++struct vdd_prcm_config vdd2_rate_table[] = { ++ {0, 0, 0}, ++ /*OPP1*/ ++ {0, VDD2_OPP1, 0}, ++ /*OPP2*/ ++ {S83M, VDD2_OPP2, 0}, ++ /*OPP3*/ ++ {S166M, VDD2_OPP3, 0}, ++}; ++ ++struct vdd_prcm_config iva2_rate_table[] = { ++ {0, 0, 0}, ++ /*OPP1*/ ++ {S90M, VDD1_OPP1, 0}, ++ /*OPP2*/ ++ {S180M, VDD1_OPP2, 0}, ++ /*OPP3*/ ++ {S360M, VDD1_OPP3, 0}, ++ /*OPP4*/ ++ {S400M, VDD1_OPP4, 0}, ++ /*OPP5*/ ++ {S430M, VDD1_OPP5, 0}, ++}; + + #define TWL4030_MSECURE_GPIO 22 + +Index: linux-omap-2.6/include/asm-arm/arch-omap/board-3430sdp.h +=================================================================== +--- linux-omap-2.6.orig/include/asm-arm/arch-omap/board-3430sdp.h 2008-08-06 +14:55:22.000000000 +0530 ++++ linux-omap-2.6/include/asm-arm/arch-omap/board-3430sdp.h 2008-08-07 +15:07:19.000000000 +0530 +@@ -68,5 +68,40 @@ extern void twl4030_bci_battery_init(voi + #define FLASH_SIZE_SDPV1 SZ_64M + #define FLASH_SIZE_SDPV2 SZ_128M + ++/* MPU speeds */ ++#define S600M 600000000 ++#define S550M 550000000 ++#define S500M 500000000 ++#define S250M 250000000 ++#define S125M 125000000 ++ ++/* IVA speeds */ ++#define S430M 430000000 ++#define S400M 400000000 ++#define S360M 360000000 ++#define S180M 180000000 ++#define S90M 90000000 ++ ++/* L3 speeds */ ++#define S83M 83000000 ++#define S166M 166000000 ++ ++/* VDD1 OPPS */ ++#define VDD1_OPP1 0x1 ++#define VDD1_OPP2 0x2 ++#define VDD1_OPP3 0x3 ++#define VDD1_OPP4 0x4 ++#define VDD1_OPP5 0x5 ++ ++/* VDD2 OPPS */ ++#define VDD2_OPP1 0x1 ++#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_OMAP_3430SDP_H */ + + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/packages/linux/linux-omap2-git/beagleboard/06-omappm-opp-resource-modeling.eml b/packages/linux/linux-omap2-git/beagleboard/06-omappm-opp-resource-modeling.eml new file mode 100644 index 0000000000..69ed0f748c --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/06-omappm-opp-resource-modeling.eml @@ -0,0 +1,228 @@ +Adds OPP/Frequency resources to SRF + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/resource34xx.c | 101 +++++++++++++++++++++++++++++++++++++ + arch/arm/mach-omap2/resource34xx.h | 74 +++++++++++++++++++++++++++ + 2 files changed, 175 insertions(+) + +Index: linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/resource34xx.c 2008-08-07 +15:07:08.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c 2008-08-07 +15:09:01.000000000 +0530 +@@ -146,3 +146,104 @@ int set_pd_latency(struct shared_resourc + } + return 0; + } ++ ++static struct clk *vdd1_clk; ++static struct clk *vdd2_clk; ++static struct device dummy_srf_dev; ++ ++/** ++ * init_opp - Initialize the OPP resource ++ */ ++void init_opp(struct shared_resource *resp) ++{ ++ resp->no_of_users = 0; ++ /* Initialize the current level of the OPP resource ++ * to the opp set by u-boot. ++ */ ++ if (strcmp(resp->name, "vdd1_opp") == 0) { ++ resp->curr_level = curr_vdd1_prcm_set->opp; ++ vdd1_clk = clk_get(NULL, "virt_vdd1_prcm_set"); ++ } else if (strcmp(resp->name, "vdd2_opp") == 0) { ++ resp->curr_level = curr_vdd2_prcm_set->opp; ++ vdd2_clk = clk_get(NULL, "virt_vdd2_prcm_set"); ++ } ++ return; ++} ++ ++int set_opp(struct shared_resource *resp, u32 target_level) ++{ ++#ifdef CONFIG_MACH_OMAP_3430SDP ++ unsigned long mpu_freq; ++ if (strcmp(resp->name, "vdd1_opp") == 0) { ++ mpu_freq = get_freq(vdd1_rate_table + MAX_VDD1_OPP, ++ target_level); ++ clk_set_rate(vdd1_clk, mpu_freq); ++ resp->curr_level = curr_vdd1_prcm_set->opp; ++ } else if (strcmp(resp->name, "vdd2_opp") == 0) { ++ /* Not supported yet */ ++ } ++#endif ++ return 0; ++} ++ ++/** ++ * validate_opp - Validates if valid VDD1 OPP's are passed as the ++ * target_level. ++ * VDD2 OPP levels are passed as L3 throughput, which are then mapped ++ * to an appropriate OPP. ++ */ ++int validate_opp(struct shared_resource *resp, u32 target_level) ++{ ++ return 0; ++} ++ ++/** ++ * init_freq - Initialize the frequency resource. ++ */ ++void init_freq(struct shared_resource *resp) ++{ ++#ifdef CONFIG_MACH_OMAP_3430SDP ++ char *linked_res_name; ++ resp->no_of_users = 0; ++ ++ linked_res_name = (char *)resp->resource_data; ++ /* Initialize the current level of the Freq resource ++ * to the frequency set by u-boot. ++ */ ++ if (strcmp(resp->name, "mpu_freq") == 0) ++ /* MPU freq in Mhz */ ++ resp->curr_level = curr_vdd1_prcm_set->speed; ++ else if (strcmp(resp->name, "dsp_freq") == 0) ++ /* DSP freq in Mhz */ ++ resp->curr_level = get_freq(iva2_rate_table + MAX_VDD2_OPP, ++ curr_vdd1_prcm_set->opp); ++#endif ++ return; ++} ++ ++int set_freq(struct shared_resource *resp, u32 target_level) ++{ ++#ifdef CONFIG_MACH_OMAP_3430SDP ++ unsigned int vdd1_opp; ++ ++ if (strcmp(resp->name, "mpu_freq") == 0) ++ vdd1_opp = get_opp(vdd1_rate_table + MAX_VDD1_OPP, ++ target_level); ++ else if (strcmp(resp->name, "dsp_freq") == 0) ++ vdd1_opp = get_opp(iva2_rate_table + MAX_VDD1_OPP, ++ target_level); ++ ++ if (vdd1_opp == MIN_VDD1_OPP) ++ resource_release("vdd1_opp", &dummy_srf_dev); ++ else ++ resource_request("vdd1_opp", &dummy_srf_dev, vdd1_opp); ++ ++ resp->curr_level = target_level; ++#endif ++ return 0; ++} ++ ++int validate_freq(struct shared_resource *resp, u32 target_level) ++{ ++ return 0; ++} +Index: linux-omap-2.6/arch/arm/mach-omap2/resource34xx.h +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/resource34xx.h 2008-08-07 +15:07:02.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/resource34xx.h 2008-08-07 +15:31:42.000000000 +0530 +@@ -22,8 +22,17 @@ + #define __ARCH_ARM_MACH_OMAP2_RESOURCE_H + + #include <asm/arch/resource.h> ++#include <linux/clk.h> ++#include <asm/arch/clock.h> + #include <asm/arch/powerdomain.h> + ++extern struct vdd_prcm_config *curr_vdd1_prcm_set; ++extern struct vdd_prcm_config *curr_vdd2_prcm_set; ++extern unsigned int get_freq(struct vdd_prcm_config *, unsigned long); ++extern unsigned int get_opp(struct vdd_prcm_config *, unsigned long); ++extern struct vdd_prcm_config vdd1_rate_table[]; ++extern struct vdd_prcm_config vdd2_rate_table[]; ++extern struct vdd_prcm_config iva2_rate_table[]; + /** + * mpu_latency/core_latency are used to control the cpuidle C state. + */ +@@ -207,6 +216,66 @@ static struct shared_resource emu_pwrdm_ + .ops = &pd_lat_res_ops, + }; + ++void init_opp(struct shared_resource *resp); ++int set_opp(struct shared_resource *resp, u32 target_level); ++int validate_opp(struct shared_resource *resp, u32 target_level); ++void init_freq(struct shared_resource *resp); ++int set_freq(struct shared_resource *resp, u32 target_level); ++int validate_freq(struct shared_resource *resp, u32 target_level); ++ ++struct bus_throughput_db { ++ /* Throughput for each OPP/Freq of the bus */ ++ unsigned long throughput[3]; ++}; ++ ++static struct shared_resource_ops opp_res_ops = { ++ .init = init_opp, ++ .change_level = set_opp, ++ .validate_level = validate_opp, ++}; ++ ++static struct shared_resource vdd1_opp = { ++ .name = "vdd1_opp", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .ops = &opp_res_ops, ++}; ++ ++/* Throughput in KiB/s */ ++static struct bus_throughput_db l3_throughput_db = { ++ .throughput[0] = 0, ++ .throughput[1] = 100, ++ .throughput[2] = 250, ++}; ++ ++static struct shared_resource vdd2_opp = { ++ .name = "vdd2_opp", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .resource_data = &l3_throughput_db, ++ .ops = &opp_res_ops, ++}; ++ ++static char linked_res[] = "vdd1_opp"; ++ ++static struct shared_resource_ops freq_res_ops = { ++ .init = init_freq, ++ .change_level = set_freq, ++ .validate_level = validate_freq, ++}; ++ ++static struct shared_resource mpu_freq = { ++ .name = "mpu_freq", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .resource_data = &linked_res, ++ .ops = &freq_res_ops, ++}; ++ ++static struct shared_resource dsp_freq = { ++ .name = "dsp_freq", ++ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), ++ .resource_data = &linked_res, ++ .ops = &freq_res_ops, ++}; ++ + struct shared_resource *resources_omap[] __initdata = { + &mpu_latency, + &core_latency, +@@ -220,6 +289,11 @@ struct shared_resource *resources_omap[] + &neon_pwrdm_latency, + &usbhost_pwrdm_latency, + &emu_pwrdm_latency, ++ /* OPP/frequency resources */ ++ &vdd1_opp, ++ &vdd2_opp, ++ &mpu_freq, ++ &dsp_freq, + NULL + }; + + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/packages/linux/linux-omap2-git/beagleboard/07-omappm-srf-updates.eml b/packages/linux/linux-omap2-git/beagleboard/07-omappm-srf-updates.eml new file mode 100644 index 0000000000..735e991298 --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/07-omappm-srf-updates.eml @@ -0,0 +1,173 @@ +Updates the omap-pm apis with calls to SRF implementation + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/plat-omap/omap-pm-srf.c | 84 +++++++++------------------------------ + 1 files changed, 20 insertions(+), 64 deletions(-) + +Index: linux-omap-2.6/arch/arm/plat-omap/omap-pm-srf.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/plat-omap/omap-pm-srf.c 2008-07-21 +12:10:19.824596984 +0530 ++++ linux-omap-2.6/arch/arm/plat-omap/omap-pm-srf.c 2008-07-21 +12:10:21.626540178 +0530 +@@ -25,6 +25,7 @@ + #include <linux/init.h> + #include <linux/cpufreq.h> + #include <linux/device.h> ++#include <linux/module.h> + + /* Interface documentation is in asm/arch/omap-pm.h */ + #include <asm/arch/omap-pm.h> +@@ -121,6 +122,7 @@ void omap_pm_set_max_dev_wakeup_lat(stru + WARN_ON(1); + return; + }; ++ + /* Look for the devices Power Domain */ + /* TODO: Put this back in once tiocp layer is available + tiocp_dev = container_of(dev, struct tiocp, dev); +@@ -138,19 +140,6 @@ void omap_pm_set_max_dev_wakeup_lat(stru + res_name = get_lat_res_name(pwrdm_dev->name); + resource_request(res_name, dev, t); + } +- +- /* +- * For current Linux, this needs to map the device to a +- * powerdomain, then go through the list of current max lat +- * constraints on that powerdomain and find the smallest. If +- * the latency constraint has changed, the code should +- * recompute the state to enter for the next powerdomain +- * state. Conceivably, this code should also determine +- * whether to actually disable the device clocks or not, +- * depending on how long it takes to re-enable the clocks. +- * +- * TI CDP code can call constraint_set here. +- */ + } + + void omap_pm_set_max_sdma_lat(struct device *dev, long t) +@@ -169,21 +158,9 @@ void omap_pm_set_max_sdma_lat(struct dev + "dev %s, t = %ld usec\n", dev_name(dev), t); + resource_request("core_latency", dev, t); + } +- +- /* +- * For current Linux PM QOS params, this code should scan the +- * list of maximum CPU and DMA latencies and select the +- * smallest, then set cpu_dma_latency pm_qos_param +- * accordingly. +- * +- * For future Linux PM QOS params, with separate CPU and DMA +- * latency params, this code should just set the dma_latency param. +- * +- * TI CDP code can call constraint_set here. +- */ +- + } + ++static struct device dummy_dsp_dev; + + /* + * DSP Bridge-specific constraints +@@ -200,6 +177,7 @@ const struct omap_opp *omap_pm_dsp_get_o + + return NULL; + } ++EXPORT_SYMBOL(omap_pm_dsp_get_opp_table); + + void omap_pm_dsp_set_min_opp(u8 opp_id) + { +@@ -210,36 +188,21 @@ void omap_pm_dsp_set_min_opp(u8 opp_id) + + pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id); + +- /* +- * +- * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we +- * can just test to see which is higher, the CPU's desired OPP +- * ID or the DSP's desired OPP ID, and use whichever is +- * highest. +- * +- * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP +- * rate is keyed on MPU speed, not the OPP ID. So we need to +- * map the OPP ID to the MPU speed for use with clk_set_rate() +- * if it is higher than the current OPP clock rate. +- * +- */ +-} ++ /* For now pass a dummy_dev struct for SRF to identify the caller. ++ * Maybe its good to have DSP pass this as an argument ++ */ ++ resource_request("vdd1_opp", &dummy_dsp_dev, opp_id); ++ return; + ++} ++EXPORT_SYMBOL(omap_pm_dsp_set_min_opp); + + u8 omap_pm_dsp_get_opp(void) + { + pr_debug("OMAP PM: DSP requests current DSP OPP ID\n"); +- +- /* +- * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock +- * +- * CDP12.14+: +- * Call clk_get_rate() on the OPP custom clock, map that to an +- * OPP ID using the tables defined in board-*.c/chip-*.c files. +- */ +- +- return 0; ++ return resource_get_level("vdd1_opp"); + } ++EXPORT_SYMBOL(omap_pm_dsp_get_opp); + + /* + * CPUFreq-originated constraint +@@ -261,6 +224,8 @@ struct cpufreq_frequency_table **omap_pm + return NULL; + } + ++static struct device dummy_cpufreq_dev; ++ + void omap_pm_cpu_set_freq(unsigned long f) + { + if (f == 0) { +@@ -271,26 +236,17 @@ void omap_pm_cpu_set_freq(unsigned long + pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n", + f); + +- /* +- * For l-o dev tree, determine whether MPU freq or DSP OPP id +- * freq is higher. Find the OPP ID corresponding to the +- * higher frequency. Call clk_round_rate() and clk_set_rate() +- * on the OPP custom clock. +- * +- * CDP should just be able to set the VDD1 OPP clock rate here. +- */ ++ resource_request("mpu_freq", &dummy_cpufreq_dev, f); ++ return; + } ++EXPORT_SYMBOL(omap_pm_cpu_set_freq); + + unsigned long omap_pm_cpu_get_freq(void) + { + pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n"); +- +- /* +- * Call clk_get_rate() on the mpu_ck. +- */ +- +- return 0; ++ return resource_get_level("mpu_freq"); + } ++EXPORT_SYMBOL(omap_pm_cpu_get_freq); + + struct device omap_pm_dev; + + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/packages/linux/linux-omap2-git/beagleboard/08-omappm-voltagescaling.eml b/packages/linux/linux-omap2-git/beagleboard/08-omappm-voltagescaling.eml new file mode 100644 index 0000000000..a7885774f4 --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/08-omappm-voltagescaling.eml @@ -0,0 +1,96 @@ +Adds Voltage scaling support + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/board-3430sdp.c | 12 ++++++++++++ + arch/arm/mach-omap2/resource34xx.c | 17 ++++++++++++++++- + arch/arm/mach-omap2/resource34xx.h | 3 +++ + 3 files changed, 31 insertions(+), 1 deletion(-) + +Index: linux-omap-2.6/arch/arm/mach-omap2/board-3430sdp.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/board-3430sdp.c 2008-08-11 +17:16:07.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/board-3430sdp.c 2008-08-11 +17:17:58.000000000 +0530 +@@ -94,6 +94,18 @@ struct vdd_prcm_config iva2_rate_table[] + + #define TWL4030_MSECURE_GPIO 22 + ++u8 vdd1_volts[MAX_VDD1_OPP] = { ++ /* Vsel corresponding to 0.9V (OPP1), 1.00V (OPP2), ++ * 1.20V (OPP3), 1.27V (OPP4), 1.35 (OPP5) ++ */ ++ 0x18, 0x20, 0x30, 0x36, 0x3C ++}; ++ ++u8 vdd2_volts[MAX_VDD2_OPP] = { ++ /* Vsel corresponding to 0.9V (OPP1), 1.00V (OPP2), 1.15 (OPP3) */ ++ 0x18, 0x20, 0x2C ++}; ++ + static struct resource sdp3430_smc91x_resources[] = { + [0] = { + .start = OMAP34XX_ETHR_START, +Index: linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/resource34xx.c 2008-08-11 +17:17:23.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c 2008-08-11 +17:22:02.000000000 +0530 +@@ -19,6 +19,7 @@ + #include <linux/pm_qos_params.h> + #include <asm/arch/powerdomain.h> + #include <asm/arch/clockdomain.h> ++#include "smartreflex.h" + #include "resource34xx.h" + + /** +@@ -174,10 +175,24 @@ int set_opp(struct shared_resource *resp + { + #ifdef CONFIG_MACH_OMAP_3430SDP + unsigned long mpu_freq; ++ ++ if (resp->curr_level == target_level) ++ return 0; ++ + if (strcmp(resp->name, "vdd1_opp") == 0) { + mpu_freq = get_freq(vdd1_rate_table + MAX_VDD1_OPP, + target_level); +- clk_set_rate(vdd1_clk, mpu_freq); ++ if (resp->curr_level > target_level) { ++ /* Scale Frequency and then voltage */ ++ clk_set_rate(vdd1_clk, mpu_freq); ++ sr_voltagescale_vcbypass(PRCM_VDD1, ++ vdd1_volts[target_level-1]); ++ } else { ++ /* Scale Voltage and then frequency */ ++ sr_voltagescale_vcbypass(PRCM_VDD1, ++ vdd1_volts[target_level-1]); ++ clk_set_rate(vdd1_clk, mpu_freq); ++ } + resp->curr_level = curr_vdd1_prcm_set->opp; + } else if (strcmp(resp->name, "vdd2_opp") == 0) { + /* Not supported yet */ +Index: linux-omap-2.6/arch/arm/mach-omap2/resource34xx.h +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/resource34xx.h 2008-08-11 +17:17:23.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/resource34xx.h 2008-08-11 +17:17:58.000000000 +0530 +@@ -33,6 +33,9 @@ extern unsigned int get_opp(struct vdd_p + extern struct vdd_prcm_config vdd1_rate_table[]; + extern struct vdd_prcm_config vdd2_rate_table[]; + extern struct vdd_prcm_config iva2_rate_table[]; ++extern u8 vdd1_volts[]; ++extern u8 vdd2_volts[]; ++extern int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel); + /** + * mpu_latency/core_latency are used to control the cpuidle C state. + */ + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/packages/linux/linux-omap2-git/beagleboard/09-omappm-vdd2-scaling.eml b/packages/linux/linux-omap2-git/beagleboard/09-omappm-vdd2-scaling.eml new file mode 100644 index 0000000000..532a9f7975 --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/09-omappm-vdd2-scaling.eml @@ -0,0 +1,102 @@ +Adds VDD2 scaling support + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/resource34xx.c | 35 +++++++++++++++++++++++++++++++++-- + arch/arm/plat-omap/omap-pm-srf.c | 15 +++++---------- + 2 files changed, 38 insertions(+), 12 deletions(-) + +Index: linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/resource34xx.c 2008-07-21 +12:10:22.032527379 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c 2008-07-21 +12:10:22.479513287 +0530 +@@ -174,7 +174,9 @@ void init_opp(struct shared_resource *re + int set_opp(struct shared_resource *resp, u32 target_level) + { + #ifdef CONFIG_MACH_OMAP_3430SDP +- unsigned long mpu_freq; ++ unsigned long mpu_freq, l3_freq, tput; ++ int ind; ++ struct bus_throughput_db *tput_db; + + if (resp->curr_level == target_level) + return 0; +@@ -195,7 +197,36 @@ int set_opp(struct shared_resource *resp + } + resp->curr_level = curr_vdd1_prcm_set->opp; + } else if (strcmp(resp->name, "vdd2_opp") == 0) { +- /* Not supported yet */ ++ tput_db = resp->resource_data; ++ tput = target_level; ++ /* using the throughput db map to the appropriate L3 Freq */ ++ for (ind = 1; ind < MAX_VDD2_OPP; ind++) ++ if (tput_db->throughput[ind] > tput) ++ target_level = ind; ++ ++ /* Set the highest OPP possible */ ++ if (ind == MAX_VDD2_OPP) ++ target_level = ind-1; ++ ++ if (resp->curr_level == target_level) ++ return 0; ++ ++ resp->curr_level = target_level; ++ ++ l3_freq = get_freq(vdd2_rate_table + MAX_VDD2_OPP, ++ target_level); ++ if (resp->curr_level > target_level) { ++ /* Scale Frequency and then voltage */ ++ clk_set_rate(vdd2_clk, l3_freq); ++ sr_voltagescale_vcbypass(PRCM_VDD2, ++ vdd2_volts[target_level-1]); ++ } else { ++ /* Scale Voltage and then frequency */ ++ sr_voltagescale_vcbypass(PRCM_VDD2, ++ vdd2_volts[target_level-1]); ++ clk_set_rate(vdd1_clk, l3_freq); ++ } ++ resp->curr_level = curr_vdd2_prcm_set->opp; + } + #endif + return 0; +Index: linux-omap-2.6/arch/arm/plat-omap/omap-pm-srf.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/plat-omap/omap-pm-srf.c 2008-07-21 +12:10:21.626540178 +0530 ++++ linux-omap-2.6/arch/arm/plat-omap/omap-pm-srf.c 2008-07-21 +12:10:22.479513287 +0530 +@@ -95,21 +95,16 @@ void omap_pm_set_min_bus_tput(struct dev + return; + }; + +- if (r == 0) ++ if (r == 0) { + pr_debug("OMAP PM: remove min bus tput constraint: " + "dev %s for agent_id %d\n", dev_name(dev), agent_id); +- else ++ resource_release("vdd2_opp", r); ++ } else { + pr_debug("OMAP PM: add min bus tput constraint: " + "dev %s for agent_id %d: rate %ld KiB\n", + dev_name(dev), agent_id, r); +- +- /* +- * This code should model the interconnect and compute the +- * required clock frequency, convert that to a VDD2 OPP ID, then +- * set the VDD2 OPP appropriately. +- * +- * TI CDP code can call constraint_set here on the VDD2 OPP. +- */ ++ resource_request("vdd2_opp", dev, r); ++ } + } + + void omap_pm_set_max_dev_wakeup_lat(struct device *dev, long t) + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/packages/linux/linux-omap2-git/beagleboard/10-omappm-off-mode.eml b/packages/linux/linux-omap2-git/beagleboard/10-omappm-off-mode.eml new file mode 100644 index 0000000000..3728440159 --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/10-omappm-off-mode.eml @@ -0,0 +1,35 @@ +A Temp patch needed only till OFF mode is implemented. + +Signed-off-by: Rajendra Nayak <rnayak@ti.com> +--- + arch/arm/mach-omap2/resource34xx.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c +=================================================================== +--- linux-omap-2.6.orig/arch/arm/mach-omap2/resource34xx.c 2008-08-11 +17:39:00.000000000 +0530 ++++ linux-omap-2.6/arch/arm/mach-omap2/resource34xx.c 2008-08-11 +17:39:00.000000000 +0530 +@@ -131,13 +131,13 @@ int set_pd_latency(struct shared_resourc + omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[i]); + } + pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_ON); +- pwrdm_set_next_pwrst(pwrdm, pd_lat_level); ++ pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET); + for (i = 0; pwrdm->pwrdm_clkdms[i]; i++) { + omap2_clkdm_sleep(pwrdm->pwrdm_clkdms[i]); + omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[i]); + } + } else +- pwrdm_set_next_pwrst(pwrdm, pd_lat_level); ++ pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_RET); + break; + case PWRDM_POWER_ON: + pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_ON); + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/packages/linux/linux-omap2-git/beagleboard/defconfig b/packages/linux/linux-omap2-git/beagleboard/defconfig index c07d0ab5e2..b3ea5f9557 100644 --- a/packages/linux/linux-omap2-git/beagleboard/defconfig +++ b/packages/linux/linux-omap2-git/beagleboard/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.26-omap1 -# Tue Aug 5 20:34:54 2008 +# Mon Aug 11 16:37:34 2008 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -189,10 +189,14 @@ CONFIG_OMAP_MCBSP=y # CONFIG_OMAP_MBOX_FWK is not set # CONFIG_OMAP_MPU_TIMER is not set CONFIG_OMAP_32K_TIMER=y +CONFIG_OMAP_32K_TIMER_HZ=128 CONFIG_OMAP_DM_TIMER=y # CONFIG_OMAP_LL_DEBUG_UART1 is not set # CONFIG_OMAP_LL_DEBUG_UART2 is not set CONFIG_OMAP_LL_DEBUG_UART3=y +# CONFIG_OMAP_PM_NONE is not set +# CONFIG_OMAP_PM_NOOP is not set +CONFIG_OMAP_PM_SRF=y CONFIG_ARCH_OMAP34XX=y CONFIG_ARCH_OMAP3430=y @@ -256,7 +260,7 @@ CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_GENERIC_CLOCKEVENTS_BUILD=y # CONFIG_PREEMPT is not set -CONFIG_HZ=100 +CONFIG_HZ=128 CONFIG_AEABI=y # CONFIG_OABI_COMPAT is not set # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set @@ -307,19 +311,19 @@ CONFIG_CPU_IDLE_GOV_MENU=y # CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_TABLE=y -# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_DEBUG=y CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_STAT_DETAILS=y -CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set # CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y -# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y # # Floating point emulation diff --git a/packages/linux/linux-omap2-git/beagleboard/omap23-pm-noop.eml b/packages/linux/linux-omap2-git/beagleboard/omap23-pm-noop.eml new file mode 100644 index 0000000000..48ff5da822 --- /dev/null +++ b/packages/linux/linux-omap2-git/beagleboard/omap23-pm-noop.eml @@ -0,0 +1,894 @@ +The interface provides device drivers, CPUFreq, and DSP Bridge with a +means of controlling OMAP power management parameters that are not yet +supported by the Linux PM PMQOS interface. Copious documentation and +rationale is in the patch in Documentation/arm/OMAP/omap_pm and the +interface header file, include/asm-arm/arch-omap/omap-pm.h. + +Signed-off-by: Paul Walmsley <paul@pwsan.com> +--- + + Documentation/arm/OMAP/omap_pm | 185 +++++++++++++++++++++ + arch/arm/mach-omap2/io.c | 4 + arch/arm/plat-omap/Kconfig | 13 + + arch/arm/plat-omap/Makefile | 1 + arch/arm/plat-omap/omap-pm-noop.c | 309 +++++++++++++++++++++++++++++++++++ + include/asm-arm/arch-omap/omap-pm.h | 300 ++++++++++++++++++++++++++++++++++ + 6 files changed, 812 insertions(+), 0 deletions(-) + create mode 100644 Documentation/arm/OMAP/omap_pm + create mode 100644 arch/arm/plat-omap/omap-pm-noop.c + create mode 100644 include/asm-arm/arch-omap/omap-pm.h + +diff --git a/Documentation/arm/OMAP/omap_pm b/Documentation/arm/OMAP/omap_pm +new file mode 100644 +index 0000000..2ec2034 +--- /dev/null ++++ b/Documentation/arm/OMAP/omap_pm +@@ -0,0 +1,185 @@ ++ ++Rationale: the OMAP PM interface ++================================ ++ ++ ++Existing PM interfaces are currently not ideal for OMAP ++------------------------------------------------------- ++ ++There are two PM interfaces in use with publicly-distributed OMAP ++Linux code: the TI Shared Resource Framework (SRF) and the Linux PM ++QoS parameters code. Neither interface is ideal for Linux OMAP code. ++ ++TI Shared Resource Framework: ++ ++The TI CDP 12.14 tree drivers currently use the TI Shared Resource ++Framework (SRF) to control chip power management. Use of the SRF ++allowed TI to get the drivers up and running quickly with considerable ++power savings; and the SRF provided debugging support. However, many ++of the SRF parameters are specified in OMAP-specific terms, such as ++target OPPs, rather than in terms of actual latency or throughput ++requirements. OPPs change depending on OMAP silicon revisions or OMAP ++types, and are meaningless for other architectures, so drivers shared ++between OMAP and other architectures would also have to #ifdef out the ++SRF constraints. ++ ++Linux PM QoS parameters: ++ ++In February 2008, the mainline Linux kernel added code that is ++somewhat similar to the SRF: the Linux PM QoS parameters code, located ++in kernel/pm_qos_params.c. (This code replaced the latency management ++code that was present in earlier kernels.) Ideally, OMAP drivers ++would be able to use this Linux PM QoS code directly, but the PM QoS ++code has some drawbacks: ++ ++- It combines some power management parameters that should be kept ++ separate for maximum power savings on OMAP3. For example, in the PM ++ QoS code, CPU and system DMA wakeup latency are combined into one ++ parameter; but on OMAP3, these are distinct parameters. The Linux ++ PM QoS code also combines all network power management knobs into ++ two non-device-specific parameters. OMAP2/3 systems can have ++ different network devices with different power management ++ requirements - for example, a wired Ethernet interface may have ++ different latency and throughput constraints than a WiFi interface. ++ ++- It does not yet cover all of the power management capabilities of ++ the OMAP3 architecture. It does not express latency constraints on ++ a per-device or per-powerdomain basis; it only covers ++ cpu_dma_latency and network throughput and latency, which would not ++ cover most of the OMAP3 devices. ++ ++The result is that drivers using the current Linux PM QoS layer ++directly are unlikely to reach the same level of power efficiency as ++driver code using the Shared Resource Framework. ++ ++To summarize, the SRF provides significant power savings, but ++expresses power constraints in an OMAP- and silicon-revision-specific ++way; and the PM QoS layer expresses PM constraints in a cross-platform ++manner (in terms of fundamental physical units), but does not support ++per-powerdomain constraints and does not cover many of the OMAP power ++management features. ++ ++ ++A medium-term alternative: the OMAP PM interface ++------------------------------------------------ ++ ++We need a way for driver code to express PM parameters which: ++ ++- supports the range of power management parameters present in the TI SRF; ++ ++- separates the drivers from the underlying PM parameter ++ implementation, whether it is the TI SRF or Linux PM QoS or Linux ++ latency framework or something else; ++ ++- specifies PM parameters in terms of fundamental units, such as ++ latency and throughput, rather than units which are specific to OMAP ++ or to particular OMAP variants; ++ ++- allows drivers which are shared with other architectures (e.g., ++ DaVinci) to add these constraints in a way which won't affect non-OMAP ++ systems, ++ ++- can be implemented immediately with minimal disruption of other ++ architectures. ++ ++ ++We therefore propose the OMAP PM interface, including the following ++four power management functions for driver code: ++ ++1. Set the maximum MPU wakeup latency: ++ (*pdata->set_max_mpu_wakeup_lat)(struct device *dev, unsigned long t) ++ ++2. Set the maximum device wakeup latency: ++ (*pdata->set_max_dev_wakeup_lat)(struct device *dev, unsigned long t) ++ ++3. Set the maximum system DMA transfer start latency (CORE pwrdm): ++ (*pdata->set_max_sdma_lat)(struct device *dev, long t) ++ ++4. Set the minimum bus throughput needed by a device: ++ (*pdata->set_min_bus_tput)(struct device *dev, u8 agent_id, unsigned long r) ++ ++ ++These functions are extensively documented in the OMAP PM interface header ++file, included in the patch. ++ ++ ++The OMAP PM layer is intended to be temporary ++--------------------------------------------- ++ ++The intention is that, in time, the Linux PM QoS layer should support ++the range of power management features present in OMAP3. As this ++happens, existing drivers using the OMAP PM interface can be modified ++to use the Linux PM QoS code; and the OMAP PM interface can disappear. ++ ++ ++Driver usage of the OMAP PM functions ++------------------------------------- ++ ++As the 'pdata' in the above examples indicates, these functions are ++exposed to drivers through function pointers in driver .platform_data ++structures. The function pointers are initialized by the board-*.c ++files to point to the corresponding OMAP PM functions: ++.set_max_dev_wakeup_lat will point to ++omap_pm_set_max_dev_wakeup_lat(), etc. Other architectures which do ++not support these functions should leave these function pointers set ++to NULL. Drivers should use the following idiom: ++ ++ if (pdata->set_max_dev_wakeup_lat) ++ (*pdata->set_max_dev_wakeup_lat)(dev, t); ++ ++The most common usage of these functions will probably be to specify ++the maximum time from when an interrupt occurs, to when the device ++becomes accessible. To accomplish this, driver writers should use the ++set_max_mpu_wakeup_lat() function to to constrain the MPU wakeup ++latency, and the set_max_dev_wakeup_lat() function to constrain the ++device wakeup latency (from clk_enable() to accessibility). For ++example, ++ ++ /* Limit MPU wakeup latency */ ++ if (pdata->set_max_mpu_wakeup_lat) ++ (*pdata->set_max_mpu_wakeup_lat)(dev, tc); ++ ++ /* Limit device powerdomain wakeup latency */ ++ if (pdata->set_max_dev_wakeup_lat) ++ (*pdata->set_max_dev_wakeup_lat)(dev, td); ++ ++ /* total wakeup latency in this example: (tc + td) */ ++ ++ ++The PM parameters can be overwritten by calling the function again ++with the new value. The settings can be removed by calling the ++function with a t argument of -1 (except in the case of ++set_max_bus_tput(), which should be called with an r argument of 0). ++ ++ ++Other specialized interface functions ++------------------------------------- ++ ++The four functions listed above are intended to be usable by any ++device driver. However, DSPBridge and CPUFreq have special ++requirements. DSPBridge expresses target DSP performance levels in ++terms of OPP IDs. CPUFreq expresses target MPU performance levels in ++terms of MPU frequency. The OMAP PM interface contains functions for ++these specialized cases to convert that input information (OPPs/MPU ++frequency) into the form that the underlying power management ++implementation needs: ++ ++5. (*pdata->omap_pm_dsp_get_opp_table)(void) ++ ++6. (*pdata->omap_pm_dsp_set_min_opp)(u8 opp_id) ++ ++7. (*pdata->omap_pm_dsp_get_opp)(void) ++ ++8. (*pdata->omap_pm_cpu_get_freq_table)(void) ++ ++9. (*pdata->omap_pm_cpu_set_freq)(unsigned long f) ++ ++10. (*pdata->omap_pm_cpu_get_freq)(void) ++ ++ ++There are also functions for use by the clockdomain layer to indicate ++that a powerdomain should wake up or be put to sleep: ++ ++11. (*pdata->omap_pm_pwrdm_active)(struct powerdomain *pwrdm) ++ ++12. (*pdata->omap_pm_pwrdm_inactive)(struct powerdomain *pwrdm) +diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig +index 960c13f..ca790ac 100644 +--- a/arch/arm/plat-omap/Kconfig ++++ b/arch/arm/plat-omap/Kconfig +@@ -247,4 +247,17 @@ config OMAP_SERIAL_WAKE + + endmenu + ++choice ++ prompt "OMAP PM layer selection" ++ depends on ARCH_OMAP ++ default OMAP_PM_NOOP ++ ++config OMAP_PM_NONE ++ bool "No PM layer" ++ ++config OMAP_PM_NOOP ++ bool "No-op/debug PM layer" ++ ++endchoice ++ + endif +diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile +index 93bbb64..d5453d5 100644 +--- a/arch/arm/plat-omap/Makefile ++++ b/arch/arm/plat-omap/Makefile +@@ -29,3 +29,4 @@ obj-$(CONFIG_OMAP_MMU_FWK) += mmu.o + # OMAP mailbox framework + obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o + ++obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o +\ No newline at end of file +diff --git a/arch/arm/plat-omap/omap-pm-noop.c b/arch/arm/plat-omap/omap-pm-noop.c +new file mode 100644 +index 0000000..5ff7962 +--- /dev/null ++++ b/arch/arm/plat-omap/omap-pm-noop.c +@@ -0,0 +1,309 @@ ++/* ++ * omap-pm-noop.c - OMAP power management interface - dummy version ++ * ++ * This code implements the OMAP power management interface to ++ * drivers, CPUIdle, CPUFreq, and DSP Bridge. It is strictly for ++ * debug/demonstration use, as it does nothing but printk() whenever a ++ * function is called (when DEBUG is defined, below) ++ * ++ * Copyright (C) 2008 Texas Instruments, Inc. ++ * Copyright (C) 2008 Nokia Corporation ++ * Paul Walmsley ++ * ++ * Interface developed by (in alphabetical order): ++ * Karthik Dasu, Amish Lakhani, Tony Lindgren, Rajendra Nayak, Sakari ++ * Poussa, Veeramanikandan Raju, Igor Stoppa, Paul Walmsley, Richard ++ * Woodruff ++ */ ++ ++#undef DEBUG ++ ++#include <linux/init.h> ++#include <linux/cpufreq.h> ++#include <linux/device.h> ++ ++/* Interface documentation is in asm/arch/omap-pm.h */ ++#include <asm/arch/omap-pm.h> ++ ++#include <asm/arch/powerdomain.h> ++ ++static struct omap_opp *dsp_opps; ++static struct omap_opp *mpu_opps; ++ ++/* ++ * Device-driver-originated constraints (via board-*.c files) ++ */ ++ ++void omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t) ++{ ++ if (!dev || t < -1) { ++ WARN_ON(1); ++ return; ++ }; ++ ++ if (t == -1) ++ pr_debug("OMAP PM: remove max MPU wakeup latency constraint: " ++ "dev %s\n", dev_name(dev)); ++ else ++ pr_debug("OMAP PM: add max MPU wakeup latency constraint: " ++ "dev %s, t = %ld usec\n", dev_name(dev), t); ++ ++ /* ++ * For current Linux, this needs to map the MPU to a ++ * powerdomain, then go through the list of current max lat ++ * constraints on the MPU and find the smallest. If ++ * the latency constraint has changed, the code should ++ * recompute the state to enter for the next powerdomain ++ * state. ++ * ++ * TI CDP code can call constraint_set here. ++ */ ++} ++ ++void omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r) ++{ ++ if (!dev || agent_id != OCP_INITIATOR_AGENT || ++ agent_id != OCP_TARGET_AGENT) { ++ WARN_ON(1); ++ return; ++ }; ++ ++ if (r == 0) ++ pr_debug("OMAP PM: remove min bus tput constraint: " ++ "dev %s for agent_id %d\n", dev_name(dev), agent_id); ++ else ++ pr_debug("OMAP PM: add min bus tput constraint: " ++ "dev %s for agent_id %d: rate %ld KiB\n", ++ dev_name(dev), agent_id, r); ++ ++ /* ++ * This code should model the interconnect and compute the ++ * required clock frequency, convert that to a VDD2 OPP ID, then ++ * set the VDD2 OPP appropriately. ++ * ++ * TI CDP code can call constraint_set here on the VDD2 OPP. ++ */ ++} ++ ++void omap_pm_set_max_dev_wakeup_lat(struct device *dev, long t) ++{ ++ if (!dev || t < -1) { ++ WARN_ON(1); ++ return; ++ }; ++ ++ if (t == -1) ++ pr_debug("OMAP PM: remove max device latency constraint: " ++ "dev %s\n", dev_name(dev)); ++ else ++ pr_debug("OMAP PM: add max device latency constraint: " ++ "dev %s, t = %ld usec\n", dev_name(dev), t); ++ ++ /* ++ * For current Linux, this needs to map the device to a ++ * powerdomain, then go through the list of current max lat ++ * constraints on that powerdomain and find the smallest. If ++ * the latency constraint has changed, the code should ++ * recompute the state to enter for the next powerdomain ++ * state. Conceivably, this code should also determine ++ * whether to actually disable the device clocks or not, ++ * depending on how long it takes to re-enable the clocks. ++ * ++ * TI CDP code can call constraint_set here. ++ */ ++} ++ ++void omap_pm_set_max_sdma_lat(struct device *dev, long t) ++{ ++ if (!dev || t < -1) { ++ WARN_ON(1); ++ return; ++ }; ++ ++ if (t == -1) ++ pr_debug("OMAP PM: remove max DMA latency constraint: " ++ "dev %s\n", dev_name(dev)); ++ else ++ pr_debug("OMAP PM: add max DMA latency constraint: " ++ "dev %s, t = %ld usec\n", dev_name(dev), t); ++ ++ /* ++ * For current Linux PM QOS params, this code should scan the ++ * list of maximum CPU and DMA latencies and select the ++ * smallest, then set cpu_dma_latency pm_qos_param ++ * accordingly. ++ * ++ * For future Linux PM QOS params, with separate CPU and DMA ++ * latency params, this code should just set the dma_latency param. ++ * ++ * TI CDP code can call constraint_set here. ++ */ ++ ++} ++ ++ ++/* ++ * DSP Bridge-specific constraints ++ */ ++ ++const struct omap_opp *omap_pm_dsp_get_opp_table(void) ++{ ++ pr_debug("OMAP PM: DSP request for OPP table\n"); ++ ++ /* ++ * Return DSP frequency table here: The final item in the ++ * array should have .rate = .opp_id = 0. ++ */ ++ ++ return NULL; ++} ++ ++void omap_pm_dsp_set_min_opp(u8 opp_id) ++{ ++ if (opp_id == 0) { ++ WARN_ON(1); ++ return; ++ } ++ ++ pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id); ++ ++ /* ++ * ++ * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we ++ * can just test to see which is higher, the CPU's desired OPP ++ * ID or the DSP's desired OPP ID, and use whichever is ++ * highest. ++ * ++ * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP ++ * rate is keyed on MPU speed, not the OPP ID. So we need to ++ * map the OPP ID to the MPU speed for use with clk_set_rate() ++ * if it is higher than the current OPP clock rate. ++ * ++ */ ++} ++ ++ ++u8 omap_pm_dsp_get_opp(void) ++{ ++ pr_debug("OMAP PM: DSP requests current DSP OPP ID\n"); ++ ++ /* ++ * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock ++ * ++ * CDP12.14+: ++ * Call clk_get_rate() on the OPP custom clock, map that to an ++ * OPP ID using the tables defined in board-*.c/chip-*.c files. ++ */ ++ ++ return 0; ++} ++ ++/* ++ * CPUFreq-originated constraint ++ * ++ * In the future, this should be handled by custom OPP clocktype ++ * functions. ++ */ ++ ++struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void) ++{ ++ pr_debug("OMAP PM: CPUFreq request for frequency table\n"); ++ ++ /* ++ * Return CPUFreq frequency table here: loop over ++ * all VDD1 clkrates, pull out the mpu_ck frequencies, build ++ * table ++ */ ++ ++ return NULL; ++} ++ ++void omap_pm_cpu_set_freq(unsigned long f) ++{ ++ if (f == 0) { ++ WARN_ON(1); ++ return; ++ } ++ ++ pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n", ++ f); ++ ++ /* ++ * For l-o dev tree, determine whether MPU freq or DSP OPP id ++ * freq is higher. Find the OPP ID corresponding to the ++ * higher frequency. Call clk_round_rate() and clk_set_rate() ++ * on the OPP custom clock. ++ * ++ * CDP should just be able to set the VDD1 OPP clock rate here. ++ */ ++} ++ ++unsigned long omap_pm_cpu_get_freq(void) ++{ ++ pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n"); ++ ++ /* ++ * Call clk_get_rate() on the mpu_ck. ++ */ ++ ++ return 0; ++} ++ ++/* ++ * Powerdomain usecounting hooks ++ */ ++ ++void omap_pm_pwrdm_active(struct powerdomain *pwrdm) ++{ ++ if (!pwrdm) { ++ WARN_ON(1); ++ return; ++ }; ++ ++ pr_debug("OMAP PM: powerdomain %s is becoming active\n", pwrdm->name); ++ ++ /* ++ * CDP code apparently will need these for the enable_power_domain() ++ * and disable_power_domain() functions. ++ */ ++} ++ ++void omap_pm_pwrdm_inactive(struct powerdomain *pwrdm) ++{ ++ if (!pwrdm) { ++ WARN_ON(1); ++ return; ++ }; ++ ++ pr_debug("OMAP PM: powerdomain %s is becoming inactive\n", ++ pwrdm->name); ++ ++ /* ++ * CDP code apparently will need these for the enable_power_domain() ++ * and disable_power_domain() functions. ++ */ ++} ++ ++/* ++ * Should be called before clk framework since clk fw will call ++ * omap_pm_pwrdm_{in,}active() ++ */ ++int __init omap_pm_if_early_init(void) ++{ ++ return 0; ++} ++ ++/* Must be called after clock framework is initialized */ ++int __init omap_pm_if_init(struct omap_opp *mpu_opp_table, ++ struct omap_opp *dsp_opp_table) ++{ ++ mpu_opps = mpu_opp_table; ++ dsp_opps = dsp_opp_table; ++ return 0; ++} ++ ++void omap_pm_if_exit(void) ++{ ++ /* Deallocate CPUFreq frequency table here */ ++} ++ +diff --git a/include/asm-arm/arch-omap/omap-pm.h b/include/asm-arm/arch-omap/omap-pm.h +new file mode 100644 +index 0000000..d272dba +--- /dev/null ++++ b/include/asm-arm/arch-omap/omap-pm.h +@@ -0,0 +1,300 @@ ++/* ++ * omap-pm.h - OMAP power management interface ++ * ++ * Copyright (C) 2008 Texas Instruments, Inc. ++ * Copyright (C) 2008 Nokia Corporation ++ * Paul Walmsley ++ * ++ * Interface developed by (in alphabetical order): Karthik Dasu, Jouni ++ * Högander, Tony Lindgren, Rajendra Nayak, Sakari Poussa, ++ * Veeramanikandan Raju, Anand Sawant, Igor Stoppa, Paul Walmsley, ++ * Richard Woodruff ++ */ ++ ++#ifndef ASM_ARM_ARCH_OMAP_OMAP_PM_H ++#define ASM_ARM_ARCH_OMAP_OMAP_PM_H ++ ++#include <linux/device.h> ++#include <linux/cpufreq.h> ++ ++#include "powerdomain.h" ++ ++/** ++ * struct omap_opp - clock frequency-to-OPP ID table for DSP, MPU ++ * @rate: target clock rate ++ * @opp_id: OPP ID ++ * @min_vdd: minimum VDD1 voltage (in millivolts) for this OPP ++ * ++ * Operating performance point data. Can vary by OMAP chip and board. ++ */ ++struct omap_opp { ++ unsigned long rate; ++ u8 opp_id; ++ u16 min_vdd; ++}; ++ ++/* ++ * agent_id values for use with omap_pm_set_min_bus_tput(): ++ * ++ * OCP_INITIATOR_AGENT is only valid for devices that can act as ++ * initiators -- it represents the device's L3 interconnect ++ * connection. OCP_TARGET_AGENT represents the device's L4 ++ * interconnect connection. ++ */ ++#define OCP_TARGET_AGENT 1 ++#define OCP_INITIATOR_AGENT 2 ++ ++/** ++ * omap_pm_if_early_init - OMAP PM init code called before clock fw init ++ * ++ * Initialize anything that must be configured before the clock ++ * framework starts. The "_if_" is to avoid name collisions with the ++ * PM idle-loop code. ++ */ ++int __init omap_pm_if_early_init(void); ++ ++/** ++ * omap_pm_if_init - OMAP PM init code called after clock fw init ++ * @mpu_opp_table: array ptr to struct omap_opp for MPU ++ * @dsp_opp_table: array ptr to struct omap_opp for DSP ++ * ++ * The main initialization code. OPP tables are passed in here. The ++ * "_if_" is to avoid name collisions with the PM idle-loop code. ++ */ ++int __init omap_pm_if_init(struct omap_opp *mpu_opp_table, ++ struct omap_opp *dsp_opp_table); ++ ++/** ++ * omap_pm_if_exit - OMAP PM exit code ++ * ++ * Exit code; currently unused. The "_if_" is to avoid name ++ * collisions with the PM idle-loop code. ++ */ ++void omap_pm_if_exit(void); ++ ++/* ++ * Device-driver-originated constraints (via board-*.c files, platform_data) ++ */ ++ ++ ++/** ++ * omap_pm_set_max_mpu_wakeup_lat - set the maximum MPU wakeup latency ++ * @dev: struct device * requesting the constraint ++ * @t: maximum MPU wakeup latency in microseconds ++ * ++ * Request that the maximum interrupt latency for the MPU to be no ++ * greater than 't' microseconds. "Interrupt latency" in this case is ++ * defined as the elapsed time from the occurrence of a hardware or ++ * timer interrupt to the time when the device driver's interrupt ++ * service routine has been entered by the MPU. ++ * ++ * It is intended that underlying PM code will use this information to ++ * determine what power state to put the MPU powerdomain into, and ++ * possibly the CORE powerdomain as well, since interrupt handling ++ * code currently runs from SDRAM. Advanced PM or board*.c code may ++ * also configure interrupt controller priorities, OCP bus priorities, ++ * CPU speed(s), etc. ++ * ++ * This function will not affect device wakeup latency, e.g., time ++ * elapsed from when a device driver enables a hardware device with ++ * clk_enable(), to when the device is ready for register access or ++ * other use. To control this device wakeup latency, use ++ * set_max_dev_wakeup_lat() ++ * ++ * Multiple calls to set_max_mpu_wakeup_lat() will replace the ++ * previous t value. To remove the latency target for the MPU, call ++ * with t = -1. ++ * ++ * No return value. ++ */ ++void omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t); ++ ++ ++/** ++ * omap_pm_set_min_bus_tput - set minimum bus throughput needed by device ++ * @dev: struct device * requesting the constraint ++ * @tbus_id: interconnect to operate on (OCP_{INITIATOR,TARGET}_AGENT) ++ * @r: minimum throughput (in KiB/s) ++ * ++ * Request that the minimum data throughput on the OCP interconnect ++ * attached to device 'dev' interconnect agent 'tbus_id' be no less ++ * than 'r' KiB/s. ++ * ++ * It is expected that the OMAP PM or bus code will use this ++ * information to set the interconnect clock to run at the lowest ++ * possible speed that satisfies all current system users. The PM or ++ * bus code will adjust the estimate based on its model of the bus, so ++ * device driver authors should attempt to specify an accurate ++ * quantity for their device use case, and let the PM or bus code ++ * overestimate the numbers as necessary to handle request/response ++ * latency, other competing users on the system, etc. On OMAP2/3, if ++ * a driver requests a minimum L4 interconnect speed constraint, the ++ * code will also need to add an minimum L3 interconnect speed ++ * constraint, ++ * ++ * Multiple calls to set_min_bus_tput() will replace the previous rate ++ * value for this device. To remove the interconnect throughput ++ * restriction for this device, call with r = 0. ++ * ++ * No return value. ++ */ ++void omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r); ++ ++ ++/** ++ * omap_pm_set_max_dev_wakeup_lat - set the maximum device enable latency ++ * @dev: struct device * ++ * @t: maximum device wakeup latency in microseconds ++ * ++ * Request that the maximum amount of time necessary for a device to ++ * become accessible after its clocks are enabled should be no greater ++ * than 't' microseconds. Specifically, this represents the time from ++ * when a device driver enables device clocks with clk_enable(), to ++ * when the register reads and writes on the device will succeed. ++ * This function should be called before clk_disable() is called, ++ * since the power state transition decision may be made during ++ * clk_disable(). ++ * ++ * It is intended that underlying PM code will use this information to ++ * determine what power state to put the powerdomain enclosing this ++ * device into. ++ * ++ * Multiple calls to set_max_dev_wakeup_lat() will replace the ++ * previous wakeup latency values for this device. To remove the wakeup ++ * latency restriction for this device, call with t = -1. ++ * ++ * No return value. ++ */ ++void omap_pm_set_max_dev_wakeup_lat(struct device *dev, long t); ++ ++ ++/** ++ * omap_pm_set_max_sdma_lat - set the maximum system DMA transfer start latency ++ * @dev: struct device * ++ * @t: maximum DMA transfer start latency in microseconds ++ * ++ * Request that the maximum system DMA transfer start latency for this ++ * device 'dev' should be no greater than 't' microseconds. "DMA ++ * transfer start latency" here is defined as the elapsed time from ++ * when a device (e.g., McBSP) requests that a system DMA transfer ++ * start or continue, to the time at which data starts to flow into ++ * that device from the system DMA controller. ++ * ++ * It is intended that underlying PM code will use this information to ++ * determine what power state to put the CORE powerdomain into. ++ * ++ * Since system DMA transfers may not involve the MPU, this function ++ * will not affect MPU wakeup latency. Use set_max_cpu_lat() to do ++ * so. Similarly, this function will not affect device wakeup latency ++ * -- use set_max_dev_wakeup_lat() to affect that. ++ * ++ * Multiple calls to set_max_sdma_lat() will replace the previous t ++ * value for this device. To remove the maximum DMA latency for this ++ * device, call with t = -1. ++ * ++ * No return value. ++ */ ++void omap_pm_set_max_sdma_lat(struct device *dev, long t); ++ ++ ++/* ++ * DSP Bridge-specific constraints ++ */ ++ ++/** ++ * omap_pm_dsp_get_opp_table - get OPP->DSP clock frequency table ++ * ++ * Intended for use by DSPBridge. Returns an array of OPP->DSP clock ++ * frequency entries. The final item in the array should have .rate = ++ * .opp_id = 0. ++ */ ++const struct omap_opp *omap_pm_dsp_get_opp_table(void); ++ ++/** ++ * omap_pm_dsp_set_min_opp - receive desired OPP target ID from DSP Bridge ++ * @opp_id: target DSP OPP ID ++ * ++ * Set a minimum OPP ID for the DSP. This is intended to be called ++ * only from the DSP Bridge MPU-side driver. Unfortunately, the only ++ * information that code receives from the DSP/BIOS load estimator is the ++ * target OPP ID; hence, this interface. No return value. ++ */ ++void omap_pm_dsp_set_min_opp(u8 opp_id); ++ ++/** ++ * omap_pm_dsp_get_opp - report the current DSP OPP ID ++ * ++ * Report the current OPP for the DSP. Since on OMAP3, the DSP and ++ * MPU share a single voltage domain, the OPP ID returned back may ++ * represent a higher DSP speed than the OPP requested via ++ * omap_pm_dsp_set_min_opp(). ++ * ++ * Returns the current VDD1 OPP ID, or 0 upon error. ++ */ ++u8 omap_pm_dsp_get_opp(void); ++ ++ ++/* ++ * CPUFreq-originated constraint ++ * ++ * In the future, this should be handled by custom OPP clocktype ++ * functions. ++ */ ++ ++/** ++ * omap_pm_cpu_get_freq_table - return a cpufreq_frequency_table array ptr ++ * ++ * Provide a frequency table usable by CPUFreq for the current chip/board. ++ * Returns a pointer to a struct cpufreq_frequency_table array or NULL ++ * upon error. ++ */ ++struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void); ++ ++/** ++ * omap_pm_cpu_set_freq - set the current minimum MPU frequency ++ * @f: MPU frequency in Hz ++ * ++ * Set the current minimum CPU frequency. The actual CPU frequency ++ * used could end up higher if the DSP requested a higher OPP. ++ * Intended to be called by plat-omap/cpu_omap.c:omap_target(). No ++ * return value. ++ */ ++void omap_pm_cpu_set_freq(unsigned long f); ++ ++/** ++ * omap_pm_cpu_get_freq - report the current CPU frequency ++ * ++ * Returns the current MPU frequency, or 0 upon error. ++ */ ++unsigned long omap_pm_cpu_get_freq(void); ++ ++ ++/* ++ * Powerdomain usecounting hooks ++ */ ++ ++/** ++ * omap_pm_pwrdm_active - indicate that a power domain has become active ++ * @pwrdm: struct powerdomain * ++ * ++ * Notify the OMAP PM layer that the power domain 'pwrdm' has become active, ++ * presumably due to a device driver enabling an underlying clock. This ++ * function is intended to be called by a clockdomain node in the clock ++ * framework. No return value. ++ */ ++void omap_pm_pwrdm_active(struct powerdomain *pwrdm); ++ ++ ++/** ++ * omap_pm_pwrdm_inactive - indicate that a power domain has become inactive ++ * @pwrdm: struct powerdomain * ++ * ++ * Notify the OMAP PM layer that the power domain 'pwrdm' has become ++ * inactive, presumably due to a device driver disabling an underlying ++ * clock. This function is intended to be called by a clockdomain ++ * node in the clock framework. No return value. ++ */ ++void omap_pm_pwrdm_inactive(struct powerdomain *pwrdm); ++ ++ ++#endif + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-omap" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + +--- /tmp/io.c 2008-08-11 15:29:32.000000000 +0200 ++++ git/arch/arm/mach-omap2/io.c 2008-08-11 15:30:20.083198000 +0200 +@@ -38,6 +38,8 @@ + #include <asm/arch/clockdomain.h> + #include "clockdomains.h" + ++#include <asm/arch/omap-pm.h> ++ + /* + * The machine specific code may provide the extra mapping besides the + * default mapping provided here. +@@ -197,9 +199,11 @@ + void __init omap2_init_common_hw(struct omap_sdrc_params *sp) + { + omap2_mux_init(); ++ omap_pm_if_early_init(); + pwrdm_init(powerdomains_omap); + clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps); + omap2_clk_init(); ++ omap_pm_if_init(NULL, NULL); + omap2_sdrc_init(sp); + gpmc_init(); + } |