diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/ar7 | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/ar7')
-rw-r--r-- | arch/mips/ar7/Makefile | 11 | ||||
-rw-r--r-- | arch/mips/ar7/Platform | 5 | ||||
-rw-r--r-- | arch/mips/ar7/clock.c | 494 | ||||
-rw-r--r-- | arch/mips/ar7/gpio.c | 331 | ||||
-rw-r--r-- | arch/mips/ar7/irq.c | 165 | ||||
-rw-r--r-- | arch/mips/ar7/memory.c | 56 | ||||
-rw-r--r-- | arch/mips/ar7/platform.c | 722 | ||||
-rw-r--r-- | arch/mips/ar7/prom.c | 256 | ||||
-rw-r--r-- | arch/mips/ar7/setup.c | 93 | ||||
-rw-r--r-- | arch/mips/ar7/time.c | 31 |
10 files changed, 2164 insertions, 0 deletions
diff --git a/arch/mips/ar7/Makefile b/arch/mips/ar7/Makefile new file mode 100644 index 000000000..cd51c6c6e --- /dev/null +++ b/arch/mips/ar7/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | obj-y := \ | ||
4 | prom.o \ | ||
5 | setup.o \ | ||
6 | memory.o \ | ||
7 | irq.o \ | ||
8 | time.o \ | ||
9 | platform.o \ | ||
10 | gpio.o \ | ||
11 | clock.o | ||
diff --git a/arch/mips/ar7/Platform b/arch/mips/ar7/Platform new file mode 100644 index 000000000..a9257cc01 --- /dev/null +++ b/arch/mips/ar7/Platform | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Texas Instruments AR7 | ||
3 | # | ||
4 | cflags-$(CONFIG_AR7) += -I$(srctree)/arch/mips/include/asm/mach-ar7 | ||
5 | load-$(CONFIG_AR7) += 0xffffffff94100000 | ||
diff --git a/arch/mips/ar7/clock.c b/arch/mips/ar7/clock.c new file mode 100644 index 000000000..95def949c --- /dev/null +++ b/arch/mips/ar7/clock.c | |||
@@ -0,0 +1,494 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> | ||
4 | * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org> | ||
5 | * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org> | ||
6 | */ | ||
7 | |||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/export.h> | ||
12 | #include <linux/delay.h> | ||
13 | #include <linux/gcd.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/clk.h> | ||
17 | |||
18 | #include <asm/addrspace.h> | ||
19 | #include <asm/mach-ar7/ar7.h> | ||
20 | |||
21 | #define BOOT_PLL_SOURCE_MASK 0x3 | ||
22 | #define CPU_PLL_SOURCE_SHIFT 16 | ||
23 | #define BUS_PLL_SOURCE_SHIFT 14 | ||
24 | #define USB_PLL_SOURCE_SHIFT 18 | ||
25 | #define DSP_PLL_SOURCE_SHIFT 22 | ||
26 | #define BOOT_PLL_SOURCE_AFE 0 | ||
27 | #define BOOT_PLL_SOURCE_BUS 0 | ||
28 | #define BOOT_PLL_SOURCE_REF 1 | ||
29 | #define BOOT_PLL_SOURCE_XTAL 2 | ||
30 | #define BOOT_PLL_SOURCE_CPU 3 | ||
31 | #define BOOT_PLL_BYPASS 0x00000020 | ||
32 | #define BOOT_PLL_ASYNC_MODE 0x02000000 | ||
33 | #define BOOT_PLL_2TO1_MODE 0x00008000 | ||
34 | |||
35 | #define TNETD7200_CLOCK_ID_CPU 0 | ||
36 | #define TNETD7200_CLOCK_ID_DSP 1 | ||
37 | #define TNETD7200_CLOCK_ID_USB 2 | ||
38 | |||
39 | #define TNETD7200_DEF_CPU_CLK 211000000 | ||
40 | #define TNETD7200_DEF_DSP_CLK 125000000 | ||
41 | #define TNETD7200_DEF_USB_CLK 48000000 | ||
42 | |||
43 | struct tnetd7300_clock { | ||
44 | u32 ctrl; | ||
45 | #define PREDIV_MASK 0x001f0000 | ||
46 | #define PREDIV_SHIFT 16 | ||
47 | #define POSTDIV_MASK 0x0000001f | ||
48 | u32 unused1[3]; | ||
49 | u32 pll; | ||
50 | #define MUL_MASK 0x0000f000 | ||
51 | #define MUL_SHIFT 12 | ||
52 | #define PLL_MODE_MASK 0x00000001 | ||
53 | #define PLL_NDIV 0x00000800 | ||
54 | #define PLL_DIV 0x00000002 | ||
55 | #define PLL_STATUS 0x00000001 | ||
56 | u32 unused2[3]; | ||
57 | }; | ||
58 | |||
59 | struct tnetd7300_clocks { | ||
60 | struct tnetd7300_clock bus; | ||
61 | struct tnetd7300_clock cpu; | ||
62 | struct tnetd7300_clock usb; | ||
63 | struct tnetd7300_clock dsp; | ||
64 | }; | ||
65 | |||
66 | struct tnetd7200_clock { | ||
67 | u32 ctrl; | ||
68 | u32 unused1[3]; | ||
69 | #define DIVISOR_ENABLE_MASK 0x00008000 | ||
70 | u32 mul; | ||
71 | u32 prediv; | ||
72 | u32 postdiv; | ||
73 | u32 postdiv2; | ||
74 | u32 unused2[6]; | ||
75 | u32 cmd; | ||
76 | u32 status; | ||
77 | u32 cmden; | ||
78 | u32 padding[15]; | ||
79 | }; | ||
80 | |||
81 | struct tnetd7200_clocks { | ||
82 | struct tnetd7200_clock cpu; | ||
83 | struct tnetd7200_clock dsp; | ||
84 | struct tnetd7200_clock usb; | ||
85 | }; | ||
86 | |||
87 | static struct clk bus_clk = { | ||
88 | .rate = 125000000, | ||
89 | }; | ||
90 | |||
91 | static struct clk cpu_clk = { | ||
92 | .rate = 150000000, | ||
93 | }; | ||
94 | |||
95 | static struct clk dsp_clk; | ||
96 | static struct clk vbus_clk; | ||
97 | |||
98 | static void approximate(int base, int target, int *prediv, | ||
99 | int *postdiv, int *mul) | ||
100 | { | ||
101 | int i, j, k, freq, res = target; | ||
102 | for (i = 1; i <= 16; i++) | ||
103 | for (j = 1; j <= 32; j++) | ||
104 | for (k = 1; k <= 32; k++) { | ||
105 | freq = abs(base / j * i / k - target); | ||
106 | if (freq < res) { | ||
107 | res = freq; | ||
108 | *mul = i; | ||
109 | *prediv = j; | ||
110 | *postdiv = k; | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static void calculate(int base, int target, int *prediv, int *postdiv, | ||
116 | int *mul) | ||
117 | { | ||
118 | int tmp_gcd, tmp_base, tmp_freq; | ||
119 | |||
120 | for (*prediv = 1; *prediv <= 32; (*prediv)++) { | ||
121 | tmp_base = base / *prediv; | ||
122 | tmp_gcd = gcd(target, tmp_base); | ||
123 | *mul = target / tmp_gcd; | ||
124 | *postdiv = tmp_base / tmp_gcd; | ||
125 | if ((*mul < 1) || (*mul >= 16)) | ||
126 | continue; | ||
127 | if ((*postdiv > 0) & (*postdiv <= 32)) | ||
128 | break; | ||
129 | } | ||
130 | |||
131 | if (base / *prediv * *mul / *postdiv != target) { | ||
132 | approximate(base, target, prediv, postdiv, mul); | ||
133 | tmp_freq = base / *prediv * *mul / *postdiv; | ||
134 | printk(KERN_WARNING | ||
135 | "Adjusted requested frequency %d to %d\n", | ||
136 | target, tmp_freq); | ||
137 | } | ||
138 | |||
139 | printk(KERN_DEBUG "Clocks: prediv: %d, postdiv: %d, mul: %d\n", | ||
140 | *prediv, *postdiv, *mul); | ||
141 | } | ||
142 | |||
143 | static int tnetd7300_dsp_clock(void) | ||
144 | { | ||
145 | u32 didr1, didr2; | ||
146 | u8 rev = ar7_chip_rev(); | ||
147 | didr1 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x18)); | ||
148 | didr2 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x1c)); | ||
149 | if (didr2 & (1 << 23)) | ||
150 | return 0; | ||
151 | if ((rev >= 0x23) && (rev != 0x57)) | ||
152 | return 250000000; | ||
153 | if ((((didr2 & 0x1fff) << 10) | ((didr1 & 0xffc00000) >> 22)) | ||
154 | > 4208000) | ||
155 | return 250000000; | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock, | ||
160 | u32 *bootcr, u32 bus_clock) | ||
161 | { | ||
162 | int product; | ||
163 | int base_clock = AR7_REF_CLOCK; | ||
164 | u32 ctrl = readl(&clock->ctrl); | ||
165 | u32 pll = readl(&clock->pll); | ||
166 | int prediv = ((ctrl & PREDIV_MASK) >> PREDIV_SHIFT) + 1; | ||
167 | int postdiv = (ctrl & POSTDIV_MASK) + 1; | ||
168 | int divisor = prediv * postdiv; | ||
169 | int mul = ((pll & MUL_MASK) >> MUL_SHIFT) + 1; | ||
170 | |||
171 | switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) { | ||
172 | case BOOT_PLL_SOURCE_BUS: | ||
173 | base_clock = bus_clock; | ||
174 | break; | ||
175 | case BOOT_PLL_SOURCE_REF: | ||
176 | base_clock = AR7_REF_CLOCK; | ||
177 | break; | ||
178 | case BOOT_PLL_SOURCE_XTAL: | ||
179 | base_clock = AR7_XTAL_CLOCK; | ||
180 | break; | ||
181 | case BOOT_PLL_SOURCE_CPU: | ||
182 | base_clock = cpu_clk.rate; | ||
183 | break; | ||
184 | } | ||
185 | |||
186 | if (*bootcr & BOOT_PLL_BYPASS) | ||
187 | return base_clock / divisor; | ||
188 | |||
189 | if ((pll & PLL_MODE_MASK) == 0) | ||
190 | return (base_clock >> (mul / 16 + 1)) / divisor; | ||
191 | |||
192 | if ((pll & (PLL_NDIV | PLL_DIV)) == (PLL_NDIV | PLL_DIV)) { | ||
193 | product = (mul & 1) ? | ||
194 | (base_clock * mul) >> 1 : | ||
195 | (base_clock * (mul - 1)) >> 2; | ||
196 | return product / divisor; | ||
197 | } | ||
198 | |||
199 | if (mul == 16) | ||
200 | return base_clock / divisor; | ||
201 | |||
202 | return base_clock * mul / divisor; | ||
203 | } | ||
204 | |||
205 | static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock, | ||
206 | u32 *bootcr, u32 frequency) | ||
207 | { | ||
208 | int prediv, postdiv, mul; | ||
209 | int base_clock = bus_clk.rate; | ||
210 | |||
211 | switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) { | ||
212 | case BOOT_PLL_SOURCE_BUS: | ||
213 | base_clock = bus_clk.rate; | ||
214 | break; | ||
215 | case BOOT_PLL_SOURCE_REF: | ||
216 | base_clock = AR7_REF_CLOCK; | ||
217 | break; | ||
218 | case BOOT_PLL_SOURCE_XTAL: | ||
219 | base_clock = AR7_XTAL_CLOCK; | ||
220 | break; | ||
221 | case BOOT_PLL_SOURCE_CPU: | ||
222 | base_clock = cpu_clk.rate; | ||
223 | break; | ||
224 | } | ||
225 | |||
226 | calculate(base_clock, frequency, &prediv, &postdiv, &mul); | ||
227 | |||
228 | writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl); | ||
229 | mdelay(1); | ||
230 | writel(4, &clock->pll); | ||
231 | while (readl(&clock->pll) & PLL_STATUS) | ||
232 | ; | ||
233 | writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll); | ||
234 | mdelay(75); | ||
235 | } | ||
236 | |||
237 | static void __init tnetd7300_init_clocks(void) | ||
238 | { | ||
239 | u32 *bootcr = (u32 *)ioremap(AR7_REGS_DCL, 4); | ||
240 | struct tnetd7300_clocks *clocks = | ||
241 | ioremap(UR8_REGS_CLOCKS, | ||
242 | sizeof(struct tnetd7300_clocks)); | ||
243 | |||
244 | bus_clk.rate = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT, | ||
245 | &clocks->bus, bootcr, AR7_AFE_CLOCK); | ||
246 | |||
247 | if (*bootcr & BOOT_PLL_ASYNC_MODE) | ||
248 | cpu_clk.rate = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT, | ||
249 | &clocks->cpu, bootcr, AR7_AFE_CLOCK); | ||
250 | else | ||
251 | cpu_clk.rate = bus_clk.rate; | ||
252 | |||
253 | if (dsp_clk.rate == 250000000) | ||
254 | tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp, | ||
255 | bootcr, dsp_clk.rate); | ||
256 | |||
257 | iounmap(clocks); | ||
258 | iounmap(bootcr); | ||
259 | } | ||
260 | |||
261 | static void tnetd7200_set_clock(int base, struct tnetd7200_clock *clock, | ||
262 | int prediv, int postdiv, int postdiv2, int mul, u32 frequency) | ||
263 | { | ||
264 | printk(KERN_INFO | ||
265 | "Clocks: base = %d, frequency = %u, prediv = %d, " | ||
266 | "postdiv = %d, postdiv2 = %d, mul = %d\n", | ||
267 | base, frequency, prediv, postdiv, postdiv2, mul); | ||
268 | |||
269 | writel(0, &clock->ctrl); | ||
270 | writel(DIVISOR_ENABLE_MASK | ((prediv - 1) & 0x1F), &clock->prediv); | ||
271 | writel((mul - 1) & 0xF, &clock->mul); | ||
272 | |||
273 | while (readl(&clock->status) & 0x1) | ||
274 | ; /* nop */ | ||
275 | |||
276 | writel(DIVISOR_ENABLE_MASK | ((postdiv - 1) & 0x1F), &clock->postdiv); | ||
277 | |||
278 | writel(readl(&clock->cmden) | 1, &clock->cmden); | ||
279 | writel(readl(&clock->cmd) | 1, &clock->cmd); | ||
280 | |||
281 | while (readl(&clock->status) & 0x1) | ||
282 | ; /* nop */ | ||
283 | |||
284 | writel(DIVISOR_ENABLE_MASK | ((postdiv2 - 1) & 0x1F), &clock->postdiv2); | ||
285 | |||
286 | writel(readl(&clock->cmden) | 1, &clock->cmden); | ||
287 | writel(readl(&clock->cmd) | 1, &clock->cmd); | ||
288 | |||
289 | while (readl(&clock->status) & 0x1) | ||
290 | ; /* nop */ | ||
291 | |||
292 | writel(readl(&clock->ctrl) | 1, &clock->ctrl); | ||
293 | } | ||
294 | |||
295 | static int tnetd7200_get_clock_base(int clock_id, u32 *bootcr) | ||
296 | { | ||
297 | if (*bootcr & BOOT_PLL_ASYNC_MODE) | ||
298 | /* Async */ | ||
299 | switch (clock_id) { | ||
300 | case TNETD7200_CLOCK_ID_DSP: | ||
301 | return AR7_REF_CLOCK; | ||
302 | default: | ||
303 | return AR7_AFE_CLOCK; | ||
304 | } | ||
305 | else | ||
306 | /* Sync */ | ||
307 | if (*bootcr & BOOT_PLL_2TO1_MODE) | ||
308 | /* 2:1 */ | ||
309 | switch (clock_id) { | ||
310 | case TNETD7200_CLOCK_ID_DSP: | ||
311 | return AR7_REF_CLOCK; | ||
312 | default: | ||
313 | return AR7_AFE_CLOCK; | ||
314 | } | ||
315 | else | ||
316 | /* 1:1 */ | ||
317 | return AR7_REF_CLOCK; | ||
318 | } | ||
319 | |||
320 | |||
321 | static void __init tnetd7200_init_clocks(void) | ||
322 | { | ||
323 | u32 *bootcr = (u32 *)ioremap(AR7_REGS_DCL, 4); | ||
324 | struct tnetd7200_clocks *clocks = | ||
325 | ioremap(AR7_REGS_CLOCKS, | ||
326 | sizeof(struct tnetd7200_clocks)); | ||
327 | int cpu_base, cpu_mul, cpu_prediv, cpu_postdiv; | ||
328 | int dsp_base, dsp_mul, dsp_prediv, dsp_postdiv; | ||
329 | int usb_base, usb_mul, usb_prediv, usb_postdiv; | ||
330 | |||
331 | cpu_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_CPU, bootcr); | ||
332 | dsp_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_DSP, bootcr); | ||
333 | |||
334 | if (*bootcr & BOOT_PLL_ASYNC_MODE) { | ||
335 | printk(KERN_INFO "Clocks: Async mode\n"); | ||
336 | |||
337 | printk(KERN_INFO "Clocks: Setting DSP clock\n"); | ||
338 | calculate(dsp_base, TNETD7200_DEF_DSP_CLK, | ||
339 | &dsp_prediv, &dsp_postdiv, &dsp_mul); | ||
340 | bus_clk.rate = | ||
341 | ((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv; | ||
342 | tnetd7200_set_clock(dsp_base, &clocks->dsp, | ||
343 | dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2, | ||
344 | bus_clk.rate); | ||
345 | |||
346 | printk(KERN_INFO "Clocks: Setting CPU clock\n"); | ||
347 | calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv, | ||
348 | &cpu_postdiv, &cpu_mul); | ||
349 | cpu_clk.rate = | ||
350 | ((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv; | ||
351 | tnetd7200_set_clock(cpu_base, &clocks->cpu, | ||
352 | cpu_prediv, cpu_postdiv, -1, cpu_mul, | ||
353 | cpu_clk.rate); | ||
354 | |||
355 | } else | ||
356 | if (*bootcr & BOOT_PLL_2TO1_MODE) { | ||
357 | printk(KERN_INFO "Clocks: Sync 2:1 mode\n"); | ||
358 | |||
359 | printk(KERN_INFO "Clocks: Setting CPU clock\n"); | ||
360 | calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv, | ||
361 | &cpu_postdiv, &cpu_mul); | ||
362 | cpu_clk.rate = ((cpu_base / cpu_prediv) * cpu_mul) | ||
363 | / cpu_postdiv; | ||
364 | tnetd7200_set_clock(cpu_base, &clocks->cpu, | ||
365 | cpu_prediv, cpu_postdiv, -1, cpu_mul, | ||
366 | cpu_clk.rate); | ||
367 | |||
368 | printk(KERN_INFO "Clocks: Setting DSP clock\n"); | ||
369 | calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv, | ||
370 | &dsp_postdiv, &dsp_mul); | ||
371 | bus_clk.rate = cpu_clk.rate / 2; | ||
372 | tnetd7200_set_clock(dsp_base, &clocks->dsp, | ||
373 | dsp_prediv, dsp_postdiv * 2, dsp_postdiv, | ||
374 | dsp_mul * 2, bus_clk.rate); | ||
375 | } else { | ||
376 | printk(KERN_INFO "Clocks: Sync 1:1 mode\n"); | ||
377 | |||
378 | printk(KERN_INFO "Clocks: Setting DSP clock\n"); | ||
379 | calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv, | ||
380 | &dsp_postdiv, &dsp_mul); | ||
381 | bus_clk.rate = ((dsp_base / dsp_prediv) * dsp_mul) | ||
382 | / dsp_postdiv; | ||
383 | tnetd7200_set_clock(dsp_base, &clocks->dsp, | ||
384 | dsp_prediv, dsp_postdiv * 2, dsp_postdiv, | ||
385 | dsp_mul * 2, bus_clk.rate); | ||
386 | |||
387 | cpu_clk.rate = bus_clk.rate; | ||
388 | } | ||
389 | |||
390 | printk(KERN_INFO "Clocks: Setting USB clock\n"); | ||
391 | usb_base = bus_clk.rate; | ||
392 | calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv, | ||
393 | &usb_postdiv, &usb_mul); | ||
394 | tnetd7200_set_clock(usb_base, &clocks->usb, | ||
395 | usb_prediv, usb_postdiv, -1, usb_mul, | ||
396 | TNETD7200_DEF_USB_CLK); | ||
397 | |||
398 | dsp_clk.rate = cpu_clk.rate; | ||
399 | |||
400 | iounmap(clocks); | ||
401 | iounmap(bootcr); | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * Linux clock API | ||
406 | */ | ||
407 | int clk_enable(struct clk *clk) | ||
408 | { | ||
409 | return 0; | ||
410 | } | ||
411 | EXPORT_SYMBOL(clk_enable); | ||
412 | |||
413 | void clk_disable(struct clk *clk) | ||
414 | { | ||
415 | } | ||
416 | EXPORT_SYMBOL(clk_disable); | ||
417 | |||
418 | unsigned long clk_get_rate(struct clk *clk) | ||
419 | { | ||
420 | if (!clk) | ||
421 | return 0; | ||
422 | |||
423 | return clk->rate; | ||
424 | } | ||
425 | EXPORT_SYMBOL(clk_get_rate); | ||
426 | |||
427 | struct clk *clk_get(struct device *dev, const char *id) | ||
428 | { | ||
429 | if (!strcmp(id, "bus")) | ||
430 | return &bus_clk; | ||
431 | /* cpmac and vbus share the same rate */ | ||
432 | if (!strcmp(id, "cpmac")) | ||
433 | return &vbus_clk; | ||
434 | if (!strcmp(id, "cpu")) | ||
435 | return &cpu_clk; | ||
436 | if (!strcmp(id, "dsp")) | ||
437 | return &dsp_clk; | ||
438 | if (!strcmp(id, "vbus")) | ||
439 | return &vbus_clk; | ||
440 | return ERR_PTR(-ENOENT); | ||
441 | } | ||
442 | EXPORT_SYMBOL(clk_get); | ||
443 | |||
444 | void clk_put(struct clk *clk) | ||
445 | { | ||
446 | } | ||
447 | EXPORT_SYMBOL(clk_put); | ||
448 | |||
449 | void __init ar7_init_clocks(void) | ||
450 | { | ||
451 | switch (ar7_chip_id()) { | ||
452 | case AR7_CHIP_7100: | ||
453 | case AR7_CHIP_7200: | ||
454 | tnetd7200_init_clocks(); | ||
455 | break; | ||
456 | case AR7_CHIP_7300: | ||
457 | dsp_clk.rate = tnetd7300_dsp_clock(); | ||
458 | tnetd7300_init_clocks(); | ||
459 | break; | ||
460 | default: | ||
461 | break; | ||
462 | } | ||
463 | /* adjust vbus clock rate */ | ||
464 | vbus_clk.rate = bus_clk.rate / 2; | ||
465 | } | ||
466 | |||
467 | /* dummy functions, should not be called */ | ||
468 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
469 | { | ||
470 | WARN_ON(clk); | ||
471 | return 0; | ||
472 | } | ||
473 | EXPORT_SYMBOL(clk_round_rate); | ||
474 | |||
475 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
476 | { | ||
477 | WARN_ON(clk); | ||
478 | return 0; | ||
479 | } | ||
480 | EXPORT_SYMBOL(clk_set_rate); | ||
481 | |||
482 | int clk_set_parent(struct clk *clk, struct clk *parent) | ||
483 | { | ||
484 | WARN_ON(clk); | ||
485 | return 0; | ||
486 | } | ||
487 | EXPORT_SYMBOL(clk_set_parent); | ||
488 | |||
489 | struct clk *clk_get_parent(struct clk *clk) | ||
490 | { | ||
491 | WARN_ON(clk); | ||
492 | return NULL; | ||
493 | } | ||
494 | EXPORT_SYMBOL(clk_get_parent); | ||
diff --git a/arch/mips/ar7/gpio.c b/arch/mips/ar7/gpio.c new file mode 100644 index 000000000..8b006addd --- /dev/null +++ b/arch/mips/ar7/gpio.c | |||
@@ -0,0 +1,331 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> | ||
4 | * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org> | ||
5 | * Copyright (C) 2009-2010 Florian Fainelli <florian@openwrt.org> | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <linux/export.h> | ||
10 | #include <linux/gpio.h> | ||
11 | |||
12 | #include <asm/mach-ar7/ar7.h> | ||
13 | |||
14 | #define AR7_GPIO_MAX 32 | ||
15 | #define TITAN_GPIO_MAX 51 | ||
16 | |||
17 | struct ar7_gpio_chip { | ||
18 | void __iomem *regs; | ||
19 | struct gpio_chip chip; | ||
20 | }; | ||
21 | |||
22 | static int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio) | ||
23 | { | ||
24 | struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); | ||
25 | void __iomem *gpio_in = gpch->regs + AR7_GPIO_INPUT; | ||
26 | |||
27 | return !!(readl(gpio_in) & (1 << gpio)); | ||
28 | } | ||
29 | |||
30 | static int titan_gpio_get_value(struct gpio_chip *chip, unsigned gpio) | ||
31 | { | ||
32 | struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); | ||
33 | void __iomem *gpio_in0 = gpch->regs + TITAN_GPIO_INPUT_0; | ||
34 | void __iomem *gpio_in1 = gpch->regs + TITAN_GPIO_INPUT_1; | ||
35 | |||
36 | return readl(gpio >> 5 ? gpio_in1 : gpio_in0) & (1 << (gpio & 0x1f)); | ||
37 | } | ||
38 | |||
39 | static void ar7_gpio_set_value(struct gpio_chip *chip, | ||
40 | unsigned gpio, int value) | ||
41 | { | ||
42 | struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); | ||
43 | void __iomem *gpio_out = gpch->regs + AR7_GPIO_OUTPUT; | ||
44 | unsigned tmp; | ||
45 | |||
46 | tmp = readl(gpio_out) & ~(1 << gpio); | ||
47 | if (value) | ||
48 | tmp |= 1 << gpio; | ||
49 | writel(tmp, gpio_out); | ||
50 | } | ||
51 | |||
52 | static void titan_gpio_set_value(struct gpio_chip *chip, | ||
53 | unsigned gpio, int value) | ||
54 | { | ||
55 | struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); | ||
56 | void __iomem *gpio_out0 = gpch->regs + TITAN_GPIO_OUTPUT_0; | ||
57 | void __iomem *gpio_out1 = gpch->regs + TITAN_GPIO_OUTPUT_1; | ||
58 | unsigned tmp; | ||
59 | |||
60 | tmp = readl(gpio >> 5 ? gpio_out1 : gpio_out0) & ~(1 << (gpio & 0x1f)); | ||
61 | if (value) | ||
62 | tmp |= 1 << (gpio & 0x1f); | ||
63 | writel(tmp, gpio >> 5 ? gpio_out1 : gpio_out0); | ||
64 | } | ||
65 | |||
66 | static int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) | ||
67 | { | ||
68 | struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); | ||
69 | void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; | ||
70 | |||
71 | writel(readl(gpio_dir) | (1 << gpio), gpio_dir); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) | ||
77 | { | ||
78 | struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); | ||
79 | void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0; | ||
80 | void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1; | ||
81 | |||
82 | if (gpio >= TITAN_GPIO_MAX) | ||
83 | return -EINVAL; | ||
84 | |||
85 | writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) | (1 << (gpio & 0x1f)), | ||
86 | gpio >> 5 ? gpio_dir1 : gpio_dir0); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int ar7_gpio_direction_output(struct gpio_chip *chip, | ||
91 | unsigned gpio, int value) | ||
92 | { | ||
93 | struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); | ||
94 | void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; | ||
95 | |||
96 | ar7_gpio_set_value(chip, gpio, value); | ||
97 | writel(readl(gpio_dir) & ~(1 << gpio), gpio_dir); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int titan_gpio_direction_output(struct gpio_chip *chip, | ||
103 | unsigned gpio, int value) | ||
104 | { | ||
105 | struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); | ||
106 | void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0; | ||
107 | void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1; | ||
108 | |||
109 | if (gpio >= TITAN_GPIO_MAX) | ||
110 | return -EINVAL; | ||
111 | |||
112 | titan_gpio_set_value(chip, gpio, value); | ||
113 | writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) & ~(1 << | ||
114 | (gpio & 0x1f)), gpio >> 5 ? gpio_dir1 : gpio_dir0); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static struct ar7_gpio_chip ar7_gpio_chip = { | ||
120 | .chip = { | ||
121 | .label = "ar7-gpio", | ||
122 | .direction_input = ar7_gpio_direction_input, | ||
123 | .direction_output = ar7_gpio_direction_output, | ||
124 | .set = ar7_gpio_set_value, | ||
125 | .get = ar7_gpio_get_value, | ||
126 | .base = 0, | ||
127 | .ngpio = AR7_GPIO_MAX, | ||
128 | } | ||
129 | }; | ||
130 | |||
131 | static struct ar7_gpio_chip titan_gpio_chip = { | ||
132 | .chip = { | ||
133 | .label = "titan-gpio", | ||
134 | .direction_input = titan_gpio_direction_input, | ||
135 | .direction_output = titan_gpio_direction_output, | ||
136 | .set = titan_gpio_set_value, | ||
137 | .get = titan_gpio_get_value, | ||
138 | .base = 0, | ||
139 | .ngpio = TITAN_GPIO_MAX, | ||
140 | } | ||
141 | }; | ||
142 | |||
143 | static inline int ar7_gpio_enable_ar7(unsigned gpio) | ||
144 | { | ||
145 | void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE; | ||
146 | |||
147 | writel(readl(gpio_en) | (1 << gpio), gpio_en); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static inline int ar7_gpio_enable_titan(unsigned gpio) | ||
153 | { | ||
154 | void __iomem *gpio_en0 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_0; | ||
155 | void __iomem *gpio_en1 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_1; | ||
156 | |||
157 | writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) | (1 << (gpio & 0x1f)), | ||
158 | gpio >> 5 ? gpio_en1 : gpio_en0); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | int ar7_gpio_enable(unsigned gpio) | ||
164 | { | ||
165 | return ar7_is_titan() ? ar7_gpio_enable_titan(gpio) : | ||
166 | ar7_gpio_enable_ar7(gpio); | ||
167 | } | ||
168 | EXPORT_SYMBOL(ar7_gpio_enable); | ||
169 | |||
170 | static inline int ar7_gpio_disable_ar7(unsigned gpio) | ||
171 | { | ||
172 | void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE; | ||
173 | |||
174 | writel(readl(gpio_en) & ~(1 << gpio), gpio_en); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static inline int ar7_gpio_disable_titan(unsigned gpio) | ||
180 | { | ||
181 | void __iomem *gpio_en0 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_0; | ||
182 | void __iomem *gpio_en1 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_1; | ||
183 | |||
184 | writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) & ~(1 << (gpio & 0x1f)), | ||
185 | gpio >> 5 ? gpio_en1 : gpio_en0); | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | int ar7_gpio_disable(unsigned gpio) | ||
191 | { | ||
192 | return ar7_is_titan() ? ar7_gpio_disable_titan(gpio) : | ||
193 | ar7_gpio_disable_ar7(gpio); | ||
194 | } | ||
195 | EXPORT_SYMBOL(ar7_gpio_disable); | ||
196 | |||
197 | struct titan_gpio_cfg { | ||
198 | u32 reg; | ||
199 | u32 shift; | ||
200 | u32 func; | ||
201 | }; | ||
202 | |||
203 | static const struct titan_gpio_cfg titan_gpio_table[] = { | ||
204 | /* reg, start bit, mux value */ | ||
205 | {4, 24, 1}, | ||
206 | {4, 26, 1}, | ||
207 | {4, 28, 1}, | ||
208 | {4, 30, 1}, | ||
209 | {5, 6, 1}, | ||
210 | {5, 8, 1}, | ||
211 | {5, 10, 1}, | ||
212 | {5, 12, 1}, | ||
213 | {7, 14, 3}, | ||
214 | {7, 16, 3}, | ||
215 | {7, 18, 3}, | ||
216 | {7, 20, 3}, | ||
217 | {7, 22, 3}, | ||
218 | {7, 26, 3}, | ||
219 | {7, 28, 3}, | ||
220 | {7, 30, 3}, | ||
221 | {8, 0, 3}, | ||
222 | {8, 2, 3}, | ||
223 | {8, 4, 3}, | ||
224 | {8, 10, 3}, | ||
225 | {8, 14, 3}, | ||
226 | {8, 16, 3}, | ||
227 | {8, 18, 3}, | ||
228 | {8, 20, 3}, | ||
229 | {9, 8, 3}, | ||
230 | {9, 10, 3}, | ||
231 | {9, 12, 3}, | ||
232 | {9, 14, 3}, | ||
233 | {9, 18, 3}, | ||
234 | {9, 20, 3}, | ||
235 | {9, 24, 3}, | ||
236 | {9, 26, 3}, | ||
237 | {9, 28, 3}, | ||
238 | {9, 30, 3}, | ||
239 | {10, 0, 3}, | ||
240 | {10, 2, 3}, | ||
241 | {10, 8, 3}, | ||
242 | {10, 10, 3}, | ||
243 | {10, 12, 3}, | ||
244 | {10, 14, 3}, | ||
245 | {13, 12, 3}, | ||
246 | {13, 14, 3}, | ||
247 | {13, 16, 3}, | ||
248 | {13, 18, 3}, | ||
249 | {13, 24, 3}, | ||
250 | {13, 26, 3}, | ||
251 | {13, 28, 3}, | ||
252 | {13, 30, 3}, | ||
253 | {14, 2, 3}, | ||
254 | {14, 6, 3}, | ||
255 | {14, 8, 3}, | ||
256 | {14, 12, 3} | ||
257 | }; | ||
258 | |||
259 | static int titan_gpio_pinsel(unsigned gpio) | ||
260 | { | ||
261 | struct titan_gpio_cfg gpio_cfg; | ||
262 | u32 mux_status, pin_sel_reg, tmp; | ||
263 | void __iomem *pin_sel = (void __iomem *)KSEG1ADDR(AR7_REGS_PINSEL); | ||
264 | |||
265 | if (gpio >= ARRAY_SIZE(titan_gpio_table)) | ||
266 | return -EINVAL; | ||
267 | |||
268 | gpio_cfg = titan_gpio_table[gpio]; | ||
269 | pin_sel_reg = gpio_cfg.reg - 1; | ||
270 | |||
271 | mux_status = (readl(pin_sel + pin_sel_reg) >> gpio_cfg.shift) & 0x3; | ||
272 | |||
273 | /* Check the mux status */ | ||
274 | if (!((mux_status == 0) || (mux_status == gpio_cfg.func))) | ||
275 | return 0; | ||
276 | |||
277 | /* Set the pin sel value */ | ||
278 | tmp = readl(pin_sel + pin_sel_reg); | ||
279 | tmp |= ((gpio_cfg.func & 0x3) << gpio_cfg.shift); | ||
280 | writel(tmp, pin_sel + pin_sel_reg); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | /* Perform minimal Titan GPIO configuration */ | ||
286 | static void titan_gpio_init(void) | ||
287 | { | ||
288 | unsigned i; | ||
289 | |||
290 | for (i = 44; i < 48; i++) { | ||
291 | titan_gpio_pinsel(i); | ||
292 | ar7_gpio_enable_titan(i); | ||
293 | titan_gpio_direction_input(&titan_gpio_chip.chip, i); | ||
294 | } | ||
295 | } | ||
296 | |||
297 | int __init ar7_gpio_init(void) | ||
298 | { | ||
299 | int ret; | ||
300 | struct ar7_gpio_chip *gpch; | ||
301 | unsigned size; | ||
302 | |||
303 | if (!ar7_is_titan()) { | ||
304 | gpch = &ar7_gpio_chip; | ||
305 | size = 0x10; | ||
306 | } else { | ||
307 | gpch = &titan_gpio_chip; | ||
308 | size = 0x1f; | ||
309 | } | ||
310 | |||
311 | gpch->regs = ioremap(AR7_REGS_GPIO, size); | ||
312 | if (!gpch->regs) { | ||
313 | printk(KERN_ERR "%s: failed to ioremap regs\n", | ||
314 | gpch->chip.label); | ||
315 | return -ENOMEM; | ||
316 | } | ||
317 | |||
318 | ret = gpiochip_add_data(&gpch->chip, gpch); | ||
319 | if (ret) { | ||
320 | printk(KERN_ERR "%s: failed to add gpiochip\n", | ||
321 | gpch->chip.label); | ||
322 | return ret; | ||
323 | } | ||
324 | printk(KERN_INFO "%s: registered %d GPIOs\n", | ||
325 | gpch->chip.label, gpch->chip.ngpio); | ||
326 | |||
327 | if (ar7_is_titan()) | ||
328 | titan_gpio_init(); | ||
329 | |||
330 | return ret; | ||
331 | } | ||
diff --git a/arch/mips/ar7/irq.c b/arch/mips/ar7/irq.c new file mode 100644 index 000000000..f0a7942d3 --- /dev/null +++ b/arch/mips/ar7/irq.c | |||
@@ -0,0 +1,165 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org> | ||
4 | * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org> | ||
5 | */ | ||
6 | |||
7 | #include <linux/interrupt.h> | ||
8 | #include <linux/io.h> | ||
9 | #include <linux/irq.h> | ||
10 | |||
11 | #include <asm/irq_cpu.h> | ||
12 | #include <asm/mipsregs.h> | ||
13 | #include <asm/mach-ar7/ar7.h> | ||
14 | |||
15 | #define EXCEPT_OFFSET 0x80 | ||
16 | #define PACE_OFFSET 0xA0 | ||
17 | #define CHNLS_OFFSET 0x200 | ||
18 | |||
19 | #define REG_OFFSET(irq, reg) ((irq) / 32 * 0x4 + reg * 0x10) | ||
20 | #define SEC_REG_OFFSET(reg) (EXCEPT_OFFSET + reg * 0x8) | ||
21 | #define SEC_SR_OFFSET (SEC_REG_OFFSET(0)) /* 0x80 */ | ||
22 | #define CR_OFFSET(irq) (REG_OFFSET(irq, 1)) /* 0x10 */ | ||
23 | #define SEC_CR_OFFSET (SEC_REG_OFFSET(1)) /* 0x88 */ | ||
24 | #define ESR_OFFSET(irq) (REG_OFFSET(irq, 2)) /* 0x20 */ | ||
25 | #define SEC_ESR_OFFSET (SEC_REG_OFFSET(2)) /* 0x90 */ | ||
26 | #define ECR_OFFSET(irq) (REG_OFFSET(irq, 3)) /* 0x30 */ | ||
27 | #define SEC_ECR_OFFSET (SEC_REG_OFFSET(3)) /* 0x98 */ | ||
28 | #define PIR_OFFSET (0x40) | ||
29 | #define MSR_OFFSET (0x44) | ||
30 | #define PM_OFFSET(irq) (REG_OFFSET(irq, 5)) /* 0x50 */ | ||
31 | #define TM_OFFSET(irq) (REG_OFFSET(irq, 6)) /* 0x60 */ | ||
32 | |||
33 | #define REG(addr) ((u32 *)(KSEG1ADDR(AR7_REGS_IRQ) + addr)) | ||
34 | |||
35 | #define CHNL_OFFSET(chnl) (CHNLS_OFFSET + (chnl * 4)) | ||
36 | |||
37 | static int ar7_irq_base; | ||
38 | |||
39 | static void ar7_unmask_irq(struct irq_data *d) | ||
40 | { | ||
41 | writel(1 << ((d->irq - ar7_irq_base) % 32), | ||
42 | REG(ESR_OFFSET(d->irq - ar7_irq_base))); | ||
43 | } | ||
44 | |||
45 | static void ar7_mask_irq(struct irq_data *d) | ||
46 | { | ||
47 | writel(1 << ((d->irq - ar7_irq_base) % 32), | ||
48 | REG(ECR_OFFSET(d->irq - ar7_irq_base))); | ||
49 | } | ||
50 | |||
51 | static void ar7_ack_irq(struct irq_data *d) | ||
52 | { | ||
53 | writel(1 << ((d->irq - ar7_irq_base) % 32), | ||
54 | REG(CR_OFFSET(d->irq - ar7_irq_base))); | ||
55 | } | ||
56 | |||
57 | static void ar7_unmask_sec_irq(struct irq_data *d) | ||
58 | { | ||
59 | writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET)); | ||
60 | } | ||
61 | |||
62 | static void ar7_mask_sec_irq(struct irq_data *d) | ||
63 | { | ||
64 | writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET)); | ||
65 | } | ||
66 | |||
67 | static void ar7_ack_sec_irq(struct irq_data *d) | ||
68 | { | ||
69 | writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET)); | ||
70 | } | ||
71 | |||
72 | static struct irq_chip ar7_irq_type = { | ||
73 | .name = "AR7", | ||
74 | .irq_unmask = ar7_unmask_irq, | ||
75 | .irq_mask = ar7_mask_irq, | ||
76 | .irq_ack = ar7_ack_irq | ||
77 | }; | ||
78 | |||
79 | static struct irq_chip ar7_sec_irq_type = { | ||
80 | .name = "AR7", | ||
81 | .irq_unmask = ar7_unmask_sec_irq, | ||
82 | .irq_mask = ar7_mask_sec_irq, | ||
83 | .irq_ack = ar7_ack_sec_irq, | ||
84 | }; | ||
85 | |||
86 | static void __init ar7_irq_init(int base) | ||
87 | { | ||
88 | int i; | ||
89 | /* | ||
90 | * Disable interrupts and clear pending | ||
91 | */ | ||
92 | writel(0xffffffff, REG(ECR_OFFSET(0))); | ||
93 | writel(0xff, REG(ECR_OFFSET(32))); | ||
94 | writel(0xffffffff, REG(SEC_ECR_OFFSET)); | ||
95 | writel(0xffffffff, REG(CR_OFFSET(0))); | ||
96 | writel(0xff, REG(CR_OFFSET(32))); | ||
97 | writel(0xffffffff, REG(SEC_CR_OFFSET)); | ||
98 | |||
99 | ar7_irq_base = base; | ||
100 | |||
101 | for (i = 0; i < 40; i++) { | ||
102 | writel(i, REG(CHNL_OFFSET(i))); | ||
103 | /* Primary IRQ's */ | ||
104 | irq_set_chip_and_handler(base + i, &ar7_irq_type, | ||
105 | handle_level_irq); | ||
106 | /* Secondary IRQ's */ | ||
107 | if (i < 32) | ||
108 | irq_set_chip_and_handler(base + i + 40, | ||
109 | &ar7_sec_irq_type, | ||
110 | handle_level_irq); | ||
111 | } | ||
112 | |||
113 | if (request_irq(2, no_action, IRQF_NO_THREAD, "AR7 cascade interrupt", | ||
114 | NULL)) | ||
115 | pr_err("Failed to request irq 2 (AR7 cascade interrupt)\n"); | ||
116 | if (request_irq(ar7_irq_base, no_action, IRQF_NO_THREAD, | ||
117 | "AR7 cascade interrupt", NULL)) { | ||
118 | pr_err("Failed to request irq %d (AR7 cascade interrupt)\n", | ||
119 | ar7_irq_base); | ||
120 | } | ||
121 | set_c0_status(IE_IRQ0); | ||
122 | } | ||
123 | |||
124 | void __init arch_init_irq(void) | ||
125 | { | ||
126 | mips_cpu_irq_init(); | ||
127 | ar7_irq_init(8); | ||
128 | } | ||
129 | |||
130 | static void ar7_cascade(void) | ||
131 | { | ||
132 | u32 status; | ||
133 | int i, irq; | ||
134 | |||
135 | /* Primary IRQ's */ | ||
136 | irq = readl(REG(PIR_OFFSET)) & 0x3f; | ||
137 | if (irq) { | ||
138 | do_IRQ(ar7_irq_base + irq); | ||
139 | return; | ||
140 | } | ||
141 | |||
142 | /* Secondary IRQ's are cascaded through primary '0' */ | ||
143 | writel(1, REG(CR_OFFSET(irq))); | ||
144 | status = readl(REG(SEC_SR_OFFSET)); | ||
145 | for (i = 0; i < 32; i++) { | ||
146 | if (status & 1) { | ||
147 | do_IRQ(ar7_irq_base + i + 40); | ||
148 | return; | ||
149 | } | ||
150 | status >>= 1; | ||
151 | } | ||
152 | |||
153 | spurious_interrupt(); | ||
154 | } | ||
155 | |||
156 | asmlinkage void plat_irq_dispatch(void) | ||
157 | { | ||
158 | unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; | ||
159 | if (pending & STATUSF_IP7) /* cpu timer */ | ||
160 | do_IRQ(7); | ||
161 | else if (pending & STATUSF_IP2) /* int0 hardware line */ | ||
162 | ar7_cascade(); | ||
163 | else | ||
164 | spurious_interrupt(); | ||
165 | } | ||
diff --git a/arch/mips/ar7/memory.c b/arch/mips/ar7/memory.c new file mode 100644 index 000000000..787716c5e --- /dev/null +++ b/arch/mips/ar7/memory.c | |||
@@ -0,0 +1,56 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> | ||
4 | * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org> | ||
5 | */ | ||
6 | #include <linux/memblock.h> | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/mm.h> | ||
9 | #include <linux/pfn.h> | ||
10 | #include <linux/proc_fs.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/swap.h> | ||
13 | |||
14 | #include <asm/bootinfo.h> | ||
15 | #include <asm/page.h> | ||
16 | #include <asm/sections.h> | ||
17 | |||
18 | #include <asm/mach-ar7/ar7.h> | ||
19 | |||
20 | static int __init memsize(void) | ||
21 | { | ||
22 | u32 size = (64 << 20); | ||
23 | u32 *addr = (u32 *)KSEG1ADDR(AR7_SDRAM_BASE + size - 4); | ||
24 | u32 *kernel_end = (u32 *)KSEG1ADDR(CPHYSADDR((u32)&_end)); | ||
25 | u32 *tmpaddr = addr; | ||
26 | |||
27 | while (tmpaddr > kernel_end) { | ||
28 | *tmpaddr = (u32)tmpaddr; | ||
29 | size >>= 1; | ||
30 | tmpaddr -= size >> 2; | ||
31 | } | ||
32 | |||
33 | do { | ||
34 | tmpaddr += size >> 2; | ||
35 | if (*tmpaddr != (u32)tmpaddr) | ||
36 | break; | ||
37 | size <<= 1; | ||
38 | } while (size < (64 << 20)); | ||
39 | |||
40 | writel((u32)tmpaddr, &addr); | ||
41 | |||
42 | return size; | ||
43 | } | ||
44 | |||
45 | void __init prom_meminit(void) | ||
46 | { | ||
47 | unsigned long pages; | ||
48 | |||
49 | pages = memsize() >> PAGE_SHIFT; | ||
50 | memblock_add(PHYS_OFFSET, pages << PAGE_SHIFT); | ||
51 | } | ||
52 | |||
53 | void __init prom_free_prom_memory(void) | ||
54 | { | ||
55 | /* Nothing to free */ | ||
56 | } | ||
diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c new file mode 100644 index 000000000..215149a85 --- /dev/null +++ b/arch/mips/ar7/platform.c | |||
@@ -0,0 +1,722 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org> | ||
4 | * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org> | ||
5 | */ | ||
6 | |||
7 | #include <linux/init.h> | ||
8 | #include <linux/types.h> | ||
9 | #include <linux/delay.h> | ||
10 | #include <linux/dma-mapping.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/mtd/physmap.h> | ||
13 | #include <linux/serial.h> | ||
14 | #include <linux/serial_8250.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/vlynq.h> | ||
18 | #include <linux/leds.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/etherdevice.h> | ||
21 | #include <linux/phy.h> | ||
22 | #include <linux/phy_fixed.h> | ||
23 | #include <linux/gpio.h> | ||
24 | #include <linux/clk.h> | ||
25 | |||
26 | #include <asm/addrspace.h> | ||
27 | #include <asm/mach-ar7/ar7.h> | ||
28 | #include <asm/mach-ar7/prom.h> | ||
29 | |||
30 | /***************************************************************************** | ||
31 | * VLYNQ Bus | ||
32 | ****************************************************************************/ | ||
33 | struct plat_vlynq_data { | ||
34 | struct plat_vlynq_ops ops; | ||
35 | int gpio_bit; | ||
36 | int reset_bit; | ||
37 | }; | ||
38 | |||
39 | static int vlynq_on(struct vlynq_device *dev) | ||
40 | { | ||
41 | int ret; | ||
42 | struct plat_vlynq_data *pdata = dev->dev.platform_data; | ||
43 | |||
44 | ret = gpio_request(pdata->gpio_bit, "vlynq"); | ||
45 | if (ret) | ||
46 | goto out; | ||
47 | |||
48 | ar7_device_reset(pdata->reset_bit); | ||
49 | |||
50 | ret = ar7_gpio_disable(pdata->gpio_bit); | ||
51 | if (ret) | ||
52 | goto out_enabled; | ||
53 | |||
54 | ret = ar7_gpio_enable(pdata->gpio_bit); | ||
55 | if (ret) | ||
56 | goto out_enabled; | ||
57 | |||
58 | ret = gpio_direction_output(pdata->gpio_bit, 0); | ||
59 | if (ret) | ||
60 | goto out_gpio_enabled; | ||
61 | |||
62 | msleep(50); | ||
63 | |||
64 | gpio_set_value(pdata->gpio_bit, 1); | ||
65 | |||
66 | msleep(50); | ||
67 | |||
68 | return 0; | ||
69 | |||
70 | out_gpio_enabled: | ||
71 | ar7_gpio_disable(pdata->gpio_bit); | ||
72 | out_enabled: | ||
73 | ar7_device_disable(pdata->reset_bit); | ||
74 | gpio_free(pdata->gpio_bit); | ||
75 | out: | ||
76 | return ret; | ||
77 | } | ||
78 | |||
79 | static void vlynq_off(struct vlynq_device *dev) | ||
80 | { | ||
81 | struct plat_vlynq_data *pdata = dev->dev.platform_data; | ||
82 | |||
83 | ar7_gpio_disable(pdata->gpio_bit); | ||
84 | gpio_free(pdata->gpio_bit); | ||
85 | ar7_device_disable(pdata->reset_bit); | ||
86 | } | ||
87 | |||
88 | static struct resource vlynq_low_res[] = { | ||
89 | { | ||
90 | .name = "regs", | ||
91 | .flags = IORESOURCE_MEM, | ||
92 | .start = AR7_REGS_VLYNQ0, | ||
93 | .end = AR7_REGS_VLYNQ0 + 0xff, | ||
94 | }, | ||
95 | { | ||
96 | .name = "irq", | ||
97 | .flags = IORESOURCE_IRQ, | ||
98 | .start = 29, | ||
99 | .end = 29, | ||
100 | }, | ||
101 | { | ||
102 | .name = "mem", | ||
103 | .flags = IORESOURCE_MEM, | ||
104 | .start = 0x04000000, | ||
105 | .end = 0x04ffffff, | ||
106 | }, | ||
107 | { | ||
108 | .name = "devirq", | ||
109 | .flags = IORESOURCE_IRQ, | ||
110 | .start = 80, | ||
111 | .end = 111, | ||
112 | }, | ||
113 | }; | ||
114 | |||
115 | static struct resource vlynq_high_res[] = { | ||
116 | { | ||
117 | .name = "regs", | ||
118 | .flags = IORESOURCE_MEM, | ||
119 | .start = AR7_REGS_VLYNQ1, | ||
120 | .end = AR7_REGS_VLYNQ1 + 0xff, | ||
121 | }, | ||
122 | { | ||
123 | .name = "irq", | ||
124 | .flags = IORESOURCE_IRQ, | ||
125 | .start = 33, | ||
126 | .end = 33, | ||
127 | }, | ||
128 | { | ||
129 | .name = "mem", | ||
130 | .flags = IORESOURCE_MEM, | ||
131 | .start = 0x0c000000, | ||
132 | .end = 0x0cffffff, | ||
133 | }, | ||
134 | { | ||
135 | .name = "devirq", | ||
136 | .flags = IORESOURCE_IRQ, | ||
137 | .start = 112, | ||
138 | .end = 143, | ||
139 | }, | ||
140 | }; | ||
141 | |||
142 | static struct plat_vlynq_data vlynq_low_data = { | ||
143 | .ops = { | ||
144 | .on = vlynq_on, | ||
145 | .off = vlynq_off, | ||
146 | }, | ||
147 | .reset_bit = 20, | ||
148 | .gpio_bit = 18, | ||
149 | }; | ||
150 | |||
151 | static struct plat_vlynq_data vlynq_high_data = { | ||
152 | .ops = { | ||
153 | .on = vlynq_on, | ||
154 | .off = vlynq_off, | ||
155 | }, | ||
156 | .reset_bit = 16, | ||
157 | .gpio_bit = 19, | ||
158 | }; | ||
159 | |||
160 | static struct platform_device vlynq_low = { | ||
161 | .id = 0, | ||
162 | .name = "vlynq", | ||
163 | .dev = { | ||
164 | .platform_data = &vlynq_low_data, | ||
165 | }, | ||
166 | .resource = vlynq_low_res, | ||
167 | .num_resources = ARRAY_SIZE(vlynq_low_res), | ||
168 | }; | ||
169 | |||
170 | static struct platform_device vlynq_high = { | ||
171 | .id = 1, | ||
172 | .name = "vlynq", | ||
173 | .dev = { | ||
174 | .platform_data = &vlynq_high_data, | ||
175 | }, | ||
176 | .resource = vlynq_high_res, | ||
177 | .num_resources = ARRAY_SIZE(vlynq_high_res), | ||
178 | }; | ||
179 | |||
180 | /***************************************************************************** | ||
181 | * Flash | ||
182 | ****************************************************************************/ | ||
183 | static struct resource physmap_flash_resource = { | ||
184 | .name = "mem", | ||
185 | .flags = IORESOURCE_MEM, | ||
186 | .start = 0x10000000, | ||
187 | .end = 0x107fffff, | ||
188 | }; | ||
189 | |||
190 | static const char *ar7_probe_types[] = { "ar7part", NULL }; | ||
191 | |||
192 | static struct physmap_flash_data physmap_flash_data = { | ||
193 | .width = 2, | ||
194 | .part_probe_types = ar7_probe_types, | ||
195 | }; | ||
196 | |||
197 | static struct platform_device physmap_flash = { | ||
198 | .name = "physmap-flash", | ||
199 | .dev = { | ||
200 | .platform_data = &physmap_flash_data, | ||
201 | }, | ||
202 | .resource = &physmap_flash_resource, | ||
203 | .num_resources = 1, | ||
204 | }; | ||
205 | |||
206 | /***************************************************************************** | ||
207 | * Ethernet | ||
208 | ****************************************************************************/ | ||
209 | static struct resource cpmac_low_res[] = { | ||
210 | { | ||
211 | .name = "regs", | ||
212 | .flags = IORESOURCE_MEM, | ||
213 | .start = AR7_REGS_MAC0, | ||
214 | .end = AR7_REGS_MAC0 + 0x7ff, | ||
215 | }, | ||
216 | { | ||
217 | .name = "irq", | ||
218 | .flags = IORESOURCE_IRQ, | ||
219 | .start = 27, | ||
220 | .end = 27, | ||
221 | }, | ||
222 | }; | ||
223 | |||
224 | static struct resource cpmac_high_res[] = { | ||
225 | { | ||
226 | .name = "regs", | ||
227 | .flags = IORESOURCE_MEM, | ||
228 | .start = AR7_REGS_MAC1, | ||
229 | .end = AR7_REGS_MAC1 + 0x7ff, | ||
230 | }, | ||
231 | { | ||
232 | .name = "irq", | ||
233 | .flags = IORESOURCE_IRQ, | ||
234 | .start = 41, | ||
235 | .end = 41, | ||
236 | }, | ||
237 | }; | ||
238 | |||
239 | static struct fixed_phy_status fixed_phy_status __initdata = { | ||
240 | .link = 1, | ||
241 | .speed = 100, | ||
242 | .duplex = 1, | ||
243 | }; | ||
244 | |||
245 | static struct plat_cpmac_data cpmac_low_data = { | ||
246 | .reset_bit = 17, | ||
247 | .power_bit = 20, | ||
248 | .phy_mask = 0x80000000, | ||
249 | }; | ||
250 | |||
251 | static struct plat_cpmac_data cpmac_high_data = { | ||
252 | .reset_bit = 21, | ||
253 | .power_bit = 22, | ||
254 | .phy_mask = 0x7fffffff, | ||
255 | }; | ||
256 | |||
257 | static u64 cpmac_dma_mask = DMA_BIT_MASK(32); | ||
258 | |||
259 | static struct platform_device cpmac_low = { | ||
260 | .id = 0, | ||
261 | .name = "cpmac", | ||
262 | .dev = { | ||
263 | .dma_mask = &cpmac_dma_mask, | ||
264 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
265 | .platform_data = &cpmac_low_data, | ||
266 | }, | ||
267 | .resource = cpmac_low_res, | ||
268 | .num_resources = ARRAY_SIZE(cpmac_low_res), | ||
269 | }; | ||
270 | |||
271 | static struct platform_device cpmac_high = { | ||
272 | .id = 1, | ||
273 | .name = "cpmac", | ||
274 | .dev = { | ||
275 | .dma_mask = &cpmac_dma_mask, | ||
276 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
277 | .platform_data = &cpmac_high_data, | ||
278 | }, | ||
279 | .resource = cpmac_high_res, | ||
280 | .num_resources = ARRAY_SIZE(cpmac_high_res), | ||
281 | }; | ||
282 | |||
283 | static void __init cpmac_get_mac(int instance, unsigned char *dev_addr) | ||
284 | { | ||
285 | char name[5], *mac; | ||
286 | |||
287 | sprintf(name, "mac%c", 'a' + instance); | ||
288 | mac = prom_getenv(name); | ||
289 | if (!mac && instance) { | ||
290 | sprintf(name, "mac%c", 'a'); | ||
291 | mac = prom_getenv(name); | ||
292 | } | ||
293 | |||
294 | if (mac) { | ||
295 | if (!mac_pton(mac, dev_addr)) { | ||
296 | pr_warn("cannot parse mac address, using random address\n"); | ||
297 | eth_random_addr(dev_addr); | ||
298 | } | ||
299 | } else | ||
300 | eth_random_addr(dev_addr); | ||
301 | } | ||
302 | |||
303 | /***************************************************************************** | ||
304 | * USB | ||
305 | ****************************************************************************/ | ||
306 | static struct resource usb_res[] = { | ||
307 | { | ||
308 | .name = "regs", | ||
309 | .flags = IORESOURCE_MEM, | ||
310 | .start = AR7_REGS_USB, | ||
311 | .end = AR7_REGS_USB + 0xff, | ||
312 | }, | ||
313 | { | ||
314 | .name = "irq", | ||
315 | .flags = IORESOURCE_IRQ, | ||
316 | .start = 32, | ||
317 | .end = 32, | ||
318 | }, | ||
319 | { | ||
320 | .name = "mem", | ||
321 | .flags = IORESOURCE_MEM, | ||
322 | .start = 0x03400000, | ||
323 | .end = 0x03401fff, | ||
324 | }, | ||
325 | }; | ||
326 | |||
327 | static struct platform_device ar7_udc = { | ||
328 | .name = "ar7_udc", | ||
329 | .resource = usb_res, | ||
330 | .num_resources = ARRAY_SIZE(usb_res), | ||
331 | }; | ||
332 | |||
333 | /***************************************************************************** | ||
334 | * LEDs | ||
335 | ****************************************************************************/ | ||
336 | static const struct gpio_led default_leds[] = { | ||
337 | { | ||
338 | .name = "status", | ||
339 | .gpio = 8, | ||
340 | .active_low = 1, | ||
341 | }, | ||
342 | }; | ||
343 | |||
344 | static const struct gpio_led titan_leds[] = { | ||
345 | { .name = "status", .gpio = 8, .active_low = 1, }, | ||
346 | { .name = "wifi", .gpio = 13, .active_low = 1, }, | ||
347 | }; | ||
348 | |||
349 | static const struct gpio_led dsl502t_leds[] = { | ||
350 | { | ||
351 | .name = "status", | ||
352 | .gpio = 9, | ||
353 | .active_low = 1, | ||
354 | }, | ||
355 | { | ||
356 | .name = "ethernet", | ||
357 | .gpio = 7, | ||
358 | .active_low = 1, | ||
359 | }, | ||
360 | { | ||
361 | .name = "usb", | ||
362 | .gpio = 12, | ||
363 | .active_low = 1, | ||
364 | }, | ||
365 | }; | ||
366 | |||
367 | static const struct gpio_led dg834g_leds[] = { | ||
368 | { | ||
369 | .name = "ppp", | ||
370 | .gpio = 6, | ||
371 | .active_low = 1, | ||
372 | }, | ||
373 | { | ||
374 | .name = "status", | ||
375 | .gpio = 7, | ||
376 | .active_low = 1, | ||
377 | }, | ||
378 | { | ||
379 | .name = "adsl", | ||
380 | .gpio = 8, | ||
381 | .active_low = 1, | ||
382 | }, | ||
383 | { | ||
384 | .name = "wifi", | ||
385 | .gpio = 12, | ||
386 | .active_low = 1, | ||
387 | }, | ||
388 | { | ||
389 | .name = "power", | ||
390 | .gpio = 14, | ||
391 | .active_low = 1, | ||
392 | .default_trigger = "default-on", | ||
393 | }, | ||
394 | }; | ||
395 | |||
396 | static const struct gpio_led fb_sl_leds[] = { | ||
397 | { | ||
398 | .name = "1", | ||
399 | .gpio = 7, | ||
400 | }, | ||
401 | { | ||
402 | .name = "2", | ||
403 | .gpio = 13, | ||
404 | .active_low = 1, | ||
405 | }, | ||
406 | { | ||
407 | .name = "3", | ||
408 | .gpio = 10, | ||
409 | .active_low = 1, | ||
410 | }, | ||
411 | { | ||
412 | .name = "4", | ||
413 | .gpio = 12, | ||
414 | .active_low = 1, | ||
415 | }, | ||
416 | { | ||
417 | .name = "5", | ||
418 | .gpio = 9, | ||
419 | .active_low = 1, | ||
420 | }, | ||
421 | }; | ||
422 | |||
423 | static const struct gpio_led fb_fon_leds[] = { | ||
424 | { | ||
425 | .name = "1", | ||
426 | .gpio = 8, | ||
427 | }, | ||
428 | { | ||
429 | .name = "2", | ||
430 | .gpio = 3, | ||
431 | .active_low = 1, | ||
432 | }, | ||
433 | { | ||
434 | .name = "3", | ||
435 | .gpio = 5, | ||
436 | }, | ||
437 | { | ||
438 | .name = "4", | ||
439 | .gpio = 4, | ||
440 | .active_low = 1, | ||
441 | }, | ||
442 | { | ||
443 | .name = "5", | ||
444 | .gpio = 11, | ||
445 | .active_low = 1, | ||
446 | }, | ||
447 | }; | ||
448 | |||
449 | static const struct gpio_led gt701_leds[] = { | ||
450 | { | ||
451 | .name = "inet:green", | ||
452 | .gpio = 13, | ||
453 | .active_low = 1, | ||
454 | }, | ||
455 | { | ||
456 | .name = "usb", | ||
457 | .gpio = 12, | ||
458 | .active_low = 1, | ||
459 | }, | ||
460 | { | ||
461 | .name = "inet:red", | ||
462 | .gpio = 9, | ||
463 | .active_low = 1, | ||
464 | }, | ||
465 | { | ||
466 | .name = "power:red", | ||
467 | .gpio = 7, | ||
468 | .active_low = 1, | ||
469 | }, | ||
470 | { | ||
471 | .name = "power:green", | ||
472 | .gpio = 8, | ||
473 | .active_low = 1, | ||
474 | .default_trigger = "default-on", | ||
475 | }, | ||
476 | { | ||
477 | .name = "ethernet", | ||
478 | .gpio = 10, | ||
479 | .active_low = 1, | ||
480 | }, | ||
481 | }; | ||
482 | |||
483 | static struct gpio_led_platform_data ar7_led_data; | ||
484 | |||
485 | static struct platform_device ar7_gpio_leds = { | ||
486 | .name = "leds-gpio", | ||
487 | .dev = { | ||
488 | .platform_data = &ar7_led_data, | ||
489 | } | ||
490 | }; | ||
491 | |||
492 | static void __init detect_leds(void) | ||
493 | { | ||
494 | char *prid, *usb_prod; | ||
495 | |||
496 | /* Default LEDs */ | ||
497 | ar7_led_data.num_leds = ARRAY_SIZE(default_leds); | ||
498 | ar7_led_data.leds = default_leds; | ||
499 | |||
500 | /* FIXME: the whole thing is unreliable */ | ||
501 | prid = prom_getenv("ProductID"); | ||
502 | usb_prod = prom_getenv("usb_prod"); | ||
503 | |||
504 | /* If we can't get the product id from PROM, use the default LEDs */ | ||
505 | if (!prid) | ||
506 | return; | ||
507 | |||
508 | if (strstr(prid, "Fritz_Box_FON")) { | ||
509 | ar7_led_data.num_leds = ARRAY_SIZE(fb_fon_leds); | ||
510 | ar7_led_data.leds = fb_fon_leds; | ||
511 | } else if (strstr(prid, "Fritz_Box_")) { | ||
512 | ar7_led_data.num_leds = ARRAY_SIZE(fb_sl_leds); | ||
513 | ar7_led_data.leds = fb_sl_leds; | ||
514 | } else if ((!strcmp(prid, "AR7RD") || !strcmp(prid, "AR7DB")) | ||
515 | && usb_prod != NULL && strstr(usb_prod, "DSL-502T")) { | ||
516 | ar7_led_data.num_leds = ARRAY_SIZE(dsl502t_leds); | ||
517 | ar7_led_data.leds = dsl502t_leds; | ||
518 | } else if (strstr(prid, "DG834")) { | ||
519 | ar7_led_data.num_leds = ARRAY_SIZE(dg834g_leds); | ||
520 | ar7_led_data.leds = dg834g_leds; | ||
521 | } else if (strstr(prid, "CYWM") || strstr(prid, "CYWL")) { | ||
522 | ar7_led_data.num_leds = ARRAY_SIZE(titan_leds); | ||
523 | ar7_led_data.leds = titan_leds; | ||
524 | } else if (strstr(prid, "GT701")) { | ||
525 | ar7_led_data.num_leds = ARRAY_SIZE(gt701_leds); | ||
526 | ar7_led_data.leds = gt701_leds; | ||
527 | } | ||
528 | } | ||
529 | |||
530 | /***************************************************************************** | ||
531 | * Watchdog | ||
532 | ****************************************************************************/ | ||
533 | static struct resource ar7_wdt_res = { | ||
534 | .name = "regs", | ||
535 | .flags = IORESOURCE_MEM, | ||
536 | .start = -1, /* Filled at runtime */ | ||
537 | .end = -1, /* Filled at runtime */ | ||
538 | }; | ||
539 | |||
540 | static struct platform_device ar7_wdt = { | ||
541 | .name = "ar7_wdt", | ||
542 | .resource = &ar7_wdt_res, | ||
543 | .num_resources = 1, | ||
544 | }; | ||
545 | |||
546 | /***************************************************************************** | ||
547 | * Init | ||
548 | ****************************************************************************/ | ||
549 | static int __init ar7_register_uarts(void) | ||
550 | { | ||
551 | #ifdef CONFIG_SERIAL_8250 | ||
552 | static struct uart_port uart_port __initdata; | ||
553 | struct clk *bus_clk; | ||
554 | int res; | ||
555 | |||
556 | memset(&uart_port, 0, sizeof(struct uart_port)); | ||
557 | |||
558 | bus_clk = clk_get(NULL, "bus"); | ||
559 | if (IS_ERR(bus_clk)) | ||
560 | panic("unable to get bus clk"); | ||
561 | |||
562 | uart_port.type = PORT_AR7; | ||
563 | uart_port.uartclk = clk_get_rate(bus_clk) / 2; | ||
564 | uart_port.iotype = UPIO_MEM32; | ||
565 | uart_port.flags = UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF; | ||
566 | uart_port.regshift = 2; | ||
567 | |||
568 | uart_port.line = 0; | ||
569 | uart_port.irq = AR7_IRQ_UART0; | ||
570 | uart_port.mapbase = AR7_REGS_UART0; | ||
571 | uart_port.membase = ioremap(uart_port.mapbase, 256); | ||
572 | |||
573 | res = early_serial_setup(&uart_port); | ||
574 | if (res) | ||
575 | return res; | ||
576 | |||
577 | /* Only TNETD73xx have a second serial port */ | ||
578 | if (ar7_has_second_uart()) { | ||
579 | uart_port.line = 1; | ||
580 | uart_port.irq = AR7_IRQ_UART1; | ||
581 | uart_port.mapbase = UR8_REGS_UART1; | ||
582 | uart_port.membase = ioremap(uart_port.mapbase, 256); | ||
583 | |||
584 | res = early_serial_setup(&uart_port); | ||
585 | if (res) | ||
586 | return res; | ||
587 | } | ||
588 | #endif | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static void __init titan_fixup_devices(void) | ||
594 | { | ||
595 | /* Set vlynq0 data */ | ||
596 | vlynq_low_data.reset_bit = 15; | ||
597 | vlynq_low_data.gpio_bit = 14; | ||
598 | |||
599 | /* Set vlynq1 data */ | ||
600 | vlynq_high_data.reset_bit = 16; | ||
601 | vlynq_high_data.gpio_bit = 7; | ||
602 | |||
603 | /* Set vlynq0 resources */ | ||
604 | vlynq_low_res[0].start = TITAN_REGS_VLYNQ0; | ||
605 | vlynq_low_res[0].end = TITAN_REGS_VLYNQ0 + 0xff; | ||
606 | vlynq_low_res[1].start = 33; | ||
607 | vlynq_low_res[1].end = 33; | ||
608 | vlynq_low_res[2].start = 0x0c000000; | ||
609 | vlynq_low_res[2].end = 0x0fffffff; | ||
610 | vlynq_low_res[3].start = 80; | ||
611 | vlynq_low_res[3].end = 111; | ||
612 | |||
613 | /* Set vlynq1 resources */ | ||
614 | vlynq_high_res[0].start = TITAN_REGS_VLYNQ1; | ||
615 | vlynq_high_res[0].end = TITAN_REGS_VLYNQ1 + 0xff; | ||
616 | vlynq_high_res[1].start = 34; | ||
617 | vlynq_high_res[1].end = 34; | ||
618 | vlynq_high_res[2].start = 0x40000000; | ||
619 | vlynq_high_res[2].end = 0x43ffffff; | ||
620 | vlynq_high_res[3].start = 112; | ||
621 | vlynq_high_res[3].end = 143; | ||
622 | |||
623 | /* Set cpmac0 data */ | ||
624 | cpmac_low_data.phy_mask = 0x40000000; | ||
625 | |||
626 | /* Set cpmac1 data */ | ||
627 | cpmac_high_data.phy_mask = 0x80000000; | ||
628 | |||
629 | /* Set cpmac0 resources */ | ||
630 | cpmac_low_res[0].start = TITAN_REGS_MAC0; | ||
631 | cpmac_low_res[0].end = TITAN_REGS_MAC0 + 0x7ff; | ||
632 | |||
633 | /* Set cpmac1 resources */ | ||
634 | cpmac_high_res[0].start = TITAN_REGS_MAC1; | ||
635 | cpmac_high_res[0].end = TITAN_REGS_MAC1 + 0x7ff; | ||
636 | } | ||
637 | |||
638 | static int __init ar7_register_devices(void) | ||
639 | { | ||
640 | void __iomem *bootcr; | ||
641 | u32 val; | ||
642 | int res; | ||
643 | |||
644 | res = ar7_gpio_init(); | ||
645 | if (res) | ||
646 | pr_warn("unable to register gpios: %d\n", res); | ||
647 | |||
648 | res = ar7_register_uarts(); | ||
649 | if (res) | ||
650 | pr_err("unable to setup uart(s): %d\n", res); | ||
651 | |||
652 | res = platform_device_register(&physmap_flash); | ||
653 | if (res) | ||
654 | pr_warn("unable to register physmap-flash: %d\n", res); | ||
655 | |||
656 | if (ar7_is_titan()) | ||
657 | titan_fixup_devices(); | ||
658 | |||
659 | ar7_device_disable(vlynq_low_data.reset_bit); | ||
660 | res = platform_device_register(&vlynq_low); | ||
661 | if (res) | ||
662 | pr_warn("unable to register vlynq-low: %d\n", res); | ||
663 | |||
664 | if (ar7_has_high_vlynq()) { | ||
665 | ar7_device_disable(vlynq_high_data.reset_bit); | ||
666 | res = platform_device_register(&vlynq_high); | ||
667 | if (res) | ||
668 | pr_warn("unable to register vlynq-high: %d\n", res); | ||
669 | } | ||
670 | |||
671 | if (ar7_has_high_cpmac()) { | ||
672 | res = fixed_phy_add(PHY_POLL, cpmac_high.id, | ||
673 | &fixed_phy_status); | ||
674 | if (!res) { | ||
675 | cpmac_get_mac(1, cpmac_high_data.dev_addr); | ||
676 | |||
677 | res = platform_device_register(&cpmac_high); | ||
678 | if (res) | ||
679 | pr_warn("unable to register cpmac-high: %d\n", | ||
680 | res); | ||
681 | } else | ||
682 | pr_warn("unable to add cpmac-high phy: %d\n", res); | ||
683 | } else | ||
684 | cpmac_low_data.phy_mask = 0xffffffff; | ||
685 | |||
686 | res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status); | ||
687 | if (!res) { | ||
688 | cpmac_get_mac(0, cpmac_low_data.dev_addr); | ||
689 | res = platform_device_register(&cpmac_low); | ||
690 | if (res) | ||
691 | pr_warn("unable to register cpmac-low: %d\n", res); | ||
692 | } else | ||
693 | pr_warn("unable to add cpmac-low phy: %d\n", res); | ||
694 | |||
695 | detect_leds(); | ||
696 | res = platform_device_register(&ar7_gpio_leds); | ||
697 | if (res) | ||
698 | pr_warn("unable to register leds: %d\n", res); | ||
699 | |||
700 | res = platform_device_register(&ar7_udc); | ||
701 | if (res) | ||
702 | pr_warn("unable to register usb slave: %d\n", res); | ||
703 | |||
704 | /* Register watchdog only if enabled in hardware */ | ||
705 | bootcr = ioremap(AR7_REGS_DCL, 4); | ||
706 | val = readl(bootcr); | ||
707 | iounmap(bootcr); | ||
708 | if (val & AR7_WDT_HW_ENA) { | ||
709 | if (ar7_has_high_vlynq()) | ||
710 | ar7_wdt_res.start = UR8_REGS_WDT; | ||
711 | else | ||
712 | ar7_wdt_res.start = AR7_REGS_WDT; | ||
713 | |||
714 | ar7_wdt_res.end = ar7_wdt_res.start + 0x20; | ||
715 | res = platform_device_register(&ar7_wdt); | ||
716 | if (res) | ||
717 | pr_warn("unable to register watchdog: %d\n", res); | ||
718 | } | ||
719 | |||
720 | return 0; | ||
721 | } | ||
722 | device_initcall(ar7_register_devices); | ||
diff --git a/arch/mips/ar7/prom.c b/arch/mips/ar7/prom.c new file mode 100644 index 000000000..5810d3993 --- /dev/null +++ b/arch/mips/ar7/prom.c | |||
@@ -0,0 +1,256 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * Carsten Langgaard, carstenl@mips.com | ||
4 | * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. | ||
5 | * | ||
6 | * Putting things on the screen/serial line using YAMONs facilities. | ||
7 | */ | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/serial_reg.h> | ||
11 | #include <linux/spinlock.h> | ||
12 | #include <linux/export.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <asm/bootinfo.h> | ||
16 | #include <asm/setup.h> | ||
17 | |||
18 | #include <asm/mach-ar7/ar7.h> | ||
19 | #include <asm/mach-ar7/prom.h> | ||
20 | |||
21 | #define MAX_ENTRY 80 | ||
22 | |||
23 | struct env_var { | ||
24 | char *name; | ||
25 | char *value; | ||
26 | }; | ||
27 | |||
28 | static struct env_var adam2_env[MAX_ENTRY]; | ||
29 | |||
30 | char *prom_getenv(const char *name) | ||
31 | { | ||
32 | int i; | ||
33 | |||
34 | for (i = 0; (i < MAX_ENTRY) && adam2_env[i].name; i++) | ||
35 | if (!strcmp(name, adam2_env[i].name)) | ||
36 | return adam2_env[i].value; | ||
37 | |||
38 | return NULL; | ||
39 | } | ||
40 | EXPORT_SYMBOL(prom_getenv); | ||
41 | |||
42 | static void __init ar7_init_cmdline(int argc, char *argv[]) | ||
43 | { | ||
44 | int i; | ||
45 | |||
46 | for (i = 1; i < argc; i++) { | ||
47 | strlcat(arcs_cmdline, argv[i], COMMAND_LINE_SIZE); | ||
48 | if (i < (argc - 1)) | ||
49 | strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | struct psbl_rec { | ||
54 | u32 psbl_size; | ||
55 | u32 env_base; | ||
56 | u32 env_size; | ||
57 | u32 ffs_base; | ||
58 | u32 ffs_size; | ||
59 | }; | ||
60 | |||
61 | static const char psp_env_version[] __initconst = "TIENV0.8"; | ||
62 | |||
63 | struct psp_env_chunk { | ||
64 | u8 num; | ||
65 | u8 ctrl; | ||
66 | u16 csum; | ||
67 | u8 len; | ||
68 | char data[11]; | ||
69 | } __packed; | ||
70 | |||
71 | struct psp_var_map_entry { | ||
72 | u8 num; | ||
73 | char *value; | ||
74 | }; | ||
75 | |||
76 | static const struct psp_var_map_entry psp_var_map[] = { | ||
77 | { 1, "cpufrequency" }, | ||
78 | { 2, "memsize" }, | ||
79 | { 3, "flashsize" }, | ||
80 | { 4, "modetty0" }, | ||
81 | { 5, "modetty1" }, | ||
82 | { 8, "maca" }, | ||
83 | { 9, "macb" }, | ||
84 | { 28, "sysfrequency" }, | ||
85 | { 38, "mipsfrequency" }, | ||
86 | }; | ||
87 | |||
88 | /* | ||
89 | |||
90 | Well-known variable (num is looked up in table above for matching variable name) | ||
91 | Example: cpufrequency=211968000 | ||
92 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
93 | | 01 |CTRL|CHECKSUM | 01 | _2 | _1 | _1 | _9 | _6 | _8 | _0 | _0 | _0 | \0 | FF | ||
94 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
95 | |||
96 | Name=Value pair in a single chunk | ||
97 | Example: NAME=VALUE | ||
98 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
99 | | 00 |CTRL|CHECKSUM | 01 | _N | _A | _M | _E | _0 | _V | _A | _L | _U | _E | \0 | ||
100 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
101 | |||
102 | Name=Value pair in 2 chunks (len is the number of chunks) | ||
103 | Example: bootloaderVersion=1.3.7.15 | ||
104 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
105 | | 00 |CTRL|CHECKSUM | 02 | _b | _o | _o | _t | _l | _o | _a | _d | _e | _r | _V | ||
106 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
107 | | _e | _r | _s | _i | _o | _n | \0 | _1 | _. | _3 | _. | _7 | _. | _1 | _5 | \0 | ||
108 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+--- | ||
109 | |||
110 | Data is padded with 0xFF | ||
111 | |||
112 | */ | ||
113 | |||
114 | #define PSP_ENV_SIZE 4096 | ||
115 | |||
116 | static char psp_env_data[PSP_ENV_SIZE] = { 0, }; | ||
117 | |||
118 | static char * __init lookup_psp_var_map(u8 num) | ||
119 | { | ||
120 | int i; | ||
121 | |||
122 | for (i = 0; i < ARRAY_SIZE(psp_var_map); i++) | ||
123 | if (psp_var_map[i].num == num) | ||
124 | return psp_var_map[i].value; | ||
125 | |||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | static void __init add_adam2_var(char *name, char *value) | ||
130 | { | ||
131 | int i; | ||
132 | |||
133 | for (i = 0; i < MAX_ENTRY; i++) { | ||
134 | if (!adam2_env[i].name) { | ||
135 | adam2_env[i].name = name; | ||
136 | adam2_env[i].value = value; | ||
137 | return; | ||
138 | } else if (!strcmp(adam2_env[i].name, name)) { | ||
139 | adam2_env[i].value = value; | ||
140 | return; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static int __init parse_psp_env(void *psp_env_base) | ||
146 | { | ||
147 | int i, n; | ||
148 | char *name, *value; | ||
149 | struct psp_env_chunk *chunks = (struct psp_env_chunk *)psp_env_data; | ||
150 | |||
151 | memcpy_fromio(chunks, psp_env_base, PSP_ENV_SIZE); | ||
152 | |||
153 | i = 1; | ||
154 | n = PSP_ENV_SIZE / sizeof(struct psp_env_chunk); | ||
155 | while (i < n) { | ||
156 | if ((chunks[i].num == 0xff) || ((i + chunks[i].len) > n)) | ||
157 | break; | ||
158 | value = chunks[i].data; | ||
159 | if (chunks[i].num) { | ||
160 | name = lookup_psp_var_map(chunks[i].num); | ||
161 | } else { | ||
162 | name = value; | ||
163 | value += strlen(name) + 1; | ||
164 | } | ||
165 | if (name) | ||
166 | add_adam2_var(name, value); | ||
167 | i += chunks[i].len; | ||
168 | } | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static void __init ar7_init_env(struct env_var *env) | ||
173 | { | ||
174 | int i; | ||
175 | struct psbl_rec *psbl = (struct psbl_rec *)(KSEG1ADDR(0x14000300)); | ||
176 | void *psp_env = (void *)KSEG1ADDR(psbl->env_base); | ||
177 | |||
178 | if (strcmp(psp_env, psp_env_version) == 0) { | ||
179 | parse_psp_env(psp_env); | ||
180 | } else { | ||
181 | for (i = 0; i < MAX_ENTRY; i++, env++) | ||
182 | if (env->name) | ||
183 | add_adam2_var(env->name, env->value); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | static void __init console_config(void) | ||
188 | { | ||
189 | #ifdef CONFIG_SERIAL_8250_CONSOLE | ||
190 | char console_string[40]; | ||
191 | int baud = 0; | ||
192 | char parity = '\0', bits = '\0', flow = '\0'; | ||
193 | char *s, *p; | ||
194 | |||
195 | if (strstr(arcs_cmdline, "console=")) | ||
196 | return; | ||
197 | |||
198 | s = prom_getenv("modetty0"); | ||
199 | if (s) { | ||
200 | baud = simple_strtoul(s, &p, 10); | ||
201 | s = p; | ||
202 | if (*s == ',') | ||
203 | s++; | ||
204 | if (*s) | ||
205 | parity = *s++; | ||
206 | if (*s == ',') | ||
207 | s++; | ||
208 | if (*s) | ||
209 | bits = *s++; | ||
210 | if (*s == ',') | ||
211 | s++; | ||
212 | if (*s == 'h') | ||
213 | flow = 'r'; | ||
214 | } | ||
215 | |||
216 | if (baud == 0) | ||
217 | baud = 38400; | ||
218 | if (parity != 'n' && parity != 'o' && parity != 'e') | ||
219 | parity = 'n'; | ||
220 | if (bits != '7' && bits != '8') | ||
221 | bits = '8'; | ||
222 | |||
223 | if (flow == 'r') | ||
224 | sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, | ||
225 | parity, bits, flow); | ||
226 | else | ||
227 | sprintf(console_string, " console=ttyS0,%d%c%c", baud, parity, | ||
228 | bits); | ||
229 | strlcat(arcs_cmdline, console_string, COMMAND_LINE_SIZE); | ||
230 | #endif | ||
231 | } | ||
232 | |||
233 | void __init prom_init(void) | ||
234 | { | ||
235 | ar7_init_cmdline(fw_arg0, (char **)fw_arg1); | ||
236 | ar7_init_env((struct env_var *)fw_arg2); | ||
237 | console_config(); | ||
238 | } | ||
239 | |||
240 | #define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4))) | ||
241 | static inline unsigned int serial_in(int offset) | ||
242 | { | ||
243 | return readl((void *)PORT(offset)); | ||
244 | } | ||
245 | |||
246 | static inline void serial_out(int offset, int value) | ||
247 | { | ||
248 | writel(value, (void *)PORT(offset)); | ||
249 | } | ||
250 | |||
251 | void prom_putchar(char c) | ||
252 | { | ||
253 | while ((serial_in(UART_LSR) & UART_LSR_TEMT) == 0) | ||
254 | ; | ||
255 | serial_out(UART_TX, c); | ||
256 | } | ||
diff --git a/arch/mips/ar7/setup.c b/arch/mips/ar7/setup.c new file mode 100644 index 000000000..352d5dbc7 --- /dev/null +++ b/arch/mips/ar7/setup.c | |||
@@ -0,0 +1,93 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * Carsten Langgaard, carstenl@mips.com | ||
4 | * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. | ||
5 | */ | ||
6 | #include <linux/init.h> | ||
7 | #include <linux/ioport.h> | ||
8 | #include <linux/pm.h> | ||
9 | #include <linux/time.h> | ||
10 | |||
11 | #include <asm/reboot.h> | ||
12 | #include <asm/mach-ar7/ar7.h> | ||
13 | #include <asm/mach-ar7/prom.h> | ||
14 | |||
15 | static void ar7_machine_restart(char *command) | ||
16 | { | ||
17 | u32 *softres_reg = ioremap(AR7_REGS_RESET + AR7_RESET_SOFTWARE, 1); | ||
18 | |||
19 | writel(1, softres_reg); | ||
20 | } | ||
21 | |||
22 | static void ar7_machine_halt(void) | ||
23 | { | ||
24 | while (1) | ||
25 | ; | ||
26 | } | ||
27 | |||
28 | static void ar7_machine_power_off(void) | ||
29 | { | ||
30 | u32 *power_reg = (u32 *)ioremap(AR7_REGS_POWER, 1); | ||
31 | u32 power_state = readl(power_reg) | (3 << 30); | ||
32 | |||
33 | writel(power_state, power_reg); | ||
34 | ar7_machine_halt(); | ||
35 | } | ||
36 | |||
37 | const char *get_system_type(void) | ||
38 | { | ||
39 | u16 chip_id = ar7_chip_id(); | ||
40 | u16 titan_variant_id = titan_chip_id(); | ||
41 | |||
42 | switch (chip_id) { | ||
43 | case AR7_CHIP_7100: | ||
44 | return "TI AR7 (TNETD7100)"; | ||
45 | case AR7_CHIP_7200: | ||
46 | return "TI AR7 (TNETD7200)"; | ||
47 | case AR7_CHIP_7300: | ||
48 | return "TI AR7 (TNETD7300)"; | ||
49 | case AR7_CHIP_TITAN: | ||
50 | switch (titan_variant_id) { | ||
51 | case TITAN_CHIP_1050: | ||
52 | return "TI AR7 (TNETV1050)"; | ||
53 | case TITAN_CHIP_1055: | ||
54 | return "TI AR7 (TNETV1055)"; | ||
55 | case TITAN_CHIP_1056: | ||
56 | return "TI AR7 (TNETV1056)"; | ||
57 | case TITAN_CHIP_1060: | ||
58 | return "TI AR7 (TNETV1060)"; | ||
59 | } | ||
60 | fallthrough; | ||
61 | default: | ||
62 | return "TI AR7 (unknown)"; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | static int __init ar7_init_console(void) | ||
67 | { | ||
68 | return 0; | ||
69 | } | ||
70 | console_initcall(ar7_init_console); | ||
71 | |||
72 | /* | ||
73 | * Initializes basic routines and structures pointers, memory size (as | ||
74 | * given by the bios and saves the command line. | ||
75 | */ | ||
76 | void __init plat_mem_setup(void) | ||
77 | { | ||
78 | unsigned long io_base; | ||
79 | |||
80 | _machine_restart = ar7_machine_restart; | ||
81 | _machine_halt = ar7_machine_halt; | ||
82 | pm_power_off = ar7_machine_power_off; | ||
83 | |||
84 | io_base = (unsigned long)ioremap(AR7_REGS_BASE, 0x10000); | ||
85 | if (!io_base) | ||
86 | panic("Can't remap IO base!"); | ||
87 | set_io_port_base(io_base); | ||
88 | |||
89 | prom_meminit(); | ||
90 | |||
91 | printk(KERN_INFO "%s, ID: 0x%04x, Revision: 0x%02x\n", | ||
92 | get_system_type(), ar7_chip_id(), ar7_chip_rev()); | ||
93 | } | ||
diff --git a/arch/mips/ar7/time.c b/arch/mips/ar7/time.c new file mode 100644 index 000000000..72aa77d70 --- /dev/null +++ b/arch/mips/ar7/time.c | |||
@@ -0,0 +1,31 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * Carsten Langgaard, carstenl@mips.com | ||
4 | * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. | ||
5 | * | ||
6 | * Setting up the clock on the MIPS boards. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/time.h> | ||
11 | #include <linux/err.h> | ||
12 | #include <linux/clk.h> | ||
13 | |||
14 | #include <asm/time.h> | ||
15 | #include <asm/mach-ar7/ar7.h> | ||
16 | |||
17 | void __init plat_time_init(void) | ||
18 | { | ||
19 | struct clk *cpu_clk; | ||
20 | |||
21 | /* Initialize ar7 clocks so the CPU clock frequency is correct */ | ||
22 | ar7_init_clocks(); | ||
23 | |||
24 | cpu_clk = clk_get(NULL, "cpu"); | ||
25 | if (IS_ERR(cpu_clk)) { | ||
26 | printk(KERN_ERR "unable to get cpu clock\n"); | ||
27 | return; | ||
28 | } | ||
29 | |||
30 | mips_hpt_frequency = clk_get_rate(cpu_clk) / 2; | ||
31 | } | ||