Skip to contentSkip to conversation

omap2 clock: framework generalization, cleanup

PATCH In review Paul Walmsley 4 participants 41 messages Aug 20, 2007 – Aug 30, 2007

Subsystems (5)
lore
Share & tools
lore

Paul Walmsley

author maintainer
#0 lore raw

cover omap2 clock: framework generalization, cleanup

Hello,

This set of patches contains some significant changes to the OMAP2 clock framework. The main goal of these patches is to generalize the framework enough to be usable for the OMAP3430 clock tree, although in the process I think the OMAP2 clock code is improved quite a bit - I hope you'll agree.

The major change in this patch set is the rewrite of clksel clock handling, which:

* enables clksel parent clocks to be updated at clock framework init, from whatever the bootloader configured,

* properly encodes platform restrictions for particular rates,

* generalizes the clksel code to be useful for OMAP3430 clocks,

* facilitates future improved clock state reporting,

* and improves readability and maintainability.

The clksel patches are patches 6 through 20. A few other notable changes in this patchset:

* Cleanups/bug fixes: patches 1, 3, 4, 5

* Generalize root clock propagation at clock framework init: patch 2

* Use OMAP clock framework enable/disable fns for osc_ck, APLLs: patches 21, 22, 23

* Recalculate osc_ck and sys_ck via recalculate fns, rather than omap2_get_crystal_rate(): patch 24

* Generalize DPLL multiplier, divider handling: patches 25

* Generalize clocks enabled at init via ENABLE_ON_INIT clock flag: patch 26

* Generalize clock autoidle configuration: patches 27, 28

The patches were boot-tested on N800. Comments and testing are appreciated. In particular, any testing on 2430SDP are particularly welcome, since I don't have one here.

Patches apply cleanly against current git head, and seem to run fine, but I've been doing most of my testing against 2.6.22-omap1, since my N800 touchscreen does not work consistently with git head.

These changes increase uncompressed kernel memory footprint by about 6kB:
text data bss dec hex filename

2877920  147788   85992 3111700  2f7b14 vmlinux.orig
2881092  150908   85992 3117992  2f93a8 vmlinux

diffstat:

 arch/arm/mach-omap2/clock.c                       |  978 +++++++++----------
 arch/arm/mach-omap2/clock.h                       | 1092 +++++++++++++++++-----
 arch/arm/plat-omap/clock.c                        |   20
 include/asm-arm/arch-omap/clock.h                 |   57 -
 linux-omap/arch/arm/mach-omap2/board-n800-audio.c |   13
 linux-omap/arch/arm/mach-omap2/clock.c            |    6
 linux-omap/arch/arm/mach-omap2/clock.h            |    2
 linux-omap/arch/arm/mach-omap2/cm_regbits_24xx.h  |   50 +
 linux-omap/arch/arm/mach-omap2/pm.c               |   63 -
 linux-omap/arch/arm/plat-omap/clock.c             |   17
 linux-omap/include/asm-arm/arch-omap/clock.h      |    1
 11 files changed, 1492 insertions(+), 807 deletions(-)

My apologies in advance for the double 'Index:' lines in some of the patches - must be some quilt bug - it seems harmless and I have not yet had the chance to track it down.

- Paul

author maintainer
#1 lore raw

PATCH 1/28 omap2 clock: dsp_ick parent is dsp_fck, not core_ck

dsp_ick's parent clock is dsp_fck, not core_ck. 2420 TRM ES2.1.1 2.2 Rev Q pp. 4-9, 5-28.

---
 arch/arm/mach-omap2/clock.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-omap/arch/arm/mach-omap2/clock.h
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================

arch/arm/mach-omap2/clock.h +1 -1
@@ -820,7 +820,7 @@ static struct clk dsp_fck = {
 
 static struct clk dsp_ick = {
 	.name		= "dsp_ick",	 /* apparently ipi and isp */
-	.parent		= &dsp_fck,
+	.parent		= &core_ck,
 	.flags		= CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1 |
 				DELAYED_APP | CONFIG_PARTICIPANT,
 	.rate_offset	= OMAP24XX_CLKSEL_DSP_IF_SHIFT,
author maintainer
#2 lore raw

PATCH 2/28 omap2 clock: generalize initial clock rate setup: recalculate_root_clocks()

In reply to Paul Walmsley

Add a new clock framework function, recalculate_root_clocks(), that recalculates all root clocks (i.e., clocks with no parent clock). Call this function in omap2_clk_arch_init(), rather than manually propagating specific clocks. Add propagate_rate() recalcs to func_32k_ck and osc_ck.

---
 arch/arm/mach-omap2/clock.c       |    6 ++----
 arch/arm/mach-omap2/clock.h       |    4 +++-
 arch/arm/plat-omap/clock.c        |   17 +++++++++++++++++
 include/asm-arm/arch-omap/clock.h |    1 +
 4 files changed, 23 insertions(+), 5 deletions(-)

Index: linux-omap/arch/arm/plat-omap/clock.c
Index: linux-omap/arch/arm/plat-omap/clock.c
===================================================================

arch/arm/plat-omap/clock.c +17 -0
@@ -312,6 +312,23 @@ void propagate_rate(struct clk * tclk)
 	}
 }
 
+/**
+ * recalculate_root_clocks - recalculate and propagate all root clocks
+ *
+ * Recalculates all root clocks (clocks with no parent), which if the
+ * clock's .recalc is set correctly, should also propagate their rates.
+ * Called at init.
+ */
+void recalculate_root_clocks(void)
+{
+	struct clk *clkp;
+
+	list_for_each_entry(clkp, &clocks, node) {
+		if (unlikely(!clkp->parent) && likely((u32)clkp->recalc))
+			clkp->recalc(clkp);
+	}
+}
+
 int clk_register(struct clk *clk)
 {
 	if (clk == NULL || IS_ERR(clk))
include/asm-arm/arch-omap/clock.h +1 -0
Index: linux-omap/include/asm-arm/arch-omap/clock.h
===================================================================
@@ -57,6 +57,7 @@ extern int clk_init(struct clk_functions
 extern int clk_register(struct clk *clk);
 extern void clk_unregister(struct clk *clk);
 extern void propagate_rate(struct clk *clk);
+extern void recalculate_root_clocks(void);
 extern void followparent_recalc(struct clk * clk);
 extern void clk_allow_idle(struct clk *clk);
 extern void clk_deny_idle(struct clk *clk);
arch/arm/mach-omap2/clock.c +2 -4
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
@@ -1179,8 +1179,7 @@ static int __init omap2_clk_arch_init(vo
 	if (omap2_select_table_rate(&virt_prcm_set, mpurate))
 		printk(KERN_ERR "Could not find matching MPU rate\n");
 
-	propagate_rate(&osc_ck);		/* update main root fast */
-	propagate_rate(&func_32k_ck);		/* update main root slow */
+	recalculate_root_clocks();
 
 	printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL/MPU): "
 	       "%ld.%01ld/%ld/%ld MHz\n",
@@ -1231,8 +1230,7 @@ int __init omap2_clk_init(void)
 	}
 	curr_prcm_set = prcm;
 
-	propagate_rate(&osc_ck);		/* update main root fast */
-	propagate_rate(&func_32k_ck);		/* update main root slow */
+	recalculate_root_clocks();
 
 	printk(KERN_INFO "Clocking rate (Crystal/DPLL/MPU): "
 	       "%ld.%01ld/%ld/%ld MHz\n",
arch/arm/mach-omap2/clock.h +3 -1
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
@@ -592,7 +592,8 @@ static struct clk func_32k_ck = {
 	.name		= "func_32k_ck",
 	.rate		= 32000,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_FIXED | ALWAYS_ENABLED,
+				RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+	.recalc		= &propagate_rate,
 };
 
 /* Typical 12/13MHz in standalone mode, will be 26Mhz in chassis mode */
@@ -601,6 +602,7 @@ static struct clk osc_ck = {		/* (*12, *
 	.rate		= 26000000,		/* fixed up in clock init */
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				RATE_FIXED | RATE_PROPAGATES,
+	.recalc		= &propagate_rate,
 };
 
 /* With out modem likely 12MHz, with modem likely 13MHz */
author maintainer
#3 lore raw

PATCH 3/28 omap2 clock: mark onchip_clks as __initdata

In reply to Paul Walmsley

The onchip_clks array is only used during init, so, mark it __initdata.

---
 arch/arm/mach-omap2/clock.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-omap/arch/arm/mach-omap2/clock.h
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================

arch/arm/mach-omap2/clock.h +1 -1
@@ -1988,7 +1988,7 @@ static struct clk virt_prcm_set = {
 	.round_rate	= &omap2_round_to_table_rate,
 };
 
-static struct clk *onchip_clks[] = {
+static struct clk *onchip_clks[] __initdata = {
 	/* external root sources */
 	&func_32k_ck,
 	&osc_ck,
author maintainer
#4 lore raw

PATCH 5/28 omap2 clock: rename, add comment to omap2_mpu_recalc()

In reply to Paul Walmsley

omap2_mpu_recalc() actually just looks up what the MPU speed 'should' currently be from the current virt_prcm_set rate set, rather than reporting the actual hardware settings. Clarify this by renaming it to omap2_table_mpu_recalc() and adding some comments.

---
 arch/arm/mach-omap2/clock.c |    9 +++++++--
 arch/arm/mach-omap2/clock.h |    4 ++--
 2 files changed, 9 insertions(+), 4 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +7 -2
@@ -592,8 +592,13 @@ dpll_exit:
 	return(ret);
 }
 
-/* Just return the MPU speed */
-static void omap2_mpu_recalc(struct clk * clk)
+/**
+ * omap2_table_mpu_recalc - just return the MPU speed
+ * @clk: virt_prcm_set struct clk
+ *
+ * Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set.
+ */
+static void omap2_table_mpu_recalc(struct clk * clk)
 {
 	clk->rate = curr_prcm_set->mpu_speed;
 }
arch/arm/mach-omap2/clock.h +2 -2
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
@@ -24,7 +24,7 @@
 
 static void omap2_sys_clk_recalc(struct clk * clk);
 static void omap2_clksel_recalc(struct clk * clk);
-static void omap2_mpu_recalc(struct clk * clk);
+static void omap2_table_mpu_recalc(struct clk *clk);
 static int omap2_select_table_rate(struct clk * clk, unsigned long rate);
 static long omap2_round_to_table_rate(struct clk * clk, unsigned long rate);
 static void omap2_clk_disable(struct clk *clk);
@@ -1982,7 +1982,7 @@ static struct clk virt_prcm_set = {
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				VIRTUAL_CLOCK | ALWAYS_ENABLED | DELAYED_APP,
 	.parent		= &mpu_ck,	/* Indexed by mpu speed, no parent */
-	.recalc		= &omap2_mpu_recalc,	/* sets are keyed on mpu rate */
+	.recalc		= &omap2_table_mpu_recalc,	/* sets are keyed on mpu rate */
 	.set_rate	= &omap2_select_table_rate,
 	.round_rate	= &omap2_round_to_table_rate,
 };
author maintainer
#5 lore raw

PATCH 6/28 omap2 clock: add clksel and clksel_rate data

In reply to Paul Walmsley

Many OMAP2 clocks are either source- or divisor-selectable by twiddling various register bits; these are 'clksel' clocks. The table of rate divisors and source clock settings was previously embedded in the clock.c source code. Encode this data in two data structures:

1) struct clksel_rate for divisor-selection, mapping divisor values to register bit field values, along with a flags field indicating which chips the rate is available for -- one for each parent-rate combination; and:

2) struct clksel for source-selection, mapping parent struct clk pointers to struct clksel_rate array pointers; one for each parent.

Also, add several fields to the clk structure:

1) clksel: pointer to the struct clksel array

2) clksel_reg: pointer to the clksel register

3) clksel_mask: mask for the clksel bitfield

Add this data to each clksel clock. All this data is not yet used by the clock framework; that functionality is in the following patches.

N.B. Two clocks, sys_clkout and sys_clkout2, could not be converted to this setup without splitting source selection and divisor selection. This is because these clocks use separate registers for each selector. So, create two new clocks, sys_clkout_src and sys_clkout2_src, and locate source-selection there, and keep divisor selection in sys_clkout/sys_clkout2. This entailed modifying board-n800-audio.c.

---
 arch/arm/mach-omap2/board-n800-audio.c |   13 
 arch/arm/mach-omap2/clock.h            |  536 ++++++++++++++++++++++++++++++++-
 include/asm-arm/arch-omap/clock.h      |   25 +
 3 files changed, 557 insertions(+), 17 deletions(-)

Index: linux-omap/include/asm-arm/arch-omap/clock.h
Index: linux-omap/include/asm-arm/arch-omap/clock.h
===================================================================

include/asm-arm/arch-omap/clock.h +25 -0
@@ -14,6 +14,22 @@
 #define __ARCH_ARM_OMAP_CLOCK_H
 
 struct module;
+struct clk;
+
+#if defined(CONFIG_ARCH_OMAP2)
+
+struct clksel_rate {
+	u8			div;
+	u32			val;
+	u8			flags;
+};
+
+struct clksel {
+	struct clk		 *parent;
+	const struct clksel_rate *rates;
+};
+
+#endif
 
 struct clk {
 	struct list_head	node;
@@ -36,6 +52,9 @@ struct clk {
 	void			(*disable)(struct clk *);
 #if defined(CONFIG_ARCH_OMAP2)
 	u8			fixed_div;
+	void __iomem		*clksel_reg;
+	u32			clksel_mask;
+	const struct clksel	*clksel;
 #endif
 };
 
@@ -94,6 +113,12 @@ extern int clk_get_usecount(struct clk *
 #define CLOCK_IN_OMAP343X	(1 << 27)
 #define PARENT_CONTROLS_CLOCK	(1 << 28)
 
+/* Clksel_rate flags */
+#define DEFAULT_RATE            (1 << 0)
+#define RATE_IN_242X            (1 << 1)
+#define RATE_IN_243X            (1 << 2)
+#define RATE_IN_343X            (1 << 3)
+#define RATE_IN_24XX            (RATE_IN_242X | RATE_IN_243X)
 
 
 /* CM_CLKSEL2_PLL.CORE_CLK_SRC options (24XX) */
arch/arm/mach-omap2/clock.h +521 -15

879 lines not on this page · raw message

arch/arm/mach-omap2/board-n800-audio.c +11 -2
Index: linux-omap/arch/arm/mach-omap2/board-n800-audio.c
===================================================================
@@ -35,6 +35,7 @@
 #define AUDIO_ENABLED
 
 static struct clk *sys_clkout2;
+static struct clk *sys_clkout2_src;
 static struct clk *func96m_clk;
 static struct device *eac_device;
 static struct device *tsc2301_device;
@@ -186,9 +187,15 @@ static void n800_eac_cleanup(struct devi
 
 static int n800_codec_get_clocks(struct device *dev)
 {
+	sys_clkout2_src = clk_get(dev, "sys_clkout2_src");
+	if (IS_ERR(sys_clkout2_src)) {
+		dev_err(dev, "Could not get sys_clkout2_src clock\n");
+		return -ENODEV;
+	}
 	sys_clkout2 = clk_get(dev, "sys_clkout2");
 	if (IS_ERR(sys_clkout2)) {
-		dev_err(dev, "Could not get sys_clkout2\n");
+		dev_err(dev, "Could not get sys_clkout2 clock\n");
+		clk_put(sys_clkout2_src);
 		return -ENODEV;
 	}
 	/* configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
@@ -197,10 +204,11 @@ static int n800_codec_get_clocks(struct 
 	if (IS_ERR(func96m_clk)) {
 		dev_err(dev, "Could not get func 96M clock\n");
 		clk_put(sys_clkout2);
+		clk_put(sys_clkout2_src);
 		return -ENODEV;
 	}
 
-	clk_set_parent(sys_clkout2, func96m_clk);
+	clk_set_parent(sys_clkout2_src, func96m_clk);
 	clk_set_rate(sys_clkout2, 12000000);
 
 	return 0;
@@ -210,6 +218,7 @@ static void n800_codec_put_clocks(struct
 {
 	clk_put(func96m_clk);
 	clk_put(sys_clkout2);
+	clk_put(sys_clkout2_src);
 }
 
 static int n800_codec_enable_clock(struct device *dev)
author maintainer
#6 lore raw

PATCH 7/28 omap2 clock: init clksel clock parents to hardware reality at clock init

In reply to Paul Walmsley

Source-selectable clksel clocks have a 'default parent' assigned to them at compile-time. This default parent may or may not match the reality that is configured in the hardware registers by the bootloader. Clock tree recalculations could be erratic if the struct clk parent field contents don't match the hardware registers.

Resolve this by creating omap2_init_clksel_parent() to read the hardware registers and update the struct clk parent field as appropriate for clksel clocks. Add an '.init' field to each source-selectable clk structure so that the parent is fixed up when the clock is initially registered. (We don't do this for clksel clocks that are only rate-selectable, since they only have one possible parent clock.)

---
 arch/arm/mach-omap2/clock.c |   58 ++++++++++++++++++++++++++++++++++++++++----
 arch/arm/mach-omap2/clock.h |   22 ++++++++++++++++
 2 files changed, 75 insertions(+), 5 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +53 -5
@@ -93,6 +93,54 @@ static u32 sysclkout_div[] = {1, 2, 4, 8
  * Omap2 specific clock functions
  *-------------------------------------------------------------------------*/
 
+static inline u8 convert_mask_to_shift(u32 mask) {
+	return ffs(mask) - 1;
+}
+
+/**
+ * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware
+ * @clk: OMAP clock struct ptr to use
+ *
+ * Given a pointer to a source-selectable struct clk, read the hardware
+ * register and determine what its parent is currently set to.  Update the
+ * clk->parent field with the appropriate clk ptr.
+ */
+static void omap2_init_clksel_parent(struct clk *clk)
+{
+	const struct clksel *clks;
+	const struct clksel_rate *clkr;
+	u32 r, found = 0;
+
+	if (!clk->clksel)
+		return;
+
+	/* XXX Should be __raw_readl for non-CM 3430 clocks ? */
+	r = cm_read_reg(clk->clksel_reg) & clk->clksel_mask;
+	r >>= convert_mask_to_shift(clk->clksel_mask);
+
+	for (clks = clk->clksel; clks->parent && !found; clks++) {
+		for (clkr = clks->rates; clkr->div && !found; clkr++) {
+			if ((clkr->flags & cpu_mask) && (clkr->val == r)) {
+				if (clk->parent != clks->parent) {
+					pr_debug("clock: inited %s parent "
+						 "to %s (was %s)\n",
+						 clk->name, clks->parent->name,
+						 ((clk->parent->name) ?
+						  clk->parent->name : "NULL"));
+					clk->parent = clks->parent;
+				};
+				found = 1;
+			}
+		}
+	}
+
+	if (!found)
+		printk(KERN_ERR "clock: init parent: could not find "
+		       "regval %0x for clock %s\n", r,  clk->name);
+
+	return;
+}
+
 /* Recalculate SYST_CLK */
 static void omap2_sys_clk_recalc(struct clk * clk)
 {
@@ -1193,6 +1241,11 @@ int __init omap2_clk_init(void)
 	struct clk ** clkp;
 	u32 clkrate;
 
+	if (cpu_is_omap242x())
+		cpu_mask = RATE_IN_242X;
+	else if (cpu_is_omap2430())
+		cpu_mask = RATE_IN_243X;
+
 	clk_init(&omap2_clk_functions);
 	omap2_get_crystal_rate(&osc_ck, &sys_ck);
 
@@ -1210,11 +1263,6 @@ int __init omap2_clk_init(void)
 		}
 	}
 
-	if (cpu_is_omap242x())
-		cpu_mask = RATE_IN_242X;
-	else if (cpu_is_omap2430())
-		cpu_mask = RATE_IN_243X;
-
 	/* Check the MPU rate set by bootloader */
 	clkrate = omap2_get_dpll_rate(&dpll_ck);
 	for (prcm = rate_table; prcm->mpu_speed; prcm++) {
arch/arm/mach-omap2/clock.h +22 -0
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
@@ -29,6 +29,7 @@ static int omap2_select_table_rate(struc
 static long omap2_round_to_table_rate(struct clk * clk, unsigned long rate);
 static void omap2_clk_disable(struct clk *clk);
 static void omap2_sys_clk_recalc(struct clk * clk);
+static void omap2_init_clksel_parent(struct clk *clk);
 static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val);
 static u32 omap2_clksel_get_divisor(struct clk *clk);
 static void omap2_dpll_recalc(struct clk *clk);
@@ -690,6 +691,7 @@ static struct clk func_54m_ck = {
 				RATE_FIXED | CM_PLL_SEL1 | RATE_PROPAGATES |
 				PARENT_CONTROLS_CLOCK,
 	.src_offset	= OMAP24XX_54M_SOURCE_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_54M_SOURCE,
 	.clksel		= func_54m_clksel,
@@ -729,6 +731,7 @@ static struct clk func_96m_ck = {
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				RATE_FIXED | RATE_PROPAGATES |
 				PARENT_CONTROLS_CLOCK,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP2430_96M_SOURCE,
 	.clksel		= func_96m_clksel,
@@ -761,6 +764,7 @@ static struct clk func_48m_ck = {
 				RATE_FIXED | CM_PLL_SEL1 | RATE_PROPAGATES |
 				PARENT_CONTROLS_CLOCK,
 	.src_offset	= OMAP24XX_48M_SOURCE_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_48M_SOURCE,
 	.clksel		= func_48m_clksel,
@@ -830,6 +834,7 @@ static struct clk sys_clkout_src = {
 	.src_offset	= OMAP24XX_CLKOUT_SOURCE_SHIFT,
 	.enable_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.enable_bit	= OMAP24XX_CLKOUT_EN_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.clksel_mask	= OMAP24XX_CLKOUT_SOURCE_MASK,
 	.clksel		= common_clkout_src_clksel,
@@ -872,6 +877,7 @@ static struct clk sys_clkout2_src = {
 				RATE_PROPAGATES,
 	.enable_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.enable_bit	= OMAP2420_CLKOUT2_EN_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.clksel_mask	= OMAP2420_CLKOUT2_SOURCE_MASK,
 	.clksel		= common_clkout_src_clksel,
@@ -937,6 +943,7 @@ static struct clk mpu_ck = {	/* Control 
 				ALWAYS_ENABLED | CM_MPU_SEL1 | DELAYED_APP |
 				CONFIG_PARTICIPANT | RATE_PROPAGATES,
 	.rate_offset	= OMAP24XX_CLKSEL_MPU_SHIFT,	/* bits 0-4 */
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL),
 	.clksel_mask	= OMAP24XX_CLKSEL_MPU_MASK,
 	.clksel		= mpu_clksel,
@@ -1431,6 +1438,7 @@ static struct clk dss1_fck = {
 	.enable_bit	= OMAP24XX_EN_DSS1_SHIFT,
 	.rate_offset	= OMAP24XX_CLKSEL_DSS1_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_DSS1_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_CLKSEL_DSS1_MASK,
 	.clksel		= dss1_fck_clksel,
@@ -1462,6 +1470,7 @@ static struct clk dss2_fck = {		/* Alt c
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_DSS2_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_DSS2_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_CLKSEL_DSS2_MASK,
 	.clksel		= dss2_fck_clksel,
@@ -1522,6 +1531,7 @@ static struct clk gpt1_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(WKUP_MOD, OMAP24XX_CM_FCLKEN),	/* Bit0 */
 	.enable_bit	= OMAP24XX_EN_GPT1_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT1_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT1_MASK,
 	.clksel		= gpt_clksel,
@@ -1545,6 +1555,7 @@ static struct clk gpt2_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT2_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT2_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT2_MASK,
 	.clksel		= gpt_clksel,
@@ -1568,6 +1579,7 @@ static struct clk gpt3_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT3_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT3_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT3_MASK,
 	.clksel		= gpt_clksel,
@@ -1591,6 +1603,7 @@ static struct clk gpt4_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT4_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT4_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT4_MASK,
 	.clksel		= gpt_clksel,
@@ -1614,6 +1627,7 @@ static struct clk gpt5_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT5_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT5_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT5_MASK,
 	.clksel		= gpt_clksel,
@@ -1637,6 +1651,7 @@ static struct clk gpt6_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT6_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT6_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT6_MASK,
 	.clksel		= gpt_clksel,
@@ -1660,6 +1675,7 @@ static struct clk gpt7_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT7_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT7_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT7_MASK,
 	.clksel		= gpt_clksel,
@@ -1683,6 +1699,7 @@ static struct clk gpt8_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT8_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT8_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT8_MASK,
 	.clksel		= gpt_clksel,
@@ -1706,6 +1723,7 @@ static struct clk gpt9_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT9_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT9_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT9_MASK,
 	.clksel		= gpt_clksel,
@@ -1729,6 +1747,7 @@ static struct clk gpt10_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT10_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT10_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT10_MASK,
 	.clksel		= gpt_clksel,
@@ -1752,6 +1771,7 @@ static struct clk gpt11_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT11_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT11_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT11_MASK,
 	.clksel		= gpt_clksel,
@@ -1775,6 +1795,7 @@ static struct clk gpt12_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT12_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT12_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT12_MASK,
 	.clksel		= gpt_clksel,
@@ -2308,6 +2329,7 @@ static struct clk vlynq_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP2420_EN_VLYNQ_SHIFT,
 	.src_offset	= OMAP2420_CLKSEL_VLYNQ_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP2420_CLKSEL_VLYNQ_MASK,
 	.clksel		= vlynq_fck_clksel,
#7 lore raw

RE: [PATCH 07/28] omap2 clock: init clksel clock parents to hardwarereality at clock init

Paul,

This will be a nice addition and was hole. Thanks.

Karthik added this type function for OMAP3 on its first go around. Might be worth looking at that also. I don't think he did it via the .init function.

BTW: Do you know if OMAP1 has this function, I don't think it used to.

In OMAP3 right now there has been a strong push to pull out much of the register accesses into a lower layer. This sets up for higher compatibility in the face of multiple changes which may come in some OMAP3 variants and OMAP4. Trying to extend the access macros to account for widely changing implementations but with similar concepts does not provide enough flexibility.

Regards,
Richard W.

Quoted 1 line

Source-selectable clksel clocks have a 'default parent' assigned to

them

Quoted 4 lines

at compile-time. This default parent may or may not match the reality that is configured in the hardware registers by the bootloader. Clock tree
recalculations could be erratic if the struct clk parent field

contents

Quoted 3 lines

don't match the hardware registers.

Resolve this by creating omap2_init_clksel_parent() to read the

hardware

Quoted 1 line

registers and update the struct clk parent field as appropriate for

clksel

Quoted 1 line

clocks. Add an '.init' field to each source-selectable clk structure

so

Quoted 1 line

that the parent is fixed up when the clock is initially registered.

(We

Quoted 1 line

don't do this for clksel clocks that are only rate-selectable, since

they

Quoted 16 lines

only have one possible parent clock.)

---
 arch/arm/mach-omap2/clock.c |   58
++++++++++++++++++++++++++++++++++++++++----
 arch/arm/mach-omap2/clock.h |   22 ++++++++++++++++
 2 files changed, 75 insertions(+), 5 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c static u32 sysclkout_div[] = {1, 2, 4, 8 · line 94

Quoted 2 lines
arch/arm/mach-omap2/clock.c +0 -0
@@ -93,6 +93,54 @@ static u32 sysclkout_div[] = {1, 2, 4, 8
  * Omap2 specific clock functions
 

*-----------------------------------------------------------------------

arch/arm/mach-omap2/clock.c static u32 sysclkout_div[] = {1, 2, 4, 8

Quoted 8 lines
arch/arm/mach-omap2/clock.c +6 -1
--*/
 
+static inline u8 convert_mask_to_shift(u32 mask) {
+	return ffs(mask) - 1;
+}
+
+/**
+ * omap2_init_clksel_parent - set a clksel clk's parent field from

the

Quoted 4 lines

hardware
+ * @clk: OMAP clock struct ptr to use
+ *
+ * Given a pointer to a source-selectable struct clk, read the

hardware

Quoted 1 line

+ * register and determine what its parent is currently set to.

Update

Quoted 9 lines

the
+ * clk->parent field with the appropriate clk ptr.
+ */

arch/arm/mach-omap2/clock.c +6 -0
+static void omap2_init_clksel_parent(struct clk *clk)
+{
+	const struct clksel *clks;
+	const struct clksel_rate *clkr;
+	u32 r, found = 0;
+

arch/arm/mach-omap2/clock.c static u32 sysclkout_div[] = {1, 2, 4, 8

Quoted 10 lines
arch/arm/mach-omap2/clock.c +10 -0
+	if (!clk->clksel)
+		return;
+
+	/* XXX Should be __raw_readl for non-CM 3430 clocks ? */
+	r = cm_read_reg(clk->clksel_reg) & clk->clksel_mask;
+	r >>= convert_mask_to_shift(clk->clksel_mask);
+
+	for (clks = clk->clksel; clks->parent && !found; clks++) {
+		for (clkr = clks->rates; clkr->div && !found; clkr++) {
+			if ((clkr->flags & cpu_mask) && (clkr->val ==

r)) {

arch/arm/mach-omap2/clock.c

Quoted 2 lines
arch/arm/mach-omap2/clock.c +2 -0
+				if (clk->parent != clks->parent) {
+					pr_debug("clock: inited %s

parent "

arch/arm/mach-omap2/clock.c

Quoted 2 lines
arch/arm/mach-omap2/clock.c +2 -0
+						 "to %s (was %s)\n",
+						 clk->name,

clks->parent->name,

arch/arm/mach-omap2/clock.c

Quoted 2 lines
arch/arm/mach-omap2/clock.c +2 -0
+						 ((clk->parent->name) ?
+						  clk->parent->name :

"NULL"));

Quoted 55 lines
arch/arm/mach-omap2/clock.c +19 -5
+					clk->parent = clks->parent;
+				};
+				found = 1;
+			}
+		}
+	}
+
+	if (!found)
+		printk(KERN_ERR "clock: init parent: could not find "
+		       "regval %0x for clock %s\n", r,  clk->name);
+
+	return;
+}
+
 /* Recalculate SYST_CLK */
 static void omap2_sys_clk_recalc(struct clk * clk)
 {
@@ -1193,6 +1241,11 @@ int __init omap2_clk_init(void)
 	struct clk ** clkp;
 	u32 clkrate;
 
+	if (cpu_is_omap242x())
+		cpu_mask = RATE_IN_242X;
+	else if (cpu_is_omap2430())
+		cpu_mask = RATE_IN_243X;
+
 	clk_init(&omap2_clk_functions);
 	omap2_get_crystal_rate(&osc_ck, &sys_ck);
 
@@ -1210,11 +1263,6 @@ int __init omap2_clk_init(void)
 		}
 	}
 
-	if (cpu_is_omap242x())
-		cpu_mask = RATE_IN_242X;
-	else if (cpu_is_omap2430())
-		cpu_mask = RATE_IN_243X;
-
 	/* Check the MPU rate set by bootloader */
 	clkrate = omap2_get_dpll_rate(&dpll_ck);
 	for (prcm = rate_table; prcm->mpu_speed; prcm++) {

Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================

arch/arm/mach-omap2/clock.h +1 -0
@@ -29,6 +29,7 @@ static int omap2_select_table_rate(struc
 static long omap2_round_to_table_rate(struct clk * clk, unsigned long
 rate);
 static void omap2_clk_disable(struct clk *clk);
 static void omap2_sys_clk_recalc(struct clk * clk);
+static void omap2_init_clksel_parent(struct clk *clk);
 static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val);
 static u32 omap2_clksel_get_divisor(struct clk *clk);

static void omap2_dpll_recalc(struct clk *clk);

arch/arm/mach-omap2/clock.h static struct clk func_54m_ck = { · line 691

Quoted 1 line
arch/arm/mach-omap2/clock.h +0 -0
@@ -690,6 +691,7 @@ static struct clk func_54m_ck = {
 				RATE_FIXED | CM_PLL_SEL1 |

RATE_PROPAGATES |

Quoted 15 lines
arch/arm/mach-omap2/clock.h +2 -0
 				PARENT_CONTROLS_CLOCK,
 	.src_offset	= OMAP24XX_54M_SOURCE_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_54M_SOURCE,
 	.clksel		= func_54m_clksel,
@@ -729,6 +731,7 @@ static struct clk func_96m_ck = {
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				RATE_FIXED | RATE_PROPAGATES |
 				PARENT_CONTROLS_CLOCK,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP2430_96M_SOURCE,
 	.clksel		= func_96m_clksel,

arch/arm/mach-omap2/clock.h static struct clk func_48m_ck = { · line 764

Quoted 1 line
arch/arm/mach-omap2/clock.h +0 -0
@@ -761,6 +764,7 @@ static struct clk func_48m_ck = {
 				RATE_FIXED | CM_PLL_SEL1 |

RATE_PROPAGATES |

Quoted 23 lines
arch/arm/mach-omap2/clock.h +3 -0
 				PARENT_CONTROLS_CLOCK,
 	.src_offset	= OMAP24XX_48M_SOURCE_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_48M_SOURCE,
 	.clksel		= func_48m_clksel,
@@ -830,6 +834,7 @@ static struct clk sys_clkout_src = {
 	.src_offset	= OMAP24XX_CLKOUT_SOURCE_SHIFT,
 	.enable_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.enable_bit	= OMAP24XX_CLKOUT_EN_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.clksel_mask	= OMAP24XX_CLKOUT_SOURCE_MASK,
 	.clksel		= common_clkout_src_clksel,
@@ -872,6 +877,7 @@ static struct clk sys_clkout2_src = {
 				RATE_PROPAGATES,
 	.enable_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.enable_bit	= OMAP2420_CLKOUT2_EN_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.clksel_mask	= OMAP2420_CLKOUT2_SOURCE_MASK,
 	.clksel		= common_clkout_src_clksel,

arch/arm/mach-omap2/clock.h static struct clk mpu_ck = { /* Control · line 943

Quoted 1 line
arch/arm/mach-omap2/clock.h +0 -0
@@ -937,6 +943,7 @@ static struct clk mpu_ck = {	/* Control
 				ALWAYS_ENABLED | CM_MPU_SEL1 |

DELAYED_APP |

Quoted 23 lines
arch/arm/mach-omap2/clock.h +3 -0
 				CONFIG_PARTICIPANT | RATE_PROPAGATES,
 	.rate_offset	= OMAP24XX_CLKSEL_MPU_SHIFT,	/* bits 0-4 */
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL),
 	.clksel_mask	= OMAP24XX_CLKSEL_MPU_MASK,
 	.clksel		= mpu_clksel,
@@ -1431,6 +1438,7 @@ static struct clk dss1_fck = {
 	.enable_bit	= OMAP24XX_EN_DSS1_SHIFT,
 	.rate_offset	= OMAP24XX_CLKSEL_DSS1_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_DSS1_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_CLKSEL_DSS1_MASK,
 	.clksel		= dss1_fck_clksel,
@@ -1462,6 +1470,7 @@ static struct clk dss2_fck = {		/* Alt c
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_DSS2_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_DSS2_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_CLKSEL_DSS2_MASK,
 	.clksel		= dss2_fck_clksel,

arch/arm/mach-omap2/clock.h static struct clk gpt1_fck = { · line 1531

Quoted 1 line
arch/arm/mach-omap2/clock.h +0 -0
@@ -1522,6 +1531,7 @@ static struct clk gpt1_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(WKUP_MOD, OMAP24XX_CM_FCLKEN),

/*

Quoted 110 lines

Bit0 */

arch/arm/mach-omap2/clock.h +13 -1
 	.enable_bit	= OMAP24XX_EN_GPT1_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT1_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT1_MASK,
 	.clksel		= gpt_clksel,
@@ -1545,6 +1555,7 @@ static struct clk gpt2_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT2_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT2_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT2_MASK,
 	.clksel		= gpt_clksel,
@@ -1568,6 +1579,7 @@ static struct clk gpt3_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT3_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT3_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT3_MASK,
 	.clksel		= gpt_clksel,
@@ -1591,6 +1603,7 @@ static struct clk gpt4_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT4_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT4_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT4_MASK,
 	.clksel		= gpt_clksel,
@@ -1614,6 +1627,7 @@ static struct clk gpt5_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT5_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT5_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT5_MASK,
 	.clksel		= gpt_clksel,
@@ -1637,6 +1651,7 @@ static struct clk gpt6_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT6_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT6_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT6_MASK,
 	.clksel		= gpt_clksel,
@@ -1660,6 +1675,7 @@ static struct clk gpt7_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT7_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT7_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT7_MASK,
 	.clksel		= gpt_clksel,
@@ -1683,6 +1699,7 @@ static struct clk gpt8_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT8_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT8_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT8_MASK,
 	.clksel		= gpt_clksel,
@@ -1706,6 +1723,7 @@ static struct clk gpt9_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT9_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT9_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT9_MASK,
 	.clksel		= gpt_clksel,
@@ -1729,6 +1747,7 @@ static struct clk gpt10_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT10_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT10_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT10_MASK,
 	.clksel		= gpt_clksel,
@@ -1752,6 +1771,7 @@ static struct clk gpt11_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT11_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT11_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT11_MASK,
 	.clksel		= gpt_clksel,
@@ -1775,6 +1795,7 @@ static struct clk gpt12_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT12_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_GPT12_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT12_MASK,
 	.clksel		= gpt_clksel,
@@ -2308,6 +2329,7 @@ static struct clk vlynq_fck = {
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP2420_EN_VLYNQ_SHIFT,
 	.src_offset	= OMAP2420_CLKSEL_VLYNQ_SHIFT,
+	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP2420_CLKSEL_VLYNQ_MASK,
 	.clksel		= vlynq_fck_clksel,
 
--

_______________________________________________
Linux-omap-open-source mailing list
[email protected]
http://linux.omap.com/mailman/listinfo/linux-omap-open-source

author maintainer
#8 lore raw

RE: [PATCH 07/28] omap2 clock: init clksel clock parents to hardwarereality at clock init

Quoted 1 line · Richard

BTW: Do you know if OMAP1 has this function, I don't think it used to.

No, just took a quick look, it doesn't seem to.

- Paul

author maintainer
#9 lore raw

PATCH 8/28 omap2 clock: convert omap2_clksel_to_divisor and omap2_divisor_to_clksel to use new clksel struct

In reply to Paul Walmsley

Convert omap2_clksel_to_divisor() and omap2_divisor_to_clksel() to use the new struct clksel and struct clksel_rate data. Add omap2_get_clksel_by_parent() utility code, called by both functions, to return the appropriate struct clksel for a given (struct clk, parent struct clk) combination.

---
 arch/arm/mach-omap2/clock.c |  132 +++++++++++++++++++++++++++++++++-----------
 arch/arm/mach-omap2/clock.h |    3 -
 2 files changed, 102 insertions(+), 33 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +100 -32
@@ -497,6 +497,38 @@ static inline u32 omap2_divider_from_tab
 	return ~0;	/* No acceptable divider */
 }
 
+/**
+ * omap2_get_clksel_by_parent - return clksel struct for a given clk & parent
+ * @clk: OMAP struct clk ptr to inspect
+ * @src_clk: OMAP struct clk ptr of the parent clk to search for
+ *
+ * Scan the struct clksel array associated with the clock to find
+ * the element associated with the supplied parent clock address.
+ * Returns a pointer to the struct clksel on success or NULL on error.
+ */
+const static struct clksel *omap2_get_clksel_by_parent(struct clk *clk,
+						       struct clk *src_clk)
+{
+	const struct clksel *clks;
+
+	if (!clk->clksel)
+		return NULL;
+
+	for (clks = clk->clksel; clks->parent; clks++) {
+		if (clks->parent == src_clk)
+			break; /* Found the requested parent */
+	}
+
+	if (!clks->parent) {
+		printk(KERN_ERR "clock: Could not find parent clock %s in "
+		       "clksel array of clock %s\n", src_clk->name,
+		       clk->name);
+		return NULL;
+	}
+
+	return clks;
+}
+
 /*
  * Find divisor for the given clock and target rate.
  *
@@ -683,38 +715,74 @@ static long omap2_round_to_table_rate(st
 	return highest_rate;
 }
 
-/*
- * omap2_clksel_to_divisor() - turn field value into integer divider
+/**
+ * omap2_clksel_to_divisor() - turn clksel field value into integer divider
+ * @clk: OMAP struct clk to use
+ * @field_val: register field value to find
+ *
+ * Given a struct clk of a rate-selectable clksel clock, and a register field
+ * value to search for, find the corresponding clock divisor.  The register
+ * field value should be pre-masked and shifted down so the LSB is at bit 0
+ * before calling.  Returns 0 on error
  */
-static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val)
+static u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val)
 {
-	u32 i;
+	const struct clksel *clks;
+	const struct clksel_rate *clkr;
 
-	if ((div_sel & SRC_RATE_SEL_MASK) == CM_SYSCLKOUT_SEL1) {
-		for (i = 0; i < ARRAY_SIZE(sysclkout_div); i++) {
-			if (field_val == i)
-				return sysclkout_div[i];
-		}
+	clks = omap2_get_clksel_by_parent(clk, clk->parent);
+	if (clks == NULL)
 		return 0;
-	} else
-		return field_val;
+
+	for (clkr = clks->rates; clkr->div; clkr++) {
+		if ((clkr->flags & cpu_mask) && (clkr->val == field_val))
+			break;
+	}
+
+	if (!clkr->div) {
+		printk(KERN_ERR "clock: Could not find fieldval %d for "
+		       "clock %s parent %s\n", field_val, clk->name,
+		       clk->parent->name);
+		return 0;
+	}
+
+	return clkr->div;
 }
 
-/*
- * omap2_divisor_to_clksel() - turn integer divider into field value
+/**
+ * omap2_divisor_to_clksel() - turn clksel integer divisor into a field value
+ * @clk: OMAP struct clk to use
+ * @div: integer divisor to search for
+ *
+ * Given a struct clk of a rate-selectable clksel clock, and a clock divisor,
+ * find the corresponding register field value.  The return register value is
+ * the value before left-shifting.  Returns 0xffffffff on error
  */
-static u32 omap2_divisor_to_clksel(u32 div_sel, u32 div)
+static u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
 {
-	u32 i;
+	const struct clksel *clks;
+	const struct clksel_rate *clkr;
+
+	/* should never happen */
+	WARN_ON(div == 0);
 
-	if ((div_sel & SRC_RATE_SEL_MASK) == CM_SYSCLKOUT_SEL1) {
-		for (i = 0; i < ARRAY_SIZE(sysclkout_div); i++) {
-			if (div == sysclkout_div[i])
-				return i;
-		}
-		return ~0;
-	} else
-		return div;
+	clks = omap2_get_clksel_by_parent(clk, clk->parent);
+	if (clks == NULL)
+		return 0;
+
+	for (clkr = clks->rates; clkr->div; clkr++) {
+		if ((clkr->flags & cpu_mask) && (clkr->div == div))
+			break;
+	}
+
+	if (!clkr->div) {
+		printk(KERN_ERR "clock: Could not find divisor %d for "
+		       "clock %s parent %s\n", div, clk->name,
+		       clk->parent->name);
+		return 0;
+	}
+
+	return clkr->val;
 }
 
 /*
@@ -800,13 +868,15 @@ static void __iomem *omap2_get_clksel(u3
 }
 
 
-/*
- * Return divider to be applied to parent clock.
- * Return 0 on error.
+/**
+ * omap2_clksel_get_divisor - get current divider applied to parent clock.
+ * @clk: OMAP struct clk to use.
+ *
+ * Returns the integer divisor upon success or 0 on error.
  */
 static u32 omap2_clksel_get_divisor(struct clk *clk)
 {
-	u32 div, field_mask, field_val;
+	u32 field_mask, field_val;
 	void __iomem *div_addr;
 
 	div_addr = omap2_get_clksel(&field_mask, clk);
@@ -814,11 +884,9 @@ static u32 omap2_clksel_get_divisor(stru
 		return 0;
 
 	field_val = cm_read_reg(div_addr) & field_mask;
-	field_val >>= clk->rate_offset;
-
-	div = omap2_clksel_to_divisor(clk->flags, field_val);
+	field_val >>= convert_mask_to_shift(field_mask);
 
-	return div;
+	return omap2_clksel_to_divisor(clk, field_val);
 }
 
 /* Set the clock rate for a clock source */
@@ -844,7 +912,7 @@ static int omap2_clk_set_rate(struct clk
 		if (div_addr == 0)
 			return ret;
 
-		field_val = omap2_divisor_to_clksel(clk->flags, new_div);
+		field_val = omap2_divisor_to_clksel(clk, new_div);
 		if (field_val == ~0)
 			return ret;
 
arch/arm/mach-omap2/clock.h +2 -1
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
@@ -30,8 +30,9 @@ static long omap2_round_to_table_rate(st
 static void omap2_clk_disable(struct clk *clk);
 static void omap2_sys_clk_recalc(struct clk * clk);
 static void omap2_init_clksel_parent(struct clk *clk);
-static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val);
 static u32 omap2_clksel_get_divisor(struct clk *clk);
+static u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val);
+static u32 omap2_divisor_to_clksel(struct clk *clk, u32 div);
 static void omap2_dpll_recalc(struct clk *clk);
 static void omap2_fixed_divisor_recalc(struct clk *clk);
 
author maintainer
#10 lore raw

PATCH 9/28 omap2 clock: convert omap2_clksel_round_rate to use new clksel struct

In reply to Paul Walmsley

Convert omap2_clksel_round_rate() to use the new clksel struct data.

---
 arch/arm/mach-omap2/clock.c |   98 ++++++++++++++++++++++----------------------
 1 file changed, 50 insertions(+), 48 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +50 -48
@@ -87,8 +87,6 @@ static struct clk *vclk;
 static struct clk *sclk;
 static u8 cpu_mask;
 
-static u32 sysclkout_div[] = {1, 2, 4, 8, 16};
-
 /*-------------------------------------------------------------------------
  * Omap2 specific clock functions
  *-------------------------------------------------------------------------*/
@@ -529,62 +527,66 @@ const static struct clksel *omap2_get_cl
 	return clks;
 }
 
-/*
- * Find divisor for the given clock and target rate.
+/**
+ * omap2_clksel_round_rate - find divisor for the given clock and target rate.
+ * @clk: OMAP struct clk to use
+ * @target_rate: desired clock rate
+ * @new_div: ptr to where we should store the divisor
  *
+ * Finds 'best' divider value in an array based on the source and target
+ * rates.  The divider array must be sorted with smallest divider first.
  * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT,
  * they are only settable as part of virtual_prcm set.
+ *
+ * Returns the rounded clock rate or returns 0xffffffff on error.
  */
-static u32 omap2_clksel_round_rate(struct clk *tclk, u32 target_rate,
-	u32 *new_div)
+static u32 omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate,
+				   u32 *new_div)
 {
-	u32 gfx_div[] = {2, 3, 4};
-	u32 dss1_div[] = {1, 2, 3, 4, 5, 6, 8, 9, 12, 16};
-	u32 vlynq_div[] = {1, 2, 3, 4, 6, 8, 9, 12, 16, 18};
-	u32 best_div = ~0, asize = 0;
-	u32 *div_array = NULL;
+	unsigned long test_rate;
+	const struct clksel *clks;
+	const struct clksel_rate *clkr;
+	u32 last_div = 0;
 
-	switch (tclk->flags & SRC_RATE_SEL_MASK) {
-	case CM_GFX_SEL1:
-		asize = ARRAY_SIZE(gfx_div);
-		div_array = gfx_div;
-		break;
-	case CM_PLL_SEL1:
-		return omap2_dpll_round_rate(target_rate);
-	case CM_SYSCLKOUT_SEL1:
-		asize = ARRAY_SIZE(sysclkout_div);
-		div_array = sysclkout_div;
-		break;
-	case CM_CORE_SEL1:
-		if (tclk == &dss1_fck) {
-			if (tclk->parent == &core_ck) {
-				asize = ARRAY_SIZE(dss1_div);
-				div_array = dss1_div;
-			} else {
-				*new_div = 0; /* fixed clk */
-				return(tclk->parent->rate);
-			}
-		} else if ((tclk == &vlynq_fck) && cpu_is_omap2420()) {
-			if (tclk->parent == &core_ck) {
-				asize = ARRAY_SIZE(vlynq_div);
-				div_array = vlynq_div;
-			} else {
-				*new_div = 0; /* fixed clk */
-				return (tclk->parent->rate);
-			}
-		}
-		break;
+	printk(KERN_INFO "clock: clksel_round_rate for %s target_rate %ld\n",
+	       clk->name, target_rate);
+
+	*new_div = 1;
+
+	clks = omap2_get_clksel_by_parent(clk, clk->parent);
+	if (clks == NULL)
+		return ~0;
+
+	for (clkr = clks->rates; clkr->div; clkr++) {
+		if (!(clkr->flags & cpu_mask))
+		    continue;
+
+		/* Sanity check */
+		if (clkr->div <= last_div)
+			printk(KERN_ERR "clock: clksel_rate table not sorted "
+			       "for clock %s", clk->name);
+
+		last_div = clkr->div;
+
+		test_rate = clk->parent->rate / clkr->div;
+
+		if (test_rate <= target_rate)
+			break; /* found it */
 	}
 
-	best_div = omap2_divider_from_table(asize, div_array,
-					    tclk->parent->rate, target_rate);
-	if (best_div == ~0) {
-		*new_div = 1;
-		return best_div; /* signal error */
+	if (!clkr->div) {
+		printk(KERN_ERR "clock: Could not find divisor for target "
+		       "rate %ld for clock %s parent %s\n", target_rate,
+		       clk->name, clk->parent->name);
+		return ~0;
 	}
 
-	*new_div = best_div;
-	return (tclk->parent->rate / best_div);
+	*new_div = clkr->div;
+
+	printk(KERN_INFO "clock: new_div = %d, new_rate = %ld\n", *new_div,
+	       (clk->parent->rate / clkr->div));
+
+	return (clk->parent->rate / clkr->div);
 }
 
 /* Given a clock and a rate apply a clock specific rounding function */
author maintainer
#11 lore raw

PATCH 10/28 omap2 clock: convert omap2_get_clksel to use new clksel struct

In reply to Paul Walmsley

Convert omap2_get_clksel to use new struct clksel and struct clksel_rate data. Also fix its parameter order to conform with the rest of the clock framework functions (i.e., struct clk first).

---
 arch/arm/mach-omap2/clock.c |   92 ++++++--------------------------------------
 1 file changed, 13 insertions(+), 79 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +13 -79
@@ -787,89 +787,23 @@ static u32 omap2_divisor_to_clksel(struc
 	return clkr->val;
 }
 
-/*
- * Returns the CLKSEL divider register value
+/**
+ * omap2_get_clksel - find clksel register addr & field mask for a clk
+ * @clk: struct clk to use
+ * @field_mask: ptr to u32 to store the register field mask
+ *
+ * Returns the address of the clksel register upon success or NULL on error.
  */
-static void __iomem *omap2_get_clksel(u32 *field_mask, struct clk *clk)
+static void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask)
 {
-	u32 div_off, mask = ~0;
-	void __iomem *div_addr = 0;
+	if (unlikely((clk->clksel_reg == 0) || (clk->clksel_mask == 0)))
+		return NULL;
 
-	div_off = clk->rate_offset;
+	*field_mask = clk->clksel_mask;
 
-	switch (clk->flags & SRC_RATE_SEL_MASK) {
-	case CM_MPU_SEL1:
-		div_addr = OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL);
-		mask = OMAP24XX_CLKSEL_MPU_MASK;
-		break;
-	case CM_DSP_SEL1:
-		div_addr = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL);
-		if (cpu_is_omap2420()) {
-			if (div_off == OMAP24XX_CLKSEL_DSP_SHIFT)
-				mask = OMAP24XX_CLKSEL_DSP_MASK;
-			else if (div_off == OMAP2420_CLKSEL_IVA_SHIFT)
-				mask = OMAP2420_CLKSEL_IVA_MASK;
-			else if (div_off == OMAP24XX_CLKSEL_DSP_IF_SHIFT)
-				mask = OMAP24XX_CLKSEL_DSP_IF_MASK;
-		} else if (cpu_is_omap2430()) {
-			if (div_off == OMAP24XX_CLKSEL_DSP_SHIFT)
-				mask = OMAP24XX_CLKSEL_DSP_MASK;
-			else if (div_off == OMAP24XX_CLKSEL_DSP_IF_SHIFT)
-				mask = OMAP24XX_CLKSEL_DSP_IF_MASK;
-		}
-	case CM_GFX_SEL1:
-		div_addr = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL);
-		if (div_off == OMAP_CLKSEL_GFX_SHIFT)
-			mask = OMAP_CLKSEL_GFX_MASK;
-		break;
-	case CM_MODEM_SEL1:
-		div_addr = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_CLKSEL);
-		if (div_off == OMAP2430_CLKSEL_MDM_SHIFT)
-			mask = OMAP2430_CLKSEL_MDM_MASK;
-		break;
-	case CM_SYSCLKOUT_SEL1:
-		div_addr = OMAP24XX_PRCM_CLKOUT_CTRL;
-		if (div_off == OMAP24XX_CLKOUT_DIV_SHIFT)
-			mask = OMAP24XX_CLKOUT_DIV_MASK;
-		else if (div_off == OMAP2420_CLKOUT2_DIV_SHIFT)
-			mask = OMAP2420_CLKOUT2_DIV_MASK;
-		break;
-	case CM_CORE_SEL1:
-		div_addr = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1);
-		switch (div_off) {
-		case OMAP24XX_CLKSEL_L3_SHIFT:
-			mask = OMAP24XX_CLKSEL_L3_MASK;
-			break;
-		case OMAP24XX_CLKSEL_L4_SHIFT:
-			mask = OMAP24XX_CLKSEL_L4_MASK;
-			break;
-		case OMAP24XX_CLKSEL_DSS1_SHIFT:
-			mask = OMAP24XX_CLKSEL_DSS1_MASK;
-			break;
-		case OMAP24XX_CLKSEL_DSS2_SHIFT:
-			mask = OMAP24XX_CLKSEL_DSS2_MASK;
-			break;
-		case OMAP2420_CLKSEL_VLYNQ_SHIFT:
-			mask = OMAP2420_CLKSEL_VLYNQ_MASK;
-			break;
-		case OMAP24XX_CLKSEL_SSI_SHIFT:
-			mask = OMAP24XX_CLKSEL_SSI_MASK;
-			break;
-		case OMAP24XX_CLKSEL_USB_SHIFT:
-			mask = OMAP24XX_CLKSEL_USB_MASK;
-			break;
-		}
-	}
-
-	if (unlikely((mask == ~0) || (div_addr == 0)))
-		return 0;
-
-	*field_mask = mask;
-
-	return div_addr;
+	return clk->clksel_reg;
 }
 
-
 /**
  * omap2_clksel_get_divisor - get current divider applied to parent clock.
  * @clk: OMAP struct clk to use.
@@ -881,7 +815,7 @@ static u32 omap2_clksel_get_divisor(stru
 	u32 field_mask, field_val;
 	void __iomem *div_addr;
 
-	div_addr = omap2_get_clksel(&field_mask, clk);
+	div_addr = omap2_get_clksel(clk, &field_mask);
 	if (div_addr == 0)
 		return 0;
 
@@ -910,7 +844,7 @@ static int omap2_clk_set_rate(struct clk
 		if (validrate != rate)
 			return ret;
 
-		div_addr = omap2_get_clksel(&field_mask, clk);
+		div_addr = omap2_get_clksel(clk, &field_mask);
 		if (div_addr == 0)
 			return ret;
 
author maintainer
#12 lore raw

PATCH 11/28 omap2 clock: convert omap2_clksel_get_src_field() to use new clksel struct

In reply to Paul Walmsley

Convert omap2_clksel_get_src_field() to use new struct clksel and struct clksel_rate data.

---
 arch/arm/mach-omap2/clock.c |  206 +++++---------------------------------------
 1 file changed, 25 insertions(+), 181 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +25 -181
@@ -46,38 +46,11 @@
 #define EN_APLL_STOPPED			0
 #define EN_APLL_LOCKED			3
 
-/* CM_{CLKSEL2_CORE,CLKSEL_WKUP}.CLKSEL_GPT* options (24XX) */
-#define CLKSEL_GPT_32K			0
-#define CLKSEL_GPT_SYSCLK		1
-#define CLKSEL_GPT_EXTALTCLK		2
-
-/* CM_CLKSEL1_CORE.CLKSEL_DSS1 options (24XX) */
-#define CLKSEL_DSS1_SYSCLK		0
-#define CLKSEL_DSS1_CORECLK_16		0x10
-
-/* CM_CLKSEL1_CORE.CLKSEL_DSS2 options (24XX) */
-#define CLKSEL_DSS2_SYSCLK		0
-#define CLKSEL_DSS2_48MHZ		1
-
 /* CM_CLKSEL1_PLL.APLLS_CLKIN options (24XX) */
 #define APLLS_CLKIN_19_2MHZ		0
 #define APLLS_CLKIN_13MHZ		2
 #define APLLS_CLKIN_12MHZ		3
 
-/* CM_CLKSEL1_PLL.54M_SOURCE options (24XX) */
-#define CLK_54M_SOURCE_APLL		0
-#define CLK_54M_SOURCE_EXTALTCLK	1
-
-/* CM_CLKSEL1_PLL.48M_SOURCE options (24XX) */
-#define CLK_48M_SOURCE_APLL		0
-#define CLK_48M_SOURCE_EXTALTCLK	1
-
-/* PRCM_CLKOUT_CTRL.CLKOUT_SOURCE options (2420) */
-#define CLKOUT_SOURCE_CORE_CLK		0
-#define CLKOUT_SOURCE_SYS_CLK		1
-#define CLKOUT_SOURCE_96M_CLK		2
-#define CLKOUT_SOURCE_54M_CLK		3
-
 #define MAX_PLL_LOCK_WAIT		100000
 
 //#define DOWN_VARIABLE_DPLL 1			/* Experimental */
@@ -473,28 +446,6 @@ static void omap2_clksel_recalc(struct c
 		propagate_rate(clk);
 }
 
-/*
- * Finds best divider value in an array based on the source and target
- * rates. The divider array must be sorted with smallest divider first.
- */
-static inline u32 omap2_divider_from_table(u32 size, u32 *div_array,
-					   u32 src_rate, u32 tgt_rate)
-{
-	int i, test_rate;
-
-	if (div_array == NULL)
-		return ~1;
-
-	for (i = 0; i < size; i++) {
-		test_rate = src_rate / *div_array;
-		if (test_rate <= tgt_rate)
-			return *div_array;
-		++div_array;
-	}
-
-	return ~0;	/* No acceptable divider */
-}
-
 /**
  * omap2_get_clksel_by_parent - return clksel struct for a given clk & parent
  * @clk: OMAP struct clk ptr to inspect
@@ -875,151 +826,44 @@ static int omap2_clk_set_rate(struct clk
 	return ret;
 }
 
-/* Converts encoded control register address into a full address */
+/*
+ * Converts encoded control register address into a full address
+ * On error, *src_addr will be returned as 0.
+ */
 static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
 				      struct clk *src_clk, u32 *field_mask,
 				      struct clk *clk, u32 *parent_div)
 {
-	u32 val = ~0, mask = 0;
-	void __iomem *src_reg_addr = 0;
-	u32 reg_offset;
+	const struct clksel *clks;
+	const struct clksel_rate *clkr;
 
 	*parent_div = 0;
-	reg_offset = clk->src_offset;
+	*src_addr = 0;
 
-	/* Find target control register.*/
-	switch (clk->flags & SRC_RATE_SEL_MASK) {
-	case CM_CORE_SEL1:
-		src_reg_addr = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1);
-		if (reg_offset == OMAP24XX_CLKSEL_DSS2_SHIFT) {
-			mask = OMAP24XX_CLKSEL_DSS2_MASK;
-			if (src_clk == &sys_ck)
-				val = CLKSEL_DSS2_SYSCLK;
-			else if (src_clk == &func_48m_ck)
-				val = CLKSEL_DSS2_48MHZ;
-			else
-				WARN_ON(1); /* unknown src_clk */
-		} else if (reg_offset == OMAP24XX_CLKSEL_DSS1_SHIFT) {
-			mask = OMAP24XX_CLKSEL_DSS1_MASK;
-			if (src_clk == &sys_ck) {
-				val = CLKSEL_DSS1_SYSCLK;
-			} else if (src_clk == &core_ck) {
-				val = CLKSEL_DSS1_CORECLK_16;
-				*parent_div = 16;
-			} else {
-				WARN_ON(1); /* unknown src clk */
-			}
-		} else if ((reg_offset == OMAP2420_CLKSEL_VLYNQ_SHIFT) &&
-			   cpu_is_omap2420()) {
-			mask = OMAP2420_CLKSEL_VLYNQ_MASK;
-			if (src_clk == &func_96m_ck) {
-				val = CLKSEL_VLYNQ_96MHZ;
-			} else if (src_clk == &core_ck) {
-				val = CLKSEL_VLYNQ_CORECLK_16;
-				*parent_div = 16;
-			} else {
-				WARN_ON(1); /* unknown src_clk */
-			}
-		} else {
-			WARN_ON(1); /* unknown reg_offset */
-		}
-		break;
-	case CM_CORE_SEL2:
-		WARN_ON(reg_offset < OMAP24XX_CLKSEL_GPT2_SHIFT ||
-			reg_offset > OMAP24XX_CLKSEL_GPT12_SHIFT);
-		src_reg_addr = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2);
-		mask = OMAP24XX_CLKSEL_GPT2_MASK;
-		mask <<= (reg_offset - OMAP24XX_CLKSEL_GPT2_SHIFT);
-		if (src_clk == &func_32k_ck)
-			val = CLKSEL_GPT_32K;
-		else if (src_clk == &sys_ck)
-			val = CLKSEL_GPT_SYSCLK;
-		else if (src_clk == &alt_ck)
-			val = CLKSEL_GPT_EXTALTCLK;
-		else
-			WARN_ON(1);  /* unknown src_clk */
-		break;
-	case CM_WKUP_SEL1:
-		WARN_ON(reg_offset != 0); /* unknown reg_offset */
-		src_reg_addr = OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL);
-		mask = OMAP24XX_CLKSEL_GPT1_MASK;
-		if (src_clk == &func_32k_ck)
-			val = CLKSEL_GPT_32K;
-		else if (src_clk == &sys_ck)
-			val = CLKSEL_GPT_SYSCLK;
-		else if (src_clk == &alt_ck)
-			val = CLKSEL_GPT_EXTALTCLK;
-		else
-			WARN_ON(1); /* unknown src_clk */
-		break;
-	case CM_PLL_SEL1:
-		src_reg_addr = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1);
-		if (reg_offset == 0x3) {
-			mask = OMAP24XX_48M_SOURCE;
-			if (src_clk == &apll96_ck)
-				val = CLK_48M_SOURCE_APLL;
-			else if (src_clk == &alt_ck)
-				val = CLK_48M_SOURCE_EXTALTCLK;
-			else
-				WARN_ON(1); /* unknown src_clk */
-		}
-		else if (reg_offset == 0x5) {
-			mask = OMAP24XX_54M_SOURCE;
-			if (src_clk == &apll54_ck)
-				val = CLK_54M_SOURCE_APLL;
-			else if (src_clk == &alt_ck)
-				val = CLK_54M_SOURCE_EXTALTCLK;
-			else
-				WARN_ON(1); /* unknown src_clk */
-		} else {
-			WARN_ON(1); /* unknown reg_offset */
-		}
-		break;
-	case CM_PLL_SEL2:
-		WARN_ON(reg_offset != 0);
-		src_reg_addr = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL2);
-		mask = OMAP24XX_CORE_CLK_SRC_MASK;
-		if (src_clk == &func_32k_ck)
-			val = CORE_CLK_SRC_32K;
-		else if (src_clk == &dpll_ck)
-			val = CORE_CLK_SRC_DPLL_X2;
-		else
-			WARN_ON(1); /* unknown src_clk */
-		break;
-	case CM_SYSCLKOUT_SEL1:
-		src_reg_addr = OMAP24XX_PRCM_CLKOUT_CTRL;
-
-		if (reg_offset == OMAP24XX_CLKOUT_SOURCE_SHIFT) {
-			mask = OMAP24XX_CLKOUT_SOURCE_MASK;
-		} else if (reg_offset == OMAP2420_CLKOUT2_SOURCE_SHIFT) {
-			mask = OMAP2420_CLKOUT2_SOURCE_MASK;
-		} else {
-			WARN_ON(1); /* unknown reg_offset */
-		}
+	clks = omap2_get_clksel_by_parent(clk, src_clk);
+	if (clks == NULL)
+		return 0;
 
-		if (src_clk == &dpll_ck)
-			val = 0;
-		else if (src_clk == &sys_ck)
-			val = 1;
-		else if (src_clk == &func_96m_ck)
-			val = 2;
-		else if (src_clk == &func_54m_ck)
-			val = 3;
-		else
-			WARN_ON(1); /* unknown src_clk */
-		break;
+	for (clkr = clks->rates; clkr->div; clkr++) {
+		if (clkr->flags & (cpu_mask | DEFAULT_RATE))
+			break; /* Found the default rate for this platform */
 	}
 
-	if (val == ~0)			/* Catch errors in offset */
-		*src_addr = 0;
-	else
-		*src_addr = src_reg_addr;
+	if (!clkr->div) {
+		printk(KERN_ERR "clock: Could not find default rate for "
+		       "clock %s parent %s\n", clk->name,
+		       src_clk->parent->name);
+		return 0;
+	}
 
-	WARN_ON(mask == 0);
+	/* Should never happen.  Add a clksel mask to the struct clk. */
+	WARN_ON(clk->clksel_mask == 0);
 
-	*field_mask = mask;
+	*field_mask = clk->clksel_mask;
+	*src_addr = clk->clksel_reg;
+	*parent_div = clkr->div;
 
-	return val;
+	return clkr->val;
 }
 
 static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
author maintainer
#13 lore raw

PATCH 12/28 omap2 clock: stop using clk->src_offset in omap2_clk_set_rate()

In reply to Paul Walmsley

Stop using clk->rate_offset in omap2_clk_set_rate(); use what we get from the clksel code instead.

---
 arch/arm/mach-omap2/clock.c |    9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +3 -6
@@ -780,17 +780,14 @@ static u32 omap2_clksel_get_divisor(stru
 static int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
 {
 	int ret = -EINVAL;
-	u32 div_off, field_mask, field_val, reg_val, validrate;
-	u32 new_div = 0;
+	u32 field_mask, field_val, reg_val, new_div = 0;
+	unsigned long validrate;
 	void __iomem *div_addr;
 
 	if (!(clk->flags & CONFIG_PARTICIPANT) && (clk->flags & RATE_CKCTL)) {
 		if (clk == &dpll_ck)
 			return omap2_reprogram_dpll(clk, rate);
 
-		/* Isolate control register */
-		div_off = clk->rate_offset;
-
 		validrate = omap2_clksel_round_rate(clk, rate, &new_div);
 		if (validrate != rate)
 			return ret;
@@ -805,7 +802,7 @@ static int omap2_clk_set_rate(struct clk
 
 		reg_val = cm_read_reg(div_addr);
 		reg_val &= ~field_mask;
-		reg_val |= (field_val << div_off);
+		reg_val |= (field_val << convert_mask_to_shift(field_mask));
 		cm_write_reg(reg_val, div_addr);
 		wmb();
 		clk->rate = clk->parent->rate / new_div;
author maintainer
#14 lore raw

PATCH 13/28 omap2 clock: stop using clk->src_offset in omap2_clk_set_parent()

In reply to Paul Walmsley

Stop using clk->src_offset in omap2_clk_set_parent(); use what we get from the clksel code instead.

---
 arch/arm/mach-omap2/clock.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +4 -1
@@ -884,7 +884,7 @@ static int omap2_clk_set_parent(struct c
 
 	/* Set new source value (previous dividers if any in effect) */
 	reg_val = __raw_readl(src_addr) & ~field_mask;
-	reg_val |= (field_val << clk->src_offset);
+	reg_val |= (field_val << convert_mask_to_shift(field_mask));
 	__raw_writel(reg_val, src_addr);
 	wmb();
 
@@ -905,6 +905,9 @@ static int omap2_clk_set_parent(struct c
 	if (parent_div > 0)
 		clk->rate /= parent_div;
 
+	pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
+		 clk->name, clk->parent->name, clk->rate);
+
 	if (unlikely(clk->flags & RATE_PROPAGATES))
 		propagate_rate(clk);
 
author maintainer
#15 lore raw

PATCH 14/28 omap2 clock: clean out old code from omap2_clksel_recalc()

In reply to Paul Walmsley

Get rid of now-obsolete code in omap2_clksel_recalc().

---
 arch/arm/mach-omap2/clock.c |   24 ++++++++----------------
 1 file changed, 8 insertions(+), 16 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +8 -16
@@ -8,6 +8,10 @@
  *  Cleaned up and modified to use omap shared clock framework by
  *  Tony Lindgren <[email protected]>
  *
+ *  Copyright (C) 2007 Texas Instruments, Inc.
+ *  Copyright (C) 2007 Nokia Corporation
+ *  Paul Walmsley
+ *
  *  Based on omap1 clock.c, Copyright (C) 2004 - 2005 Nokia corporation
  *  Written by Tuukka Tikkanen <[email protected]>
  *
@@ -38,10 +42,6 @@
 
 #undef DEBUG
 
-/* CM_CLKSEL1_CORE.CLKSEL_VLYNQ options (2420) */
-#define CLKSEL_VLYNQ_96MHZ		0
-#define CLKSEL_VLYNQ_CORECLK_16		0x10
-
 /* CM_CLKEN_PLL.EN_{54,96}M_PLL options (24XX) */
 #define EN_APLL_STOPPED			0
 #define EN_APLL_LOCKED			3
@@ -420,19 +420,9 @@ static void omap2_dpll_recalc(struct clk
  */
 static void omap2_clksel_recalc(struct clk * clk)
 {
-	u32 clksel1_core, div = 0;
+	u32 div = 0;
 
-	clksel1_core = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1);
-
-	if ((clk == &dss1_fck) &&
-	    (clksel1_core & OMAP24XX_CLKSEL_DSS1_MASK) == 0) {
-		div = 1;
-	}
-
-	if ((clk == &vlynq_fck) && cpu_is_omap2420() &&
-	    (clksel1_core & OMAP2420_CLKSEL_VLYNQ_MASK) == CLKSEL_VLYNQ_96MHZ) {
-		div = 1;
-	}
+	pr_debug("clock: recalc'ing clksel clk %s\n", clk->name);
 
 	div = omap2_clksel_get_divisor(clk);
 	if (div == 0)
@@ -442,6 +432,8 @@ static void omap2_clksel_recalc(struct c
 		return;
 	clk->rate = clk->parent->rate / div;
 
+	pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div);
+
 	if (unlikely(clk->flags & RATE_PROPAGATES))
 		propagate_rate(clk);
 }
author maintainer
#16 lore raw

PATCH 15/28 omap2 clock: convert remaining clksel clocks to use omap2_clksel_recalc

In reply to Paul Walmsley

This completes the transition to struct clksel/clksel_rate by converting the remaining clksel clocks to call omap2_clksel_recalc() on rate recalculation. Also remove RATE_FIXED from some clocks that can now recalculate their own rates correctly via clksel.

---
 arch/arm/mach-omap2/clock.h |   56 +++++++++++++++++++++-----------------------
 1 file changed, 27 insertions(+), 29 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.h
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================

arch/arm/mach-omap2/clock.h +27 -29
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/arm/mach-omap24xx/clock.h
+ *  linux/arch/arm/mach-omap2/clock.h
  *
  *  Copyright (C) 2005 Texas Instruments Inc.
  *  Richard Woodruff <[email protected]>
@@ -9,6 +9,10 @@
  *  Written by Tuukka Tikkanen <[email protected]>
  *  Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
  *
+ *  Copyright (C) 2007 Texas Instruments, Inc.
+ *  Copyright (C) 2007 Nokia Corporation
+ *  Revised by Paul Walmsley
+ *
  * 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.
@@ -687,16 +691,15 @@ static const struct clksel func_54m_clks
 static struct clk func_54m_ck = {
 	.name		= "func_54m_ck",
 	.parent		= &apll54_ck,	/* can also be alt_clk */
-	.rate		= 54000000,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_FIXED | CM_PLL_SEL1 | RATE_PROPAGATES |
+				CM_PLL_SEL1 | RATE_PROPAGATES |
 				PARENT_CONTROLS_CLOCK,
 	.src_offset	= OMAP24XX_54M_SOURCE_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_54M_SOURCE,
 	.clksel		= func_54m_clksel,
-	.recalc		= &propagate_rate,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk core_ck = {
@@ -728,15 +731,13 @@ static const struct clksel func_96m_clks
 static struct clk func_96m_ck = {
 	.name		= "func_96m_ck",
 	.parent		= &apll96_ck,
-	.rate		= 96000000,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_FIXED | RATE_PROPAGATES |
-				PARENT_CONTROLS_CLOCK,
+				RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP2430_96M_SOURCE,
 	.clksel		= func_96m_clksel,
-	.recalc		= &propagate_rate,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 /* func_48m_ck */
@@ -760,16 +761,15 @@ static const struct clksel func_48m_clks
 static struct clk func_48m_ck = {
 	.name		= "func_48m_ck",
 	.parent		= &apll96_ck,	 /* 96M or Alt */
-	.rate		= 48000000,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_FIXED | CM_PLL_SEL1 | RATE_PROPAGATES |
+				CM_PLL_SEL1 | RATE_PROPAGATES |
 				PARENT_CONTROLS_CLOCK,
 	.src_offset	= OMAP24XX_48M_SOURCE_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_48M_SOURCE,
 	.clksel		= func_48m_clksel,
-	.recalc		= &propagate_rate,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk func_12m_ck = {
@@ -828,7 +828,6 @@ static const struct clksel common_clkout
 static struct clk sys_clkout_src = {
 	.name		= "sys_clkout_src",
 	.parent		= &func_54m_ck,
-	.rate		= 54000000,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				CM_SYSCLKOUT_SEL1 | RATE_CKCTL |
 				RATE_PROPAGATES,
@@ -839,7 +838,7 @@ static struct clk sys_clkout_src = {
 	.clksel_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.clksel_mask	= OMAP24XX_CLKOUT_SOURCE_MASK,
 	.clksel		= common_clkout_src_clksel,
-	.recalc		= &propagate_rate,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static const struct clksel_rate common_clkout_rates[] = {
@@ -882,7 +881,7 @@ static struct clk sys_clkout2_src = {
 	.clksel_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.clksel_mask	= OMAP2420_CLKOUT2_SOURCE_MASK,
 	.clksel		= common_clkout_src_clksel,
-	.recalc		= &propagate_rate,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static const struct clksel sys_clkout2_clksel[] = {
@@ -900,7 +899,7 @@ static struct clk sys_clkout2 = {
 	.clksel_mask	= OMAP2420_CLKOUT2_DIV_MASK,
 	.clksel		= sys_clkout2_clksel,
 	.rate_offset	= OMAP2420_CLKOUT2_DIV_SHIFT,
-	.recalc		= &propagate_rate,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk emul_ck = {
@@ -1466,8 +1465,7 @@ static struct clk dss2_fck = {		/* Alt c
 	.name		= "dss2_fck",
 	.parent		= &sys_ck,		/* fixed at sys_ck or 48MHz */
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_CKCTL | CM_CORE_SEL1 | RATE_FIXED |
-				DELAYED_APP,
+				RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_DSS2_SHIFT,
 	.src_offset	= OMAP24XX_CLKSEL_DSS2_SHIFT,
@@ -1536,7 +1534,7 @@ static struct clk gpt1_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT1_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk gpt2_ick = {
@@ -1560,7 +1558,7 @@ static struct clk gpt2_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT2_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk gpt3_ick = {
@@ -1584,7 +1582,7 @@ static struct clk gpt3_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT3_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk gpt4_ick = {
@@ -1608,7 +1606,7 @@ static struct clk gpt4_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT4_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk gpt5_ick = {
@@ -1632,7 +1630,7 @@ static struct clk gpt5_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT5_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk gpt6_ick = {
@@ -1656,7 +1654,7 @@ static struct clk gpt6_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT6_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk gpt7_ick = {
@@ -1680,7 +1678,7 @@ static struct clk gpt7_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT7_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk gpt8_ick = {
@@ -1704,7 +1702,7 @@ static struct clk gpt8_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT8_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk gpt9_ick = {
@@ -1728,7 +1726,7 @@ static struct clk gpt9_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT9_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk gpt10_ick = {
@@ -1752,7 +1750,7 @@ static struct clk gpt10_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT10_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk gpt11_ick = {
@@ -1776,7 +1774,7 @@ static struct clk gpt11_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT11_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk gpt12_ick = {
@@ -1800,7 +1798,7 @@ static struct clk gpt12_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT12_MASK,
 	.clksel		= gpt_clksel,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk mcbsp1_ick = {
author maintainer
#17 lore raw

PATCH 16/28 omap2 clock: remove all {src, rate}_offset fields from struct clk

In reply to Paul Walmsley

src_offset and rate_offset are no longer used in OMAP2 clock framework after the struct clksel/struct clksel_rate additions. Remove these fields from clock.h and #ifdef out those fields for OMAP24XX compiles.

---
 arch/arm/mach-omap2/clock.c       |    4 ++--
 arch/arm/mach-omap2/clock.h       |   38 +-------------------------------------
 include/asm-arm/arch-omap/clock.h |    5 +++--
 3 files changed, 6 insertions(+), 41 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +2 -2
@@ -121,7 +121,7 @@ static void omap2_sys_clk_recalc(struct 
 		div = prm_read_reg(OMAP24XX_PRCM_CLKSRC_CTRL);
 		/* Test if ext clk divided by 1 or 2 */
 		div &= OMAP_SYSCLKDIV_MASK;
-		div >>= clk->rate_offset;
+		div >>= OMAP_SYSCLKDIV_SHIFT;
 		clk->rate = (clk->parent->rate / div);
 	}
 	propagate_rate(clk);
@@ -1032,7 +1032,7 @@ static void __init omap2_get_crystal_rat
 
 	div = prm_read_reg(OMAP24XX_PRCM_CLKSRC_CTRL);
 	div &= OMAP_SYSCLKDIV_MASK;
-	div >>= sys->rate_offset;
+	div >>= OMAP_SYSCLKDIV_SHIFT;
 
 	osc->rate = sclk * div;
 	sys->rate = sclk;
arch/arm/mach-omap2/clock.h +1 -37
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
@@ -11,7 +11,7 @@
  *
  *  Copyright (C) 2007 Texas Instruments, Inc.
  *  Copyright (C) 2007 Nokia Corporation
- *  Revised by Paul Walmsley
+ *  Paul Walmsley
  *
  * 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
@@ -615,7 +615,6 @@ static struct clk sys_ck = {		/* (*12, *
 	.rate		= 13000000,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
-	.rate_offset	= OMAP_SYSCLKDIV_SHIFT, /* sysclkdiv 1 or 2, already handled or no boot */
 	.recalc		= &omap2_sys_clk_recalc,
 };
 
@@ -694,7 +693,6 @@ static struct clk func_54m_ck = {
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				CM_PLL_SEL1 | RATE_PROPAGATES |
 				PARENT_CONTROLS_CLOCK,
-	.src_offset	= OMAP24XX_54M_SOURCE_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_54M_SOURCE,
@@ -764,7 +762,6 @@ static struct clk func_48m_ck = {
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				CM_PLL_SEL1 | RATE_PROPAGATES |
 				PARENT_CONTROLS_CLOCK,
-	.src_offset	= OMAP24XX_48M_SOURCE_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_48M_SOURCE,
@@ -831,7 +828,6 @@ static struct clk sys_clkout_src = {
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				CM_SYSCLKOUT_SEL1 | RATE_CKCTL |
 				RATE_PROPAGATES,
-	.src_offset	= OMAP24XX_CLKOUT_SOURCE_SHIFT,
 	.enable_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.enable_bit	= OMAP24XX_CLKOUT_EN_SHIFT,
 	.init		= &omap2_init_clksel_parent,
@@ -864,7 +860,6 @@ static struct clk sys_clkout = {
 	.clksel_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.clksel_mask	= OMAP24XX_CLKOUT_DIV_MASK,
 	.clksel		= sys_clkout_clksel,
-	.rate_offset	= OMAP24XX_CLKOUT_DIV_SHIFT,
 	.recalc		= &omap2_clksel_recalc,
 };
 
@@ -872,7 +867,6 @@ static struct clk sys_clkout = {
 static struct clk sys_clkout2_src = {
 	.name		= "sys_clkout2_src",
 	.parent		= &func_54m_ck,
-	.src_offset	= OMAP2420_CLKOUT2_SOURCE_SHIFT,
 	.flags		= CLOCK_IN_OMAP242X | CM_SYSCLKOUT_SEL1 | RATE_CKCTL |
 				RATE_PROPAGATES,
 	.enable_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
@@ -898,7 +892,6 @@ static struct clk sys_clkout2 = {
 	.clksel_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.clksel_mask	= OMAP2420_CLKOUT2_DIV_MASK,
 	.clksel		= sys_clkout2_clksel,
-	.rate_offset	= OMAP2420_CLKOUT2_DIV_SHIFT,
 	.recalc		= &omap2_clksel_recalc,
 };
 
@@ -942,7 +935,6 @@ static struct clk mpu_ck = {	/* Control 
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_CKCTL |
 				ALWAYS_ENABLED | CM_MPU_SEL1 | DELAYED_APP |
 				CONFIG_PARTICIPANT | RATE_PROPAGATES,
-	.rate_offset	= OMAP24XX_CLKSEL_MPU_SHIFT,	/* bits 0-4 */
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL),
 	.clksel_mask	= OMAP24XX_CLKSEL_MPU_MASK,
@@ -983,7 +975,6 @@ static struct clk iva2_1_fck = {
 	.flags		= CLOCK_IN_OMAP243X | RATE_CKCTL | CM_DSP_SEL1 |
 				DELAYED_APP | RATE_PROPAGATES |
 				CONFIG_PARTICIPANT,
-	.rate_offset	= OMAP24XX_CLKSEL_DSP_SHIFT,
 	.enable_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP24XX_CM_FCLKEN),
 	.enable_bit	= OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
@@ -1010,7 +1001,6 @@ static struct clk iva2_1_ick = {
 	.parent		= &iva2_1_fck,
 	.flags		= CLOCK_IN_OMAP243X | RATE_CKCTL | CM_DSP_SEL1 |
 				DELAYED_APP | CONFIG_PARTICIPANT,
-	.rate_offset	= OMAP24XX_CLKSEL_DSP_IF_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
 	.clksel_mask	= OMAP24XX_CLKSEL_DSP_IF_MASK,
 	.clksel		= iva2_1_ick_clksel,
@@ -1044,7 +1034,6 @@ static struct clk dsp_fck = {
 	.parent		= &core_ck,
 	.flags		= CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1 |
 			DELAYED_APP | CONFIG_PARTICIPANT | RATE_PROPAGATES,
-	.rate_offset	= OMAP24XX_CLKSEL_DSP_SHIFT,
 	.enable_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP24XX_CM_FCLKEN),
 	.enable_bit	= OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
@@ -1070,7 +1059,6 @@ static struct clk dsp_ick = {
 	.parent		= &core_ck,
 	.flags		= CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1 |
 				DELAYED_APP | CONFIG_PARTICIPANT,
-	.rate_offset	= OMAP24XX_CLKSEL_DSP_IF_SHIFT,
 	.enable_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_ICLKEN),
 	.enable_bit	= OMAP2420_EN_DSP_IPI_SHIFT,		/* for ipi */
 	.clksel_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
@@ -1100,7 +1088,6 @@ static struct clk iva1_ifck = {
 	.parent		= &core_ck,
 	.flags		= CLOCK_IN_OMAP242X | CM_DSP_SEL1 | RATE_CKCTL |
 			CONFIG_PARTICIPANT | RATE_PROPAGATES | DELAYED_APP,
-	.rate_offset	= OMAP2420_CLKSEL_IVA_SHIFT,
 	.enable_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP24XX_CM_FCLKEN),
 	.enable_bit	= OMAP2420_EN_IVA_COP_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
@@ -1162,7 +1149,6 @@ static struct clk core_l3_ck = {	/* Used
 				RATE_CKCTL | ALWAYS_ENABLED | CM_CORE_SEL1 |
 				DELAYED_APP | CONFIG_PARTICIPANT |
 				RATE_PROPAGATES,
-	.rate_offset	= OMAP24XX_CLKSEL_L3_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_CLKSEL_L3_MASK,
 	.clksel		= core_l3_clksel,
@@ -1190,7 +1176,6 @@ static struct clk usb_l4_ick = {	/* FS-U
 				CONFIG_PARTICIPANT,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
 	.enable_bit	= OMAP24XX_EN_USB_SHIFT,
-	.rate_offset	= OMAP24XX_CLKSEL_USB_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_CLKSEL_USB_MASK,
 	.clksel		= usb_l4_ick_clksel,
@@ -1231,7 +1216,6 @@ static struct clk ssi_ssr_sst_fck = {
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_CLKSEL_SSI_MASK,
 	.clksel		= ssi_ssr_sst_fck_clksel,
-	.rate_offset	= OMAP24XX_CLKSEL_SSI_SHIFT,
 	.recalc		= &omap2_clksel_recalc,
 };
 
@@ -1272,7 +1256,6 @@ static struct clk gfx_3d_fck = {
 				RATE_CKCTL | CM_GFX_SEL1,
 	.enable_reg	= OMAP_CM_REGADDR(GFX_MOD, OMAP24XX_CM_FCLKEN),
 	.enable_bit	= OMAP24XX_EN_3D_SHIFT,
-	.rate_offset	= OMAP_CLKSEL_GFX_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
 	.clksel_mask	= OMAP_CLKSEL_GFX_MASK,
 	.clksel		= gfx_fck_clksel,
@@ -1286,7 +1269,6 @@ static struct clk gfx_2d_fck = {
 				RATE_CKCTL | CM_GFX_SEL1,
 	.enable_reg	= OMAP_CM_REGADDR(GFX_MOD, OMAP24XX_CM_FCLKEN),
 	.enable_bit	= OMAP24XX_EN_2D_SHIFT,
-	.rate_offset	= OMAP_CLKSEL_GFX_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
 	.clksel_mask	= OMAP_CLKSEL_GFX_MASK,
 	.clksel		= gfx_fck_clksel,
@@ -1327,7 +1309,6 @@ static struct clk mdm_ick = {		/* used b
 	.parent		= &core_ck,
 	.flags		= CLOCK_IN_OMAP243X | RATE_CKCTL | CM_MODEM_SEL1 |
 				DELAYED_APP | CONFIG_PARTICIPANT,
-	.rate_offset	= OMAP2430_CLKSEL_MDM_SHIFT,
 	.enable_reg	= OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_ICLKEN),
 	.enable_bit	= OMAP2430_CM_ICLKEN_MDM_EN_MDM_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_CLKSEL),
@@ -1369,7 +1350,6 @@ static struct clk l4_ck = {		/* used bot
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				RATE_CKCTL | ALWAYS_ENABLED | CM_CORE_SEL1 |
 				DELAYED_APP | RATE_PROPAGATES,
-	.rate_offset	= OMAP24XX_CLKSEL_L4_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_CLKSEL_L4_MASK,
 	.clksel		= l4_clksel,
@@ -1436,8 +1416,6 @@ static struct clk dss1_fck = {
 				RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_DSS1_SHIFT,
-	.rate_offset	= OMAP24XX_CLKSEL_DSS1_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_DSS1_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_CLKSEL_DSS1_MASK,
@@ -1468,7 +1446,6 @@ static struct clk dss2_fck = {		/* Alt c
 				RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_DSS2_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_DSS2_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_CLKSEL_DSS2_MASK,
@@ -1529,7 +1506,6 @@ static struct clk gpt1_fck = {
 				CM_WKUP_SEL1,
 	.enable_reg	= OMAP_CM_REGADDR(WKUP_MOD, OMAP24XX_CM_FCLKEN),	/* Bit0 */
 	.enable_bit	= OMAP24XX_EN_GPT1_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT1_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT1_MASK,
@@ -1553,7 +1529,6 @@ static struct clk gpt2_fck = {
 				CM_CORE_SEL2,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT2_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT2_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT2_MASK,
@@ -1577,7 +1552,6 @@ static struct clk gpt3_fck = {
 				CM_CORE_SEL2,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT3_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT3_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT3_MASK,
@@ -1601,7 +1575,6 @@ static struct clk gpt4_fck = {
 				CM_CORE_SEL2,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT4_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT4_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT4_MASK,
@@ -1625,7 +1598,6 @@ static struct clk gpt5_fck = {
 				CM_CORE_SEL2,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT5_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT5_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT5_MASK,
@@ -1649,7 +1621,6 @@ static struct clk gpt6_fck = {
 				CM_CORE_SEL2,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT6_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT6_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT6_MASK,
@@ -1673,7 +1644,6 @@ static struct clk gpt7_fck = {
 				CM_CORE_SEL2,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT7_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT7_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT7_MASK,
@@ -1697,7 +1667,6 @@ static struct clk gpt8_fck = {
 				CM_CORE_SEL2,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT8_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT8_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT8_MASK,
@@ -1721,7 +1690,6 @@ static struct clk gpt9_fck = {
 					CM_CORE_SEL2,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT9_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT9_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT9_MASK,
@@ -1745,7 +1713,6 @@ static struct clk gpt10_fck = {
 					CM_CORE_SEL2,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT10_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT10_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT10_MASK,
@@ -1769,7 +1736,6 @@ static struct clk gpt11_fck = {
 					CM_CORE_SEL2,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT11_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT11_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT11_MASK,
@@ -1793,7 +1759,6 @@ static struct clk gpt12_fck = {
 					CM_CORE_SEL2,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_GPT12_SHIFT,
-	.src_offset	= OMAP24XX_CLKSEL_GPT12_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT12_MASK,
@@ -2327,7 +2292,6 @@ static struct clk vlynq_fck = {
 	.flags		= CLOCK_IN_OMAP242X  | RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP2420_EN_VLYNQ_SHIFT,
-	.src_offset	= OMAP2420_CLKSEL_VLYNQ_SHIFT,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP2420_CLKSEL_VLYNQ_MASK,
include/asm-arm/arch-omap/clock.h +3 -2
Index: linux-omap/include/asm-arm/arch-omap/clock.h
===================================================================
@@ -41,8 +41,6 @@ struct clk {
 	__u32			flags;
 	void __iomem		*enable_reg;
 	__u8			enable_bit;
-	__u8			rate_offset;
-	__u8			src_offset;
 	__s8			usecount;
 	void			(*recalc)(struct clk *);
 	int			(*set_rate)(struct clk *, unsigned long);
@@ -55,6 +53,9 @@ struct clk {
 	void __iomem		*clksel_reg;
 	u32			clksel_mask;
 	const struct clksel	*clksel;
+#else
+	__u8			rate_offset;
+	__u8			src_offset;
 #endif
 };
 
author maintainer
#18 lore raw

PATCH 17/28 omap2 clock: use the struct clk round_rate field for clksel rate rounding code

In reply to Paul Walmsley

The OMAP clock framework struct clk contains a field, .round_rate, that is intended to contain a function pointer to rate rounding code. Take advantage of it by converting all clksel clocks' round_rate field to point to omap2_clksel_round_rate(). Rename the existing omap2_clksel_round_rate() to omap2_clksel_round_rate_div(), to signify that it returns divisor information as well, and set up omap2_clksel_round_rate() as a wrapper for the clock framework to use. Simplify omap2_clk_round_rate() accordingly.

---
 arch/arm/mach-omap2/clock.c |   42 ++++++++++++++++++++++++++++++------------
 arch/arm/mach-omap2/clock.h |   21 +++++++++++++++++++++
 2 files changed, 51 insertions(+), 12 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +30 -12
@@ -471,7 +471,7 @@ const static struct clksel *omap2_get_cl
 }
 
 /**
- * omap2_clksel_round_rate - find divisor for the given clock and target rate.
+ * omap2_clksel_round_rate_div - find divisor for the given clock and rate
  * @clk: OMAP struct clk to use
  * @target_rate: desired clock rate
  * @new_div: ptr to where we should store the divisor
@@ -483,15 +483,16 @@ const static struct clksel *omap2_get_cl
  *
  * Returns the rounded clock rate or returns 0xffffffff on error.
  */
-static u32 omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate,
-				   u32 *new_div)
+static u32 omap2_clksel_round_rate_div(struct clk *clk,
+				       unsigned long target_rate,
+				       u32 *new_div)
 {
 	unsigned long test_rate;
 	const struct clksel *clks;
 	const struct clksel_rate *clkr;
 	u32 last_div = 0;
 
-	printk(KERN_INFO "clock: clksel_round_rate for %s target_rate %ld\n",
+	printk(KERN_INFO "clock: clksel_round_rate_div: %s target_rate %ld\n",
 	       clk->name, target_rate);
 
 	*new_div = 1;
@@ -532,20 +533,37 @@ static u32 omap2_clksel_round_rate(struc
 	return (clk->parent->rate / clkr->div);
 }
 
-/* Given a clock and a rate apply a clock specific rounding function */
-static long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
+/**
+ * omap2_clksel_round_rate - find rounded rate for the given clock and rate
+ * @clk: OMAP struct clk to use
+ * @target_rate: desired clock rate
+ *
+ * Compatibility wrapper for OMAP clock framework
+ * Finds best target rate based on the source clock and possible dividers.
+ * rates. The divider array must be sorted with smallest divider first.
+ * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT,
+ * they are only settable as part of virtual_prcm set.
+ *
+ * Returns the rounded clock rate or returns 0xffffffff on error.
+ */
+static long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
 {
-	u32 new_div = 0;
+	u32 new_div;
 
-	if (clk->flags & RATE_FIXED)
-		return clk->rate;
+	return omap2_clksel_round_rate_div(clk, target_rate, &new_div);
+}
 
-	if (clk->flags & RATE_CKCTL)
-		return omap2_clksel_round_rate(clk, rate, &new_div);
 
+/* Given a clock and a rate apply a clock specific rounding function */
+static long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
+{
 	if (clk->round_rate != 0)
 		return clk->round_rate(clk, rate);
 
+	if (clk->flags & RATE_FIXED)
+		printk(KERN_ERR "clock: generic omap2_clk_round_rate called "
+		       "on fixed-rate clock %s\n", clk->name);
+
 	return clk->rate;
 }
 
@@ -780,7 +798,7 @@ static int omap2_clk_set_rate(struct clk
 		if (clk == &dpll_ck)
 			return omap2_reprogram_dpll(clk, rate);
 
-		validrate = omap2_clksel_round_rate(clk, rate, &new_div);
+		validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
 		if (validrate != rate)
 			return ret;
 
arch/arm/mach-omap2/clock.h +21 -0
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
@@ -39,6 +39,8 @@ static u32 omap2_clksel_to_divisor(struc
 static u32 omap2_divisor_to_clksel(struct clk *clk, u32 div);
 static void omap2_dpll_recalc(struct clk *clk);
 static void omap2_fixed_divisor_recalc(struct clk *clk);
+static long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
+
 
 /* Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated.
  * xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,CM_CLKSEL_DSP
@@ -736,6 +738,7 @@ static struct clk func_96m_ck = {
 	.clksel_mask	= OMAP2430_96M_SOURCE,
 	.clksel		= func_96m_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 /* func_48m_ck */
@@ -767,6 +770,7 @@ static struct clk func_48m_ck = {
 	.clksel_mask	= OMAP24XX_48M_SOURCE,
 	.clksel		= func_48m_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 static struct clk func_12m_ck = {
@@ -861,6 +865,7 @@ static struct clk sys_clkout = {
 	.clksel_mask	= OMAP24XX_CLKOUT_DIV_MASK,
 	.clksel		= sys_clkout_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 /* In 2430, new in 2420 ES2 */
@@ -940,6 +945,7 @@ static struct clk mpu_ck = {	/* Control 
 	.clksel_mask	= OMAP24XX_CLKSEL_MPU_MASK,
 	.clksel		= mpu_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate     = &omap2_clksel_round_rate
 };
 
 /*
@@ -981,6 +987,7 @@ static struct clk iva2_1_fck = {
 	.clksel_mask	= OMAP24XX_CLKSEL_DSP_MASK,
 	.clksel		= iva2_1_fck_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 /* iva2_1_ick */
@@ -1005,6 +1012,8 @@ static struct clk iva2_1_ick = {
 	.clksel_mask	= OMAP24XX_CLKSEL_DSP_IF_MASK,
 	.clksel		= iva2_1_ick_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
+
 };
 
 /*
@@ -1040,6 +1049,7 @@ static struct clk dsp_fck = {
 	.clksel_mask	= OMAP24XX_CLKSEL_DSP_MASK,
 	.clksel		= dsp_fck_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 static const struct clksel_rate dsp_ick_core_rates[] = {
@@ -1094,6 +1104,7 @@ static struct clk iva1_ifck = {
 	.clksel_mask	= OMAP2420_CLKSEL_IVA_MASK,
 	.clksel		= iva1_ifck_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 /* IVA1 mpu/int/i/f clocks are /2 of parent */
@@ -1153,6 +1164,7 @@ static struct clk core_l3_ck = {	/* Used
 	.clksel_mask	= OMAP24XX_CLKSEL_L3_MASK,
 	.clksel		= core_l3_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 /* usb_l4_ick */
@@ -1180,6 +1192,7 @@ static struct clk usb_l4_ick = {	/* FS-U
 	.clksel_mask	= OMAP24XX_CLKSEL_USB_MASK,
 	.clksel		= usb_l4_ick_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 /*
@@ -1217,6 +1230,7 @@ static struct clk ssi_ssr_sst_fck = {
 	.clksel_mask	= OMAP24XX_CLKSEL_SSI_MASK,
 	.clksel		= ssi_ssr_sst_fck_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 /*
@@ -1260,6 +1274,7 @@ static struct clk gfx_3d_fck = {
 	.clksel_mask	= OMAP_CLKSEL_GFX_MASK,
 	.clksel		= gfx_fck_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 static struct clk gfx_2d_fck = {
@@ -1273,6 +1288,7 @@ static struct clk gfx_2d_fck = {
 	.clksel_mask	= OMAP_CLKSEL_GFX_MASK,
 	.clksel		= gfx_fck_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 static struct clk gfx_ick = {
@@ -1315,6 +1331,7 @@ static struct clk mdm_ick = {		/* used b
 	.clksel_mask	= OMAP2430_CLKSEL_MDM_MASK,
 	.clksel		= mdm_ick_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 static struct clk mdm_osc_ck = {
@@ -1354,6 +1371,7 @@ static struct clk l4_ck = {		/* used bot
 	.clksel_mask	= OMAP24XX_CLKSEL_L4_MASK,
 	.clksel		= l4_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 static struct clk ssi_l4_ick = {
@@ -1421,6 +1439,7 @@ static struct clk dss1_fck = {
 	.clksel_mask	= OMAP24XX_CLKSEL_DSS1_MASK,
 	.clksel		= dss1_fck_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 static const struct clksel_rate dss2_fck_sys_rates[] = {
@@ -1511,6 +1530,7 @@ static struct clk gpt1_fck = {
 	.clksel_mask	= OMAP24XX_CLKSEL_GPT1_MASK,
 	.clksel		= gpt_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 static struct clk gpt2_ick = {
@@ -2297,6 +2317,7 @@ static struct clk vlynq_fck = {
 	.clksel_mask	= OMAP2420_CLKSEL_VLYNQ_MASK,
 	.clksel		= vlynq_fck_clksel,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate
 };
 
 static struct clk sdrc_ick = {
author maintainer
#19 lore raw

PATCH 19/28 omap2 clock: drop RATE_CKCTL from all OMAP2 clocks

In reply to Paul Walmsley

RATE_CKCTL is no longer meaningful in the OMAP2 clock framework, so, drop it from all clocks. We keep the flag around since it's still used by OMAP1.

---
 arch/arm/mach-omap2/clock.h |   45 ++++++++++++++++++++------------------------
 1 file changed, 21 insertions(+), 24 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.h
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================

arch/arm/mach-omap2/clock.h +21 -24
@@ -641,8 +641,7 @@ static struct clk dpll_ck = {
 	.name		= "dpll_ck",
 	.parent		= &sys_ck,		/* Can be func_32k also */
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_PROPAGATES | RATE_CKCTL | CM_PLL_SEL1 |
-				ALWAYS_ENABLED,
+				RATE_PROPAGATES | CM_PLL_SEL1 |	ALWAYS_ENABLED,
 	.recalc		= &omap2_dpll_recalc,
 	.set_rate	= &omap2_reprogram_dpll,
 };
@@ -834,8 +833,7 @@ static struct clk sys_clkout_src = {
 	.name		= "sys_clkout_src",
 	.parent		= &func_54m_ck,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				CM_SYSCLKOUT_SEL1 | RATE_CKCTL |
-				RATE_PROPAGATES,
+				CM_SYSCLKOUT_SEL1 | RATE_PROPAGATES,
 	.enable_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.enable_bit	= OMAP24XX_CLKOUT_EN_SHIFT,
 	.init		= &omap2_init_clksel_parent,
@@ -865,8 +863,7 @@ static struct clk sys_clkout = {
 	.name		= "sys_clkout",
 	.parent		= &sys_clkout_src,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				CM_SYSCLKOUT_SEL1 | RATE_CKCTL |
-				PARENT_CONTROLS_CLOCK,
+				CM_SYSCLKOUT_SEL1 | PARENT_CONTROLS_CLOCK,
 	.clksel_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.clksel_mask	= OMAP24XX_CLKOUT_DIV_MASK,
 	.clksel		= sys_clkout_clksel,
@@ -879,7 +876,7 @@ static struct clk sys_clkout = {
 static struct clk sys_clkout2_src = {
 	.name		= "sys_clkout2_src",
 	.parent		= &func_54m_ck,
-	.flags		= CLOCK_IN_OMAP242X | CM_SYSCLKOUT_SEL1 | RATE_CKCTL |
+	.flags		= CLOCK_IN_OMAP242X | CM_SYSCLKOUT_SEL1 |
 				RATE_PROPAGATES,
 	.enable_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.enable_bit	= OMAP2420_CLKOUT2_EN_SHIFT,
@@ -901,7 +898,7 @@ static const struct clksel sys_clkout2_c
 static struct clk sys_clkout2 = {
 	.name		= "sys_clkout2",
 	.parent		= &sys_clkout2_src,
-	.flags		= CLOCK_IN_OMAP242X | CM_SYSCLKOUT_SEL1 | RATE_CKCTL |
+	.flags		= CLOCK_IN_OMAP242X | CM_SYSCLKOUT_SEL1 |
 				PARENT_CONTROLS_CLOCK,
 	.clksel_reg	= OMAP24XX_PRCM_CLKOUT_CTRL,
 	.clksel_mask	= OMAP2420_CLKOUT2_DIV_MASK,
@@ -948,7 +945,7 @@ static const struct clksel mpu_clksel[] 
 static struct clk mpu_ck = {	/* Control cpu */
 	.name		= "mpu_ck",
 	.parent		= &core_ck,
-	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | RATE_CKCTL |
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				ALWAYS_ENABLED | CM_MPU_SEL1 | DELAYED_APP |
 				CONFIG_PARTICIPANT | RATE_PROPAGATES,
 	.init		= &omap2_init_clksel_parent,
@@ -990,7 +987,7 @@ static const struct clksel iva2_1_fck_cl
 static struct clk iva2_1_fck = {
 	.name		= "iva2_1_fck",
 	.parent		= &core_ck,
-	.flags		= CLOCK_IN_OMAP243X | RATE_CKCTL | CM_DSP_SEL1 |
+	.flags		= CLOCK_IN_OMAP243X | CM_DSP_SEL1 |
 				DELAYED_APP | RATE_PROPAGATES |
 				CONFIG_PARTICIPANT,
 	.enable_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP24XX_CM_FCLKEN),
@@ -1019,7 +1016,7 @@ static const struct clksel iva2_1_ick_cl
 static struct clk iva2_1_ick = {
 	.name		= "iva2_1_ick",
 	.parent		= &iva2_1_fck,
-	.flags		= CLOCK_IN_OMAP243X | RATE_CKCTL | CM_DSP_SEL1 |
+	.flags		= CLOCK_IN_OMAP243X | CM_DSP_SEL1 |
 				DELAYED_APP | CONFIG_PARTICIPANT,
 	.clksel_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
 	.clksel_mask	= OMAP24XX_CLKSEL_DSP_IF_MASK,
@@ -1054,7 +1051,7 @@ static const struct clksel dsp_fck_clkse
 static struct clk dsp_fck = {
 	.name		= "dsp_fck",
 	.parent		= &core_ck,
-	.flags		= CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1 |
+	.flags		= CLOCK_IN_OMAP242X | CM_DSP_SEL1 |
 			DELAYED_APP | CONFIG_PARTICIPANT | RATE_PROPAGATES,
 	.enable_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP24XX_CM_FCLKEN),
 	.enable_bit	= OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT,
@@ -1081,7 +1078,7 @@ static const struct clksel dsp_ick_clkse
 static struct clk dsp_ick = {
 	.name		= "dsp_ick",	 /* apparently ipi and isp */
 	.parent		= &core_ck,
-	.flags		= CLOCK_IN_OMAP242X | RATE_CKCTL | CM_DSP_SEL1 |
+	.flags		= CLOCK_IN_OMAP242X | CM_DSP_SEL1 |
 				DELAYED_APP | CONFIG_PARTICIPANT,
 	.enable_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_ICLKEN),
 	.enable_bit	= OMAP2420_EN_DSP_IPI_SHIFT,		/* for ipi */
@@ -1110,7 +1107,7 @@ static const struct clksel iva1_ifck_clk
 static struct clk iva1_ifck = {
 	.name		= "iva1_ifck",
 	.parent		= &core_ck,
-	.flags		= CLOCK_IN_OMAP242X | CM_DSP_SEL1 | RATE_CKCTL |
+	.flags		= CLOCK_IN_OMAP242X | CM_DSP_SEL1 |
 			CONFIG_PARTICIPANT | RATE_PROPAGATES | DELAYED_APP,
 	.enable_reg	= OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, OMAP24XX_CM_FCLKEN),
 	.enable_bit	= OMAP2420_EN_IVA_COP_SHIFT,
@@ -1172,7 +1169,7 @@ static struct clk core_l3_ck = {	/* Used
 	.name		= "core_l3_ck",
 	.parent		= &core_ck,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_CKCTL | ALWAYS_ENABLED | CM_CORE_SEL1 |
+				ALWAYS_ENABLED | CM_CORE_SEL1 |
 				DELAYED_APP | CONFIG_PARTICIPANT |
 				RATE_PROPAGATES,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
@@ -1200,7 +1197,7 @@ static struct clk usb_l4_ick = {	/* FS-U
 	.name		= "usb_l4_ick",
 	.parent		= &core_l3_ck,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP |
+				CM_CORE_SEL1 | DELAYED_APP |
 				CONFIG_PARTICIPANT,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
 	.enable_bit	= OMAP24XX_EN_USB_SHIFT,
@@ -1240,7 +1237,7 @@ static struct clk ssi_ssr_sst_fck = {
 	.name		= "ssi_fck",
 	.parent		= &core_ck,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
+				CM_CORE_SEL1 | DELAYED_APP,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),	/* bit 1 */
 	.enable_bit	= OMAP24XX_EN_SSI_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
@@ -1285,7 +1282,7 @@ static struct clk gfx_3d_fck = {
 	.name		= "gfx_3d_fck",
 	.parent		= &core_l3_ck,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_CKCTL | CM_GFX_SEL1,
+				CM_GFX_SEL1,
 	.enable_reg	= OMAP_CM_REGADDR(GFX_MOD, OMAP24XX_CM_FCLKEN),
 	.enable_bit	= OMAP24XX_EN_3D_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
@@ -1300,7 +1297,7 @@ static struct clk gfx_2d_fck = {
 	.name		= "gfx_2d_fck",
 	.parent		= &core_l3_ck,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_CKCTL | CM_GFX_SEL1,
+				CM_GFX_SEL1,
 	.enable_reg	= OMAP_CM_REGADDR(GFX_MOD, OMAP24XX_CM_FCLKEN),
 	.enable_bit	= OMAP24XX_EN_2D_SHIFT,
 	.clksel_reg	= OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
@@ -1343,7 +1340,7 @@ static const struct clksel mdm_ick_clkse
 static struct clk mdm_ick = {		/* used both as a ick and fck */
 	.name		= "mdm_ick",
 	.parent		= &core_ck,
-	.flags		= CLOCK_IN_OMAP243X | RATE_CKCTL | CM_MODEM_SEL1 |
+	.flags		= CLOCK_IN_OMAP243X | CM_MODEM_SEL1 |
 				DELAYED_APP | CONFIG_PARTICIPANT,
 	.enable_reg	= OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_ICLKEN),
 	.enable_bit	= OMAP2430_CM_ICLKEN_MDM_EN_MDM_SHIFT,
@@ -1386,7 +1383,7 @@ static struct clk l4_ck = {		/* used bot
 	.name		= "l4_ck",
 	.parent		= &core_l3_ck,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_CKCTL | ALWAYS_ENABLED | CM_CORE_SEL1 |
+				ALWAYS_ENABLED | CM_CORE_SEL1 |
 				DELAYED_APP | RATE_PROPAGATES,
 	.clksel_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
 	.clksel_mask	= OMAP24XX_CLKSEL_L4_MASK,
@@ -1453,7 +1450,7 @@ static struct clk dss1_fck = {
 	.name		= "dss1_fck",
 	.parent		= &core_ck,		/* Core or sys */
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
+				CM_CORE_SEL1 | DELAYED_APP,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_DSS1_SHIFT,
 	.init		= &omap2_init_clksel_parent,
@@ -1485,7 +1482,7 @@ static struct clk dss2_fck = {		/* Alt c
 	.name		= "dss2_fck",
 	.parent		= &sys_ck,		/* fixed at sys_ck or 48MHz */
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
+				CM_CORE_SEL1 | DELAYED_APP,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_DSS2_SHIFT,
 	.init		= &omap2_init_clksel_parent,
@@ -2333,7 +2330,7 @@ static const struct clksel vlynq_fck_clk
 static struct clk vlynq_fck = {
 	.name		= "vlynq_fck",
 	.parent		= &func_96m_ck,
-	.flags		= CLOCK_IN_OMAP242X  | RATE_CKCTL | CM_CORE_SEL1 | DELAYED_APP,
+	.flags		= CLOCK_IN_OMAP242X | CM_CORE_SEL1 | DELAYED_APP,
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP2420_EN_VLYNQ_SHIFT,
 	.init		= &omap2_init_clksel_parent,
author maintainer
#20 lore raw

PATCH 20/28 omap2 clock: remove *_SEL* clock flags

In reply to Paul Walmsley

We no longer need the *_SEL* clock flags with the struct clksel conversion, so we get rid of them. This frees up 10 clock flag bits.

---
 arch/arm/mach-omap2/clock.c       |    4 -
 arch/arm/mach-omap2/clock.h       |  111 +++++++++++++-------------------------
 include/asm-arm/arch-omap/clock.h |   11 ---
 3 files changed, 41 insertions(+), 85 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +2 -2
@@ -890,7 +890,7 @@ static int omap2_clk_set_parent(struct c
 	if (unlikely(clk->flags & CONFIG_PARTICIPANT))
 		return -EINVAL;
 
-	if (unlikely(!(clk->flags & SRC_SEL_MASK)))
+	if (!clk->clksel)
 		return -EINVAL;
 
 	field_val = omap2_clksel_get_src_field(&src_addr, new_parent,
@@ -918,7 +918,7 @@ static int omap2_clk_set_parent(struct c
 
 	clk->parent = new_parent;
 
-	/* SRC_RATE_SEL_MASK clocks follow their parents rates.*/
+	/* CLKSEL clocks follow their parents' rates, divided by a divisor */
 	clk->rate = new_parent->rate;
 
 	if (parent_div > 0)
arch/arm/mach-omap2/clock.h +38 -73

327 lines not on this page · raw message

include/asm-arm/arch-omap/clock.h +1 -10
Index: linux-omap/include/asm-arm/arch-omap/clock.h
===================================================================
@@ -95,16 +95,7 @@ extern int clk_get_usecount(struct clk *
 #define CLOCK_NO_IDLE_PARENT	(1 << 8)
 #define DELAYED_APP		(1 << 9)	/* Delay application of clock */
 #define CONFIG_PARTICIPANT	(1 << 10)	/* Fundamental clock */
-#define CM_MPU_SEL1		(1 << 11)	/* Domain divider/source */
-#define CM_DSP_SEL1		(1 << 12)
-#define CM_GFX_SEL1		(1 << 13)
-#define CM_MODEM_SEL1		(1 << 14)
-#define CM_CORE_SEL1		(1 << 15)	/* Sets divider for many */
-#define CM_CORE_SEL2		(1 << 16)	/* sets parent for GPT */
-#define CM_WKUP_SEL1		(1 << 17)
-#define CM_PLL_SEL1		(1 << 18)
-#define CM_PLL_SEL2		(1 << 19)
-#define CM_SYSCLKOUT_SEL1	(1 << 20)
+/* bits 11-20 are currently free */
 #define CLOCK_IN_OMAP310	(1 << 21)
 #define CLOCK_IN_OMAP730	(1 << 22)
 #define CLOCK_IN_OMAP1510	(1 << 23)
author maintainer
#21 lore raw

PATCH 21/28 omap2 clock: call clock-specific enable/disable functions if present

In reply to Paul Walmsley

Call clock-specific enable/disable functions if .enable/.disable function pointer fields are present in struct clk. Similar to OMAP1 clock code.

---
 arch/arm/mach-omap2/clock.c |    8 ++++++++
 1 file changed, 8 insertions(+)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +8 -0
@@ -276,6 +276,9 @@ static int _omap2_clk_enable(struct clk 
 		return 0;
 	}
 
+	if (clk->enable)
+		return clk->enable(clk);
+
 	if (unlikely(clk->enable_reg == 0)) {
 		printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
 		       clk->name);
@@ -315,6 +318,11 @@ static void _omap2_clk_disable(struct cl
 	if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK))
 		return;
 
+	if (clk->disable) {
+	        clk->disable(clk);
+		return;
+	}
+
 	if (unlikely(clk == &osc_ck)) {
 		omap2_set_osc_ck(0);
 		return;
author maintainer
#22 lore raw

PATCH 22/28 omap2 clock: use custom osc_ck enable/disable routines

In reply to Paul Walmsley

Now that we're paying attention to the .enable/.disable fields in struct clk, convert the osc_ck enable and disable code to use this standard mechanism. (osc_ck enable/disable does not technically enable or disable the osc_ck; it actually enables/disables autoidling.)

---
 arch/arm/mach-omap2/clock.c |   32 +++++++++++++++-----------------
 arch/arm/mach-omap2/clock.h |    5 ++++-
 2 files changed, 19 insertions(+), 18 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +15 -17
@@ -162,18 +162,26 @@ static void omap2_fixed_divisor_recalc(s
 		propagate_rate(clk);
 }
 
-static void omap2_set_osc_ck(int enable)
+static int omap2_enable_osc_ck(struct clk *clk)
 {
 	u32 pcc;
 
 	pcc = prm_read_reg(OMAP24XX_PRCM_CLKSRC_CTRL);
 
-	if (enable)
-		prm_write_reg(pcc & ~OMAP_AUTOEXTCLKMODE_MASK,
-			      OMAP24XX_PRCM_CLKSRC_CTRL);
-	else
-		prm_write_reg(pcc | OMAP_AUTOEXTCLKMODE_MASK,
-			      OMAP24XX_PRCM_CLKSRC_CTRL);
+	prm_write_reg(pcc & ~OMAP_AUTOEXTCLKMODE_MASK,
+		      OMAP24XX_PRCM_CLKSRC_CTRL);
+
+	return 0;
+}
+
+static void omap2_disable_osc_ck(struct clk *clk)
+{
+	u32 pcc;
+
+	pcc = prm_read_reg(OMAP24XX_PRCM_CLKSRC_CTRL);
+
+	prm_write_reg(pcc | OMAP_AUTOEXTCLKMODE_MASK,
+		      OMAP24XX_PRCM_CLKSRC_CTRL);
 }
 
 /*
@@ -271,11 +279,6 @@ static int _omap2_clk_enable(struct clk 
 	if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK))
 		return 0;
 
-	if (unlikely(clk == &osc_ck)) {
-		omap2_set_osc_ck(1);
-		return 0;
-	}
-
 	if (clk->enable)
 		return clk->enable(clk);
 
@@ -323,11 +326,6 @@ static void _omap2_clk_disable(struct cl
 		return;
 	}
 
-	if (unlikely(clk == &osc_ck)) {
-		omap2_set_osc_ck(0);
-		return;
-	}
-
 	if (clk->enable_reg == 0) {
 		/*
 		 * 'Independent' here refers to a clock which is not
arch/arm/mach-omap2/clock.h +4 -1
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
@@ -26,7 +26,6 @@
 #include "prm_regbits_24xx.h"
 #include "cm_regbits_24xx.h"
 
-static void omap2_sys_clk_recalc(struct clk * clk);
 static void omap2_clksel_recalc(struct clk * clk);
 static void omap2_table_mpu_recalc(struct clk *clk);
 static int omap2_select_table_rate(struct clk * clk, unsigned long rate);
@@ -42,6 +41,8 @@ static void omap2_fixed_divisor_recalc(s
 static long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
 static int omap2_clksel_set_rate(struct clk *clk, unsigned long rate);
 static int omap2_reprogram_dpll(struct clk * clk, unsigned long rate);
+static int omap2_enable_osc_ck(struct clk *clk);
+static void omap2_disable_osc_ck(struct clk *clk);
 
 /* Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated.
  * xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,CM_CLKSEL_DSP
@@ -598,6 +599,8 @@ static struct clk osc_ck = {		/* (*12, *
 	.rate		= 26000000,		/* fixed up in clock init */
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				RATE_FIXED | RATE_PROPAGATES,
+	.enable		= &omap2_enable_osc_ck,
+	.disable	= &omap2_disable_osc_ck,
 	.recalc		= &propagate_rate,
 };
 
author maintainer
#23 lore raw

PATCH 23/28 omap2 clock: use standard clk->enable/disable for APLLs

In reply to Paul Walmsley

Now that we're calling the clock-specific enable & disable code, we can get rid of the special-case code in _omap2_clk_{enable,disable}() for the APLLs.

---
 arch/arm/mach-omap2/clock.c |   20 ++++++++------------
 arch/arm/mach-omap2/clock.h |    6 ++++++
 2 files changed, 14 insertions(+), 12 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +8 -12
@@ -212,7 +212,7 @@ static int omap2_wait_clock_ready(void _
 
 
 /* Enable an APLL if off */
-static void omap2_clk_fixed_enable(struct clk *clk)
+static int omap2_clk_fixed_enable(struct clk *clk)
 {
 	u32 cval, apll_mask;
 
@@ -221,7 +221,7 @@ static void omap2_clk_fixed_enable(struc
 	cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN);
 
 	if ((cval & apll_mask) == apll_mask)
-		return;   /* apll already enabled */
+		return 0;   /* apll already enabled */
 
 	cval &= ~apll_mask;
 	cval |= apll_mask;
@@ -234,6 +234,12 @@ static void omap2_clk_fixed_enable(struc
 
 	omap2_wait_clock_ready(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), cval,
 			    clk->name);
+
+	/*
+	 * REVISIT: Should we return an error code if omap2_wait_clock_ready()
+	 * fails?
+	 */
+	return 0;
 }
 
 static void omap2_clk_wait_ready(struct clk *clk)
@@ -288,11 +294,6 @@ static int _omap2_clk_enable(struct clk 
 		return -EINVAL;
 	}
 
-	if (clk->enable_reg == OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN)) {
-		omap2_clk_fixed_enable(clk);
-		return 0;
-	}
-
 	regval32 = cm_read_reg(clk->enable_reg);
 	regval32 |= (1 << clk->enable_bit);
 	cm_write_reg(regval32, clk->enable_reg);
@@ -336,11 +337,6 @@ static void _omap2_clk_disable(struct cl
 		return;
 	}
 
-	if (clk->enable_reg == OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN)) {
-		omap2_clk_fixed_disable(clk);
-		return;
-	}
-
 	regval32 = cm_read_reg(clk->enable_reg);
 	regval32 &= ~(1 << clk->enable_bit);
 	cm_write_reg(regval32, clk->enable_reg);
arch/arm/mach-omap2/clock.h +6 -0
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
@@ -38,6 +38,8 @@ static u32 omap2_clksel_to_divisor(struc
 static u32 omap2_divisor_to_clksel(struct clk *clk, u32 div);
 static void omap2_dpll_recalc(struct clk *clk);
 static void omap2_fixed_divisor_recalc(struct clk *clk);
+static int omap2_clk_fixed_enable(struct clk *clk);
+static void omap2_clk_fixed_disable(struct clk *clk);
 static long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
 static int omap2_clksel_set_rate(struct clk *clk, unsigned long rate);
 static int omap2_reprogram_dpll(struct clk * clk, unsigned long rate);
@@ -647,6 +649,8 @@ static struct clk apll96_ck = {
 				RATE_FIXED | RATE_PROPAGATES,
 	.enable_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
 	.enable_bit	= OMAP24XX_EN_96M_PLL_SHIFT,
+	.enable		= &omap2_clk_fixed_enable,
+	.disable	= &omap2_clk_fixed_disable,
 	.recalc		= &propagate_rate,
 };
 
@@ -658,6 +662,8 @@ static struct clk apll54_ck = {
 				RATE_FIXED | RATE_PROPAGATES,
 	.enable_reg	= OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
 	.enable_bit	= OMAP24XX_EN_54M_PLL_SHIFT,
+	.enable		= &omap2_clk_fixed_enable,
+	.disable	= &omap2_clk_fixed_disable,
 	.recalc		= &propagate_rate,
 };
 
author maintainer
#24 lore raw

PATCH 24/28 omap2 clock: replace omap2_get_crystal_rate() with clock-specific recalc code

In reply to Paul Walmsley

The OMAP2 clock framework currently uses a nonstandard function to assign the osc_ck and sys_ck rates, omap2_get_crystal_rate(). By using custom recalc code for these clocks, we can get rid of it and rely on the existing clock tree recalculation process.

---
 arch/arm/mach-omap2/clock.c |   44 ++++++++++++++++++++++++--------------------
 arch/arm/mach-omap2/clock.h |   10 +++++-----
 2 files changed, 29 insertions(+), 25 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +24 -20
@@ -112,21 +112,6 @@ static void omap2_init_clksel_parent(str
 	return;
 }
 
-/* Recalculate SYST_CLK */
-static void omap2_sys_clk_recalc(struct clk * clk)
-{
-	u32 div;
-
-	if (!cpu_is_omap34xx()) {
-		div = prm_read_reg(OMAP24XX_PRCM_CLKSRC_CTRL);
-		/* Test if ext clk divided by 1 or 2 */
-		div &= OMAP_SYSCLKDIV_MASK;
-		div >>= OMAP_SYSCLKDIV_SHIFT;
-		clk->rate = (clk->parent->rate / div);
-	}
-	propagate_rate(clk);
-}
-
 static u32 omap2_get_dpll_rate(struct clk * tclk)
 {
 	long long dpll_clk;
@@ -1044,9 +1029,9 @@ static struct clk_functions omap2_clk_fu
 	.clk_disable_unused	= omap2_clk_disable_unused,
 };
 
-static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys)
+static u32 omap2_get_apll_clkin(void)
 {
-	u32 div, aplls, sclk = 13000000;
+	u32 aplls, sclk = 0;
 
 	aplls = cm_read_mod_reg(PLL_MOD, CM_CLKSEL1);
 	aplls &= OMAP24XX_APLLS_CLKIN_MASK;
@@ -1059,12 +1044,30 @@ static void __init omap2_get_crystal_rat
 	else if (aplls == APLLS_CLKIN_12MHZ)
 		sclk = 12000000;
 
+	return sclk;
+}
+
+static u32 omap2_get_sysclkdiv(void)
+{
+	u32 div;
+
 	div = prm_read_reg(OMAP24XX_PRCM_CLKSRC_CTRL);
 	div &= OMAP_SYSCLKDIV_MASK;
 	div >>= OMAP_SYSCLKDIV_SHIFT;
 
-	osc->rate = sclk * div;
-	sys->rate = sclk;
+	return div;
+}
+
+static void omap2_osc_clk_recalc(struct clk *clk)
+{
+	clk->rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv();
+	propagate_rate(clk);
+}
+
+static void omap2_sys_clk_recalc(struct clk *clk)
+{
+	clk->rate = clk->parent->rate / omap2_get_sysclkdiv();
+	propagate_rate(clk);
 }
 
 /*
@@ -1116,7 +1119,8 @@ int __init omap2_clk_init(void)
 		cpu_mask = RATE_IN_243X;
 
 	clk_init(&omap2_clk_functions);
-	omap2_get_crystal_rate(&osc_ck, &sys_ck);
+
+	omap2_osc_clk_recalc(&osc_ck);
 
 	for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks);
 	     clkp++) {
arch/arm/mach-omap2/clock.h +5 -5
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
@@ -36,6 +36,8 @@ static void omap2_init_clksel_parent(str
 static u32 omap2_clksel_get_divisor(struct clk *clk);
 static u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val);
 static u32 omap2_divisor_to_clksel(struct clk *clk, u32 div);
+static void omap2_osc_clk_recalc(struct clk *clk);
+static void omap2_sys_clk_recalc(struct clk *clk);
 static void omap2_dpll_recalc(struct clk *clk);
 static void omap2_fixed_divisor_recalc(struct clk *clk);
 static int omap2_clk_fixed_enable(struct clk *clk);
@@ -598,21 +600,19 @@ static struct clk func_32k_ck = {
 /* Typical 12/13MHz in standalone mode, will be 26Mhz in chassis mode */
 static struct clk osc_ck = {		/* (*12, *13, 19.2, *26, 38.4)MHz */
 	.name		= "osc_ck",
-	.rate		= 26000000,		/* fixed up in clock init */
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_FIXED | RATE_PROPAGATES,
+				RATE_PROPAGATES,
 	.enable		= &omap2_enable_osc_ck,
 	.disable	= &omap2_disable_osc_ck,
-	.recalc		= &propagate_rate,
+	.recalc		= &omap2_osc_clk_recalc,
 };
 
 /* With out modem likely 12MHz, with modem likely 13MHz */
 static struct clk sys_ck = {		/* (*12, *13, 19.2, 26, 38.4)MHz */
 	.name		= "sys_ck",		/* ~ ref_clk also */
 	.parent		= &osc_ck,
-	.rate		= 13000000,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-				RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+				ALWAYS_ENABLED | RATE_PROPAGATES,
 	.recalc		= &omap2_sys_clk_recalc,
 };
 
author maintainer
#25 lore raw

PATCH 25/28 omap2 clock: Standardize DPLL rate recalculation with struct dpll_data

In reply to Paul Walmsley

Introduce a new data structure, struct dpll_data, that contains DPLL multiplier, divider, and autoidle information. Update existing DPLL code to use struct dpll_data. The goal here is to set up something that will be usable for OMAP3430 clock tree. Note that this does not affect the SRAM DPLL assembly code - the DPLL register addresses are still hard-coded there.

---
 arch/arm/mach-omap2/clock.c       |   61 ++++++++++++++++++++++++++------------
 arch/arm/mach-omap2/clock.h       |   10 ++++++
 include/asm-arm/arch-omap/clock.h |    9 +++++
 3 files changed, 61 insertions(+), 19 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +42 -19
@@ -112,20 +112,38 @@ static void omap2_init_clksel_parent(str
 	return;
 }
 
-static u32 omap2_get_dpll_rate(struct clk * tclk)
+/* Returns the DPLL rate */
+static u32 omap2_get_dpll_rate(struct clk *clk)
+{
+ 	long long dpll_clk;
+ 	u32 dpll_mult, dpll_div, dpll;
+ 	const struct dpll_data *dd;
+
+ 	dd = clk->dpll_data;
+ 	/* REVISIT: What do we return on error? */
+ 	if (!dd)
+ 		return 0;
+
+ 	dpll = cm_read_reg(dd->mult_div1_reg);
+ 	dpll_mult = dpll & dd->mult_mask;
+ 	dpll_mult >>= convert_mask_to_shift(dd->mult_mask);
+ 	dpll_div = dpll & dd->div1_mask;
+ 	dpll_div >>= convert_mask_to_shift(dd->div1_mask);
+
+ 	dpll_clk = (long long)clk->parent->rate * dpll_mult;
+ 	do_div(dpll_clk, dpll_div + 1);
+
+	return dpll_clk;
+}
+
+/* This actually returns the rate of core_ck, not dpll_ck. */
+static u32 omap2_get_dpll_rate_24xx(struct clk *tclk)
 {
 	long long dpll_clk;
-	int dpll_mult, dpll_div, amult;
-	u32 dpll;
+	u8 amult;
 
-	dpll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL1);
+	dpll_clk = omap2_get_dpll_rate(tclk);
 
-	dpll_mult = dpll & OMAP24XX_DPLL_MULT_MASK;
-	dpll_mult >>= OMAP24XX_DPLL_MULT_SHIFT;		/* 10 bits */
-	dpll_div = dpll & OMAP24XX_DPLL_DIV_MASK;
-	dpll_div >>= OMAP24XX_DPLL_DIV_SHIFT;		/* 4 bits */
-	dpll_clk = (long long)tclk->parent->rate * dpll_mult;
-	do_div(dpll_clk, dpll_div + 1);
 	amult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
 	amult &= OMAP24XX_CORE_CLK_SRC_MASK;
 	dpll_clk *= amult;
@@ -396,7 +414,7 @@ static u32 omap2_dpll_round_rate(unsigne
 
 static void omap2_dpll_recalc(struct clk *clk)
 {
-	clk->rate = omap2_get_dpll_rate(clk);
+	clk->rate = omap2_get_dpll_rate_24xx(clk);
 
 	propagate_rate(clk);
 }
@@ -559,10 +577,11 @@ static int omap2_reprogram_dpll(struct c
 	u32 flags, cur_rate, low, mult, div, valid_rate, done_rate;
 	u32 bypass = 0;
 	struct prcm_config tmpset;
+	const struct dpll_data *dd;
 	int ret = -EINVAL;
 
 	local_irq_save(flags);
-	cur_rate = omap2_get_dpll_rate(&dpll_ck);
+	cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
 	mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
 	mult &= OMAP24XX_CORE_CLK_SRC_MASK;
 
@@ -580,9 +599,13 @@ static int omap2_reprogram_dpll(struct c
 		else
 			low = curr_prcm_set->dpll_speed / 2;
 
-		tmpset.cm_clksel1_pll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL1);
-		tmpset.cm_clksel1_pll &= ~(OMAP24XX_DPLL_MULT_MASK |
-					   OMAP24XX_DPLL_DIV_MASK);
+		dd = clk->dpll_data;
+		if (!dd)
+			goto dpll_exit;
+
+		tmpset.cm_clksel1_pll = cm_read_reg(dd->mult_div1_reg);
+		tmpset.cm_clksel1_pll &= ~(dd->mult_mask |
+					   dd->div1_mask);
 		div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
 		tmpset.cm_clksel2_pll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
 		tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK;
@@ -595,8 +618,8 @@ static int omap2_reprogram_dpll(struct c
 			mult = (rate / 1000000);
 			done_rate = CORE_CLK_SRC_DPLL;
 		}
-		tmpset.cm_clksel1_pll |= (div << OMAP24XX_DPLL_DIV_SHIFT);
-		tmpset.cm_clksel1_pll |= (mult << OMAP24XX_DPLL_MULT_SHIFT);
+		tmpset.cm_clksel1_pll |= (div << convert_mask_to_shift(dd->mult_mask));
+		tmpset.cm_clksel1_pll |= (mult << convert_mask_to_shift(dd->div1_mask));
 
 		/* Worst case */
 		tmpset.base_sdrc_rfr = V24XX_SDRC_RFR_CTRL_BYPASS;
@@ -950,7 +973,7 @@ static int omap2_select_table_rate(struc
 	}
 
 	curr_prcm_set = prcm;
-	cur_rate = omap2_get_dpll_rate(&dpll_ck);
+	cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
 
 	if (prcm->dpll_speed == cur_rate / 2) {
 		omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1);
@@ -1137,7 +1160,7 @@ int __init omap2_clk_init(void)
 	}
 
 	/* Check the MPU rate set by bootloader */
-	clkrate = omap2_get_dpll_rate(&dpll_ck);
+	clkrate = omap2_get_dpll_rate_24xx(&dpll_ck);
 	for (prcm = rate_table; prcm->mpu_speed; prcm++) {
 		if (!(prcm->flags & cpu_mask))
 			continue;
arch/arm/mach-omap2/clock.h +10 -0
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================
@@ -632,9 +632,19 @@ static struct clk alt_ck = {		/* Typical
 /* REVISIT: Rate changes on dpll_ck trigger a full set change.	...
  * deal with this
  */
+
+static const struct dpll_data dpll_dd = {
+	.mult_div1_reg		= OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+	.mult_mask		= OMAP24XX_DPLL_MULT_MASK,
+	.div1_mask		= OMAP24XX_DPLL_DIV_MASK,
+	.auto_idle_mask		= OMAP24XX_AUTO_DPLL_MASK,
+	.auto_idle_val		= 0x3, /* stop DPLL upon idle */
+};
+
 static struct clk dpll_ck = {
 	.name		= "dpll_ck",
 	.parent		= &sys_ck,		/* Can be func_32k also */
+	.dpll_data	= &dpll_dd,
 	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
 				RATE_PROPAGATES | ALWAYS_ENABLED,
 	.recalc		= &omap2_dpll_recalc,
include/asm-arm/arch-omap/clock.h +9 -0
Index: linux-omap/include/asm-arm/arch-omap/clock.h
===================================================================
@@ -29,6 +29,14 @@ struct clksel {
 	const struct clksel_rate *rates;
 };
 
+struct dpll_data {
+	void __iomem		*mult_div1_reg;
+	u32			mult_mask;
+	u32			div1_mask;
+	u32			auto_idle_mask;
+	u8			auto_idle_val;
+};
+
 #endif
 
 struct clk {
@@ -53,6 +61,7 @@ struct clk {
 	void __iomem		*clksel_reg;
 	u32			clksel_mask;
 	const struct clksel	*clksel;
+	const struct dpll_data	*dpll_data;
 #else
 	__u8			rate_offset;
 	__u8			src_offset;
author maintainer
#26 lore raw

PATCH 27/28 omap2 clock: add three missing clocks: gpmc_fck, sdma_{i, f}ck

In reply to Paul Walmsley

Add three missing clocks: gpmc_fck, sdma_ick, and sdma_fck. This is in preparation for struct clk-based autoidling, added in the next patch.

---
 arch/arm/mach-omap2/clock.h |   24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

Index: linux-omap/arch/arm/mach-omap2/clock.h
Index: linux-omap/arch/arm/mach-omap2/clock.h
===================================================================

arch/arm/mach-omap2/clock.h +24 -0
@@ -2277,6 +2277,27 @@ static struct clk i2chs1_fck = {
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk gpmc_fck = {
+	.name		= "gpmc_fck",
+	.parent		= &core_l3_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk sdma_fck = {
+	.name		= "sdma_fck",
+	.parent		= &core_l3_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk sdma_ick = {
+	.name		= "sdma_ick",
+	.parent		= &l4_ck,
+	.flags		= CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk vlynq_ick = {
 	.name		= "vlynq_ick",
 	.parent		= &core_l3_ck,
@@ -2633,6 +2654,9 @@ static struct clk *onchip_clks[] __initd
 	&i2c2_ick,
 	&i2c2_fck,
 	&i2chs2_fck,
+	&gpmc_fck,
+	&sdma_fck,
+	&sdma_ick,
 	&vlynq_ick,
 	&vlynq_fck,
 	&sdrc_ick,
author maintainer
#27 lore raw

PATCH 28/28 omap2 clock: handle (almost) all clock autoidling via the clock framework

In reply to Paul Walmsley

Existing OMAP2 code autoidles clocks via pm.c. OMAP clock framework already has some support for enabling autoidle mode via the allow_idle function; however, this is currently unused. Take advantage of this support by adding autoidle register and bit information for each clock, defining an omap2_clk_allow_idle() function, and adding a framework-wide function, clk_allow_idle_all(), to autoidle all clocks, intended to be called on init. Remove all but the APLL/DPLL autoidle bit twiddling from pm.c -- we don't yet have generalized support for APLL autoidle. Handling autoidle via the clock framework ensures that we only touch clocks that are currently configured.

---
 arch/arm/mach-omap2/clock.c           |   34 +++++++++++
 arch/arm/mach-omap2/clock.h           |  103 ++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/cm_regbits_24xx.h |   50 ++++++++++++++++
 arch/arm/mach-omap2/pm.c              |   63 +-------------------
 arch/arm/plat-omap/clock.c            |    9 ++
 include/asm-arm/arch-omap/clock.h     |    3 
 6 files changed, 204 insertions(+), 58 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================

arch/arm/mach-omap2/clock.c +34 -0
@@ -165,6 +165,7 @@ static void omap2_fixed_divisor_recalc(s
 		propagate_rate(clk);
 }
 
+/* REVISIT: This is really autoidle control, not enable/disable */
 static int omap2_enable_osc_ck(struct clk *clk)
 {
 	u32 pcc;
@@ -177,6 +178,7 @@ static int omap2_enable_osc_ck(struct cl
 	return 0;
 }
 
+/* REVISIT: This is really autoidle control, not enable/disable */
 static void omap2_disable_osc_ck(struct clk *clk)
 {
 	u32 pcc;
@@ -1023,6 +1025,34 @@ static int omap2_select_table_rate(struc
 	return 0;
 }
 
+static void omap2_clk_allow_idle(struct clk *clk)
+{
+	u32 regval;
+	u8 shift;
+	const struct dpll_data *dd;
+
+	if (clk->auto_idle_reg) {
+		regval = cm_read_reg(clk->auto_idle_reg);
+
+		if (clk->dpll_data) {
+			/* Special handling for DPLLs */
+
+			dd = clk->dpll_data;
+			if (!dd->auto_idle_mask || !dd->auto_idle_val)
+				return;
+
+			shift = convert_mask_to_shift(dd->auto_idle_mask);
+			regval &= dd->auto_idle_mask;
+			regval |= dd->auto_idle_val << shift;
+
+		} else if (clk->auto_idle_bit) {
+			regval |= (1 << clk->auto_idle_bit);
+		}
+
+		cm_write_reg(regval, clk->auto_idle_reg);
+	}
+}
+
 /*-------------------------------------------------------------------------
  * Omap2 clock reset and init functions
  *-------------------------------------------------------------------------*/
@@ -1049,6 +1079,7 @@ static struct clk_functions omap2_clk_fu
 	.clk_round_rate		= omap2_clk_round_rate,
 	.clk_set_rate		= omap2_clk_set_rate,
 	.clk_set_parent		= omap2_clk_set_parent,
+	.clk_allow_idle		= omap2_clk_allow_idle,
 	.clk_disable_unused	= omap2_clk_disable_unused,
 };
 
@@ -1184,6 +1215,9 @@ int __init omap2_clk_init(void)
 	 */
 	clk_enable_init_clocks();
 
+	/* Autoidle all clocks that can be autoidled */
+	clk_allow_idle_all();
+
 	/* Avoid sleeping sleeping during omap2_clk_prepare_for_reboot() */
 	vclk = clk_get(NULL, "virt_prcm_set");
 	sclk = clk_get(NULL, "sys_ck");
arch/arm/mach-omap2/clock.h +103 -0

415 lines not on this page · raw message

include/asm-arm/arch-omap/clock.h +3 -0
Index: linux-omap/include/asm-arm/arch-omap/clock.h
===================================================================
@@ -62,6 +62,8 @@ struct clk {
 	u32			clksel_mask;
 	const struct clksel	*clksel;
 	const struct dpll_data	*dpll_data;
+	void __iomem		*auto_idle_reg;
+	u8			auto_idle_bit;
 #else
 	__u8			rate_offset;
 	__u8			src_offset;
@@ -92,6 +94,7 @@ extern void clk_allow_idle(struct clk *c
 extern void clk_deny_idle(struct clk *clk);
 extern int clk_get_usecount(struct clk *clk);
 extern void clk_enable_init_clocks(void);
+extern void clk_allow_idle_all(void);
 
 /* Clock flags */
 #define RATE_CKCTL		(1 << 0)	/* Main fixed ratio clocks */
arch/arm/mach-omap2/pm.c +5 -58

74 lines not on this page · raw message

arch/arm/plat-omap/clock.c +9 -0
Index: linux-omap/arch/arm/plat-omap/clock.c
===================================================================
@@ -383,6 +383,15 @@ void clk_allow_idle(struct clk *clk)
 }
 EXPORT_SYMBOL(clk_allow_idle);
 
+void clk_allow_idle_all(void)
+{
+	struct clk *clkp;
+
+	list_for_each_entry(clkp, &clocks, node)
+		clk_allow_idle(clkp);
+}
+EXPORT_SYMBOL(clk_allow_idle_all);
+
 void clk_enable_init_clocks(void)
 {
 	struct clk *clkp;
arch/arm/mach-omap2/cm_regbits_24xx.h +50 -0

111 lines not on this page · raw message

#28 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework

Hi Paul,

Quoted 8 lines

Existing OMAP2 code autoidles clocks via pm.c. OMAP clock framework already has some support for enabling autoidle mode via the allow_idle function; however, this is currently unused. Take advantage of this support by adding autoidle register and bit information for each clock, defining an omap2_clk_allow_idle() function, and adding a framework-wide function, clk_allow_idle_all(), to autoidle all clocks, intended to be called on init. Remove all but the APLL/DPLL autoidle bit twiddling from pm.c -- we don't yet have generalized support for

APLL

Quoted 1 line

autoidle. Handling autoidle via the clock framework ensures that we

only

Quoted 1 line

touch clocks that are currently configured.

I thought about doing this back when OMAP1 added this when I was more active on OMAP2. However, I dropped it as it didn't have enough 'bang' in this form. I think these registers (even in OMAP1) are widely mis-understood. This is partially a TRM issue and one of complexity.

Meaning you can set this register on a per-clock basis however they do nothing for run time except at L3/L4 domain change time. In the OMAP-GIT code this means at retention time the PRCM has permission to shut off your ICLK assuming your module acknowledges it. If the PM code does this manually (enable/disable) then this register has no effect.

It does have a useful run time property in that it is one form to gate a clock stop state assuming you have not forced it. This is one way to stop a cascade clock stop from happening when you are not expecting it. It would be a lighter weight way then the mutex which OMAP2-GIT code uses. However, for that to work other code would have to change.

Each IP-Module _does_ have an AUTOIDLE bit in its SYSCONIG space which does act as you might expect this bit to. Setting this AUTOIDLE does save significant power. It would be more useful to control that one from here.

If you hook up a current meter you can toggle all the CM_AUTOIDLES you like and nothing will happen. But if you do the same with the module autoidle you will see a bit change.

Regards,
Richard W.

author maintainer
#29 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework

Hi Richard,

Quoted 9 lines · Richard

I thought about doing this back when OMAP1 added this when I was more active on OMAP2. However, I dropped it as it didn't have enough 'bang' in this form. I think these registers (even in OMAP1) are widely mis-understood. This is partially a TRM issue and one of complexity.

Meaning you can set this register on a per-clock basis however they do nothing for run time except at L3/L4 domain change time. In the OMAP-GIT code this means at retention time the PRCM has permission to shut off your ICLK assuming your module acknowledges it.

I see. Thanks for the explanation. So in practical terms, it seems best to just enable this for all clocks unconditionally, as before in pm.c, no?

Quoted 2 lines

If the PM code
does this manually (enable/disable) then this register has no effect.

So, if the clock's enable/disable bit in its ICLKEN register is touched in any way, the clock auto-idle bit is ignored? Does that hidden state persist until reset?

Quoted 5 lines

It does have a useful run time property in that it is one form to gate a clock stop state assuming you have not forced it. This is one way to stop a cascade clock stop from happening when you are not expecting it. It would be a lighter weight way then the mutex which OMAP2-GIT code uses. However, for that to work other code would have to change.

But that would only happen when going to retention or off, correct?

Quoted 4 lines

Each IP-Module _does_ have an AUTOIDLE bit in its SYSCONIG space which does act as you might expect this bit to. Setting this AUTOIDLE does save significant power. It would be more useful to control that one from here.

Those cover potentially large numbers of clocks... So in lieu of a more general power domain API, is there a reason not to set all of those bits unconditionally in pm.c?

- Paul

#30 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework

Hi Paul,

Quoted 7 lines · Richard
Quoted 6 lines

I thought about doing this back when OMAP1 added this when I was more active on OMAP2. However, I dropped it as it didn't have enough 'bang' in this form. I think these registers (even in OMAP1) are widely mis-understood. This is partially a TRM issue and one of complexity.

Quoted 7 lines
Quoted 4 lines

Meaning you can set this register on a per-clock basis however they do nothing for run time except at L3/L4 domain change time. In the OMAP-GIT code this means at retention time the PRCM has permission to shut off your ICLK assuming your module acknowledges it.

I see. Thanks for the explanation. So in practical terms, it seems best to just enable this for all clocks unconditionally, as before in pm.c, no?

Probably so... Given the current surrounding implementation it is not so effective and will result in many drivers adding some calls which are just noise. Hollow code...

I think even in OMAP1 a similar condition exists, it's been a long while since I looked. But its clock manager bits also allowed auto control during only full domain changes to its couple of sleep modes. One can consider an OMAP1 as only have a single big domain where and OMAP2 as several and an OMAP3 has many. Some ideas and techniques have been carried forward.

Like I was indicating for OMAP2/3 if the PRCM auto idle was switched with the module auto-idle it would not be noise it would be substantive.
-- One issue here is the address range for this bit is with each driver in the _generic_ IP OCP (open core protocol bus interface) wrapper header. To write to this you need i+f clock on. It still helps to set this bit even if the module is off as the clock tree can still be active and dissipating some power in the module. -- This is what the patch I sent out a while back was about (RFC/PATCH) to just enable all of these. It did save a lot of power.
-- A PRCM library can provide these access functions
-- It can be in lined in ever driver
-- Or the clock frame work can provide an interface for it.
** As its generic and symmetric for every IP in the OCP wrapper I personally like to stick it all in one spot inside of adding a bunch of defines to every driver.
** Recently we internally were debating a bit about if an API was needed as you really in some cases do need to set the CLOCKACTIVITY bits in the OCP wrapper depending on the drivers mode of activity.

Quoted 6 lines
Quoted 2 lines

If the PM code
does this manually (enable/disable) then this register has no effect.

So, if the clock's enable/disable bit in its ICLKEN register is touched in any way, the clock auto-idle bit is ignored? Does that hidden state persist until reset?

No, not the way I read your question.

When ICLKEN is enabled and the PRCM-auto-idle is enabled hardware can manage that clock at domain change time assuming the peripheral handshakes it ok (force/no/smart).

If the ICLKEN is disabled the setting of PRCM-auto-idle has no effect.

Quoted 7 lines
Quoted 5 lines

It does have a useful run time property in that it is one form to gate a clock stop state assuming you have not forced it. This is one way to stop a cascade clock stop from happening when you are not expecting it. It would be a lighter weight way then the mutex which OMAP2-GIT code uses. However, for that to work other code would have to change.

But that would only happen when going to retention or off, correct?

Given the current OMAP-GIT code this is correct.

However this is a bit more to it than that. These clocks can be auto-handled during clock domain stop mode. The power domains have the properties of On/Retention/Off while the clock domains have properties of On/Inactive.

The i-clocks controlled by prcm-autoidle can be hardware managed (shut down) when the L3 and L4 clock domains go inactive. The power domains can be in any state at this time. As it likely turns out in the GIT code today, the L3/L4 clock domain and the core power domain effectively state change at the same time.

One of the big target states for big power savings is this so called 'partially' active state. In this case you do want the clock domains and the power domains states to not be in sync. The L3/L4 can be stopped, but say an F-Clock to a McBSP can still be running pushing data out to a codec. If programmed up correctly, the codec need for data can automatically signal the prcm to re-activate the L3/L4 then allow the new data to flow. This is the 10mA vs. 200mA kind of thing I was describing (you do need to clear the wake up status for it to happen again). When you hit 'retention' or OFF your currents are in the 50-100uA range, but there is absolutely no activity.

Quoted 8 lines
Quoted 4 lines

Each IP-Module _does_ have an AUTOIDLE bit in its SYSCONIG space which does act as you might expect this bit to. Setting this AUTOIDLE does save significant power. It would be more useful to control that one from here.

Those cover potentially large numbers of clocks... So in lieu of a more general power domain API, is there a reason not to set all of those bits unconditionally in pm.c?

In the general case for this bit it turns out that you can set it at init time. Some bug work around might require some access.

However, other bits in the same range CLOCKACTIVTY do have a bit more need of dynamic access. WE enable also might be conditionally set. Also the handshakes sometimes take different settings (smart/force/no-idle/standby) for some bug work arounds (software or hardware). A force idle might clear some internal status in say a HSMMC which a driver didn't fully clear out.

Regards,
Richard W.

author maintainer
#31 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework

Hi Richard,

Quoted 1 line · Richard

Like I was indicating for OMAP2/3 if the PRCM auto idle was switched with the module auto-idle it would not be noise it would be substantive.

It sounds like one doesn't even need to switch these bits, once we turn them on, correct? Just enable *_SYSCONFIG autoidle and ICLK autoidle at boot in pm.c, and then never disable them, with no ill effects. Some extra latency perhaps? Drivers that need to toggle them to work around some hardware bug can just do that themselves, for the time being...

Quoted 2 lines

-- One issue here is the address range for this bit is with each
driver in the _generic_ IP OCP (open core protocol bus interface) wrapper header. To write to this you need i+f clock on. It still helps to set this bit even if the module is off as the clock tree can still be active and dissipating some power in the module.

You're talking about the *_SYSCONFIG autoidle bits here, right? So to set those properly we'd need to walk the clock tree, enabling module clocks and setting the *_SYSCONFIG autoidle bit, then powering the module clocks back down again?

Quoted 2 lines

-- This is what the patch I sent out a while back was about
(RFC/PATCH) to just enable all of these. It did save a lot of power.

I just took another look at that patch. The only downside is latency, right? Are you thinking about updating the patch for the new PRCM access code? That would make it much easier to test...

Quoted 2 lines

** As its generic and symmetric for every IP in the OCP wrapper I
personally like to stick it all in one spot inside of adding a bunch of defines to every driver.

Since all of those registers are in SCM space, perhaps an scm.h/scm.c file might be useful here. I've been running into this with CONTROL_DEVCONF* on 3430 code. I don't think the *_SYSCONFIG powersave bits fit well into the clock framework, so we should probably place it outside the clocks. I do think it would make sense to specifically encode the power domain that each clock resides in into the struct clk, for use by PM or SCM code.

Quoted 2 lines

** Recently we internally were debating a bit about if an API was
needed as you really in some cases do need to set the CLOCKACTIVITY bits in the OCP wrapper depending on the drivers mode of activity.

I've been looking at these CLOCKACTIVITY bits and am not clear on the intended use. They are read-only in many modules, at least according to the TRM. There is a notation about "Clock activity during wakeup mode period" -- could you elaborate about what that means?

Quoted 3 lines

When ICLKEN is enabled and the PRCM-auto-idle is enabled hardware can manage that clock at domain change time assuming the peripheral handshakes it ok (force/no/smart).

If the ICLKEN is disabled the setting of PRCM-auto-idle has no effect.

Okay, makes sense.

Quoted 1 line

One of the big target states for big power savings is this so called 'partially' active state. In this case you do want the clock domains and the power domains states to not be in sync. The L3/L4 can be stopped, but say an F-Clock to a McBSP can still be running pushing data out to a codec. If programmed up correctly, the codec need for data can automatically signal the prcm to re-activate the L3/L4 then allow the new data to flow.

This is via the WKDEP/SLEEPDEP registers, correct? or is this via another mechanism?

Quoted 1 line

However, other bits in the same range CLOCKACTIVTY do have a bit more need of dynamic access. WE enable also might be conditionally set.

Sorry, you lost me there - what is WE enable?

Thanks for all of the detailed information, Richard,

- Paul

#32 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework

Hi Paul,

Quoted 1 line

From: [email protected] [mailto:[email protected]] On

Behalf

Quoted 2 lines
Quoted 2 lines

Like I was indicating for OMAP2/3 if the PRCM auto idle was switched with the module auto-idle it would not be noise it would be

substantive.

Quoted 2 lines

It sounds like one doesn't even need to switch these bits, once we

turn

Quoted 1 line

them on, correct? Just enable *_SYSCONFIG autoidle and ICLK autoidle

at

Quoted 2 lines

boot in pm.c, and then never disable them, with no ill effects. Some extra latency perhaps? Drivers that need to toggle them to work

around

Quoted 1 line

some hardware bug can just do that themselves, for the time being...

Yes.

There are some nuances which could be talked about but probably not needed at this point.

Quoted 3 lines
Quoted 3 lines

-- One issue here is the address range for this bit is with each
driver in the _generic_ IP OCP (open core protocol bus interface) wrapper header. To write to this you need i+f clock on. It still

helps

Quoted 1 line
Quoted 1 line

to set this bit even if the module is off as the clock tree can

still be

Quoted 3 lines
Quoted 1 line

active and dissipating some power in the module.

You're talking about the *_SYSCONFIG autoidle bits here, right? So to

set

Quoted 1 line

those properly we'd need to walk the clock tree, enabling module

clocks

Quoted 1 line

and setting the *_SYSCONFIG autoidle bit, then powering the module

clocks

Quoted 1 line

back down again?

Yes.

Quoted 2 lines
Quoted 2 lines

-- This is what the patch I sent out a while back was about
(RFC/PATCH) to just enable all of these. It did save a lot of

power.

Quoted 3 lines

I just took another look at that patch. The only downside is latency, right? Are you thinking about updating the patch for the new PRCM

access

Quoted 1 line

code? That would make it much easier to test...

At this level the latency should be very minimal compared to the active power savings. At the module level it should be on the order of a few clocks. With many of these clocks in the MHz range its some nano seconds.

The danger is in cascade latency if all modules are set this way and the upper members of the tree have their auto controls set. The big latencies are not at the modules (except for some in OFF mode).

Actually the patch as I sent it was completely self contained it was done that way just to be fast :) Changing it to use the macros is no problem. I'd probably shy away from using the clock frame work to turn on and off each clock via name string though. They would result way too much code.

Quoted 1 line
Quoted 1 line

** As its generic and symmetric for every IP in the OCP wrapper

I

Quoted 1 line
Quoted 1 line

personally like to stick it all in one spot inside of adding a bunch

of

Quoted 3 lines
Quoted 1 line

defines to every driver.

Since all of those registers are in SCM space, perhaps an scm.h/scm.c

file

Quoted 1 line

might be useful here. I've been running into this with

CONTROL_DEVCONF*

Quoted 1 line

on 3430 code. I don't think the *_SYSCONFIG powersave bits fit well

into

Quoted 1 line

the clock framework, so we should probably place it outside the

clocks.

Quoted 2 lines

I do think it would make sense to specifically encode the power domain that each clock resides in into the struct clk, for use by PM or SCM

code.

The OCP registers are in each modules address space. An example of what I was talking about is GTP1.TIOCP_CFG:0x48318010.

The SCM (system control module) is something else. It has bearing for power in setting the right state for pins in sleep and io ring wake up. I don't think they belong in the clock frame work either. Though the prcm many need to make api calls to it.

Quoted 1 line
Quoted 1 line

** Recently we internally were debating a bit about if an API

was

Quoted 1 line
Quoted 1 line

needed as you really in some cases do need to set the CLOCKACTIVITY

bits

Quoted 4 lines
Quoted 1 line

in the OCP wrapper depending on the drivers mode of activity.

I've been looking at these CLOCKACTIVITY bits and am not clear on the intended use. They are read-only in many modules, at least according

to

Quoted 2 lines

the TRM. There is a notation about "Clock activity during wakeup mode period" -- could you elaborate about what that means?

Well some aspects of this are a little fuzzy to me also. However, I know generally how they are to be used in practice.

I think of them as how the internal clocks of the module will be handled at idle-ack time (like when the L3/L4{interconnect} clock domains go idle, i.e. this auto ICLK handling time stuff which was being talked about).

Internally in the module at these times the module can choose to handle its clocks in different ways. If you don't need 'partial' activity (meaning functional clock working while iclock is cut) you set it up to allow gating of both I and F clocks. If you want partial activity you make sure the F clock isn't module-internal modified.

One example is say a timer. If I target a low power idle mode I can get the interconnects to go to clock stop (Iclocks off to CORE say) but I can set the activity on the gp-timer such that it keeps ticking -and- can even say generate a wake up (from clock stop) interrupt which brings the L3/L4 out of clock stop. On say a 2430 this will have a system at say average of 2mA but still be ticking at a HZ=100 rate from a core domain clock. This is compared to say a 60mA idle when not hitting clock stop. I can telnet into a system and it is still responsive but has really very low power. This is distinct from system wide retention who's currents might be in the 100uA range but nothing is functional. Only a 'wakeup' domain interrupt will start you chip going again. Make sure not to mix up 'chip' retention (all domains) with just say MPU-retention which is more or less independent of the CORE.

If during this idle time I don't' care about a particular modules I and F clocks I can set the clockactivity bits to allow internal gating of both I and F clocks. The F-clock tree won't stop as some other module might need it, but my module can gate it saving power.

On OMAP3 if you are using software control methods you may need to set these in a particular way to ensure data has cleared before shutting down the module. I don't expect control at this granularity makes sense for our typical usage, but if you are doing full hardware dependency for idling it is relevant.

Quoted 1 line
Quoted 1 line

When ICLKEN is enabled and the PRCM-auto-idle is enabled hardware

can

Quoted 4 lines
Quoted 4 lines

manage that clock at domain change time assuming the peripheral handshakes it ok (force/no/smart).

If the ICLKEN is disabled the setting of PRCM-auto-idle has no

effect.

Quoted 5 lines

Okay, makes sense.

Quoted 2 lines

One of the big target states for big power savings is this so called 'partially' active state. In this case you do want the clock

domains

Quoted 2 lines
Quoted 2 lines

and the power domains states to not be in sync. The L3/L4 can be stopped, but say an F-Clock to a McBSP can still be running pushing

data

Quoted 1 line
Quoted 1 line

out to a codec. If programmed up correctly, the codec need for data

can

Quoted 1 line
Quoted 1 line

automatically signal the prcm to re-activate the L3/L4 then allow

the

Quoted 3 lines
Quoted 1 line

new data to flow.

This is via the WKDEP/SLEEPDEP registers, correct? or is this via

another

Quoted 1 line

mechanism?

No. These registers are more targeted at reducing latency when OFF mode is used. They allow early power up of domains. These are useful when coming from inactive states not active or partially active ones.

One fun fact here is you can say set up a WKDEP such that the MPU is powered on when something happens on say the DSP (MPU used to be in retention). However, if you don't have an interrupt routed to the MPU, it will still be stuck in clock domain stop and just now be drawing more power in ON state. Some time later the OS timer fires and the MPU can wake do its thing and then re-WFI back to retention. The power draw due to the mis-programming of the WKDEP caused extra consumption even though the ARM wasn't doing work. Now, if the ARM was in OFF mode, this early power up could have saved some time.

Quoted 1 line
Quoted 1 line

However, other bits in the same range CLOCKACTIVTY do have a bit

more

Quoted 3 lines
Quoted 1 line

need of dynamic access. WE enable also might be conditionally set.

Sorry, you lost me there - what is WE enable?

I was talking about XYZ_SYSCONFIG.ENWAWAKEUP bit in OCP header.

Quoted 1 line

Thanks for all of the detailed information, Richard,

Happy to, especially if it translates to better functionality.

Regards,
Richard W.

author maintainer
#33 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework

Hello Richard,

Quoted 3 lines · Richard

Actually the patch as I sent it was completely self contained it was done that way just to be fast :) Changing it to use the macros is no problem.

Cool.

Quoted 1 line

I'd probably shy away from using the clock frame work to turn on and off each clock via name string though. They would result way too much code.

Yeah, in the autoidle patch I added a clk_allow_idle_all() function that just walked down the clock list and called ->allow_idle() on each clock that had one. This avoided the search by name string. Nevertheless, I think I will set that patch aside for now, it's not critical; maybe we'll take another look at it after the 3430 clock code shows up.

Quoted 2 lines

The OCP registers are in each modules address space. An example of what I was talking about is GTP1.TIOCP_CFG:0x48318010.

Indeed, my mistake; not sure what register I was looking at when I wrote the earlier post.

Quoted 5 lines

On OMAP3 if you are using software control methods you may need to set these in a particular way to ensure data has cleared before shutting down the module. I don't expect control at this granularity makes sense for our typical usage, but if you are doing full hardware dependency for idling it is relevant.

Is this only if we set *_SYSCONFIG.AUTOIDLE to force-idle?

- Paul

#34 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework

Quoted 6 lines
Quoted 2 lines

The OCP registers are in each modules address space. An example of what I was talking about is GTP1.TIOCP_CFG:0x48318010.

Indeed, my mistake; not sure what register I was looking at when I wrote the earlier post.

Quoted 7 lines
Quoted 5 lines

On OMAP3 if you are using software control methods you may need to set these in a particular way to ensure data has cleared before shutting down the module. I don't expect control at this granularity makes sense for our typical usage, but if you are doing full hardware dependency for idling it is relevant.

Is this only if we set *_SYSCONFIG.AUTOIDLE to force-idle?

Yes that is the bit I was talking about in this case.

Regards,
Richard W.

#35 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidlingviathe clock framework

In reply to Woodruff, Richard

-----Original Message-----

Quoted 1 line

Subject: RE: [PATCH 28/28] omap2 clock: handle (almost) all clock

autoidlingviathe clock framework

Quoted 5 lines

Hi Paul,

Quoted 2 lines

Existing OMAP2 code autoidles clocks via pm.c. OMAP clock framework already has some support for enabling autoidle mode via the

allow_idle

Quoted 4 lines
Quoted 4 lines

function; however, this is currently unused. Take advantage of this support by adding autoidle register and bit information for each clock, defining an omap2_clk_allow_idle() function, and adding a framework-wide function, clk_allow_idle_all(), to autoidle all

clocks,

Quoted 1 line
Quoted 1 line

intended to be called on init. Remove all but the APLL/DPLL

autoidle

Quoted 8 lines
Quoted 1 line

bit twiddling from pm.c -- we don't yet have generalized support for

APLL

Quoted 1 line

autoidle. Handling autoidle via the clock framework ensures that we

only

Quoted 1 line

touch clocks that are currently configured.

I thought about doing this back when OMAP1 added this when I was more active on OMAP2. However, I dropped it as it didn't have enough

'bang'

Quoted 2 lines

in this form. I think these registers (even in OMAP1) are widely mis-understood. This is partially a TRM issue and one of complexity.

One minor detail to note is that on OMAP2 the sleep code sometimes has to disable the autoidle feature on certain clocks. Not doing so would prevent desired functionality. This - at least the action of setting the autoidle state - of course could be handled via the clock framework. However, it was deemed to be unnecessary extra layer, as the sleep code already has to be very aware of the hardware its running on and any abstraction is useless. I think at least timers and DMA have some special restrictions in pm.c. Thus the original design of PM code handling the autoidle bits.

Tuukka

----------------------------------------------------------------
Please note: This e-mail may contain confidential information intended solely for the addressee. If you have received this e-mail in error, please do not disclose it to anyone, notify the sender promptly, and delete the message from your system. Thank you.

author maintainer
#36 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidlingviathe clock framework

Quoted 9 lines · On Thu, 23 Aug 2007, [email protected] wrote:

One minor detail to note is that on OMAP2 the sleep code sometimes has to disable the autoidle feature on certain clocks. Not doing so would prevent desired functionality. This - at least the action of setting the autoidle state - of course could be handled via the clock framework. However, it was deemed to be unnecessary extra layer, as the sleep code already has to be very aware of the hardware its running on and any abstraction is useless. I think at least timers and DMA have some special restrictions in pm.c. Thus the original design of PM code handling the autoidle bits.

Hi Tuukka,

I took a quick look at pm.c, it configures ICLK autoidling for SDMA and GPT*, and sleep.S doesn't look like it touches the autoidle regs. Could you point me at the code you're talking about?

thanks,

- Paul

#37 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidlingviathe clock framework

From: [email protected] [mailto:[email protected]] On Behalf Of Paul Walmsley

Quoted 4 lines · On Thu, 23 Aug 2007, [email protected] wrote:
Quoted 2 lines

One minor detail to note is that on OMAP2 the sleep code sometimes

has

Quoted 1 line
Quoted 1 line

to disable the autoidle feature on certain clocks. Not doing so

would

Quoted 1 line
Quoted 1 line

prevent desired functionality. This - at least the action of setting

the

Quoted 2 lines
Quoted 2 lines

autoidle state - of course could be handled via the clock framework. However, it was deemed to be unnecessary extra layer, as the sleep

code

Quoted 8 lines
Quoted 4 lines

already has to be very aware of the hardware its running on and any abstraction is useless. I think at least timers and DMA have some special restrictions in pm.c. Thus the original design of PM code handling the autoidle bits.

Hi Tuukka,

I took a quick look at pm.c, it configures ICLK autoidling for SDMA

and

Quoted 1 line

GPT*, and sleep.S doesn't look like it touches the autoidle regs.

Could

Quoted 1 line

you point me at the code you're talking about?

Sorry for the false alarm, guys. The code I was thinking about lives in OMAP1 tree. The clock framework updates variable called arm_idlect1_mask. That value is programmed after some masking into hardware in omap_pm_idle when entering sleep state. Essentially what we have there is a mask of clocks that may not be autoidled during that particular idle call.

The OMAP2 tree seems to handle its special cases in another way by skipping the sleep completely.

Tuukka

----------------------------------------------------------------
Please note: This e-mail may contain confidential information intended solely for the addressee. If you have received this e-mail in error, please do not disclose it to anyone, notify the sender promptly, and delete the message from your system. Thank you.

#38 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework

In reply to Paul Walmsley

One further note is in the 'ideal' model you should never have to control your I-CLK at all just your F-CLK. I'm sure our hardware people would be very pleased if the code moved in that direction (me too if it turned out to all work). They generally dislike the idea of the clock frame work as they feel it allows duplication of work the hardware can do if setup properly. Its APIs open up some choices which can nullify or reduce understanding of hardware capabilities. For OMAP1 there was no other way. For OMAP2/3 there are some options. I do very much like the frame work but do understand their points.

Ideally, you set all idles at all levels and all async interrupt wake and use the PRCM interrupt to clear status at wake up time, then the system can handle all clocks based on dependency. Iclocks can be managed automatically. Fclocks should be dynamically controlled by drivers on a demand basis. This means some activity timers. When this does work the savings are really massive and dramatic. The catch in it is that one dependency break from a bad driver (sw or hw) at any of the multiple levels will stop it from working. Looking at that way rather than OMAP1 compatibility results in something which looks a bit different.

Regards,
Richard W.

Quoted 4 lines

Hi Paul,

Quoted 2 lines

Existing OMAP2 code autoidles clocks via pm.c. OMAP clock framework already has some support for enabling autoidle mode via the

allow_idle

Quoted 4 lines
Quoted 4 lines

function; however, this is currently unused. Take advantage of this support by adding autoidle register and bit information for each clock, defining an omap2_clk_allow_idle() function, and adding a framework-wide function, clk_allow_idle_all(), to autoidle all

clocks,

Quoted 1 line
Quoted 1 line

intended to be called on init. Remove all but the APLL/DPLL

autoidle

Quoted 8 lines
Quoted 1 line

bit twiddling from pm.c -- we don't yet have generalized support for

APLL

Quoted 1 line

autoidle. Handling autoidle via the clock framework ensures that we

only

Quoted 1 line

touch clocks that are currently configured.

I thought about doing this back when OMAP1 added this when I was more active on OMAP2. However, I dropped it as it didn't have enough

'bang' in

Quoted 5 lines

this form. I think these registers (even in OMAP1) are widely mis- understood. This is partially a TRM issue and one of complexity.

Meaning you can set this register on a per-clock basis however they do nothing for run time except at L3/L4 domain change time. In the

OMAP-GIT

Quoted 1 line

code this means at retention time the PRCM has permission to shut off

your

Quoted 4 lines

ICLK assuming your module acknowledges it. If the PM code does this manually (enable/disable) then this register has no effect.

It does have a useful run time property in that it is one form to gate

a

Quoted 1 line

clock stop state assuming you have not forced it. This is one way to

stop

Quoted 2 lines

a cascade clock stop from happening when you are not expecting it. It would be a lighter weight way then the mutex which OMAP2-GIT code

uses.

Quoted 4 lines

However, for that to work other code would have to change.

Each IP-Module _does_ have an AUTOIDLE bit in its SYSCONIG space which does act as you might expect this bit to. Setting this AUTOIDLE does

save

Quoted 1 line

significant power. It would be more useful to control that one from

here.

Quoted 7 lines

If you hook up a current meter you can toggle all the CM_AUTOIDLES you like and nothing will happen. But if you do the same with the module autoidle you will see a bit change.

Regards,
Richard W.

#39 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clock autoidling viathe clock framework

Quoted 10 lines · Richard

One further note is in the 'ideal' model you should never have to control your I-CLK at all just your F-CLK. I'm sure our hardware people would be very pleased if the code moved in that direction (me too if it turned out to all work). They generally dislike the idea of the clock frame work as they feel it allows duplication of work the hardware can do if setup properly. Its APIs open up some choices which can nullify or reduce understanding of hardware capabilities. For OMAP1 there was no other way. For OMAP2/3 there are some options. I do very much like the frame work but do understand their points.

Quoted 5 lines

Ideally, you set all idles at all levels and all async interrupt wake and use the PRCM interrupt to clear status at wake up time, then the system can handle all clocks based on dependency. Iclocks can be managed automatically. Fclocks should be dynamically controlled by drivers on a demand basis. This means some activity timers.

I'm not new to these concepts, however I find extremely hard to accept the idea of using timers, since they assume to know what the duration of the activity will be.

Could that work on an internet tablet?
For the tablet there is not really a set of use-cases like on a phone, where you can have a closed set of fapplications and do some serious profiling.

Quoted 4 lines

When this
does work the savings are really massive and dramatic. The catch in it is that one dependency break from a bad driver (sw or hw) at any of the multiple levels will stop it from working.

And how easy is it to trace that? All the refcounting seems to be done in HW ...

Signature · 4 lines
Cheers, Igor

Igor Stoppa <[email protected]>
(Nokia Multimedia - CP - OSSO / Helsinki, Finland)
#40 lore raw

RE: [PATCH 28/28] omap2 clock: handle (almost) all clockautoidling viathe clock framework

Quoted 4 lines

From: Igor Stoppa [mailto:[email protected]]

Quoted 2 lines · Richard

One further note is in the 'ideal' model you should never have to control your I-CLK at all just your F-CLK. I'm sure our hardware

people

Quoted 1 line
Quoted 1 line

would be very pleased if the code moved in that direction (me too if

it

Quoted 1 line
Quoted 1 line

turned out to all work). They generally dislike the idea of the

clock

Quoted 1 line
Quoted 1 line

frame work as they feel it allows duplication of work the hardware

can

Quoted 1 line
Quoted 1 line

do if setup properly. Its APIs open up some choices which can

nullify

Quoted 1 line
Quoted 1 line

or reduce understanding of hardware capabilities. For OMAP1 there

was no

Quoted 1 line
Quoted 1 line

other way. For OMAP2/3 there are some options. I do very much like

the

Quoted 3 lines
Quoted 3 lines

frame work but do understand their points.

Ideally, you set all idles at all levels and all async interrupt

wake

Quoted 7 lines
Quoted 4 lines

and use the PRCM interrupt to clear status at wake up time, then the system can handle all clocks based on dependency. Iclocks can be managed automatically. Fclocks should be dynamically controlled by drivers on a demand basis. This means some activity timers.

I'm not new to these concepts, however I find extremely hard to accept the idea of using timers, since they assume to know what the duration

of

Quoted 1 line

the activity will be.

Activity timers on your FCLKS. Many of the Fclks can be tied to input activity and screen blanking. The rest of the clocks are set to driver activity. For some drivers like MMC this isn't so bad as you talk to the device. The main issue with these is making the clock usage well behaved.

The last set of drivers like UART (or Irda) are a bit more tricky as you much make sure the protocol can send a 'wakeup' packet. If the peripheral and its firmware work to spec and all code is right there is a chance. There are just a lot of details. Many of them can sort out such that it can work.

Quoted 1 line

Could that work on an internet tablet?

You can still optimized for some big usecases which you know about. Screen blanking type things. MP3 is a favorite one to talk about. Other things can only be as good as they can be.

One catch in some of these like low power refresh is you much recognize when you are there and adjust some parameters (like FIFO). Once you do this you are at really good power. This kind of activity timer is ok. What is needed is some notion of cost around some of these optimizations. Latency API and some extension can help make the choice for the few major cases it matters at.

Quoted 3 lines

For the tablet there is not really a set of use-cases like on a phone, where you can have a closed set of fapplications and do some serious profiling.

You can't compete with a closed system for sure in optimizations. But because you can't be a 200uA all the time doesn't mean you should settle for 200mA when you could be a 10mA.

Applying such control in fast moving open source is another level of challenge.

Quoted 2 lines
Quoted 2 lines

When this
does work the savings are really massive and dramatic. The catch in

it

Quoted 1 line
Quoted 1 line

is that one dependency break from a bad driver (sw or hw) at any of

the

Quoted 4 lines
Quoted 1 line

multiple levels will stop it from working.

And how easy is it to trace that? All the refcounting seems to be done in HW ...

Not so easy. This was one of the arguments of using a lower layer below the clock frame work. You can catch traces going in and out and send them off to simulation.

Hitting the states has been prototyped and proven on HLOS's so it can happen. It is not just a completely static validation level test.

Regards,
Richard W.