From 5cf49c96a744508ff2dcbb49c86f709096a8f39e Mon Sep 17 00:00:00 2001 From: Koen Kooi Date: Mon, 11 Aug 2008 14:39:50 +0000 Subject: linux-omap2 git: check in WIP cpufreq patches for beagleboard --- .../beagleboard/01-beagle-cpufreq.diff | 178 ++++ .../beagleboard/01-omap3-cpufreq.eml | 319 ++++++++ .../linux-omap2-git/beagleboard/01-omappm-srf.eml | 513 ++++++++++++ .../beagleboard/01-postrate-notifier.eml | 392 +++++++++ .../beagleboard/02-beagle_use_gptimer12 | 38 + .../beagleboard/02-omappm-mpu-latency-modeling.eml | 245 ++++++ .../beagleboard/02-postrate-notifier.eml | 186 +++++ .../beagleboard/03-omappm-omap3srf.eml | 167 ++++ .../beagleboard/04-omappm-srf-noop.eml | 497 ++++++++++++ .../beagleboard/05-omappm-virtualclocks.eml | 456 +++++++++++ .../06-omappm-opp-resource-modeling.eml | 228 ++++++ .../beagleboard/07-omappm-srf-updates.eml | 173 ++++ .../beagleboard/08-omappm-voltagescaling.eml | 96 +++ .../beagleboard/09-omappm-vdd2-scaling.eml | 102 +++ .../beagleboard/10-omappm-off-mode.eml | 35 + .../linux/linux-omap2-git/beagleboard/defconfig | 18 +- .../linux-omap2-git/beagleboard/omap23-pm-noop.eml | 894 +++++++++++++++++++++ packages/linux/linux-omap2_git.bb | 17 +- 18 files changed, 4546 insertions(+), 8 deletions(-) create mode 100644 packages/linux/linux-omap2-git/beagleboard/01-beagle-cpufreq.diff create mode 100644 packages/linux/linux-omap2-git/beagleboard/01-omap3-cpufreq.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/01-omappm-srf.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/01-postrate-notifier.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/02-beagle_use_gptimer12 create mode 100644 packages/linux/linux-omap2-git/beagleboard/02-omappm-mpu-latency-modeling.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/02-postrate-notifier.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/03-omappm-omap3srf.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/04-omappm-srf-noop.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/05-omappm-virtualclocks.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/06-omappm-opp-resource-modeling.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/07-omappm-srf-updates.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/08-omappm-voltagescaling.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/09-omappm-vdd2-scaling.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/10-omappm-off-mode.eml create mode 100644 packages/linux/linux-omap2-git/beagleboard/omap23-pm-noop.eml (limited to 'packages/linux') 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 + #include + ++#include ++ + #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 +--- + 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 + #include + #include ++#include + + #include + #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 ++ * + * 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 + #include + #include ++#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) ++#include ++#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 +--- + 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 ++ * ++ * 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 ++#include ++#include ++#include ++ ++/* 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 ++ * ++ * 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 ++#include ++#include ++#include ++ ++#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 +--- + + 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 ++ + #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 + +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 +--- + 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 ++ * ++ * 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 ++#include ++ ++/** ++ * 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 +--- + + 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 + #include + #include ++#include + #include + + #include +@@ -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 +--- + 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 ++ * ++ * 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 ++#include ++#include ++#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. ++ */ ++