Explorar o código

sh: Fix clock multiplier on SH7722.

This fixes up the master clock multiplier and initial rate
propagation for the SH7722 clocks.

Signed-off-by: dmitry pervushin <dimka@nomadgs.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
dmitry pervushin %!s(int64=18) %!d(string=hai) anos
pai
achega
dfbbbe9295
Modificáronse 2 ficheiros con 29 adicións e 12 borrados
  1. 7 0
      arch/sh/kernel/cpu/clock.c
  2. 22 12
      arch/sh/kernel/cpu/sh4a/clock-sh7722.c

+ 7 - 0
arch/sh/kernel/cpu/clock.c

@@ -278,6 +278,11 @@ arch_init_clk_ops(struct clk_ops **ops, int type)
 {
 {
 }
 }
 
 
+void __init __attribute__ ((weak))
+arch_clk_init(void)
+{
+}
+
 static int show_clocks(char *buf, char **start, off_t off,
 static int show_clocks(char *buf, char **start, off_t off,
 		       int len, int *eof, void *data)
 		       int len, int *eof, void *data)
 {
 {
@@ -314,6 +319,8 @@ int __init clk_init(void)
 		ret |= clk_register(clk);
 		ret |= clk_register(clk);
 	}
 	}
 
 
+	arch_clk_init();
+
 	/* Kick the child clocks.. */
 	/* Kick the child clocks.. */
 	propagate_rate(&master_clk);
 	propagate_rate(&master_clk);
 	propagate_rate(&bus_clk);
 	propagate_rate(&bus_clk);

+ 22 - 12
arch/sh/kernel/cpu/sh4a/clock-sh7722.c

@@ -17,7 +17,6 @@
 #include <asm/clock.h>
 #include <asm/clock.h>
 #include <asm/freq.h>
 #include <asm/freq.h>
 
 
-#define SH7722_PLL_FREQ (32000000/8)
 #define N  (-1)
 #define N  (-1)
 #define NM (-2)
 #define NM (-2)
 #define ROUND_NEAREST 0
 #define ROUND_NEAREST 0
@@ -141,28 +140,36 @@ static void adjust_clocks(int originate, int *l, unsigned long v[],
 */
 */
 static int divisors2[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40 };
 static int divisors2[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40 };
 
 
+static void master_clk_recalc(struct clk *clk)
+{
+	unsigned frqcr = ctrl_inl(FRQCR);
+
+	clk->rate = CONFIG_SH_PCLK_FREQ * (((frqcr >> 24) & 0x1f) + 1);
+}
+
 static void master_clk_init(struct clk *clk)
 static void master_clk_init(struct clk *clk)
 {
 {
-	clk_set_rate(clk, clk_get_rate(clk));
+	clk->parent = NULL;
+	clk->flags |= CLK_RATE_PROPAGATES;
+	clk->rate = CONFIG_SH_PCLK_FREQ;
+	master_clk_recalc(clk);
 }
 }
 
 
-static void master_clk_recalc(struct clk *clk)
+
+static void module_clk_recalc(struct clk *clk)
 {
 {
 	unsigned long frqcr = ctrl_inl(FRQCR);
 	unsigned long frqcr = ctrl_inl(FRQCR);
 
 
-	clk->rate = CONFIG_SH_PCLK_FREQ * (1 + (frqcr >> 24 & 0xF));
+	clk->rate = clk->parent->rate / (((frqcr >> 24) & 0x1f) + 1);
 }
 }
 
 
 static int master_clk_setrate(struct clk *clk, unsigned long rate, int id)
 static int master_clk_setrate(struct clk *clk, unsigned long rate, int id)
 {
 {
-	int div = rate / SH7722_PLL_FREQ;
+	int div = rate / clk->rate;
 	int master_divs[] = { 2, 3, 4, 6, 8, 16 };
 	int master_divs[] = { 2, 3, 4, 6, 8, 16 };
 	int index;
 	int index;
 	unsigned long frqcr;
 	unsigned long frqcr;
 
 
-	if (rate < SH7722_PLL_FREQ * 2)
-		return -EINVAL;
-
 	for (index = 1; index < ARRAY_SIZE(master_divs); index++)
 	for (index = 1; index < ARRAY_SIZE(master_divs); index++)
 		if (div >= master_divs[index - 1] && div < master_divs[index])
 		if (div >= master_divs[index - 1] && div < master_divs[index])
 			break;
 			break;
@@ -185,6 +192,10 @@ static struct clk_ops sh7722_master_clk_ops = {
 	.set_rate = master_clk_setrate,
 	.set_rate = master_clk_setrate,
 };
 };
 
 
+static struct clk_ops sh7722_module_clk_ops = {
+       .recalc = module_clk_recalc,
+};
+
 struct frqcr_context {
 struct frqcr_context {
 	unsigned mask;
 	unsigned mask;
 	unsigned shift;
 	unsigned shift;
@@ -489,7 +500,7 @@ static void sh7722_siu_recalc(struct clk *clk)
 
 
 	if (siu < 0)
 	if (siu < 0)
 		return /* siu */ ;
 		return /* siu */ ;
-	BUG_ON(siu > 1);
+	BUG_ON(siu > 2);
 	r = ctrl_inl(sh7722_siu_regs[siu]);
 	r = ctrl_inl(sh7722_siu_regs[siu]);
 	clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF];
 	clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF];
 }
 }
@@ -571,7 +582,7 @@ static struct clk *sh7722_clocks[] = {
  */
  */
 struct clk_ops *onchip_ops[] = {
 struct clk_ops *onchip_ops[] = {
 	&sh7722_master_clk_ops,
 	&sh7722_master_clk_ops,
-	&sh7722_frqcr_clk_ops,
+	&sh7722_module_clk_ops,
 	&sh7722_frqcr_clk_ops,
 	&sh7722_frqcr_clk_ops,
 	&sh7722_frqcr_clk_ops,
 	&sh7722_frqcr_clk_ops,
 };
 };
@@ -583,7 +594,7 @@ arch_init_clk_ops(struct clk_ops **ops, int type)
 	*ops = onchip_ops[type];
 	*ops = onchip_ops[type];
 }
 }
 
 
-int __init sh7722_clock_init(void)
+int __init arch_clk_init(void)
 {
 {
 	struct clk *master;
 	struct clk *master;
 	int i;
 	int i;
@@ -597,4 +608,3 @@ int __init sh7722_clock_init(void)
 	clk_put(master);
 	clk_put(master);
 	return 0;
 	return 0;
 }
 }
-arch_initcall(sh7722_clock_init);