diff options
Diffstat (limited to 'arch/sh/kernel/cpu/sh4a/clock-sh7757.c')
-rw-r--r-- | arch/sh/kernel/cpu/sh4a/clock-sh7757.c | 199 |
1 files changed, 111 insertions, 88 deletions
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c index 0a752bd324ac..ce39a2ae8c6c 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SH7757 support for the clock framework | 4 | * SH7757 support for the clock framework |
5 | * | 5 | * |
6 | * Copyright (C) 2009 Renesas Solutions Corp. | 6 | * Copyright (C) 2009-2010 Renesas Solutions Corp. |
7 | * | 7 | * |
8 | * This file is subject to the terms and conditions of the GNU General Public | 8 | * This file is subject to the terms and conditions of the GNU General Public |
9 | * License. See the file "COPYING" in the main directory of this archive | 9 | * License. See the file "COPYING" in the main directory of this archive |
@@ -16,124 +16,147 @@ | |||
16 | #include <asm/clock.h> | 16 | #include <asm/clock.h> |
17 | #include <asm/freq.h> | 17 | #include <asm/freq.h> |
18 | 18 | ||
19 | static int ifc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, | 19 | /* |
20 | 16, 1, 1, 32, 1, 1, 1, 1 }; | 20 | * Default rate for the root input clock, reset this with clk_set_rate() |
21 | static int sfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, | 21 | * from the platform code. |
22 | 16, 1, 1, 32, 1, 1, 1, 1 }; | 22 | */ |
23 | static int bfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, | 23 | static struct clk extal_clk = { |
24 | 16, 1, 1, 32, 1, 1, 1, 1 }; | 24 | .rate = 48000000, |
25 | static int p1fc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1, | 25 | }; |
26 | 16, 1, 1, 32, 1, 1, 1, 1 }; | ||
27 | 26 | ||
28 | static void master_clk_init(struct clk *clk) | 27 | static unsigned long pll_recalc(struct clk *clk) |
29 | { | 28 | { |
30 | clk->rate = CONFIG_SH_PCLK_FREQ * 16; | 29 | int multiplier; |
31 | } | ||
32 | 30 | ||
33 | static struct clk_ops sh7757_master_clk_ops = { | 31 | multiplier = test_mode_pin(MODE_PIN0) ? 24 : 16; |
34 | .init = master_clk_init, | ||
35 | }; | ||
36 | 32 | ||
37 | static void module_clk_recalc(struct clk *clk) | 33 | return clk->parent->rate * multiplier; |
38 | { | ||
39 | int idx = __raw_readl(FRQCR) & 0x0000000f; | ||
40 | clk->rate = clk->parent->rate / p1fc_divisors[idx]; | ||
41 | } | 34 | } |
42 | 35 | ||
43 | static struct clk_ops sh7757_module_clk_ops = { | 36 | static struct clk_ops pll_clk_ops = { |
44 | .recalc = module_clk_recalc, | 37 | .recalc = pll_recalc, |
45 | }; | 38 | }; |
46 | 39 | ||
47 | static void bus_clk_recalc(struct clk *clk) | 40 | static struct clk pll_clk = { |
48 | { | 41 | .ops = &pll_clk_ops, |
49 | int idx = (__raw_readl(FRQCR) >> 8) & 0x0000000f; | 42 | .parent = &extal_clk, |
50 | clk->rate = clk->parent->rate / bfc_divisors[idx]; | 43 | .flags = CLK_ENABLE_ON_INIT, |
51 | } | 44 | }; |
52 | 45 | ||
53 | static struct clk_ops sh7757_bus_clk_ops = { | 46 | static struct clk *clks[] = { |
54 | .recalc = bus_clk_recalc, | 47 | &extal_clk, |
48 | &pll_clk, | ||
55 | }; | 49 | }; |
56 | 50 | ||
57 | static void cpu_clk_recalc(struct clk *clk) | 51 | static unsigned int div2[] = { 1, 1, 2, 1, 1, 4, 1, 6, |
58 | { | 52 | 1, 1, 1, 16, 1, 24, 1, 1 }; |
59 | int idx = (__raw_readl(FRQCR) >> 20) & 0x0000000f; | ||
60 | clk->rate = clk->parent->rate / ifc_divisors[idx]; | ||
61 | } | ||
62 | 53 | ||
63 | static struct clk_ops sh7757_cpu_clk_ops = { | 54 | static struct clk_div_mult_table div4_div_mult_table = { |
64 | .recalc = cpu_clk_recalc, | 55 | .divisors = div2, |
56 | .nr_divisors = ARRAY_SIZE(div2), | ||
65 | }; | 57 | }; |
66 | 58 | ||
67 | static struct clk_ops *sh7757_clk_ops[] = { | 59 | static struct clk_div4_table div4_table = { |
68 | &sh7757_master_clk_ops, | 60 | .div_mult_table = &div4_div_mult_table, |
69 | &sh7757_module_clk_ops, | ||
70 | &sh7757_bus_clk_ops, | ||
71 | &sh7757_cpu_clk_ops, | ||
72 | }; | 61 | }; |
73 | 62 | ||
74 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | 63 | enum { DIV4_I, DIV4_SH, DIV4_P, DIV4_NR }; |
75 | { | ||
76 | if (idx < ARRAY_SIZE(sh7757_clk_ops)) | ||
77 | *ops = sh7757_clk_ops[idx]; | ||
78 | } | ||
79 | 64 | ||
80 | static void shyway_clk_recalc(struct clk *clk) | 65 | #define DIV4(_bit, _mask, _flags) \ |
81 | { | 66 | SH_CLK_DIV4(&pll_clk, FRQCR, _bit, _mask, _flags) |
82 | int idx = (__raw_readl(FRQCR) >> 12) & 0x0000000f; | ||
83 | clk->rate = clk->parent->rate / sfc_divisors[idx]; | ||
84 | } | ||
85 | |||
86 | static struct clk_ops sh7757_shyway_clk_ops = { | ||
87 | .recalc = shyway_clk_recalc, | ||
88 | }; | ||
89 | 67 | ||
90 | static struct clk sh7757_shyway_clk = { | 68 | struct clk div4_clks[DIV4_NR] = { |
91 | .flags = CLK_ENABLE_ON_INIT, | 69 | /* |
92 | .ops = &sh7757_shyway_clk_ops, | 70 | * P clock is always enable, because some P clock modules is used |
71 | * by Host PC. | ||
72 | */ | ||
73 | [DIV4_P] = DIV4(0, 0x2800, CLK_ENABLE_ON_INIT), | ||
74 | [DIV4_SH] = DIV4(12, 0x00a0, CLK_ENABLE_ON_INIT), | ||
75 | [DIV4_I] = DIV4(20, 0x0004, CLK_ENABLE_ON_INIT), | ||
93 | }; | 76 | }; |
94 | 77 | ||
95 | /* | 78 | #define MSTPCR0 0xffc80030 |
96 | * Additional sh7757-specific on-chip clocks that aren't already part of the | 79 | #define MSTPCR1 0xffc80034 |
97 | * clock framework | 80 | |
98 | */ | 81 | enum { MSTP004, MSTP000, MSTP114, MSTP113, MSTP112, |
99 | static struct clk *sh7757_onchip_clocks[] = { | 82 | MSTP111, MSTP110, MSTP103, MSTP102, |
100 | &sh7757_shyway_clk, | 83 | MSTP_NR }; |
84 | |||
85 | static struct clk mstp_clks[MSTP_NR] = { | ||
86 | /* MSTPCR0 */ | ||
87 | [MSTP004] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 4, 0), | ||
88 | [MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0), | ||
89 | |||
90 | /* MSTPCR1 */ | ||
91 | [MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0), | ||
92 | [MSTP113] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 13, 0), | ||
93 | [MSTP112] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 12, 0), | ||
94 | [MSTP111] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 11, 0), | ||
95 | [MSTP110] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 10, 0), | ||
96 | [MSTP103] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 3, 0), | ||
97 | [MSTP102] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 2, 0), | ||
101 | }; | 98 | }; |
102 | 99 | ||
103 | #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } | 100 | #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } |
104 | 101 | ||
105 | static struct clk_lookup lookups[] = { | 102 | static struct clk_lookup lookups[] = { |
106 | /* main clocks */ | 103 | /* main clocks */ |
107 | CLKDEV_CON_ID("shyway_clk", &sh7757_shyway_clk), | 104 | CLKDEV_CON_ID("extal", &extal_clk), |
105 | CLKDEV_CON_ID("pll_clk", &pll_clk), | ||
106 | |||
107 | /* DIV4 clocks */ | ||
108 | CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]), | ||
109 | CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]), | ||
110 | CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]), | ||
111 | |||
112 | /* MSTP32 clocks */ | ||
113 | CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP004]), | ||
114 | CLKDEV_CON_ID("riic", &mstp_clks[MSTP000]), | ||
115 | { | ||
116 | /* TMU0 */ | ||
117 | .dev_id = "sh_tmu.0", | ||
118 | .con_id = "tmu_fck", | ||
119 | .clk = &mstp_clks[MSTP113], | ||
120 | }, { | ||
121 | /* TMU1 */ | ||
122 | .dev_id = "sh_tmu.1", | ||
123 | .con_id = "tmu_fck", | ||
124 | .clk = &mstp_clks[MSTP114], | ||
125 | }, | ||
126 | { | ||
127 | /* SCIF4 (But, ID is 2) */ | ||
128 | .dev_id = "sh-sci.2", | ||
129 | .con_id = "sci_fck", | ||
130 | .clk = &mstp_clks[MSTP112], | ||
131 | }, { | ||
132 | /* SCIF3 */ | ||
133 | .dev_id = "sh-sci.1", | ||
134 | .con_id = "sci_fck", | ||
135 | .clk = &mstp_clks[MSTP111], | ||
136 | }, { | ||
137 | /* SCIF2 */ | ||
138 | .dev_id = "sh-sci.0", | ||
139 | .con_id = "sci_fck", | ||
140 | .clk = &mstp_clks[MSTP110], | ||
141 | }, | ||
142 | CLKDEV_CON_ID("usb0", &mstp_clks[MSTP102]), | ||
108 | }; | 143 | }; |
109 | 144 | ||
110 | static int __init sh7757_clk_init(void) | 145 | int __init arch_clk_init(void) |
111 | { | 146 | { |
112 | struct clk *clk = clk_get(NULL, "master_clk"); | 147 | int i, ret = 0; |
113 | int i; | ||
114 | |||
115 | for (i = 0; i < ARRAY_SIZE(sh7757_onchip_clocks); i++) { | ||
116 | struct clk *clkp = sh7757_onchip_clocks[i]; | ||
117 | 148 | ||
118 | clkp->parent = clk; | 149 | for (i = 0; i < ARRAY_SIZE(clks); i++) |
119 | clk_register(clkp); | 150 | ret |= clk_register(clks[i]); |
120 | clk_enable(clkp); | 151 | for (i = 0; i < ARRAY_SIZE(lookups); i++) |
121 | } | 152 | clkdev_add(&lookups[i]); |
122 | 153 | ||
123 | /* | 154 | if (!ret) |
124 | * Now that we have the rest of the clocks registered, we need to | 155 | ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks), |
125 | * force the parent clock to propagate so that these clocks will | 156 | &div4_table); |
126 | * automatically figure out their rate. We cheat by handing the | 157 | if (!ret) |
127 | * parent clock its current rate and forcing child propagation. | 158 | ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); |
128 | */ | ||
129 | clk_set_rate(clk, clk_get_rate(clk)); | ||
130 | 159 | ||
131 | clk_put(clk); | 160 | return ret; |
132 | |||
133 | clkdev_add_table(lookups, ARRAY_SIZE(lookups)); | ||
134 | |||
135 | return 0; | ||
136 | } | 161 | } |
137 | 162 | ||
138 | arch_initcall(sh7757_clk_init); | ||
139 | |||