1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * arch/sh/kernel/cpu/sh4a/clock-sh7366.c
4  *
5  * SH7366 clock framework support
6  *
7  * Copyright (C) 2009 Magnus Damm
8  */
9 #include <linux/init.h>
10 #include <linux/kernel.h>
11 #include <linux/io.h>
12 #include <linux/clkdev.h>
13 #include <asm/clock.h>
14 
15 /* SH7366 registers */
16 #define FRQCR		0xa4150000
17 #define VCLKCR		0xa4150004
18 #define SCLKACR		0xa4150008
19 #define SCLKBCR		0xa415000c
20 #define PLLCR		0xa4150024
21 #define MSTPCR0		0xa4150030
22 #define MSTPCR1		0xa4150034
23 #define MSTPCR2		0xa4150038
24 #define DLLFRQ		0xa4150050
25 
26 /* Fixed 32 KHz root clock for RTC and Power Management purposes */
27 static struct clk r_clk = {
28 	.rate           = 32768,
29 };
30 
31 /*
32  * Default rate for the root input clock, reset this with clk_set_rate()
33  * from the platform code.
34  */
35 struct clk extal_clk = {
36 	.rate		= 33333333,
37 };
38 
39 /* The dll block multiplies the 32khz r_clk, may be used instead of extal */
40 static unsigned long dll_recalc(struct clk *clk)
41 {
42 	unsigned long mult;
43 
44 	if (__raw_readl(PLLCR) & 0x1000)
45 		mult = __raw_readl(DLLFRQ);
46 	else
47 		mult = 0;
48 
49 	return clk->parent->rate * mult;
50 }
51 
52 static struct sh_clk_ops dll_clk_ops = {
53 	.recalc		= dll_recalc,
54 };
55 
56 static struct clk dll_clk = {
57 	.ops		= &dll_clk_ops,
58 	.parent		= &r_clk,
59 	.flags		= CLK_ENABLE_ON_INIT,
60 };
61 
62 static unsigned long pll_recalc(struct clk *clk)
63 {
64 	unsigned long mult = 1;
65 	unsigned long div = 1;
66 
67 	if (__raw_readl(PLLCR) & 0x4000)
68 		mult = (((__raw_readl(FRQCR) >> 24) & 0x1f) + 1);
69 	else
70 		div = 2;
71 
72 	return (clk->parent->rate * mult) / div;
73 }
74 
75 static struct sh_clk_ops pll_clk_ops = {
76 	.recalc		= pll_recalc,
77 };
78 
79 static struct clk pll_clk = {
80 	.ops		= &pll_clk_ops,
81 	.flags		= CLK_ENABLE_ON_INIT,
82 };
83 
84 struct clk *main_clks[] = {
85 	&r_clk,
86 	&extal_clk,
87 	&dll_clk,
88 	&pll_clk,
89 };
90 
91 static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
92 static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
93 
94 static struct clk_div_mult_table div4_div_mult_table = {
95 	.divisors = divisors,
96 	.nr_divisors = ARRAY_SIZE(divisors),
97 	.multipliers = multipliers,
98 	.nr_multipliers = ARRAY_SIZE(multipliers),
99 };
100 
101 static struct clk_div4_table div4_table = {
102 	.div_mult_table = &div4_div_mult_table,
103 };
104 
105 enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
106        DIV4_SIUA, DIV4_SIUB, DIV4_NR };
107 
108 #define DIV4(_reg, _bit, _mask, _flags) \
109   SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
110 
111 struct clk div4_clks[DIV4_NR] = {
112 	[DIV4_I] = DIV4(FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT),
113 	[DIV4_U] = DIV4(FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
114 	[DIV4_SH] = DIV4(FRQCR, 12, 0x1fff, CLK_ENABLE_ON_INIT),
115 	[DIV4_B] = DIV4(FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
116 	[DIV4_B3] = DIV4(FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
117 	[DIV4_P] = DIV4(FRQCR, 0, 0x1fff, 0),
118 	[DIV4_SIUA] = DIV4(SCLKACR, 0, 0x1fff, 0),
119 	[DIV4_SIUB] = DIV4(SCLKBCR, 0, 0x1fff, 0),
120 };
121 
122 enum { DIV6_V, DIV6_NR };
123 
124 struct clk div6_clks[DIV6_NR] = {
125 	[DIV6_V] = SH_CLK_DIV6(&pll_clk, VCLKCR, 0),
126 };
127 
128 #define MSTP(_parent, _reg, _bit, _flags) \
129   SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
130 
131 enum { MSTP031, MSTP030, MSTP029, MSTP028, MSTP026,
132        MSTP023, MSTP022, MSTP021, MSTP020, MSTP019, MSTP018, MSTP017, MSTP016,
133        MSTP015, MSTP014, MSTP013, MSTP012, MSTP011, MSTP010,
134        MSTP007, MSTP006, MSTP005, MSTP002, MSTP001,
135        MSTP109, MSTP100,
136        MSTP227, MSTP226, MSTP224, MSTP223, MSTP222, MSTP218, MSTP217,
137        MSTP211, MSTP207, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
138        MSTP_NR };
139 
140 static struct clk mstp_clks[MSTP_NR] = {
141 	/* See page 52 of Datasheet V0.40: Overview -> Block Diagram */
142 	[MSTP031] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 31, CLK_ENABLE_ON_INIT),
143 	[MSTP030] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 30, CLK_ENABLE_ON_INIT),
144 	[MSTP029] = MSTP(&div4_clks[DIV4_I], MSTPCR0, 29, CLK_ENABLE_ON_INIT),
145 	[MSTP028] = MSTP(&div4_clks[DIV4_SH], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
146 	[MSTP026] = MSTP(&div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
147 	[MSTP023] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 23, 0),
148 	[MSTP022] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 22, 0),
149 	[MSTP021] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 21, 0),
150 	[MSTP020] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 20, 0),
151 	[MSTP019] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
152 	[MSTP017] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 17, 0),
153 	[MSTP015] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
154 	[MSTP014] = MSTP(&r_clk, MSTPCR0, 14, 0),
155 	[MSTP013] = MSTP(&r_clk, MSTPCR0, 13, 0),
156 	[MSTP011] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
157 	[MSTP010] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
158 	[MSTP007] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
159 	[MSTP006] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 6, 0),
160 	[MSTP005] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 5, 0),
161 	[MSTP002] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
162 	[MSTP001] = MSTP(&div4_clks[DIV4_P], MSTPCR0, 1, 0),
163 
164 	[MSTP109] = MSTP(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
165 
166 	[MSTP227] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 27, 0),
167 	[MSTP226] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 26, 0),
168 	[MSTP224] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 24, 0),
169 	[MSTP223] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 23, 0),
170 	[MSTP222] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 22, 0),
171 	[MSTP218] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 18, 0),
172 	[MSTP217] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 17, 0),
173 	[MSTP211] = MSTP(&div4_clks[DIV4_P], MSTPCR2, 11, 0),
174 	[MSTP207] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 7, CLK_ENABLE_ON_INIT),
175 	[MSTP205] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
176 	[MSTP204] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
177 	[MSTP203] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
178 	[MSTP202] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT),
179 	[MSTP201] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT),
180 	[MSTP200] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
181 };
182 
183 static struct clk_lookup lookups[] = {
184 	/* main clocks */
185 	CLKDEV_CON_ID("rclk", &r_clk),
186 	CLKDEV_CON_ID("extal", &extal_clk),
187 	CLKDEV_CON_ID("dll_clk", &dll_clk),
188 	CLKDEV_CON_ID("pll_clk", &pll_clk),
189 
190 	/* DIV4 clocks */
191 	CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
192 	CLKDEV_CON_ID("umem_clk", &div4_clks[DIV4_U]),
193 	CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
194 	CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
195 	CLKDEV_CON_ID("b3_clk", &div4_clks[DIV4_B3]),
196 	CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
197 	CLKDEV_CON_ID("siua_clk", &div4_clks[DIV4_SIUA]),
198 	CLKDEV_CON_ID("siub_clk", &div4_clks[DIV4_SIUB]),
199 
200 	/* DIV6 clocks */
201 	CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
202 
203 	/* MSTP32 clocks */
204 	CLKDEV_CON_ID("tlb0", &mstp_clks[MSTP031]),
205 	CLKDEV_CON_ID("ic0", &mstp_clks[MSTP030]),
206 	CLKDEV_CON_ID("oc0", &mstp_clks[MSTP029]),
207 	CLKDEV_CON_ID("rsmem0", &mstp_clks[MSTP028]),
208 	CLKDEV_CON_ID("xymem0", &mstp_clks[MSTP026]),
209 	CLKDEV_CON_ID("intc3", &mstp_clks[MSTP023]),
210 	CLKDEV_CON_ID("intc0", &mstp_clks[MSTP022]),
211 	CLKDEV_CON_ID("dmac0", &mstp_clks[MSTP021]),
212 	CLKDEV_CON_ID("sh0", &mstp_clks[MSTP020]),
213 	CLKDEV_CON_ID("hudi0", &mstp_clks[MSTP019]),
214 	CLKDEV_CON_ID("ubc0", &mstp_clks[MSTP017]),
215 	CLKDEV_CON_ID("tmu_fck", &mstp_clks[MSTP015]),
216 	CLKDEV_ICK_ID("fck", "sh-cmt-32.0", &mstp_clks[MSTP014]),
217 	CLKDEV_CON_ID("rwdt0", &mstp_clks[MSTP013]),
218 	CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
219 	CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
220 
221 	CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP007]),
222 	CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP006]),
223 	CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP005]),
224 
225 	CLKDEV_CON_ID("msiof0", &mstp_clks[MSTP002]),
226 	CLKDEV_CON_ID("sbr0", &mstp_clks[MSTP001]),
227 	CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP109]),
228 	CLKDEV_CON_ID("icb0", &mstp_clks[MSTP227]),
229 	CLKDEV_CON_ID("meram0", &mstp_clks[MSTP226]),
230 	CLKDEV_CON_ID("dacy1", &mstp_clks[MSTP224]),
231 	CLKDEV_CON_ID("dacy0", &mstp_clks[MSTP223]),
232 	CLKDEV_CON_ID("tsif0", &mstp_clks[MSTP222]),
233 	CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP218]),
234 	CLKDEV_CON_ID("mmcif0", &mstp_clks[MSTP217]),
235 	CLKDEV_CON_ID("usbf0", &mstp_clks[MSTP211]),
236 	CLKDEV_CON_ID("veu1", &mstp_clks[MSTP207]),
237 	CLKDEV_CON_ID("vou0", &mstp_clks[MSTP205]),
238 	CLKDEV_CON_ID("beu0", &mstp_clks[MSTP204]),
239 	CLKDEV_CON_ID("ceu0", &mstp_clks[MSTP203]),
240 	CLKDEV_CON_ID("veu0", &mstp_clks[MSTP202]),
241 	CLKDEV_CON_ID("vpu0", &mstp_clks[MSTP201]),
242 	CLKDEV_CON_ID("lcdc0", &mstp_clks[MSTP200]),
243 };
244 
245 int __init arch_clk_init(void)
246 {
247 	int k, ret = 0;
248 
249 	/* autodetect extal or dll configuration */
250 	if (__raw_readl(PLLCR) & 0x1000)
251 		pll_clk.parent = &dll_clk;
252 	else
253 		pll_clk.parent = &extal_clk;
254 
255 	for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
256 		ret = clk_register(main_clks[k]);
257 
258 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
259 
260 	if (!ret)
261 		ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
262 
263 	if (!ret)
264 		ret = sh_clk_div6_register(div6_clks, DIV6_NR);
265 
266 	if (!ret)
267 		ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
268 
269 	return ret;
270 }
271