diff options
author | Paul Mundt <lethal@linux-sh.org> | 2010-10-01 10:49:56 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-10-01 10:49:56 -0400 |
commit | 5924ad0d86fbc05bfb0c90afa15e20ccb7155549 (patch) | |
tree | 6e1a60dbadfbb1238f5ebb0d3cbcd37f3aee26ee /arch/sh/kernel | |
parent | 68a1aed7039e5a94a8e60e23fdf676738c36086a (diff) |
sh: Update SH-X3 subtype for clkdev lookups.
Rewrite the SH-X3 proto CPU clock framework for clkdev.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/cpu/sh4a/clock-shx3.c | 225 |
1 files changed, 142 insertions, 83 deletions
diff --git a/arch/sh/kernel/cpu/sh4a/clock-shx3.c b/arch/sh/kernel/cpu/sh4a/clock-shx3.c index 236a6282d778..4f70df6b6169 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/clock-shx3.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * Copyright (C) 2006-2007 Renesas Technology Corp. | 6 | * Copyright (C) 2006-2007 Renesas Technology Corp. |
7 | * Copyright (C) 2006-2007 Renesas Solutions Corp. | 7 | * Copyright (C) 2006-2007 Renesas Solutions Corp. |
8 | * Copyright (C) 2006-2007 Paul Mundt | 8 | * Copyright (C) 2006-2010 Paul Mundt |
9 | * | 9 | * |
10 | * This file is subject to the terms and conditions of the GNU General Public | 10 | * This file is subject to the terms and conditions of the GNU General Public |
11 | * License. See the file "COPYING" in the main directory of this archive | 11 | * License. See the file "COPYING" in the main directory of this archive |
@@ -18,120 +18,179 @@ | |||
18 | #include <asm/clock.h> | 18 | #include <asm/clock.h> |
19 | #include <asm/freq.h> | 19 | #include <asm/freq.h> |
20 | 20 | ||
21 | static int ifc_divisors[] = { 1, 2, 4 ,6 }; | 21 | /* |
22 | static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18, 24, 32, 36, 48 }; | 22 | * Default rate for the root input clock, reset this with clk_set_rate() |
23 | static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18, 24, 32, 36, 48 }; | 23 | * from the platform code. |
24 | static int cfc_divisors[] = { 1, 1, 4, 6 }; | 24 | */ |
25 | 25 | static struct clk extal_clk = { | |
26 | #define IFC_POS 28 | 26 | .rate = 16666666, |
27 | #define IFC_MSK 0x0003 | ||
28 | #define BFC_MSK 0x000f | ||
29 | #define PFC_MSK 0x000f | ||
30 | #define CFC_MSK 0x0003 | ||
31 | #define BFC_POS 16 | ||
32 | #define PFC_POS 0 | ||
33 | #define CFC_POS 20 | ||
34 | |||
35 | static void master_clk_init(struct clk *clk) | ||
36 | { | ||
37 | clk->rate *= pfc_divisors[(__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK]; | ||
38 | } | ||
39 | |||
40 | static struct clk_ops shx3_master_clk_ops = { | ||
41 | .init = master_clk_init, | ||
42 | }; | 27 | }; |
43 | 28 | ||
44 | static unsigned long module_clk_recalc(struct clk *clk) | 29 | static unsigned long pll_recalc(struct clk *clk) |
45 | { | 30 | { |
46 | int idx = ((__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK); | 31 | /* PLL1 has a fixed x72 multiplier. */ |
47 | return clk->parent->rate / pfc_divisors[idx]; | 32 | return clk->parent->rate * 72; |
48 | } | 33 | } |
49 | 34 | ||
50 | static struct clk_ops shx3_module_clk_ops = { | 35 | static struct clk_ops pll_clk_ops = { |
51 | .recalc = module_clk_recalc, | 36 | .recalc = pll_recalc, |
52 | }; | 37 | }; |
53 | 38 | ||
54 | static unsigned long bus_clk_recalc(struct clk *clk) | 39 | static struct clk pll_clk = { |
55 | { | 40 | .ops = &pll_clk_ops, |
56 | int idx = ((__raw_readl(FRQCR) >> BFC_POS) & BFC_MSK); | 41 | .parent = &extal_clk, |
57 | return clk->parent->rate / bfc_divisors[idx]; | 42 | .flags = CLK_ENABLE_ON_INIT, |
58 | } | 43 | }; |
59 | 44 | ||
60 | static struct clk_ops shx3_bus_clk_ops = { | 45 | static struct clk *clks[] = { |
61 | .recalc = bus_clk_recalc, | 46 | &extal_clk, |
47 | &pll_clk, | ||
62 | }; | 48 | }; |
63 | 49 | ||
64 | static unsigned long cpu_clk_recalc(struct clk *clk) | 50 | static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18, |
65 | { | 51 | 24, 32, 36, 48 }; |
66 | int idx = ((__raw_readl(FRQCR) >> IFC_POS) & IFC_MSK); | ||
67 | return clk->parent->rate / ifc_divisors[idx]; | ||
68 | } | ||
69 | 52 | ||
70 | static struct clk_ops shx3_cpu_clk_ops = { | 53 | static struct clk_div_mult_table div4_div_mult_table = { |
71 | .recalc = cpu_clk_recalc, | 54 | .divisors = div2, |
55 | .nr_divisors = ARRAY_SIZE(div2), | ||
72 | }; | 56 | }; |
73 | 57 | ||
74 | static struct clk_ops *shx3_clk_ops[] = { | 58 | static struct clk_div4_table div4_table = { |
75 | &shx3_master_clk_ops, | 59 | .div_mult_table = &div4_div_mult_table, |
76 | &shx3_module_clk_ops, | ||
77 | &shx3_bus_clk_ops, | ||
78 | &shx3_cpu_clk_ops, | ||
79 | }; | 60 | }; |
80 | 61 | ||
81 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | 62 | enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_DDR, DIV4_SHA, DIV4_P, DIV4_NR }; |
82 | { | ||
83 | if (idx < ARRAY_SIZE(shx3_clk_ops)) | ||
84 | *ops = shx3_clk_ops[idx]; | ||
85 | } | ||
86 | 63 | ||
87 | static unsigned long shyway_clk_recalc(struct clk *clk) | 64 | #define DIV4(_bit, _mask, _flags) \ |
88 | { | 65 | SH_CLK_DIV4(&pll_clk, FRQMR1, _bit, _mask, _flags) |
89 | int idx = ((__raw_readl(FRQCR) >> CFC_POS) & CFC_MSK); | ||
90 | return clk->parent->rate / cfc_divisors[idx]; | ||
91 | } | ||
92 | 66 | ||
93 | static struct clk_ops shx3_shyway_clk_ops = { | 67 | struct clk div4_clks[DIV4_NR] = { |
94 | .recalc = shyway_clk_recalc, | 68 | [DIV4_P] = DIV4(0, 0x0f80, 0), |
69 | [DIV4_SHA] = DIV4(4, 0x0ff0, 0), | ||
70 | [DIV4_DDR] = DIV4(12, 0x000c, CLK_ENABLE_ON_INIT), | ||
71 | [DIV4_B] = DIV4(16, 0x0fe0, CLK_ENABLE_ON_INIT), | ||
72 | [DIV4_SH] = DIV4(20, 0x000c, CLK_ENABLE_ON_INIT), | ||
73 | [DIV4_I] = DIV4(28, 0x000e, CLK_ENABLE_ON_INIT), | ||
95 | }; | 74 | }; |
96 | 75 | ||
97 | static struct clk shx3_shyway_clk = { | 76 | #define MSTPCR0 0xffc00030 |
98 | .flags = CLK_ENABLE_ON_INIT, | 77 | #define MSTPCR1 0xffc00034 |
99 | .ops = &shx3_shyway_clk_ops, | 78 | |
100 | }; | 79 | enum { MSTP027, MSTP026, MSTP025, MSTP024, |
101 | 80 | MSTP009, MSTP008, MSTP003, MSTP002, | |
102 | /* | 81 | MSTP001, MSTP000, MSTP119, MSTP105, |
103 | * Additional SHx3-specific on-chip clocks that aren't already part of the | 82 | MSTP104, MSTP_NR }; |
104 | * clock framework | 83 | |
105 | */ | 84 | static struct clk mstp_clks[MSTP_NR] = { |
106 | static struct clk *shx3_onchip_clocks[] = { | 85 | /* MSTPCR0 */ |
107 | &shx3_shyway_clk, | 86 | [MSTP027] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 27, 0), |
87 | [MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0), | ||
88 | [MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0), | ||
89 | [MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0), | ||
90 | [MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0), | ||
91 | [MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0), | ||
92 | [MSTP003] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 3, 0), | ||
93 | [MSTP002] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 2, 0), | ||
94 | [MSTP001] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 1, 0), | ||
95 | [MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0), | ||
96 | |||
97 | /* MSTPCR1 */ | ||
98 | [MSTP119] = SH_CLK_MSTP32(NULL, MSTPCR1, 19, 0), | ||
99 | [MSTP105] = SH_CLK_MSTP32(NULL, MSTPCR1, 5, 0), | ||
100 | [MSTP104] = SH_CLK_MSTP32(NULL, MSTPCR1, 4, 0), | ||
108 | }; | 101 | }; |
109 | 102 | ||
110 | #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } | 103 | #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } |
111 | 104 | ||
112 | static struct clk_lookup lookups[] = { | 105 | static struct clk_lookup lookups[] = { |
113 | /* main clocks */ | 106 | /* main clocks */ |
114 | CLKDEV_CON_ID("shyway_clk", &shx3_shyway_clk), | 107 | CLKDEV_CON_ID("extal", &extal_clk), |
108 | CLKDEV_CON_ID("pll_clk", &pll_clk), | ||
109 | |||
110 | /* DIV4 clocks */ | ||
111 | CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]), | ||
112 | CLKDEV_CON_ID("shywaya_clk", &div4_clks[DIV4_SHA]), | ||
113 | CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_DDR]), | ||
114 | CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]), | ||
115 | CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]), | ||
116 | CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]), | ||
117 | |||
118 | /* MSTP32 clocks */ | ||
119 | { | ||
120 | /* SCIF3 */ | ||
121 | .dev_id = "sh-sci.3", | ||
122 | .con_id = "sci_fck", | ||
123 | .clk = &mstp_clks[MSTP027], | ||
124 | }, { | ||
125 | /* SCIF2 */ | ||
126 | .dev_id = "sh-sci.2", | ||
127 | .con_id = "sci_fck", | ||
128 | .clk = &mstp_clks[MSTP026], | ||
129 | }, { | ||
130 | /* SCIF1 */ | ||
131 | .dev_id = "sh-sci.1", | ||
132 | .con_id = "sci_fck", | ||
133 | .clk = &mstp_clks[MSTP025], | ||
134 | }, { | ||
135 | /* SCIF0 */ | ||
136 | .dev_id = "sh-sci.0", | ||
137 | .con_id = "sci_fck", | ||
138 | .clk = &mstp_clks[MSTP024], | ||
139 | }, | ||
140 | CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]), | ||
141 | CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]), | ||
142 | CLKDEV_CON_ID("fe1_fck", &mstp_clks[MSTP001]), | ||
143 | CLKDEV_CON_ID("fe0_fck", &mstp_clks[MSTP000]), | ||
144 | { | ||
145 | /* TMU0 */ | ||
146 | .dev_id = "sh_tmu.0", | ||
147 | .con_id = "tmu_fck", | ||
148 | .clk = &mstp_clks[MSTP008], | ||
149 | }, { | ||
150 | /* TMU1 */ | ||
151 | .dev_id = "sh_tmu.1", | ||
152 | .con_id = "tmu_fck", | ||
153 | .clk = &mstp_clks[MSTP008], | ||
154 | }, { | ||
155 | /* TMU2 */ | ||
156 | .dev_id = "sh_tmu.2", | ||
157 | .con_id = "tmu_fck", | ||
158 | .clk = &mstp_clks[MSTP008], | ||
159 | }, { | ||
160 | /* TMU3 */ | ||
161 | .dev_id = "sh_tmu.3", | ||
162 | .con_id = "tmu_fck", | ||
163 | .clk = &mstp_clks[MSTP009], | ||
164 | }, { | ||
165 | /* TMU4 */ | ||
166 | .dev_id = "sh_tmu.4", | ||
167 | .con_id = "tmu_fck", | ||
168 | .clk = &mstp_clks[MSTP009], | ||
169 | }, { | ||
170 | /* TMU5 */ | ||
171 | .dev_id = "sh_tmu.5", | ||
172 | .con_id = "tmu_fck", | ||
173 | .clk = &mstp_clks[MSTP009], | ||
174 | }, | ||
175 | CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]), | ||
176 | CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]), | ||
177 | CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]), | ||
115 | }; | 178 | }; |
116 | 179 | ||
117 | int __init arch_clk_init(void) | 180 | int __init arch_clk_init(void) |
118 | { | 181 | { |
119 | struct clk *clk; | ||
120 | int i, ret = 0; | 182 | int i, ret = 0; |
121 | 183 | ||
122 | cpg_clk_init(); | 184 | for (i = 0; i < ARRAY_SIZE(clks); i++) |
123 | 185 | ret |= clk_register(clks[i]); | |
124 | clk = clk_get(NULL, "master_clk"); | 186 | for (i = 0; i < ARRAY_SIZE(lookups); i++) |
125 | for (i = 0; i < ARRAY_SIZE(shx3_onchip_clocks); i++) { | 187 | clkdev_add(&lookups[i]); |
126 | struct clk *clkp = shx3_onchip_clocks[i]; | ||
127 | |||
128 | clkp->parent = clk; | ||
129 | ret |= clk_register(clkp); | ||
130 | } | ||
131 | |||
132 | clk_put(clk); | ||
133 | 188 | ||
134 | clkdev_add_table(lookups, ARRAY_SIZE(lookups)); | 189 | if (!ret) |
190 | ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks), | ||
191 | &div4_table); | ||
192 | if (!ret) | ||
193 | ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); | ||
135 | 194 | ||
136 | return ret; | 195 | return ret; |
137 | } | 196 | } |