aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/ar7
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/ar7')
-rw-r--r--arch/mips/ar7/Makefile11
-rw-r--r--arch/mips/ar7/clock.c427
-rw-r--r--arch/mips/ar7/gpio.c48
-rw-r--r--arch/mips/ar7/irq.c176
-rw-r--r--arch/mips/ar7/memory.c72
-rw-r--r--arch/mips/ar7/platform.c555
-rw-r--r--arch/mips/ar7/prom.c297
-rw-r--r--arch/mips/ar7/setup.c93
-rw-r--r--arch/mips/ar7/time.c30
9 files changed, 1709 insertions, 0 deletions
diff --git a/arch/mips/ar7/Makefile b/arch/mips/ar7/Makefile
new file mode 100644
index 000000000000..26bc5da18997
--- /dev/null
+++ b/arch/mips/ar7/Makefile
@@ -0,0 +1,11 @@
1
2obj-y := \
3 prom.o \
4 setup.o \
5 memory.o \
6 irq.o \
7 time.o \
8 platform.o \
9 gpio.o \
10 clock.o
11EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/ar7/clock.c b/arch/mips/ar7/clock.c
new file mode 100644
index 000000000000..cc65c8eb391b
--- /dev/null
+++ b/arch/mips/ar7/clock.c
@@ -0,0 +1,427 @@
1/*
2 * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/types.h>
23#include <linux/module.h>
24#include <linux/delay.h>
25#include <linux/gcd.h>
26#include <linux/io.h>
27
28#include <asm/addrspace.h>
29#include <asm/mach-ar7/ar7.h>
30
31#define BOOT_PLL_SOURCE_MASK 0x3
32#define CPU_PLL_SOURCE_SHIFT 16
33#define BUS_PLL_SOURCE_SHIFT 14
34#define USB_PLL_SOURCE_SHIFT 18
35#define DSP_PLL_SOURCE_SHIFT 22
36#define BOOT_PLL_SOURCE_AFE 0
37#define BOOT_PLL_SOURCE_BUS 0
38#define BOOT_PLL_SOURCE_REF 1
39#define BOOT_PLL_SOURCE_XTAL 2
40#define BOOT_PLL_SOURCE_CPU 3
41#define BOOT_PLL_BYPASS 0x00000020
42#define BOOT_PLL_ASYNC_MODE 0x02000000
43#define BOOT_PLL_2TO1_MODE 0x00008000
44
45#define TNETD7200_CLOCK_ID_CPU 0
46#define TNETD7200_CLOCK_ID_DSP 1
47#define TNETD7200_CLOCK_ID_USB 2
48
49#define TNETD7200_DEF_CPU_CLK 211000000
50#define TNETD7200_DEF_DSP_CLK 125000000
51#define TNETD7200_DEF_USB_CLK 48000000
52
53struct tnetd7300_clock {
54 u32 ctrl;
55#define PREDIV_MASK 0x001f0000
56#define PREDIV_SHIFT 16
57#define POSTDIV_MASK 0x0000001f
58 u32 unused1[3];
59 u32 pll;
60#define MUL_MASK 0x0000f000
61#define MUL_SHIFT 12
62#define PLL_MODE_MASK 0x00000001
63#define PLL_NDIV 0x00000800
64#define PLL_DIV 0x00000002
65#define PLL_STATUS 0x00000001
66 u32 unused2[3];
67};
68
69struct tnetd7300_clocks {
70 struct tnetd7300_clock bus;
71 struct tnetd7300_clock cpu;
72 struct tnetd7300_clock usb;
73 struct tnetd7300_clock dsp;
74};
75
76struct tnetd7200_clock {
77 u32 ctrl;
78 u32 unused1[3];
79#define DIVISOR_ENABLE_MASK 0x00008000
80 u32 mul;
81 u32 prediv;
82 u32 postdiv;
83 u32 postdiv2;
84 u32 unused2[6];
85 u32 cmd;
86 u32 status;
87 u32 cmden;
88 u32 padding[15];
89};
90
91struct tnetd7200_clocks {
92 struct tnetd7200_clock cpu;
93 struct tnetd7200_clock dsp;
94 struct tnetd7200_clock usb;
95};
96
97int ar7_cpu_clock = 150000000;
98EXPORT_SYMBOL(ar7_cpu_clock);
99int ar7_bus_clock = 125000000;
100EXPORT_SYMBOL(ar7_bus_clock);
101int ar7_dsp_clock;
102EXPORT_SYMBOL(ar7_dsp_clock);
103
104static void approximate(int base, int target, int *prediv,
105 int *postdiv, int *mul)
106{
107 int i, j, k, freq, res = target;
108 for (i = 1; i <= 16; i++)
109 for (j = 1; j <= 32; j++)
110 for (k = 1; k <= 32; k++) {
111 freq = abs(base / j * i / k - target);
112 if (freq < res) {
113 res = freq;
114 *mul = i;
115 *prediv = j;
116 *postdiv = k;
117 }
118 }
119}
120
121static void calculate(int base, int target, int *prediv, int *postdiv,
122 int *mul)
123{
124 int tmp_gcd, tmp_base, tmp_freq;
125
126 for (*prediv = 1; *prediv <= 32; (*prediv)++) {
127 tmp_base = base / *prediv;
128 tmp_gcd = gcd(target, tmp_base);
129 *mul = target / tmp_gcd;
130 *postdiv = tmp_base / tmp_gcd;
131 if ((*mul < 1) || (*mul >= 16))
132 continue;
133 if ((*postdiv > 0) & (*postdiv <= 32))
134 break;
135 }
136
137 if (base / *prediv * *mul / *postdiv != target) {
138 approximate(base, target, prediv, postdiv, mul);
139 tmp_freq = base / *prediv * *mul / *postdiv;
140 printk(KERN_WARNING
141 "Adjusted requested frequency %d to %d\n",
142 target, tmp_freq);
143 }
144
145 printk(KERN_DEBUG "Clocks: prediv: %d, postdiv: %d, mul: %d\n",
146 *prediv, *postdiv, *mul);
147}
148
149static int tnetd7300_dsp_clock(void)
150{
151 u32 didr1, didr2;
152 u8 rev = ar7_chip_rev();
153 didr1 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x18));
154 didr2 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x1c));
155 if (didr2 & (1 << 23))
156 return 0;
157 if ((rev >= 0x23) && (rev != 0x57))
158 return 250000000;
159 if ((((didr2 & 0x1fff) << 10) | ((didr1 & 0xffc00000) >> 22))
160 > 4208000)
161 return 250000000;
162 return 0;
163}
164
165static int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock,
166 u32 *bootcr, u32 bus_clock)
167{
168 int product;
169 int base_clock = AR7_REF_CLOCK;
170 u32 ctrl = readl(&clock->ctrl);
171 u32 pll = readl(&clock->pll);
172 int prediv = ((ctrl & PREDIV_MASK) >> PREDIV_SHIFT) + 1;
173 int postdiv = (ctrl & POSTDIV_MASK) + 1;
174 int divisor = prediv * postdiv;
175 int mul = ((pll & MUL_MASK) >> MUL_SHIFT) + 1;
176
177 switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
178 case BOOT_PLL_SOURCE_BUS:
179 base_clock = bus_clock;
180 break;
181 case BOOT_PLL_SOURCE_REF:
182 base_clock = AR7_REF_CLOCK;
183 break;
184 case BOOT_PLL_SOURCE_XTAL:
185 base_clock = AR7_XTAL_CLOCK;
186 break;
187 case BOOT_PLL_SOURCE_CPU:
188 base_clock = ar7_cpu_clock;
189 break;
190 }
191
192 if (*bootcr & BOOT_PLL_BYPASS)
193 return base_clock / divisor;
194
195 if ((pll & PLL_MODE_MASK) == 0)
196 return (base_clock >> (mul / 16 + 1)) / divisor;
197
198 if ((pll & (PLL_NDIV | PLL_DIV)) == (PLL_NDIV | PLL_DIV)) {
199 product = (mul & 1) ?
200 (base_clock * mul) >> 1 :
201 (base_clock * (mul - 1)) >> 2;
202 return product / divisor;
203 }
204
205 if (mul == 16)
206 return base_clock / divisor;
207
208 return base_clock * mul / divisor;
209}
210
211static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock,
212 u32 *bootcr, u32 frequency)
213{
214 int prediv, postdiv, mul;
215 int base_clock = ar7_bus_clock;
216
217 switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
218 case BOOT_PLL_SOURCE_BUS:
219 base_clock = ar7_bus_clock;
220 break;
221 case BOOT_PLL_SOURCE_REF:
222 base_clock = AR7_REF_CLOCK;
223 break;
224 case BOOT_PLL_SOURCE_XTAL:
225 base_clock = AR7_XTAL_CLOCK;
226 break;
227 case BOOT_PLL_SOURCE_CPU:
228 base_clock = ar7_cpu_clock;
229 break;
230 }
231
232 calculate(base_clock, frequency, &prediv, &postdiv, &mul);
233
234 writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl);
235 msleep(1);
236 writel(4, &clock->pll);
237 while (readl(&clock->pll) & PLL_STATUS)
238 ;
239 writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll);
240 msleep(75);
241}
242
243static void __init tnetd7300_init_clocks(void)
244{
245 u32 *bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4);
246 struct tnetd7300_clocks *clocks =
247 ioremap_nocache(UR8_REGS_CLOCKS,
248 sizeof(struct tnetd7300_clocks));
249
250 ar7_bus_clock = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT,
251 &clocks->bus, bootcr, AR7_AFE_CLOCK);
252
253 if (*bootcr & BOOT_PLL_ASYNC_MODE)
254 ar7_cpu_clock = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT,
255 &clocks->cpu, bootcr, AR7_AFE_CLOCK);
256 else
257 ar7_cpu_clock = ar7_bus_clock;
258
259 if (ar7_dsp_clock == 250000000)
260 tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp,
261 bootcr, ar7_dsp_clock);
262
263 iounmap(clocks);
264 iounmap(bootcr);
265}
266
267static void tnetd7200_set_clock(int base, struct tnetd7200_clock *clock,
268 int prediv, int postdiv, int postdiv2, int mul, u32 frequency)
269{
270 printk(KERN_INFO
271 "Clocks: base = %d, frequency = %u, prediv = %d, "
272 "postdiv = %d, postdiv2 = %d, mul = %d\n",
273 base, frequency, prediv, postdiv, postdiv2, mul);
274
275 writel(0, &clock->ctrl);
276 writel(DIVISOR_ENABLE_MASK | ((prediv - 1) & 0x1F), &clock->prediv);
277 writel((mul - 1) & 0xF, &clock->mul);
278
279 while (readl(&clock->status) & 0x1)
280 ; /* nop */
281
282 writel(DIVISOR_ENABLE_MASK | ((postdiv - 1) & 0x1F), &clock->postdiv);
283
284 writel(readl(&clock->cmden) | 1, &clock->cmden);
285 writel(readl(&clock->cmd) | 1, &clock->cmd);
286
287 while (readl(&clock->status) & 0x1)
288 ; /* nop */
289
290 writel(DIVISOR_ENABLE_MASK | ((postdiv2 - 1) & 0x1F), &clock->postdiv2);
291
292 writel(readl(&clock->cmden) | 1, &clock->cmden);
293 writel(readl(&clock->cmd) | 1, &clock->cmd);
294
295 while (readl(&clock->status) & 0x1)
296 ; /* nop */
297
298 writel(readl(&clock->ctrl) | 1, &clock->ctrl);
299}
300
301static int tnetd7200_get_clock_base(int clock_id, u32 *bootcr)
302{
303 if (*bootcr & BOOT_PLL_ASYNC_MODE)
304 /* Async */
305 switch (clock_id) {
306 case TNETD7200_CLOCK_ID_DSP:
307 return AR7_REF_CLOCK;
308 default:
309 return AR7_AFE_CLOCK;
310 }
311 else
312 /* Sync */
313 if (*bootcr & BOOT_PLL_2TO1_MODE)
314 /* 2:1 */
315 switch (clock_id) {
316 case TNETD7200_CLOCK_ID_DSP:
317 return AR7_REF_CLOCK;
318 default:
319 return AR7_AFE_CLOCK;
320 }
321 else
322 /* 1:1 */
323 return AR7_REF_CLOCK;
324}
325
326
327static void __init tnetd7200_init_clocks(void)
328{
329 u32 *bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4);
330 struct tnetd7200_clocks *clocks =
331 ioremap_nocache(AR7_REGS_CLOCKS,
332 sizeof(struct tnetd7200_clocks));
333 int cpu_base, cpu_mul, cpu_prediv, cpu_postdiv;
334 int dsp_base, dsp_mul, dsp_prediv, dsp_postdiv;
335 int usb_base, usb_mul, usb_prediv, usb_postdiv;
336
337 cpu_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_CPU, bootcr);
338 dsp_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_DSP, bootcr);
339
340 if (*bootcr & BOOT_PLL_ASYNC_MODE) {
341 printk(KERN_INFO "Clocks: Async mode\n");
342
343 printk(KERN_INFO "Clocks: Setting DSP clock\n");
344 calculate(dsp_base, TNETD7200_DEF_DSP_CLK,
345 &dsp_prediv, &dsp_postdiv, &dsp_mul);
346 ar7_bus_clock =
347 ((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv;
348 tnetd7200_set_clock(dsp_base, &clocks->dsp,
349 dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2,
350 ar7_bus_clock);
351
352 printk(KERN_INFO "Clocks: Setting CPU clock\n");
353 calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
354 &cpu_postdiv, &cpu_mul);
355 ar7_cpu_clock =
356 ((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv;
357 tnetd7200_set_clock(cpu_base, &clocks->cpu,
358 cpu_prediv, cpu_postdiv, -1, cpu_mul,
359 ar7_cpu_clock);
360
361 } else
362 if (*bootcr & BOOT_PLL_2TO1_MODE) {
363 printk(KERN_INFO "Clocks: Sync 2:1 mode\n");
364
365 printk(KERN_INFO "Clocks: Setting CPU clock\n");
366 calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
367 &cpu_postdiv, &cpu_mul);
368 ar7_cpu_clock = ((cpu_base / cpu_prediv) * cpu_mul)
369 / cpu_postdiv;
370 tnetd7200_set_clock(cpu_base, &clocks->cpu,
371 cpu_prediv, cpu_postdiv, -1, cpu_mul,
372 ar7_cpu_clock);
373
374 printk(KERN_INFO "Clocks: Setting DSP clock\n");
375 calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
376 &dsp_postdiv, &dsp_mul);
377 ar7_bus_clock = ar7_cpu_clock / 2;
378 tnetd7200_set_clock(dsp_base, &clocks->dsp,
379 dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
380 dsp_mul * 2, ar7_bus_clock);
381 } else {
382 printk(KERN_INFO "Clocks: Sync 1:1 mode\n");
383
384 printk(KERN_INFO "Clocks: Setting DSP clock\n");
385 calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
386 &dsp_postdiv, &dsp_mul);
387 ar7_bus_clock = ((dsp_base / dsp_prediv) * dsp_mul)
388 / dsp_postdiv;
389 tnetd7200_set_clock(dsp_base, &clocks->dsp,
390 dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
391 dsp_mul * 2, ar7_bus_clock);
392
393 ar7_cpu_clock = ar7_bus_clock;
394 }
395
396 printk(KERN_INFO "Clocks: Setting USB clock\n");
397 usb_base = ar7_bus_clock;
398 calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv,
399 &usb_postdiv, &usb_mul);
400 tnetd7200_set_clock(usb_base, &clocks->usb,
401 usb_prediv, usb_postdiv, -1, usb_mul,
402 TNETD7200_DEF_USB_CLK);
403
404 ar7_dsp_clock = ar7_cpu_clock;
405
406 iounmap(clocks);
407 iounmap(bootcr);
408}
409
410int __init ar7_init_clocks(void)
411{
412 switch (ar7_chip_id()) {
413 case AR7_CHIP_7100:
414 case AR7_CHIP_7200:
415 tnetd7200_init_clocks();
416 break;
417 case AR7_CHIP_7300:
418 ar7_dsp_clock = tnetd7300_dsp_clock();
419 tnetd7300_init_clocks();
420 break;
421 default:
422 break;
423 }
424
425 return 0;
426}
427arch_initcall(ar7_init_clocks);
diff --git a/arch/mips/ar7/gpio.c b/arch/mips/ar7/gpio.c
new file mode 100644
index 000000000000..74e14a3dbf4a
--- /dev/null
+++ b/arch/mips/ar7/gpio.c
@@ -0,0 +1,48 @@
1/*
2 * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <linux/module.h>
21
22#include <asm/mach-ar7/gpio.h>
23
24static const char *ar7_gpio_list[AR7_GPIO_MAX];
25
26int gpio_request(unsigned gpio, const char *label)
27{
28 if (gpio >= AR7_GPIO_MAX)
29 return -EINVAL;
30
31 if (ar7_gpio_list[gpio])
32 return -EBUSY;
33
34 if (label)
35 ar7_gpio_list[gpio] = label;
36 else
37 ar7_gpio_list[gpio] = "busy";
38
39 return 0;
40}
41EXPORT_SYMBOL(gpio_request);
42
43void gpio_free(unsigned gpio)
44{
45 BUG_ON(!ar7_gpio_list[gpio]);
46 ar7_gpio_list[gpio] = NULL;
47}
48EXPORT_SYMBOL(gpio_free);
diff --git a/arch/mips/ar7/irq.c b/arch/mips/ar7/irq.c
new file mode 100644
index 000000000000..c781556c44e4
--- /dev/null
+++ b/arch/mips/ar7/irq.c
@@ -0,0 +1,176 @@
1/*
2 * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <linux/interrupt.h>
21#include <linux/io.h>
22
23#include <asm/irq_cpu.h>
24#include <asm/mipsregs.h>
25#include <asm/mach-ar7/ar7.h>
26
27#define EXCEPT_OFFSET 0x80
28#define PACE_OFFSET 0xA0
29#define CHNLS_OFFSET 0x200
30
31#define REG_OFFSET(irq, reg) ((irq) / 32 * 0x4 + reg * 0x10)
32#define SEC_REG_OFFSET(reg) (EXCEPT_OFFSET + reg * 0x8)
33#define SEC_SR_OFFSET (SEC_REG_OFFSET(0)) /* 0x80 */
34#define CR_OFFSET(irq) (REG_OFFSET(irq, 1)) /* 0x10 */
35#define SEC_CR_OFFSET (SEC_REG_OFFSET(1)) /* 0x88 */
36#define ESR_OFFSET(irq) (REG_OFFSET(irq, 2)) /* 0x20 */
37#define SEC_ESR_OFFSET (SEC_REG_OFFSET(2)) /* 0x90 */
38#define ECR_OFFSET(irq) (REG_OFFSET(irq, 3)) /* 0x30 */
39#define SEC_ECR_OFFSET (SEC_REG_OFFSET(3)) /* 0x98 */
40#define PIR_OFFSET (0x40)
41#define MSR_OFFSET (0x44)
42#define PM_OFFSET(irq) (REG_OFFSET(irq, 5)) /* 0x50 */
43#define TM_OFFSET(irq) (REG_OFFSET(irq, 6)) /* 0x60 */
44
45#define REG(addr) ((u32 *)(KSEG1ADDR(AR7_REGS_IRQ) + addr))
46
47#define CHNL_OFFSET(chnl) (CHNLS_OFFSET + (chnl * 4))
48
49static int ar7_irq_base;
50
51static void ar7_unmask_irq(unsigned int irq)
52{
53 writel(1 << ((irq - ar7_irq_base) % 32),
54 REG(ESR_OFFSET(irq - ar7_irq_base)));
55}
56
57static void ar7_mask_irq(unsigned int irq)
58{
59 writel(1 << ((irq - ar7_irq_base) % 32),
60 REG(ECR_OFFSET(irq - ar7_irq_base)));
61}
62
63static void ar7_ack_irq(unsigned int irq)
64{
65 writel(1 << ((irq - ar7_irq_base) % 32),
66 REG(CR_OFFSET(irq - ar7_irq_base)));
67}
68
69static void ar7_unmask_sec_irq(unsigned int irq)
70{
71 writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET));
72}
73
74static void ar7_mask_sec_irq(unsigned int irq)
75{
76 writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET));
77}
78
79static void ar7_ack_sec_irq(unsigned int irq)
80{
81 writel(1 << (irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET));
82}
83
84static struct irq_chip ar7_irq_type = {
85 .name = "AR7",
86 .unmask = ar7_unmask_irq,
87 .mask = ar7_mask_irq,
88 .ack = ar7_ack_irq
89};
90
91static struct irq_chip ar7_sec_irq_type = {
92 .name = "AR7",
93 .unmask = ar7_unmask_sec_irq,
94 .mask = ar7_mask_sec_irq,
95 .ack = ar7_ack_sec_irq,
96};
97
98static struct irqaction ar7_cascade_action = {
99 .handler = no_action,
100 .name = "AR7 cascade interrupt"
101};
102
103static void __init ar7_irq_init(int base)
104{
105 int i;
106 /*
107 * Disable interrupts and clear pending
108 */
109 writel(0xffffffff, REG(ECR_OFFSET(0)));
110 writel(0xff, REG(ECR_OFFSET(32)));
111 writel(0xffffffff, REG(SEC_ECR_OFFSET));
112 writel(0xffffffff, REG(CR_OFFSET(0)));
113 writel(0xff, REG(CR_OFFSET(32)));
114 writel(0xffffffff, REG(SEC_CR_OFFSET));
115
116 ar7_irq_base = base;
117
118 for (i = 0; i < 40; i++) {
119 writel(i, REG(CHNL_OFFSET(i)));
120 /* Primary IRQ's */
121 set_irq_chip_and_handler(base + i, &ar7_irq_type,
122 handle_level_irq);
123 /* Secondary IRQ's */
124 if (i < 32)
125 set_irq_chip_and_handler(base + i + 40,
126 &ar7_sec_irq_type,
127 handle_level_irq);
128 }
129
130 setup_irq(2, &ar7_cascade_action);
131 setup_irq(ar7_irq_base, &ar7_cascade_action);
132 set_c0_status(IE_IRQ0);
133}
134
135void __init arch_init_irq(void)
136{
137 mips_cpu_irq_init();
138 ar7_irq_init(8);
139}
140
141static void ar7_cascade(void)
142{
143 u32 status;
144 int i, irq;
145
146 /* Primary IRQ's */
147 irq = readl(REG(PIR_OFFSET)) & 0x3f;
148 if (irq) {
149 do_IRQ(ar7_irq_base + irq);
150 return;
151 }
152
153 /* Secondary IRQ's are cascaded through primary '0' */
154 writel(1, REG(CR_OFFSET(irq)));
155 status = readl(REG(SEC_SR_OFFSET));
156 for (i = 0; i < 32; i++) {
157 if (status & 1) {
158 do_IRQ(ar7_irq_base + i + 40);
159 return;
160 }
161 status >>= 1;
162 }
163
164 spurious_interrupt();
165}
166
167asmlinkage void plat_irq_dispatch(void)
168{
169 unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
170 if (pending & STATUSF_IP7) /* cpu timer */
171 do_IRQ(7);
172 else if (pending & STATUSF_IP2) /* int0 hardware line */
173 ar7_cascade();
174 else
175 spurious_interrupt();
176}
diff --git a/arch/mips/ar7/memory.c b/arch/mips/ar7/memory.c
new file mode 100644
index 000000000000..696c723dc6d4
--- /dev/null
+++ b/arch/mips/ar7/memory.c
@@ -0,0 +1,72 @@
1/*
2 * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include <linux/bootmem.h>
20#include <linux/init.h>
21#include <linux/mm.h>
22#include <linux/module.h>
23#include <linux/pfn.h>
24#include <linux/proc_fs.h>
25#include <linux/string.h>
26#include <linux/swap.h>
27
28#include <asm/bootinfo.h>
29#include <asm/page.h>
30#include <asm/sections.h>
31
32#include <asm/mach-ar7/ar7.h>
33#include <asm/mips-boards/prom.h>
34
35static int __init memsize(void)
36{
37 u32 size = (64 << 20);
38 u32 *addr = (u32 *)KSEG1ADDR(AR7_SDRAM_BASE + size - 4);
39 u32 *kernel_end = (u32 *)KSEG1ADDR(CPHYSADDR((u32)&_end));
40 u32 *tmpaddr = addr;
41
42 while (tmpaddr > kernel_end) {
43 *tmpaddr = (u32)tmpaddr;
44 size >>= 1;
45 tmpaddr -= size >> 2;
46 }
47
48 do {
49 tmpaddr += size >> 2;
50 if (*tmpaddr != (u32)tmpaddr)
51 break;
52 size <<= 1;
53 } while (size < (64 << 20));
54
55 writel((u32)tmpaddr, &addr);
56
57 return size;
58}
59
60void __init prom_meminit(void)
61{
62 unsigned long pages;
63
64 pages = memsize() >> PAGE_SHIFT;
65 add_memory_region(PHYS_OFFSET, pages << PAGE_SHIFT,
66 BOOT_MEM_RAM);
67}
68
69void __init prom_free_prom_memory(void)
70{
71 /* Nothing to free */
72}
diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
new file mode 100644
index 000000000000..2ecab6155932
--- /dev/null
+++ b/arch/mips/ar7/platform.c
@@ -0,0 +1,555 @@
1/*
2 * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <linux/init.h>
21#include <linux/types.h>
22#include <linux/module.h>
23#include <linux/delay.h>
24#include <linux/dma-mapping.h>
25#include <linux/platform_device.h>
26#include <linux/mtd/physmap.h>
27#include <linux/serial.h>
28#include <linux/serial_8250.h>
29#include <linux/ioport.h>
30#include <linux/io.h>
31#include <linux/vlynq.h>
32#include <linux/leds.h>
33#include <linux/string.h>
34#include <linux/etherdevice.h>
35
36#include <asm/addrspace.h>
37#include <asm/mach-ar7/ar7.h>
38#include <asm/mach-ar7/gpio.h>
39#include <asm/mach-ar7/prom.h>
40
41struct plat_vlynq_data {
42 struct plat_vlynq_ops ops;
43 int gpio_bit;
44 int reset_bit;
45};
46
47
48static int vlynq_on(struct vlynq_device *dev)
49{
50 int result;
51 struct plat_vlynq_data *pdata = dev->dev.platform_data;
52
53 result = gpio_request(pdata->gpio_bit, "vlynq");
54 if (result)
55 goto out;
56
57 ar7_device_reset(pdata->reset_bit);
58
59 result = ar7_gpio_disable(pdata->gpio_bit);
60 if (result)
61 goto out_enabled;
62
63 result = ar7_gpio_enable(pdata->gpio_bit);
64 if (result)
65 goto out_enabled;
66
67 result = gpio_direction_output(pdata->gpio_bit, 0);
68 if (result)
69 goto out_gpio_enabled;
70
71 msleep(50);
72
73 gpio_set_value(pdata->gpio_bit, 1);
74 msleep(50);
75
76 return 0;
77
78out_gpio_enabled:
79 ar7_gpio_disable(pdata->gpio_bit);
80out_enabled:
81 ar7_device_disable(pdata->reset_bit);
82 gpio_free(pdata->gpio_bit);
83out:
84 return result;
85}
86
87static void vlynq_off(struct vlynq_device *dev)
88{
89 struct plat_vlynq_data *pdata = dev->dev.platform_data;
90 ar7_gpio_disable(pdata->gpio_bit);
91 gpio_free(pdata->gpio_bit);
92 ar7_device_disable(pdata->reset_bit);
93}
94
95static struct resource physmap_flash_resource = {
96 .name = "mem",
97 .flags = IORESOURCE_MEM,
98 .start = 0x10000000,
99 .end = 0x107fffff,
100};
101
102static struct resource cpmac_low_res[] = {
103 {
104 .name = "regs",
105 .flags = IORESOURCE_MEM,
106 .start = AR7_REGS_MAC0,
107 .end = AR7_REGS_MAC0 + 0x7ff,
108 },
109 {
110 .name = "irq",
111 .flags = IORESOURCE_IRQ,
112 .start = 27,
113 .end = 27,
114 },
115};
116
117static struct resource cpmac_high_res[] = {
118 {
119 .name = "regs",
120 .flags = IORESOURCE_MEM,
121 .start = AR7_REGS_MAC1,
122 .end = AR7_REGS_MAC1 + 0x7ff,
123 },
124 {
125 .name = "irq",
126 .flags = IORESOURCE_IRQ,
127 .start = 41,
128 .end = 41,
129 },
130};
131
132static struct resource vlynq_low_res[] = {
133 {
134 .name = "regs",
135 .flags = IORESOURCE_MEM,
136 .start = AR7_REGS_VLYNQ0,
137 .end = AR7_REGS_VLYNQ0 + 0xff,
138 },
139 {
140 .name = "irq",
141 .flags = IORESOURCE_IRQ,
142 .start = 29,
143 .end = 29,
144 },
145 {
146 .name = "mem",
147 .flags = IORESOURCE_MEM,
148 .start = 0x04000000,
149 .end = 0x04ffffff,
150 },
151 {
152 .name = "devirq",
153 .flags = IORESOURCE_IRQ,
154 .start = 80,
155 .end = 111,
156 },
157};
158
159static struct resource vlynq_high_res[] = {
160 {
161 .name = "regs",
162 .flags = IORESOURCE_MEM,
163 .start = AR7_REGS_VLYNQ1,
164 .end = AR7_REGS_VLYNQ1 + 0xff,
165 },
166 {
167 .name = "irq",
168 .flags = IORESOURCE_IRQ,
169 .start = 33,
170 .end = 33,
171 },
172 {
173 .name = "mem",
174 .flags = IORESOURCE_MEM,
175 .start = 0x0c000000,
176 .end = 0x0cffffff,
177 },
178 {
179 .name = "devirq",
180 .flags = IORESOURCE_IRQ,
181 .start = 112,
182 .end = 143,
183 },
184};
185
186static struct resource usb_res[] = {
187 {
188 .name = "regs",
189 .flags = IORESOURCE_MEM,
190 .start = AR7_REGS_USB,
191 .end = AR7_REGS_USB + 0xff,
192 },
193 {
194 .name = "irq",
195 .flags = IORESOURCE_IRQ,
196 .start = 32,
197 .end = 32,
198 },
199 {
200 .name = "mem",
201 .flags = IORESOURCE_MEM,
202 .start = 0x03400000,
203 .end = 0x034001fff,
204 },
205};
206
207static struct physmap_flash_data physmap_flash_data = {
208 .width = 2,
209};
210
211static struct plat_cpmac_data cpmac_low_data = {
212 .reset_bit = 17,
213 .power_bit = 20,
214 .phy_mask = 0x80000000,
215};
216
217static struct plat_cpmac_data cpmac_high_data = {
218 .reset_bit = 21,
219 .power_bit = 22,
220 .phy_mask = 0x7fffffff,
221};
222
223static struct plat_vlynq_data vlynq_low_data = {
224 .ops.on = vlynq_on,
225 .ops.off = vlynq_off,
226 .reset_bit = 20,
227 .gpio_bit = 18,
228};
229
230static struct plat_vlynq_data vlynq_high_data = {
231 .ops.on = vlynq_on,
232 .ops.off = vlynq_off,
233 .reset_bit = 16,
234 .gpio_bit = 19,
235};
236
237static struct platform_device physmap_flash = {
238 .id = 0,
239 .name = "physmap-flash",
240 .dev.platform_data = &physmap_flash_data,
241 .resource = &physmap_flash_resource,
242 .num_resources = 1,
243};
244
245static u64 cpmac_dma_mask = DMA_BIT_MASK(32);
246static struct platform_device cpmac_low = {
247 .id = 0,
248 .name = "cpmac",
249 .dev = {
250 .dma_mask = &cpmac_dma_mask,
251 .coherent_dma_mask = DMA_BIT_MASK(32),
252 .platform_data = &cpmac_low_data,
253 },
254 .resource = cpmac_low_res,
255 .num_resources = ARRAY_SIZE(cpmac_low_res),
256};
257
258static struct platform_device cpmac_high = {
259 .id = 1,
260 .name = "cpmac",
261 .dev = {
262 .dma_mask = &cpmac_dma_mask,
263 .coherent_dma_mask = DMA_BIT_MASK(32),
264 .platform_data = &cpmac_high_data,
265 },
266 .resource = cpmac_high_res,
267 .num_resources = ARRAY_SIZE(cpmac_high_res),
268};
269
270static struct platform_device vlynq_low = {
271 .id = 0,
272 .name = "vlynq",
273 .dev.platform_data = &vlynq_low_data,
274 .resource = vlynq_low_res,
275 .num_resources = ARRAY_SIZE(vlynq_low_res),
276};
277
278static struct platform_device vlynq_high = {
279 .id = 1,
280 .name = "vlynq",
281 .dev.platform_data = &vlynq_high_data,
282 .resource = vlynq_high_res,
283 .num_resources = ARRAY_SIZE(vlynq_high_res),
284};
285
286
287static struct gpio_led default_leds[] = {
288 {
289 .name = "status",
290 .gpio = 8,
291 .active_low = 1,
292 },
293};
294
295static struct gpio_led dsl502t_leds[] = {
296 {
297 .name = "status",
298 .gpio = 9,
299 .active_low = 1,
300 },
301 {
302 .name = "ethernet",
303 .gpio = 7,
304 .active_low = 1,
305 },
306 {
307 .name = "usb",
308 .gpio = 12,
309 .active_low = 1,
310 },
311};
312
313static struct gpio_led dg834g_leds[] = {
314 {
315 .name = "ppp",
316 .gpio = 6,
317 .active_low = 1,
318 },
319 {
320 .name = "status",
321 .gpio = 7,
322 .active_low = 1,
323 },
324 {
325 .name = "adsl",
326 .gpio = 8,
327 .active_low = 1,
328 },
329 {
330 .name = "wifi",
331 .gpio = 12,
332 .active_low = 1,
333 },
334 {
335 .name = "power",
336 .gpio = 14,
337 .active_low = 1,
338 .default_trigger = "default-on",
339 },
340};
341
342static struct gpio_led fb_sl_leds[] = {
343 {
344 .name = "1",
345 .gpio = 7,
346 },
347 {
348 .name = "2",
349 .gpio = 13,
350 .active_low = 1,
351 },
352 {
353 .name = "3",
354 .gpio = 10,
355 .active_low = 1,
356 },
357 {
358 .name = "4",
359 .gpio = 12,
360 .active_low = 1,
361 },
362 {
363 .name = "5",
364 .gpio = 9,
365 .active_low = 1,
366 },
367};
368
369static struct gpio_led fb_fon_leds[] = {
370 {
371 .name = "1",
372 .gpio = 8,
373 },
374 {
375 .name = "2",
376 .gpio = 3,
377 .active_low = 1,
378 },
379 {
380 .name = "3",
381 .gpio = 5,
382 },
383 {
384 .name = "4",
385 .gpio = 4,
386 .active_low = 1,
387 },
388 {
389 .name = "5",
390 .gpio = 11,
391 .active_low = 1,
392 },
393};
394
395static struct gpio_led_platform_data ar7_led_data;
396
397static struct platform_device ar7_gpio_leds = {
398 .name = "leds-gpio",
399 .id = -1,
400 .dev = {
401 .platform_data = &ar7_led_data,
402 }
403};
404
405static struct platform_device ar7_udc = {
406 .id = -1,
407 .name = "ar7_udc",
408 .resource = usb_res,
409 .num_resources = ARRAY_SIZE(usb_res),
410};
411
412static inline unsigned char char2hex(char h)
413{
414 switch (h) {
415 case '0': case '1': case '2': case '3': case '4':
416 case '5': case '6': case '7': case '8': case '9':
417 return h - '0';
418 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
419 return h - 'A' + 10;
420 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
421 return h - 'a' + 10;
422 default:
423 return 0;
424 }
425}
426
427static void cpmac_get_mac(int instance, unsigned char *dev_addr)
428{
429 int i;
430 char name[5], default_mac[ETH_ALEN], *mac;
431
432 mac = NULL;
433 sprintf(name, "mac%c", 'a' + instance);
434 mac = prom_getenv(name);
435 if (!mac) {
436 sprintf(name, "mac%c", 'a');
437 mac = prom_getenv(name);
438 }
439 if (!mac) {
440 random_ether_addr(default_mac);
441 mac = default_mac;
442 }
443 for (i = 0; i < 6; i++)
444 dev_addr[i] = (char2hex(mac[i * 3]) << 4) +
445 char2hex(mac[i * 3 + 1]);
446}
447
448static void __init detect_leds(void)
449{
450 char *prid, *usb_prod;
451
452 /* Default LEDs */
453 ar7_led_data.num_leds = ARRAY_SIZE(default_leds);
454 ar7_led_data.leds = default_leds;
455
456 /* FIXME: the whole thing is unreliable */
457 prid = prom_getenv("ProductID");
458 usb_prod = prom_getenv("usb_prod");
459
460 /* If we can't get the product id from PROM, use the default LEDs */
461 if (!prid)
462 return;
463
464 if (strstr(prid, "Fritz_Box_FON")) {
465 ar7_led_data.num_leds = ARRAY_SIZE(fb_fon_leds);
466 ar7_led_data.leds = fb_fon_leds;
467 } else if (strstr(prid, "Fritz_Box_")) {
468 ar7_led_data.num_leds = ARRAY_SIZE(fb_sl_leds);
469 ar7_led_data.leds = fb_sl_leds;
470 } else if ((!strcmp(prid, "AR7RD") || !strcmp(prid, "AR7DB"))
471 && usb_prod != NULL && strstr(usb_prod, "DSL-502T")) {
472 ar7_led_data.num_leds = ARRAY_SIZE(dsl502t_leds);
473 ar7_led_data.leds = dsl502t_leds;
474 } else if (strstr(prid, "DG834")) {
475 ar7_led_data.num_leds = ARRAY_SIZE(dg834g_leds);
476 ar7_led_data.leds = dg834g_leds;
477 }
478}
479
480static int __init ar7_register_devices(void)
481{
482 int res;
483#ifdef CONFIG_SERIAL_8250
484 static struct uart_port uart_port[2];
485
486 memset(uart_port, 0, sizeof(struct uart_port) * 2);
487
488 uart_port[0].type = PORT_16550A;
489 uart_port[0].line = 0;
490 uart_port[0].irq = AR7_IRQ_UART0;
491 uart_port[0].uartclk = ar7_bus_freq() / 2;
492 uart_port[0].iotype = UPIO_MEM32;
493 uart_port[0].mapbase = AR7_REGS_UART0;
494 uart_port[0].membase = ioremap(uart_port[0].mapbase, 256);
495 uart_port[0].regshift = 2;
496 res = early_serial_setup(&uart_port[0]);
497 if (res)
498 return res;
499
500
501 /* Only TNETD73xx have a second serial port */
502 if (ar7_has_second_uart()) {
503 uart_port[1].type = PORT_16550A;
504 uart_port[1].line = 1;
505 uart_port[1].irq = AR7_IRQ_UART1;
506 uart_port[1].uartclk = ar7_bus_freq() / 2;
507 uart_port[1].iotype = UPIO_MEM32;
508 uart_port[1].mapbase = UR8_REGS_UART1;
509 uart_port[1].membase = ioremap(uart_port[1].mapbase, 256);
510 uart_port[1].regshift = 2;
511 res = early_serial_setup(&uart_port[1]);
512 if (res)
513 return res;
514 }
515#endif /* CONFIG_SERIAL_8250 */
516 res = platform_device_register(&physmap_flash);
517 if (res)
518 return res;
519
520 ar7_device_disable(vlynq_low_data.reset_bit);
521 res = platform_device_register(&vlynq_low);
522 if (res)
523 return res;
524
525 if (ar7_has_high_vlynq()) {
526 ar7_device_disable(vlynq_high_data.reset_bit);
527 res = platform_device_register(&vlynq_high);
528 if (res)
529 return res;
530 }
531
532 if (ar7_has_high_cpmac()) {
533 cpmac_get_mac(1, cpmac_high_data.dev_addr);
534 res = platform_device_register(&cpmac_high);
535 if (res)
536 return res;
537 } else {
538 cpmac_low_data.phy_mask = 0xffffffff;
539 }
540
541 cpmac_get_mac(0, cpmac_low_data.dev_addr);
542 res = platform_device_register(&cpmac_low);
543 if (res)
544 return res;
545
546 detect_leds();
547 res = platform_device_register(&ar7_gpio_leds);
548 if (res)
549 return res;
550
551 res = platform_device_register(&ar7_udc);
552
553 return res;
554}
555arch_initcall(ar7_register_devices);
diff --git a/arch/mips/ar7/prom.c b/arch/mips/ar7/prom.c
new file mode 100644
index 000000000000..5ad6f1db6567
--- /dev/null
+++ b/arch/mips/ar7/prom.c
@@ -0,0 +1,297 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Putting things on the screen/serial line using YAMONs facilities.
19 */
20#include <linux/init.h>
21#include <linux/kernel.h>
22#include <linux/serial_reg.h>
23#include <linux/spinlock.h>
24#include <linux/module.h>
25#include <linux/string.h>
26#include <linux/io.h>
27#include <asm/bootinfo.h>
28
29#include <asm/mach-ar7/ar7.h>
30#include <asm/mach-ar7/prom.h>
31
32#define MAX_ENTRY 80
33
34struct env_var {
35 char *name;
36 char *value;
37};
38
39static struct env_var adam2_env[MAX_ENTRY];
40
41char *prom_getenv(const char *name)
42{
43 int i;
44 for (i = 0; (i < MAX_ENTRY) && adam2_env[i].name; i++)
45 if (!strcmp(name, adam2_env[i].name))
46 return adam2_env[i].value;
47
48 return NULL;
49}
50EXPORT_SYMBOL(prom_getenv);
51
52char * __init prom_getcmdline(void)
53{
54 return &(arcs_cmdline[0]);
55}
56
57static void __init ar7_init_cmdline(int argc, char *argv[])
58{
59 char *cp;
60 int actr;
61
62 actr = 1; /* Always ignore argv[0] */
63
64 cp = &(arcs_cmdline[0]);
65 while (actr < argc) {
66 strcpy(cp, argv[actr]);
67 cp += strlen(argv[actr]);
68 *cp++ = ' ';
69 actr++;
70 }
71 if (cp != &(arcs_cmdline[0])) {
72 /* get rid of trailing space */
73 --cp;
74 *cp = '\0';
75 }
76}
77
78struct psbl_rec {
79 u32 psbl_size;
80 u32 env_base;
81 u32 env_size;
82 u32 ffs_base;
83 u32 ffs_size;
84};
85
86static __initdata char psp_env_version[] = "TIENV0.8";
87
88struct psp_env_chunk {
89 u8 num;
90 u8 ctrl;
91 u16 csum;
92 u8 len;
93 char data[11];
94} __attribute__ ((packed));
95
96struct psp_var_map_entry {
97 u8 num;
98 char *value;
99};
100
101static struct psp_var_map_entry psp_var_map[] = {
102 { 1, "cpufrequency" },
103 { 2, "memsize" },
104 { 3, "flashsize" },
105 { 4, "modetty0" },
106 { 5, "modetty1" },
107 { 8, "maca" },
108 { 9, "macb" },
109 { 28, "sysfrequency" },
110 { 38, "mipsfrequency" },
111};
112
113/*
114
115Well-known variable (num is looked up in table above for matching variable name)
116Example: cpufrequency=211968000
117+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
118| 01 |CTRL|CHECKSUM | 01 | _2 | _1 | _1 | _9 | _6 | _8 | _0 | _0 | _0 | \0 | FF
119+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
120
121Name=Value pair in a single chunk
122Example: NAME=VALUE
123+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
124| 00 |CTRL|CHECKSUM | 01 | _N | _A | _M | _E | _0 | _V | _A | _L | _U | _E | \0
125+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
126
127Name=Value pair in 2 chunks (len is the number of chunks)
128Example: bootloaderVersion=1.3.7.15
129+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
130| 00 |CTRL|CHECKSUM | 02 | _b | _o | _o | _t | _l | _o | _a | _d | _e | _r | _V
131+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
132| _e | _r | _s | _i | _o | _n | \0 | _1 | _. | _3 | _. | _7 | _. | _1 | _5 | \0
133+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
134
135Data is padded with 0xFF
136
137*/
138
139#define PSP_ENV_SIZE 4096
140
141static char psp_env_data[PSP_ENV_SIZE] = { 0, };
142
143static char * __init lookup_psp_var_map(u8 num)
144{
145 int i;
146
147 for (i = 0; i < ARRAY_SIZE(psp_var_map); i++)
148 if (psp_var_map[i].num == num)
149 return psp_var_map[i].value;
150
151 return NULL;
152}
153
154static void __init add_adam2_var(char *name, char *value)
155{
156 int i;
157 for (i = 0; i < MAX_ENTRY; i++) {
158 if (!adam2_env[i].name) {
159 adam2_env[i].name = name;
160 adam2_env[i].value = value;
161 return;
162 } else if (!strcmp(adam2_env[i].name, name)) {
163 adam2_env[i].value = value;
164 return;
165 }
166 }
167}
168
169static int __init parse_psp_env(void *psp_env_base)
170{
171 int i, n;
172 char *name, *value;
173 struct psp_env_chunk *chunks = (struct psp_env_chunk *)psp_env_data;
174
175 memcpy_fromio(chunks, psp_env_base, PSP_ENV_SIZE);
176
177 i = 1;
178 n = PSP_ENV_SIZE / sizeof(struct psp_env_chunk);
179 while (i < n) {
180 if ((chunks[i].num == 0xff) || ((i + chunks[i].len) > n))
181 break;
182 value = chunks[i].data;
183 if (chunks[i].num) {
184 name = lookup_psp_var_map(chunks[i].num);
185 } else {
186 name = value;
187 value += strlen(name) + 1;
188 }
189 if (name)
190 add_adam2_var(name, value);
191 i += chunks[i].len;
192 }
193 return 0;
194}
195
196static void __init ar7_init_env(struct env_var *env)
197{
198 int i;
199 struct psbl_rec *psbl = (struct psbl_rec *)(KSEG1ADDR(0x14000300));
200 void *psp_env = (void *)KSEG1ADDR(psbl->env_base);
201
202 if (strcmp(psp_env, psp_env_version) == 0) {
203 parse_psp_env(psp_env);
204 } else {
205 for (i = 0; i < MAX_ENTRY; i++, env++)
206 if (env->name)
207 add_adam2_var(env->name, env->value);
208 }
209}
210
211static void __init console_config(void)
212{
213#ifdef CONFIG_SERIAL_8250_CONSOLE
214 char console_string[40];
215 int baud = 0;
216 char parity = '\0', bits = '\0', flow = '\0';
217 char *s, *p;
218
219 if (strstr(prom_getcmdline(), "console="))
220 return;
221
222#ifdef CONFIG_KGDB
223 if (!strstr(prom_getcmdline(), "nokgdb")) {
224 strcat(prom_getcmdline(), " console=kgdb");
225 kgdb_enabled = 1;
226 return;
227 }
228#endif
229
230 s = prom_getenv("modetty0");
231 if (s) {
232 baud = simple_strtoul(s, &p, 10);
233 s = p;
234 if (*s == ',')
235 s++;
236 if (*s)
237 parity = *s++;
238 if (*s == ',')
239 s++;
240 if (*s)
241 bits = *s++;
242 if (*s == ',')
243 s++;
244 if (*s == 'h')
245 flow = 'r';
246 }
247
248 if (baud == 0)
249 baud = 38400;
250 if (parity != 'n' && parity != 'o' && parity != 'e')
251 parity = 'n';
252 if (bits != '7' && bits != '8')
253 bits = '8';
254
255 if (flow == 'r')
256 sprintf(console_string, " console=ttyS0,%d%c%c%c", baud,
257 parity, bits, flow);
258 else
259 sprintf(console_string, " console=ttyS0,%d%c%c", baud, parity,
260 bits);
261 strcat(prom_getcmdline(), console_string);
262#endif
263}
264
265void __init prom_init(void)
266{
267 ar7_init_cmdline(fw_arg0, (char **)fw_arg1);
268 ar7_init_env((struct env_var *)fw_arg2);
269 console_config();
270}
271
272#define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4)))
273static inline unsigned int serial_in(int offset)
274{
275 return readl((void *)PORT(offset));
276}
277
278static inline void serial_out(int offset, int value)
279{
280 writel(value, (void *)PORT(offset));
281}
282
283char prom_getchar(void)
284{
285 while (!(serial_in(UART_LSR) & UART_LSR_DR))
286 ;
287 return serial_in(UART_RX);
288}
289
290int prom_putchar(char c)
291{
292 while ((serial_in(UART_LSR) & UART_LSR_TEMT) == 0)
293 ;
294 serial_out(UART_TX, c);
295 return 1;
296}
297
diff --git a/arch/mips/ar7/setup.c b/arch/mips/ar7/setup.c
new file mode 100644
index 000000000000..39f6b5b96463
--- /dev/null
+++ b/arch/mips/ar7/setup.c
@@ -0,0 +1,93 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 */
18#include <linux/init.h>
19#include <linux/ioport.h>
20#include <linux/pm.h>
21#include <linux/time.h>
22
23#include <asm/reboot.h>
24#include <asm/mach-ar7/ar7.h>
25#include <asm/mach-ar7/prom.h>
26
27static void ar7_machine_restart(char *command)
28{
29 u32 *softres_reg = ioremap(AR7_REGS_RESET +
30 AR7_RESET_SOFTWARE, 1);
31 writel(1, softres_reg);
32}
33
34static void ar7_machine_halt(void)
35{
36 while (1)
37 ;
38}
39
40static void ar7_machine_power_off(void)
41{
42 u32 *power_reg = (u32 *)ioremap(AR7_REGS_POWER, 1);
43 u32 power_state = readl(power_reg) | (3 << 30);
44 writel(power_state, power_reg);
45 ar7_machine_halt();
46}
47
48const char *get_system_type(void)
49{
50 u16 chip_id = ar7_chip_id();
51 switch (chip_id) {
52 case AR7_CHIP_7300:
53 return "TI AR7 (TNETD7300)";
54 case AR7_CHIP_7100:
55 return "TI AR7 (TNETD7100)";
56 case AR7_CHIP_7200:
57 return "TI AR7 (TNETD7200)";
58 default:
59 return "TI AR7 (Unknown)";
60 }
61}
62
63static int __init ar7_init_console(void)
64{
65 return 0;
66}
67console_initcall(ar7_init_console);
68
69/*
70 * Initializes basic routines and structures pointers, memory size (as
71 * given by the bios and saves the command line.
72 */
73
74void __init plat_mem_setup(void)
75{
76 unsigned long io_base;
77
78 _machine_restart = ar7_machine_restart;
79 _machine_halt = ar7_machine_halt;
80 pm_power_off = ar7_machine_power_off;
81 panic_timeout = 3;
82
83 io_base = (unsigned long)ioremap(AR7_REGS_BASE, 0x10000);
84 if (!io_base)
85 panic("Can't remap IO base!\n");
86 set_io_port_base(io_base);
87
88 prom_meminit();
89
90 printk(KERN_INFO "%s, ID: 0x%04x, Revision: 0x%02x\n",
91 get_system_type(),
92 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 000000000000..a1fba894daa2
--- /dev/null
+++ b/arch/mips/ar7/time.c
@@ -0,0 +1,30 @@
1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * This program is free software; you can distribute it and/or modify it
6 * under the terms of the GNU General Public License (Version 2) as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 *
18 * Setting up the clock on the MIPS boards.
19 */
20
21#include <linux/init.h>
22#include <linux/time.h>
23
24#include <asm/time.h>
25#include <asm/mach-ar7/ar7.h>
26
27void __init plat_time_init(void)
28{
29 mips_hpt_frequency = ar7_cpu_freq() / 2;
30}