public inbox for linux-omap@vger.kernel.org
 help / color / mirror / Atom feed
From: Paul Walmsley <paul@pwsan.com>
To: linux-omap-open-source@linux.omap.com
Subject: [PATCH 17/22] omap2 clock: Cleanup in clksel-related code; add sys_clkout2 divisor handling
Date: Thu, 02 Aug 2007 12:10:19 -0600	[thread overview]
Message-ID: <20070802181143.242524981@pwsan.com> (raw)
In-Reply-To: 20070802181002.792550043@pwsan.com

[-- Attachment #1: get_clksel_cleanup.patch --]
[-- Type: text/plain, Size: 11242 bytes --]

Convert omap2_get_clksel to use void __iomem *.  Add
omap2_divisor_to_clksel(), to convert clock divisors into appropriate
register bit field values.  Use non-shifted register bit field masks
in clksel code, rather than masks that have been preshifted down to
bit 0 -- this simplifies existing code and facilitates the use of
symbolic constants from the recent PRCM cleanup.  Also add code to
properly handle divisors for sys_clkout2 on OMAP2420.  Previously
this clock's divisor settings were ignored.

Signed-off-by: Paul Walmsley <paul@pwsan.com>

---
 arch/arm/mach-omap2/clock.c |  192 +++++++++++++++++++++-----------------------
 1 file changed, 93 insertions(+), 99 deletions(-)

Index: linux-omap/arch/arm/mach-omap2/clock.c
Index: linux-omap/arch/arm/mach-omap2/clock.c
===================================================================
--- linux-omap.orig/arch/arm/mach-omap2/clock.c
+++ linux-omap/arch/arm/mach-omap2/clock.c
@@ -52,6 +52,8 @@ 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
  *-------------------------------------------------------------------------*/
@@ -428,7 +430,6 @@ static u32 omap2_clksel_round_rate(struc
 	u32 *new_div)
 {
 	u32 gfx_div[] = {2, 3, 4};
-	u32 sysclkout_div[] = {1, 2, 4, 8, 16};
 	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;
@@ -601,38 +602,50 @@ static long omap2_round_to_table_rate(st
 }
 
 /*
- * omap2_convert_field_to_div() - turn field value into integer divider
+ * omap2_clksel_to_divisor() - turn field value into integer divider
  */
 static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val)
 {
 	u32 i;
-	u32 clkout_array[] = {1, 2, 4, 8, 16};
 
 	if ((div_sel & SRC_RATE_SEL_MASK) == CM_SYSCLKOUT_SEL1) {
-		for (i = 0; i < 5; i++) {
+		for (i = 0; i < ARRAY_SIZE(sysclkout_div); i++) {
 			if (field_val == i)
-				return clkout_array[i];
+				return sysclkout_div[i];
 		}
-		return ~0;
+		return 0;
 	} else
 		return field_val;
 }
 
 /*
+ * omap2_divisor_to_clksel() - turn integer divider into field value
+ */
+static u32 omap2_divisor_to_clksel(u32 div_sel, u32 div)
+{
+	u32 i;
+
+	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;
+}
+
+/*
  * Returns the CLKSEL divider register value
- * REVISIT: This should be cleaned up to work nicely with void __iomem *
  */
-static u32 omap2_get_clksel(u32 *div_sel, u32 *field_mask,
-			    struct clk *clk)
+static void __iomem *omap2_get_clksel(u32 *field_mask, struct clk *clk)
 {
-	int ret = ~0;
-	u32 reg_val, div_off;
+	u32 div_off, mask = ~0;
 	void __iomem *div_addr = 0;
-	u32 mask = ~0;
 
 	div_off = clk->rate_offset;
 
-	switch ((*div_sel & SRC_RATE_SEL_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;
@@ -696,44 +709,32 @@ static u32 omap2_get_clksel(u32 *div_sel
 		}
 	}
 
-	*field_mask = (mask >> div_off);
-
-	if (unlikely(mask == ~0))
-		div_addr = 0;
-
-	*div_sel = (u32)div_addr;
-
-	if (unlikely(div_addr == 0))
-		return ret;
-
-	/* Isolate field */
-	reg_val = cm_read_reg(div_addr) & mask;
+	if (unlikely((mask == ~0) || (div_addr == 0)))
+		return 0;
 
-	/* Normalize back to divider value */
-	reg_val >>= div_off;
+	*field_mask = mask;
 
-	return reg_val;
+	return div_addr;
 }
 
+
 /*
  * Return divider to be applied to parent clock.
  * Return 0 on error.
  */
 static u32 omap2_clksel_get_divisor(struct clk *clk)
 {
-	int ret = 0;
-	u32 div, div_sel, div_off, field_mask, field_val;
+	u32 div, field_mask, field_val;
+	void __iomem *div_addr;
 
-	/* isolate control register */
-	div_sel = (SRC_RATE_SEL_MASK & clk->flags);
+	div_addr = omap2_get_clksel(&field_mask, clk);
+	if (div_addr == 0)
+		return 0;
 
-	div_off = clk->rate_offset;
-	field_val = omap2_get_clksel(&div_sel, &field_mask, clk);
-	if (div_sel == 0)
-		return ret;
+	field_val = cm_read_reg(div_addr) & field_mask;
+	field_val >>= clk->rate_offset;
 
-	div_sel = (SRC_RATE_SEL_MASK & clk->flags);
-	div = omap2_clksel_to_divisor(div_sel, field_val);
+	div = omap2_clksel_to_divisor(clk->flags, field_val);
 
 	return div;
 }
@@ -742,53 +743,33 @@ static u32 omap2_clksel_get_divisor(stru
 static int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
 {
 	int ret = -EINVAL;
-	void __iomem * reg;
-	u32 div_sel, div_off, field_mask, field_val, reg_val, validrate;
+	u32 div_off, field_mask, field_val, reg_val, validrate;
 	u32 new_div = 0;
+	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_sel = (SRC_RATE_SEL_MASK & clk->flags);
 		div_off = clk->rate_offset;
 
 		validrate = omap2_clksel_round_rate(clk, rate, &new_div);
 		if (validrate != rate)
 			return ret;
 
-		field_val = omap2_get_clksel(&div_sel, &field_mask, clk);
-		if (div_sel == 0)
+		div_addr = omap2_get_clksel(&field_mask, clk);
+		if (div_addr == 0)
 			return ret;
 
-		if (clk->flags & CM_SYSCLKOUT_SEL1) {
-			switch (new_div) {
-			case 16:
-				field_val = 4;
-				break;
-			case 8:
-				field_val = 3;
-				break;
-			case 4:
-				field_val = 2;
-				break;
-			case 2:
-				field_val = 1;
-				break;
-			case 1:
-				field_val = 0;
-				break;
-			}
-		} else
-			field_val = new_div;
-
-		reg = (void __iomem *)div_sel;
+		field_val = omap2_divisor_to_clksel(clk->flags, new_div);
+		if (field_val == ~0)
+			return ret;
 
-		reg_val = cm_read_reg(reg);
-		reg_val &= ~(field_mask << div_off);
+		reg_val = cm_read_reg(div_addr);
+		reg_val &= ~field_mask;
 		reg_val |= (field_val << div_off);
-		cm_write_reg(reg_val, reg);
+		cm_write_reg(reg_val, div_addr);
 		wmb();
 		clk->rate = clk->parent->rate / new_div;
 
@@ -809,26 +790,28 @@ static int omap2_clk_set_rate(struct clk
 }
 
 /* Converts encoded control register address into a full address */
-static u32 omap2_get_src_field(u32 *type_to_addr, u32 reg_offset,
-			       struct clk *src_clk, u32 *field_mask)
+static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
+				      struct clk *src_clk, u32 *field_mask,
+				      struct clk *clk)
 {
 	u32 val = ~0, mask = 0;
 	void __iomem *src_reg_addr = 0;
+	u32 reg_offset;
+
+	reg_offset = clk->src_offset;
 
 	/* Find target control register.*/
-	switch ((*type_to_addr & SRC_RATE_SEL_MASK)) {
+	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;
-			mask >>= OMAP24XX_CLKSEL_DSS2_SHIFT;
 			if (src_clk == &sys_ck)
 				val = 0;
 			if (src_clk == &func_48m_ck)
 				val = 1;
 		} else if (reg_offset == OMAP24XX_CLKSEL_DSS1_SHIFT) {
 			mask = OMAP24XX_CLKSEL_DSS1_MASK;
-			mask >>= OMAP24XX_CLKSEL_DSS1_SHIFT;
 			if (src_clk == &sys_ck)
 				val = 0;
 			else if (src_clk == &core_ck)	/* divided clock */
@@ -836,16 +819,20 @@ static u32 omap2_get_src_field(u32 *type
 		} else if ((reg_offset == OMAP2420_CLKSEL_VLYNQ_SHIFT) &&
 			   cpu_is_omap2420()) {
 			mask = OMAP2420_CLKSEL_VLYNQ_MASK;
-			mask >>= OMAP2420_CLKSEL_VLYNQ_SHIFT;
 			if (src_clk == &func_96m_ck)
 				val = 0;
 			else if (src_clk == &core_ck)
 				val = 0x10;             /* rate needs fixing */
+		} 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 = 0x3;
+		mask = OMAP24XX_CLKSEL_GPT2_MASK;
+		mask <<= (reg_offset - OMAP24XX_CLKSEL_GPT2_SHIFT);
 		if (src_clk == &func_32k_ck)
 			val = 0x0;
 		if (src_clk == &sys_ck)
@@ -854,8 +841,9 @@ static u32 omap2_get_src_field(u32 *type
 			val = 0x2;
 		break;
 	case CM_WKUP_SEL1:
+		WARN_ON(reg_offset != 0); /* unknown reg_offset */
 		src_reg_addr = OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL);
-		mask = 0x3;
+		mask = OMAP24XX_CLKSEL_GPT1_MASK;
 		if (src_clk == &func_32k_ck)
 			val = 0x0;
 		if (src_clk == &sys_ck)
@@ -865,23 +853,27 @@ static u32 omap2_get_src_field(u32 *type
 		break;
 	case CM_PLL_SEL1:
 		src_reg_addr = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1);
-		mask = 0x1;
 		if (reg_offset == 0x3) {
+			mask = OMAP24XX_48M_SOURCE;
 			if (src_clk == &apll96_ck)
 				val = 0;
 			if (src_clk == &alt_ck)
 				val = 1;
 		}
 		else if (reg_offset == 0x5) {
+			mask = OMAP24XX_54M_SOURCE;
 			if (src_clk == &apll54_ck)
 				val = 0;
 			if (src_clk == &alt_ck)
 				val = 1;
+		} 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 = 0x3;
+		mask = OMAP24XX_CORE_CLK_SRC_MASK;
 		if (src_clk == &func_32k_ck)
 			val = 0x0;
 		if (src_clk == &dpll_ck)
@@ -889,7 +881,15 @@ static u32 omap2_get_src_field(u32 *type
 		break;
 	case CM_SYSCLKOUT_SEL1:
 		src_reg_addr = OMAP24XX_PRCM_CLKOUT_CTRL;
-		mask = 0x3;
+
+		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 */
+		}
+
 		if (src_clk == &dpll_ck)
 			val = 0;
 		if (src_clk == &sys_ck)
@@ -902,9 +902,10 @@ static u32 omap2_get_src_field(u32 *type
 	}
 
 	if (val == ~0)			/* Catch errors in offset */
-		*type_to_addr = 0;
+		*src_addr = 0;
 	else
-		*type_to_addr = (u32)src_reg_addr;
+		*src_addr = src_reg_addr;
+
 	*field_mask = mask;
 
 	return val;
@@ -912,34 +913,27 @@ static u32 omap2_get_src_field(u32 *type
 
 static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
 {
-	void __iomem * reg;
-	u32 src_sel, src_off, field_val, field_mask, reg_val;
-	int ret = -EINVAL;
+	void __iomem *src_addr;
+	u32 field_val, field_mask, reg_val;
 
 	if (unlikely(clk->flags & CONFIG_PARTICIPANT))
-		return ret;
+		return -EINVAL;
 
 	if (unlikely(!(clk->flags & SRC_SEL_MASK)))
-		return ret;
-
-	src_sel = (SRC_RATE_SEL_MASK & clk->flags);
-	src_off = clk->src_offset;
-
-	if (src_sel == 0)
-		return ret;
-
-	field_val = omap2_get_src_field(&src_sel, src_off, new_parent,
-					&field_mask);
+		return -EINVAL;
 
-	reg = (void __iomem *)src_sel;
+	field_val = omap2_clksel_get_src_field(&src_addr, new_parent,
+					       &field_mask, clk);
+	if (src_addr == 0)
+		return -EINVAL;
 
 	if (clk->usecount > 0)
 		_omap2_clk_disable(clk);
 
 	/* Set new source value (previous dividers if any in effect) */
-	reg_val = __raw_readl(reg) & ~(field_mask << src_off);
-	reg_val |= (field_val << src_off);
-	__raw_writel(reg_val, reg);
+	reg_val = __raw_readl(src_addr) & ~field_mask;
+	reg_val |= (field_val << clk->src_offset);
+	__raw_writel(reg_val, src_addr);
 	wmb();
 
 	if (clk->flags & DELAYED_APP) {

-- 

  parent reply	other threads:[~2007-08-02 18:10 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-08-02 18:10 [PATCH 00/22] omap2 clock: Bugfixes and cleanups in OMAP2 clock framework Paul Walmsley
2007-08-02 18:10 ` [PATCH 01/22] omap2 clock: drop meaningless RATE_CKCTLs Paul Walmsley
2007-08-02 18:10 ` [PATCH 02/22] omap2 clock: fix incorrect rate calculation for osc_ck, sys_ck Paul Walmsley
2007-08-10 21:08   ` [PATCH 02/22 - Reverse] omap2 osc & sys clock calculation Woodruff, Richard
2007-08-13  7:03     ` Tony Lindgren
2007-08-02 18:10 ` [PATCH 03/22] omap2 clock: fix clksel divisor bug Paul Walmsley
2007-08-02 18:10 ` [PATCH 04/22] omap2 clock: vlynq_fck recalc should be clksel, not followparent Paul Walmsley
2007-08-02 18:10 ` [PATCH 05/22] omap2 clock: fix CodingStyle issues Paul Walmsley
2007-08-02 18:10 ` [PATCH 06/22] omap2 clock: drop unnecessary variable in omap2_clk_round_rate() Paul Walmsley
2007-08-02 18:10 ` [PATCH 07/22] omap2 clock: get rid of sleep_ck Paul Walmsley
2007-08-02 18:10 ` [PATCH 08/22] omap2 clock: clean up dss2_fck clock flags Paul Walmsley
2007-08-02 18:10 ` [PATCH 09/22] omap2 clock: move SDRC-related code from clock.c to memory.c Paul Walmsley
2007-08-02 18:10 ` [PATCH 10/22] omap2 clock: use symbolic constants in clock.h rate_offset/src_offset fields Paul Walmsley
2007-08-02 18:10 ` [PATCH 11/22] omap2 clock: fix some clocks incorrectly marked as present on OMAP2430 Paul Walmsley
2007-08-02 18:45   ` [PATCH 11/22] omap2 clock: fix some clocks incorrectly marked aspresent " Woodruff, Richard
2007-08-02 19:05   ` Woodruff, Richard
2007-08-03 18:09     ` Paul Walmsley
2007-08-03 18:47       ` Woodruff, Richard
2007-08-04 15:56         ` Paul Walmsley
2007-08-04 22:02           ` Woodruff, Richard
2007-08-10  9:43             ` Tony Lindgren
2007-08-02 18:10 ` [PATCH 12/22] omap2 clock: vlynq_fck is missing clksel divider code Paul Walmsley
2007-08-02 18:10 ` [PATCH 13/22] omap2 clock: convert PARENT_CONTROLS_CLOCK into a clock flag Paul Walmsley
2007-08-02 18:10 ` [PATCH 14/22] omap2 clock: omap2 clock.c: Consolidate wait-for-lock code Paul Walmsley
2007-08-02 18:10 ` [PATCH 15/22] omap2 clock: return -EINVAL if no clock enable code; fix dpll_ck enable Paul Walmsley
2007-08-02 18:10 ` [PATCH 16/22] omap2 clock: From: Paul Walmsley <paul@pwsan.com> Subject: Paul Walmsley
2007-08-02 18:10 ` Paul Walmsley [this message]
2007-08-02 18:10 ` [PATCH 18/22] omap2 clock: Use symbolic constants in clock.c Paul Walmsley
2007-08-02 18:10 ` [PATCH 19/22] omap2 clock: use dedicated omap2_dpll_recalc() for DPLL recalc func Paul Walmsley
2007-08-02 18:10 ` [PATCH 20/22] omap2 clock: add fixed divisor clock code Paul Walmsley
2007-08-02 18:10 ` [PATCH 21/22] omap2 clock: remove fixed rate from mdm_osc_ck Paul Walmsley
2007-08-02 18:10 ` [PATCH 22/22] omap2 clock: get rid of omap2_followparent_recalc() Paul Walmsley

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070802181143.242524981@pwsan.com \
    --to=paul@pwsan.com \
    --cc=linux-omap-open-source@linux.omap.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox