Commit | Line | Data |
---|---|---|
287e3f3f JC |
1 | /* |
2 | * This program is free software; you can redistribute it and/or modify it | |
3 | * under the terms of the GNU General Public License version 2 as published | |
4 | * by the Free Software Foundation. | |
5 | * | |
6 | * Copyright (C) 2011-2012 John Crispin <blogic@openwrt.org> | |
7 | */ | |
8 | ||
9 | #include <linux/ioport.h> | |
10 | #include <linux/export.h> | |
11 | #include <linux/clkdev.h> | |
12 | #include <linux/of.h> | |
13 | #include <linux/of_platform.h> | |
14 | #include <linux/of_address.h> | |
15 | ||
16 | #include <lantiq_soc.h> | |
17 | ||
18 | #include "../clk.h" | |
19 | #include "../prom.h" | |
20 | ||
21 | /* clock control register */ | |
22 | #define CGU_IFCCR 0x0018 | |
e29b72f5 | 23 | #define CGU_IFCCR_VR9 0x0024 |
287e3f3f JC |
24 | /* system clock register */ |
25 | #define CGU_SYS 0x0010 | |
26 | /* pci control register */ | |
27 | #define CGU_PCICR 0x0034 | |
e29b72f5 | 28 | #define CGU_PCICR_VR9 0x0038 |
287e3f3f JC |
29 | /* ephy configuration register */ |
30 | #define CGU_EPHY 0x10 | |
31 | /* power control register */ | |
32 | #define PMU_PWDCR 0x1C | |
33 | /* power status register */ | |
34 | #define PMU_PWDSR 0x20 | |
35 | /* power control register */ | |
36 | #define PMU_PWDCR1 0x24 | |
37 | /* power status register */ | |
38 | #define PMU_PWDSR1 0x28 | |
39 | /* power control register */ | |
40 | #define PWDCR(x) ((x) ? (PMU_PWDCR1) : (PMU_PWDCR)) | |
41 | /* power status register */ | |
42 | #define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR)) | |
43 | ||
44 | /* clock gates that we can en/disable */ | |
45 | #define PMU_USB0_P BIT(0) | |
46 | #define PMU_PCI BIT(4) | |
009d6914 | 47 | #define PMU_DMA BIT(5) |
287e3f3f JC |
48 | #define PMU_USB0 BIT(6) |
49 | #define PMU_ASC0 BIT(7) | |
50 | #define PMU_EPHY BIT(7) /* ase */ | |
51 | #define PMU_SPI BIT(8) | |
52 | #define PMU_DFE BIT(9) | |
53 | #define PMU_EBU BIT(10) | |
54 | #define PMU_STP BIT(11) | |
009d6914 | 55 | #define PMU_GPT BIT(12) |
287e3f3f | 56 | #define PMU_AHBS BIT(13) /* vr9 */ |
009d6914 | 57 | #define PMU_FPI BIT(14) |
287e3f3f JC |
58 | #define PMU_AHBM BIT(15) |
59 | #define PMU_ASC1 BIT(17) | |
60 | #define PMU_PPE_QSB BIT(18) | |
61 | #define PMU_PPE_SLL01 BIT(19) | |
62 | #define PMU_PPE_TC BIT(21) | |
63 | #define PMU_PPE_EMA BIT(22) | |
64 | #define PMU_PPE_DPLUM BIT(23) | |
65 | #define PMU_PPE_DPLUS BIT(24) | |
66 | #define PMU_USB1_P BIT(26) | |
67 | #define PMU_USB1 BIT(27) | |
009d6914 | 68 | #define PMU_SWITCH BIT(28) |
287e3f3f JC |
69 | #define PMU_PPE_TOP BIT(29) |
70 | #define PMU_GPHY BIT(30) | |
71 | #define PMU_PCIE_CLK BIT(31) | |
72 | ||
73 | #define PMU1_PCIE_PHY BIT(0) | |
74 | #define PMU1_PCIE_CTL BIT(1) | |
75 | #define PMU1_PCIE_PDI BIT(4) | |
76 | #define PMU1_PCIE_MSI BIT(5) | |
77 | ||
78 | #define pmu_w32(x, y) ltq_w32((x), pmu_membase + (y)) | |
79 | #define pmu_r32(x) ltq_r32(pmu_membase + (x)) | |
80 | ||
81 | static void __iomem *pmu_membase; | |
82 | void __iomem *ltq_cgu_membase; | |
83 | void __iomem *ltq_ebu_membase; | |
84 | ||
e29b72f5 JC |
85 | static u32 ifccr = CGU_IFCCR; |
86 | static u32 pcicr = CGU_PCICR; | |
87 | ||
287e3f3f JC |
88 | /* legacy function kept alive to ease clkdev transition */ |
89 | void ltq_pmu_enable(unsigned int module) | |
90 | { | |
91 | int err = 1000000; | |
92 | ||
93 | pmu_w32(pmu_r32(PMU_PWDCR) & ~module, PMU_PWDCR); | |
94 | do {} while (--err && (pmu_r32(PMU_PWDSR) & module)); | |
95 | ||
96 | if (!err) | |
97 | panic("activating PMU module failed!"); | |
98 | } | |
99 | EXPORT_SYMBOL(ltq_pmu_enable); | |
100 | ||
101 | /* legacy function kept alive to ease clkdev transition */ | |
102 | void ltq_pmu_disable(unsigned int module) | |
103 | { | |
104 | pmu_w32(pmu_r32(PMU_PWDCR) | module, PMU_PWDCR); | |
105 | } | |
106 | EXPORT_SYMBOL(ltq_pmu_disable); | |
107 | ||
108 | /* enable a hw clock */ | |
109 | static int cgu_enable(struct clk *clk) | |
110 | { | |
e29b72f5 | 111 | ltq_cgu_w32(ltq_cgu_r32(ifccr) | clk->bits, ifccr); |
287e3f3f JC |
112 | return 0; |
113 | } | |
114 | ||
115 | /* disable a hw clock */ | |
116 | static void cgu_disable(struct clk *clk) | |
117 | { | |
e29b72f5 | 118 | ltq_cgu_w32(ltq_cgu_r32(ifccr) & ~clk->bits, ifccr); |
287e3f3f JC |
119 | } |
120 | ||
121 | /* enable a clock gate */ | |
122 | static int pmu_enable(struct clk *clk) | |
123 | { | |
124 | int retry = 1000000; | |
125 | ||
126 | pmu_w32(pmu_r32(PWDCR(clk->module)) & ~clk->bits, | |
127 | PWDCR(clk->module)); | |
128 | do {} while (--retry && (pmu_r32(PWDSR(clk->module)) & clk->bits)); | |
129 | ||
130 | if (!retry) | |
131 | panic("activating PMU module failed!\n"); | |
132 | ||
133 | return 0; | |
134 | } | |
135 | ||
136 | /* disable a clock gate */ | |
137 | static void pmu_disable(struct clk *clk) | |
138 | { | |
139 | pmu_w32(pmu_r32(PWDCR(clk->module)) | clk->bits, | |
140 | PWDCR(clk->module)); | |
141 | } | |
142 | ||
143 | /* the pci enable helper */ | |
144 | static int pci_enable(struct clk *clk) | |
145 | { | |
e29b72f5 | 146 | unsigned int val = ltq_cgu_r32(ifccr); |
287e3f3f | 147 | /* set bus clock speed */ |
f40e1f9d JC |
148 | if (of_machine_is_compatible("lantiq,ar9") || |
149 | of_machine_is_compatible("lantiq,vr9")) { | |
e29b72f5 | 150 | val &= ~0x1f00000; |
287e3f3f | 151 | if (clk->rate == CLOCK_33M) |
e29b72f5 | 152 | val |= 0xe00000; |
287e3f3f | 153 | else |
e29b72f5 | 154 | val |= 0x700000; /* 62.5M */ |
287e3f3f | 155 | } else { |
e29b72f5 | 156 | val &= ~0xf00000; |
287e3f3f | 157 | if (clk->rate == CLOCK_33M) |
e29b72f5 | 158 | val |= 0x800000; |
287e3f3f | 159 | else |
e29b72f5 | 160 | val |= 0x400000; /* 62.5M */ |
287e3f3f | 161 | } |
e29b72f5 | 162 | ltq_cgu_w32(val, ifccr); |
287e3f3f JC |
163 | pmu_enable(clk); |
164 | return 0; | |
165 | } | |
166 | ||
167 | /* enable the external clock as a source */ | |
168 | static int pci_ext_enable(struct clk *clk) | |
169 | { | |
e29b72f5 JC |
170 | ltq_cgu_w32(ltq_cgu_r32(ifccr) & ~(1 << 16), ifccr); |
171 | ltq_cgu_w32((1 << 30), pcicr); | |
287e3f3f JC |
172 | return 0; |
173 | } | |
174 | ||
175 | /* disable the external clock as a source */ | |
176 | static void pci_ext_disable(struct clk *clk) | |
177 | { | |
e29b72f5 JC |
178 | ltq_cgu_w32(ltq_cgu_r32(ifccr) | (1 << 16), ifccr); |
179 | ltq_cgu_w32((1 << 31) | (1 << 30), pcicr); | |
287e3f3f JC |
180 | } |
181 | ||
182 | /* enable a clockout source */ | |
183 | static int clkout_enable(struct clk *clk) | |
184 | { | |
185 | int i; | |
186 | ||
187 | /* get the correct rate */ | |
188 | for (i = 0; i < 4; i++) { | |
189 | if (clk->rates[i] == clk->rate) { | |
190 | int shift = 14 - (2 * clk->module); | |
98dbc576 | 191 | int enable = 7 - clk->module; |
e29b72f5 | 192 | unsigned int val = ltq_cgu_r32(ifccr); |
287e3f3f | 193 | |
e29b72f5 JC |
194 | val &= ~(3 << shift); |
195 | val |= i << shift; | |
98dbc576 | 196 | val |= enable; |
e29b72f5 | 197 | ltq_cgu_w32(val, ifccr); |
287e3f3f JC |
198 | return 0; |
199 | } | |
200 | } | |
201 | return -1; | |
202 | } | |
203 | ||
204 | /* manage the clock gates via PMU */ | |
205 | static void clkdev_add_pmu(const char *dev, const char *con, | |
206 | unsigned int module, unsigned int bits) | |
207 | { | |
208 | struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); | |
209 | ||
210 | clk->cl.dev_id = dev; | |
211 | clk->cl.con_id = con; | |
212 | clk->cl.clk = clk; | |
213 | clk->enable = pmu_enable; | |
214 | clk->disable = pmu_disable; | |
215 | clk->module = module; | |
216 | clk->bits = bits; | |
217 | clkdev_add(&clk->cl); | |
218 | } | |
219 | ||
220 | /* manage the clock generator */ | |
221 | static void clkdev_add_cgu(const char *dev, const char *con, | |
222 | unsigned int bits) | |
223 | { | |
224 | struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); | |
225 | ||
226 | clk->cl.dev_id = dev; | |
227 | clk->cl.con_id = con; | |
228 | clk->cl.clk = clk; | |
229 | clk->enable = cgu_enable; | |
230 | clk->disable = cgu_disable; | |
231 | clk->bits = bits; | |
232 | clkdev_add(&clk->cl); | |
233 | } | |
234 | ||
235 | /* pci needs its own enable function as the setup is a bit more complex */ | |
236 | static unsigned long valid_pci_rates[] = {CLOCK_33M, CLOCK_62_5M, 0}; | |
237 | ||
238 | static void clkdev_add_pci(void) | |
239 | { | |
240 | struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); | |
241 | struct clk *clk_ext = kzalloc(sizeof(struct clk), GFP_KERNEL); | |
242 | ||
243 | /* main pci clock */ | |
244 | clk->cl.dev_id = "17000000.pci"; | |
245 | clk->cl.con_id = NULL; | |
246 | clk->cl.clk = clk; | |
247 | clk->rate = CLOCK_33M; | |
248 | clk->rates = valid_pci_rates; | |
249 | clk->enable = pci_enable; | |
250 | clk->disable = pmu_disable; | |
251 | clk->module = 0; | |
252 | clk->bits = PMU_PCI; | |
253 | clkdev_add(&clk->cl); | |
254 | ||
255 | /* use internal/external bus clock */ | |
256 | clk_ext->cl.dev_id = "17000000.pci"; | |
257 | clk_ext->cl.con_id = "external"; | |
258 | clk_ext->cl.clk = clk_ext; | |
259 | clk_ext->enable = pci_ext_enable; | |
260 | clk_ext->disable = pci_ext_disable; | |
261 | clkdev_add(&clk_ext->cl); | |
262 | } | |
263 | ||
264 | /* xway socs can generate clocks on gpio pins */ | |
265 | static unsigned long valid_clkout_rates[4][5] = { | |
266 | {CLOCK_32_768K, CLOCK_1_536M, CLOCK_2_5M, CLOCK_12M, 0}, | |
267 | {CLOCK_40M, CLOCK_12M, CLOCK_24M, CLOCK_48M, 0}, | |
268 | {CLOCK_25M, CLOCK_40M, CLOCK_30M, CLOCK_60M, 0}, | |
269 | {CLOCK_12M, CLOCK_50M, CLOCK_32_768K, CLOCK_25M, 0}, | |
270 | }; | |
271 | ||
272 | static void clkdev_add_clkout(void) | |
273 | { | |
274 | int i; | |
275 | ||
276 | for (i = 0; i < 4; i++) { | |
277 | struct clk *clk; | |
278 | char *name; | |
279 | ||
280 | name = kzalloc(sizeof("clkout0"), GFP_KERNEL); | |
281 | sprintf(name, "clkout%d", i); | |
282 | ||
283 | clk = kzalloc(sizeof(struct clk), GFP_KERNEL); | |
284 | clk->cl.dev_id = "1f103000.cgu"; | |
285 | clk->cl.con_id = name; | |
286 | clk->cl.clk = clk; | |
287 | clk->rate = 0; | |
288 | clk->rates = valid_clkout_rates[i]; | |
289 | clk->enable = clkout_enable; | |
290 | clk->module = i; | |
291 | clkdev_add(&clk->cl); | |
292 | } | |
293 | } | |
294 | ||
295 | /* bring up all register ranges that we need for basic system control */ | |
296 | void __init ltq_soc_init(void) | |
297 | { | |
298 | struct resource res_pmu, res_cgu, res_ebu; | |
299 | struct device_node *np_pmu = | |
300 | of_find_compatible_node(NULL, NULL, "lantiq,pmu-xway"); | |
301 | struct device_node *np_cgu = | |
302 | of_find_compatible_node(NULL, NULL, "lantiq,cgu-xway"); | |
303 | struct device_node *np_ebu = | |
304 | of_find_compatible_node(NULL, NULL, "lantiq,ebu-xway"); | |
305 | ||
306 | /* check if all the core register ranges are available */ | |
307 | if (!np_pmu || !np_cgu || !np_ebu) | |
308 | panic("Failed to load core nodess from devicetree"); | |
309 | ||
310 | if (of_address_to_resource(np_pmu, 0, &res_pmu) || | |
311 | of_address_to_resource(np_cgu, 0, &res_cgu) || | |
312 | of_address_to_resource(np_ebu, 0, &res_ebu)) | |
313 | panic("Failed to get core resources"); | |
314 | ||
315 | if ((request_mem_region(res_pmu.start, resource_size(&res_pmu), | |
316 | res_pmu.name) < 0) || | |
317 | (request_mem_region(res_cgu.start, resource_size(&res_cgu), | |
318 | res_cgu.name) < 0) || | |
319 | (request_mem_region(res_ebu.start, resource_size(&res_ebu), | |
320 | res_ebu.name) < 0)) | |
321 | pr_err("Failed to request core reources"); | |
322 | ||
323 | pmu_membase = ioremap_nocache(res_pmu.start, resource_size(&res_pmu)); | |
324 | ltq_cgu_membase = ioremap_nocache(res_cgu.start, | |
325 | resource_size(&res_cgu)); | |
326 | ltq_ebu_membase = ioremap_nocache(res_ebu.start, | |
327 | resource_size(&res_ebu)); | |
328 | if (!pmu_membase || !ltq_cgu_membase || !ltq_ebu_membase) | |
329 | panic("Failed to remap core resources"); | |
330 | ||
331 | /* make sure to unprotect the memory region where flash is located */ | |
332 | ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); | |
333 | ||
334 | /* add our generic xway clocks */ | |
335 | clkdev_add_pmu("10000000.fpi", NULL, 0, PMU_FPI); | |
336 | clkdev_add_pmu("1e100400.serial", NULL, 0, PMU_ASC0); | |
337 | clkdev_add_pmu("1e100a00.gptu", NULL, 0, PMU_GPT); | |
338 | clkdev_add_pmu("1e100bb0.stp", NULL, 0, PMU_STP); | |
339 | clkdev_add_pmu("1e104100.dma", NULL, 0, PMU_DMA); | |
340 | clkdev_add_pmu("1e100800.spi", NULL, 0, PMU_SPI); | |
341 | clkdev_add_pmu("1e105300.ebu", NULL, 0, PMU_EBU); | |
342 | clkdev_add_clkout(); | |
343 | ||
344 | /* add the soc dependent clocks */ | |
e29b72f5 JC |
345 | if (of_machine_is_compatible("lantiq,vr9")) { |
346 | ifccr = CGU_IFCCR_VR9; | |
347 | pcicr = CGU_PCICR_VR9; | |
348 | } else { | |
287e3f3f | 349 | clkdev_add_pmu("1e180000.etop", NULL, 0, PMU_PPE); |
e29b72f5 | 350 | } |
287e3f3f JC |
351 | |
352 | if (!of_machine_is_compatible("lantiq,ase")) { | |
353 | clkdev_add_pmu("1e100c00.serial", NULL, 0, PMU_ASC1); | |
354 | clkdev_add_pci(); | |
355 | } | |
356 | ||
357 | if (of_machine_is_compatible("lantiq,ase")) { | |
358 | if (ltq_cgu_r32(CGU_SYS) & (1 << 5)) | |
359 | clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); | |
360 | else | |
361 | clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); | |
362 | clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY), | |
363 | clkdev_add_pmu("1e180000.etop", "ephy", 0, PMU_EPHY); | |
364 | } else if (of_machine_is_compatible("lantiq,vr9")) { | |
365 | clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), | |
366 | ltq_vr9_fpi_hz()); | |
367 | clkdev_add_pmu("1d900000.pcie", "phy", 1, PMU1_PCIE_PHY); | |
368 | clkdev_add_pmu("1d900000.pcie", "bus", 0, PMU_PCIE_CLK); | |
369 | clkdev_add_pmu("1d900000.pcie", "msi", 1, PMU1_PCIE_MSI); | |
370 | clkdev_add_pmu("1d900000.pcie", "pdi", 1, PMU1_PCIE_PDI); | |
371 | clkdev_add_pmu("1d900000.pcie", "ctl", 1, PMU1_PCIE_CTL); | |
372 | clkdev_add_pmu("1d900000.pcie", "ahb", 0, PMU_AHBM | PMU_AHBS); | |
f2bbe41c JC |
373 | clkdev_add_pmu("1e108000.eth", NULL, 0, |
374 | PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | | |
375 | PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | | |
376 | PMU_PPE_QSB | PMU_PPE_TOP); | |
287e3f3f JC |
377 | } else if (of_machine_is_compatible("lantiq,ar9")) { |
378 | clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(), | |
379 | ltq_ar9_fpi_hz()); | |
380 | clkdev_add_pmu("1e180000.etop", "switch", 0, PMU_SWITCH); | |
381 | } else { | |
382 | clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), | |
383 | ltq_danube_fpi_hz()); | |
384 | } | |
385 | } |