aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/rb532
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2008-07-16 11:12:25 -0400
committerRalf Baechle <ralf@linux-mips.org>2008-07-20 09:38:18 -0400
commit73b4390fb23456964201abda79f1210fe337d01a (patch)
treebc613dfa0a3926bd889025cebbc28ae034b8c854 /arch/mips/rb532
parent36a0a3cd45b49ceff78ac28efef1cbeec413d8c2 (diff)
[MIPS] Routerboard 532: Support for base system
Signed-off-by: Phil Sutter <n0-1@freewrt.org> Signed-off-by: Florian Fainelli <florian.fainelli@telecomint.eu> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/rb532')
-rw-r--r--arch/mips/rb532/Makefile7
-rw-r--r--arch/mips/rb532/devices.c331
-rw-r--r--arch/mips/rb532/gpio.c220
-rw-r--r--arch/mips/rb532/irq.c209
-rw-r--r--arch/mips/rb532/prom.c158
-rw-r--r--arch/mips/rb532/serial.c53
-rw-r--r--arch/mips/rb532/setup.c79
-rw-r--r--arch/mips/rb532/time.c67
8 files changed, 1124 insertions, 0 deletions
diff --git a/arch/mips/rb532/Makefile b/arch/mips/rb532/Makefile
new file mode 100644
index 000000000000..8f0b6b6a1625
--- /dev/null
+++ b/arch/mips/rb532/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the RB532 board specific parts of the kernel
3#
4
5obj-y += irq.o time.o setup.o serial.o prom.o gpio.o devices.o
6
7EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c
new file mode 100644
index 000000000000..44fb0a62877f
--- /dev/null
+++ b/arch/mips/rb532/devices.c
@@ -0,0 +1,331 @@
1/*
2 * RouterBoard 500 Platform devices
3 *
4 * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
5 * Copyright (C) 2007 Florian Fainelli <florian@openwrt.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/ctype.h>
20#include <linux/string.h>
21#include <linux/platform_device.h>
22#include <linux/mtd/nand.h>
23#include <linux/mtd/mtd.h>
24#include <linux/mtd/partitions.h>
25#include <linux/gpio_keys.h>
26#include <linux/input.h>
27
28#include <asm/bootinfo.h>
29
30#include <asm/mach-rc32434/rc32434.h>
31#include <asm/mach-rc32434/dma.h>
32#include <asm/mach-rc32434/dma_v.h>
33#include <asm/mach-rc32434/eth.h>
34#include <asm/mach-rc32434/rb.h>
35#include <asm/mach-rc32434/integ.h>
36#include <asm/mach-rc32434/gpio.h>
37
38#define ETH0_DMA_RX_IRQ (GROUP1_IRQ_BASE + 0)
39#define ETH0_DMA_TX_IRQ (GROUP1_IRQ_BASE + 1)
40#define ETH0_RX_OVR_IRQ (GROUP3_IRQ_BASE + 9)
41#define ETH0_TX_UND_IRQ (GROUP3_IRQ_BASE + 10)
42
43#define ETH0_RX_DMA_ADDR (DMA0_BASE_ADDR + 0 * DMA_CHAN_OFFSET)
44#define ETH0_TX_DMA_ADDR (DMA0_BASE_ADDR + 1 * DMA_CHAN_OFFSET)
45
46/* NAND definitions */
47#define GPIO_RDY (1 << 0x08)
48#define GPIO_WPX (1 << 0x09)
49#define GPIO_ALE (1 << 0x0a)
50#define GPIO_CLE (1 << 0x0b)
51
52extern char *board_type;
53
54static struct resource korina_dev0_res[] = {
55 {
56 .name = "korina_regs",
57 .start = ETH0_BASE_ADDR,
58 .end = ETH0_BASE_ADDR + sizeof(struct eth_regs),
59 .flags = IORESOURCE_MEM,
60 }, {
61 .name = "korina_rx",
62 .start = ETH0_DMA_RX_IRQ,
63 .end = ETH0_DMA_RX_IRQ,
64 .flags = IORESOURCE_IRQ
65 }, {
66 .name = "korina_tx",
67 .start = ETH0_DMA_TX_IRQ,
68 .end = ETH0_DMA_TX_IRQ,
69 .flags = IORESOURCE_IRQ
70 }, {
71 .name = "korina_ovr",
72 .start = ETH0_RX_OVR_IRQ,
73 .end = ETH0_RX_OVR_IRQ,
74 .flags = IORESOURCE_IRQ
75 }, {
76 .name = "korina_und",
77 .start = ETH0_TX_UND_IRQ,
78 .end = ETH0_TX_UND_IRQ,
79 .flags = IORESOURCE_IRQ
80 }, {
81 .name = "korina_dma_rx",
82 .start = ETH0_RX_DMA_ADDR,
83 .end = ETH0_RX_DMA_ADDR + DMA_CHAN_OFFSET - 1,
84 .flags = IORESOURCE_MEM,
85 }, {
86 .name = "korina_dma_tx",
87 .start = ETH0_TX_DMA_ADDR,
88 .end = ETH0_TX_DMA_ADDR + DMA_CHAN_OFFSET - 1,
89 .flags = IORESOURCE_MEM,
90 }
91};
92
93static struct korina_device korina_dev0_data = {
94 .name = "korina0",
95 .mac = {0xde, 0xca, 0xff, 0xc0, 0xff, 0xee}
96};
97
98static struct platform_device korina_dev0 = {
99 .id = 0,
100 .name = "korina",
101 .dev.platform_data = &korina_dev0_data,
102 .resource = korina_dev0_res,
103 .num_resources = ARRAY_SIZE(korina_dev0_res),
104};
105
106#define CF_GPIO_NUM 13
107
108static struct resource cf_slot0_res[] = {
109 {
110 .name = "cf_membase",
111 .flags = IORESOURCE_MEM
112 }, {
113 .name = "cf_irq",
114 .start = (8 + 4 * 32 + CF_GPIO_NUM), /* 149 */
115 .end = (8 + 4 * 32 + CF_GPIO_NUM),
116 .flags = IORESOURCE_IRQ
117 }
118};
119
120static struct cf_device cf_slot0_data = {
121 .gpio_pin = 13
122};
123
124static struct platform_device cf_slot0 = {
125 .id = 0,
126 .name = "pata-rb532-cf",
127 .dev.platform_data = &cf_slot0_data,
128 .resource = cf_slot0_res,
129 .num_resources = ARRAY_SIZE(cf_slot0_res),
130};
131
132/* Resources and device for NAND */
133static int rb532_dev_ready(struct mtd_info *mtd)
134{
135 return readl(IDT434_REG_BASE + GPIOD) & GPIO_RDY;
136}
137
138static void rb532_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
139{
140 struct nand_chip *chip = mtd->priv;
141 unsigned char orbits, nandbits;
142
143 if (ctrl & NAND_CTRL_CHANGE) {
144 orbits = (ctrl & NAND_CLE) << 1;
145 orbits |= (ctrl & NAND_ALE) >> 1;
146
147 nandbits = (~ctrl & NAND_CLE) << 1;
148 nandbits |= (~ctrl & NAND_ALE) >> 1;
149
150 set_latch_u5(orbits, nandbits);
151 }
152 if (cmd != NAND_CMD_NONE)
153 writeb(cmd, chip->IO_ADDR_W);
154}
155
156static struct resource nand_slot0_res[] = {
157 [0] = {
158 .name = "nand_membase",
159 .flags = IORESOURCE_MEM
160 }
161};
162
163static struct platform_nand_data rb532_nand_data = {
164 .ctrl.dev_ready = rb532_dev_ready,
165 .ctrl.cmd_ctrl = rb532_cmd_ctrl,
166};
167
168static struct platform_device nand_slot0 = {
169 .name = "gen_nand",
170 .id = -1,
171 .resource = nand_slot0_res,
172 .num_resources = ARRAY_SIZE(nand_slot0_res),
173 .dev.platform_data = &rb532_nand_data,
174};
175
176static struct mtd_partition rb532_partition_info[] = {
177 {
178 .name = "Routerboard NAND boot",
179 .offset = 0,
180 .size = 4 * 1024 * 1024,
181 }, {
182 .name = "rootfs",
183 .offset = MTDPART_OFS_NXTBLK,
184 .size = MTDPART_SIZ_FULL,
185 }
186};
187
188static struct platform_device rb532_led = {
189 .name = "rb532-led",
190 .id = 0,
191};
192
193static struct gpio_keys_button rb532_gpio_btn[] = {
194 {
195 .gpio = 1,
196 .code = BTN_0,
197 .desc = "S1",
198 .active_low = 1,
199 }
200};
201
202static struct gpio_keys_platform_data rb532_gpio_btn_data = {
203 .buttons = rb532_gpio_btn,
204 .nbuttons = ARRAY_SIZE(rb532_gpio_btn),
205};
206
207static struct platform_device rb532_button = {
208 .name = "gpio-keys",
209 .id = -1,
210 .dev = {
211 .platform_data = &rb532_gpio_btn_data,
212 }
213};
214
215static struct resource rb532_wdt_res[] = {
216 {
217 .name = "rb532_wdt_res",
218 .start = INTEG0_BASE_ADDR,
219 .end = INTEG0_BASE_ADDR + sizeof(struct integ),
220 .flags = IORESOURCE_MEM,
221 }
222};
223
224static struct platform_device rb532_wdt = {
225 .name = "rc32434_wdt",
226 .id = -1,
227 .resource = rb532_wdt_res,
228 .num_resources = ARRAY_SIZE(rb532_wdt_res),
229};
230
231static struct platform_device *rb532_devs[] = {
232 &korina_dev0,
233 &nand_slot0,
234 &cf_slot0,
235 &rb532_led,
236 &rb532_button,
237 &rb532_wdt
238};
239
240static void __init parse_mac_addr(char *macstr)
241{
242 int i, j;
243 unsigned char result, value;
244
245 for (i = 0; i < 6; i++) {
246 result = 0;
247
248 if (i != 5 && *(macstr + 2) != ':')
249 return;
250
251 for (j = 0; j < 2; j++) {
252 if (isxdigit(*macstr)
253 && (value =
254 isdigit(*macstr) ? *macstr -
255 '0' : toupper(*macstr) - 'A' + 10) < 16) {
256 result = result * 16 + value;
257 macstr++;
258 } else
259 return;
260 }
261
262 macstr++;
263 korina_dev0_data.mac[i] = result;
264 }
265}
266
267
268/* DEVICE CONTROLLER 1 */
269#define CFG_DC_DEV1 ((void *)0xb8010010)
270#define CFG_DC_DEV2 ((void *)0xb8010020)
271#define CFG_DC_DEVBASE 0x0
272#define CFG_DC_DEVMASK 0x4
273#define CFG_DC_DEVC 0x8
274#define CFG_DC_DEVTC 0xC
275
276/* NAND definitions */
277#define NAND_CHIP_DELAY 25
278
279static void __init rb532_nand_setup(void)
280{
281 switch (mips_machtype) {
282 case MACH_MIKROTIK_RB532A:
283 set_latch_u5(LO_FOFF | LO_CEX,
284 LO_ULED | LO_ALE | LO_CLE | LO_WPX);
285 break;
286 default:
287 set_latch_u5(LO_WPX | LO_FOFF | LO_CEX,
288 LO_ULED | LO_ALE | LO_CLE);
289 break;
290 }
291
292 /* Setup NAND specific settings */
293 rb532_nand_data.chip.nr_chips = 1;
294 rb532_nand_data.chip.nr_partitions = ARRAY_SIZE(rb532_partition_info);
295 rb532_nand_data.chip.partitions = rb532_partition_info;
296 rb532_nand_data.chip.chip_delay = NAND_CHIP_DELAY;
297 rb532_nand_data.chip.options = NAND_NO_AUTOINCR;
298}
299
300
301static int __init plat_setup_devices(void)
302{
303 /* Look for the CF card reader */
304 if (!readl(CFG_DC_DEV1 + CFG_DC_DEVMASK))
305 rb532_devs[1] = NULL;
306 else {
307 cf_slot0_res[0].start =
308 readl(CFG_DC_DEV1 + CFG_DC_DEVBASE);
309 cf_slot0_res[0].end = cf_slot0_res[0].start + 0x1000;
310 }
311
312 /* Read the NAND resources from the device controller */
313 nand_slot0_res[0].start = readl(CFG_DC_DEV2 + CFG_DC_DEVBASE);
314 nand_slot0_res[0].end = nand_slot0_res[0].start + 0x1000;
315
316 /* Initialise the NAND device */
317 rb532_nand_setup();
318
319 return platform_add_devices(rb532_devs, ARRAY_SIZE(rb532_devs));
320}
321
322static int __init setup_kmac(char *s)
323{
324 printk(KERN_INFO "korina mac = %s\n", s);
325 parse_mac_addr(s);
326 return 0;
327}
328
329__setup("kmac=", setup_kmac);
330
331arch_initcall(plat_setup_devices);
diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c
new file mode 100644
index 000000000000..b2fe82dba0a5
--- /dev/null
+++ b/arch/mips/rb532/gpio.c
@@ -0,0 +1,220 @@
1/*
2 * Miscellaneous functions for IDT EB434 board
3 *
4 * Copyright 2004 IDT Inc. (rischelp@idt.com)
5 * Copyright 2006 Phil Sutter <n0-1@freewrt.org>
6 * Copyright 2007 Florian Fainelli <florian@openwrt.org>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
14 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
16 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
19 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29#include <linux/kernel.h>
30#include <linux/gpio.h>
31#include <linux/init.h>
32#include <linux/types.h>
33#include <linux/pci.h>
34#include <linux/spinlock.h>
35#include <linux/io.h>
36#include <linux/platform_device.h>
37
38#include <asm/addrspace.h>
39
40#include <asm/mach-rc32434/rb.h>
41
42struct rb532_gpio_reg __iomem *rb532_gpio_reg0;
43EXPORT_SYMBOL(rb532_gpio_reg0);
44
45struct mpmc_device dev3;
46
47static struct resource rb532_gpio_reg0_res[] = {
48 {
49 .name = "gpio_reg0",
50 .start = (u32)(IDT434_REG_BASE + GPIOBASE),
51 .end = (u32)(IDT434_REG_BASE + GPIOBASE + sizeof(struct rb532_gpio_reg)),
52 .flags = IORESOURCE_MEM,
53 }
54};
55
56static struct resource rb532_dev3_ctl_res[] = {
57 {
58 .name = "dev3_ctl",
59 .start = (u32)(IDT434_REG_BASE + DEV3BASE),
60 .end = (u32)(IDT434_REG_BASE + DEV3BASE + sizeof(struct dev_reg)),
61 .flags = IORESOURCE_MEM,
62 }
63};
64
65void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned val)
66{
67 unsigned flags, data;
68 unsigned i = 0;
69
70 spin_lock_irqsave(&dev3.lock, flags);
71
72 data = *(volatile unsigned *) (IDT434_REG_BASE + reg_offs);
73 for (i = 0; i != len; ++i) {
74 if (val & (1 << i))
75 data |= (1 << (i + bit));
76 else
77 data &= ~(1 << (i + bit));
78 }
79 writel(data, (IDT434_REG_BASE + reg_offs));
80
81 spin_unlock_irqrestore(&dev3.lock, flags);
82}
83EXPORT_SYMBOL(set_434_reg);
84
85unsigned get_434_reg(unsigned reg_offs)
86{
87 return readl(IDT434_REG_BASE + reg_offs);
88}
89EXPORT_SYMBOL(get_434_reg);
90
91void set_latch_u5(unsigned char or_mask, unsigned char nand_mask)
92{
93 unsigned flags;
94
95 spin_lock_irqsave(&dev3.lock, flags);
96
97 dev3.state = (dev3.state | or_mask) & ~nand_mask;
98 writel(dev3.state, &dev3.base);
99
100 spin_unlock_irqrestore(&dev3.lock, flags);
101}
102EXPORT_SYMBOL(set_latch_u5);
103
104unsigned char get_latch_u5(void)
105{
106 return dev3.state;
107}
108EXPORT_SYMBOL(get_latch_u5);
109
110int rb532_gpio_get_value(unsigned gpio)
111{
112 return readl(&rb532_gpio_reg0->gpiod) & (1 << gpio);
113}
114EXPORT_SYMBOL(rb532_gpio_get_value);
115
116void rb532_gpio_set_value(unsigned gpio, int value)
117{
118 unsigned tmp;
119
120 tmp = readl(&rb532_gpio_reg0->gpiod) & ~(1 << gpio);
121 if (value)
122 tmp |= 1 << gpio;
123
124 writel(tmp, (void *)&rb532_gpio_reg0->gpiod);
125}
126EXPORT_SYMBOL(rb532_gpio_set_value);
127
128int rb532_gpio_direction_input(unsigned gpio)
129{
130 writel(readl(&rb532_gpio_reg0->gpiocfg) & ~(1 << gpio),
131 (void *)&rb532_gpio_reg0->gpiocfg);
132
133 return 0;
134}
135EXPORT_SYMBOL(rb532_gpio_direction_input);
136
137int rb532_gpio_direction_output(unsigned gpio, int value)
138{
139 gpio_set_value(gpio, value);
140 writel(readl(&rb532_gpio_reg0->gpiocfg) | (1 << gpio),
141 (void *)&rb532_gpio_reg0->gpiocfg);
142
143 return 0;
144}
145EXPORT_SYMBOL(rb532_gpio_direction_output);
146
147void rb532_gpio_set_int_level(unsigned gpio, int value)
148{
149 unsigned tmp;
150
151 tmp = readl(&rb532_gpio_reg0->gpioilevel) & ~(1 << gpio);
152 if (value)
153 tmp |= 1 << gpio;
154 writel(tmp, (void *)&rb532_gpio_reg0->gpioilevel);
155}
156EXPORT_SYMBOL(rb532_gpio_set_int_level);
157
158int rb532_gpio_get_int_level(unsigned gpio)
159{
160 return readl(&rb532_gpio_reg0->gpioilevel) & (1 << gpio);
161}
162EXPORT_SYMBOL(rb532_gpio_get_int_level);
163
164void rb532_gpio_set_int_status(unsigned gpio, int value)
165{
166 unsigned tmp;
167
168 tmp = readl(&rb532_gpio_reg0->gpioistat);
169 if (value)
170 tmp |= 1 << gpio;
171 writel(tmp, (void *)&rb532_gpio_reg0->gpioistat);
172}
173EXPORT_SYMBOL(rb532_gpio_set_int_status);
174
175int rb532_gpio_get_int_status(unsigned gpio)
176{
177 return readl(&rb532_gpio_reg0->gpioistat) & (1 << gpio);
178}
179EXPORT_SYMBOL(rb532_gpio_get_int_status);
180
181void rb532_gpio_set_func(unsigned gpio, int value)
182{
183 unsigned tmp;
184
185 tmp = readl(&rb532_gpio_reg0->gpiofunc);
186 if (value)
187 tmp |= 1 << gpio;
188 writel(tmp, (void *)&rb532_gpio_reg0->gpiofunc);
189}
190EXPORT_SYMBOL(rb532_gpio_set_func);
191
192int rb532_gpio_get_func(unsigned gpio)
193{
194 return readl(&rb532_gpio_reg0->gpiofunc) & (1 << gpio);
195}
196EXPORT_SYMBOL(rb532_gpio_get_func);
197
198int __init rb532_gpio_init(void)
199{
200 rb532_gpio_reg0 = ioremap_nocache(rb532_gpio_reg0_res[0].start,
201 rb532_gpio_reg0_res[0].end -
202 rb532_gpio_reg0_res[0].start);
203
204 if (!rb532_gpio_reg0) {
205 printk(KERN_ERR "rb532: cannot remap GPIO register 0\n");
206 return -ENXIO;
207 }
208
209 dev3.base = ioremap_nocache(rb532_dev3_ctl_res[0].start,
210 rb532_dev3_ctl_res[0].end -
211 rb532_dev3_ctl_res[0].start);
212
213 if (!dev3.base) {
214 printk(KERN_ERR "rb532: cannot remap device controller 3\n");
215 return -ENXIO;
216 }
217
218 return 0;
219}
220arch_initcall(rb532_gpio_init);
diff --git a/arch/mips/rb532/irq.c b/arch/mips/rb532/irq.c
new file mode 100644
index 000000000000..c0d0f950caf2
--- /dev/null
+++ b/arch/mips/rb532/irq.c
@@ -0,0 +1,209 @@
1/*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the License, or (at your
5 * option) any later version.
6 *
7 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
8 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
10 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
11 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
12 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
13 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
14 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
15 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
16 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * Copyright 2002 MontaVista Software Inc.
23 * Author: MontaVista Software, Inc.
24 * stevel@mvista.com or source@mvista.com
25 */
26
27#include <linux/bitops.h>
28#include <linux/errno.h>
29#include <linux/init.h>
30#include <linux/io.h>
31#include <linux/kernel_stat.h>
32#include <linux/module.h>
33#include <linux/signal.h>
34#include <linux/sched.h>
35#include <linux/types.h>
36#include <linux/interrupt.h>
37#include <linux/ioport.h>
38#include <linux/timex.h>
39#include <linux/slab.h>
40#include <linux/random.h>
41#include <linux/delay.h>
42
43#include <asm/bootinfo.h>
44#include <asm/time.h>
45#include <asm/mipsregs.h>
46#include <asm/system.h>
47
48#include <asm/mach-rc32434/rc32434.h>
49
50struct intr_group {
51 u32 mask; /* mask of valid bits in pending/mask registers */
52 volatile u32 *base_addr;
53};
54
55#define RC32434_NR_IRQS (GROUP4_IRQ_BASE + 32)
56
57#if (NR_IRQS < RC32434_NR_IRQS)
58#error Too little irqs defined. Did you override <asm/irq.h> ?
59#endif
60
61static const struct intr_group intr_group[NUM_INTR_GROUPS] = {
62 {
63 .mask = 0x0000efff,
64 .base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)},
65 {
66 .mask = 0x00001fff,
67 .base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)},
68 {
69 .mask = 0x00000007,
70 .base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)},
71 {
72 .mask = 0x0003ffff,
73 .base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)},
74 {
75 .mask = 0xffffffff,
76 .base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET)}
77};
78
79#define READ_PEND(base) (*(base))
80#define READ_MASK(base) (*(base + 2))
81#define WRITE_MASK(base, val) (*(base + 2) = (val))
82
83static inline int irq_to_group(unsigned int irq_nr)
84{
85 return (irq_nr - GROUP0_IRQ_BASE) >> 5;
86}
87
88static inline int group_to_ip(unsigned int group)
89{
90 return group + 2;
91}
92
93static inline void enable_local_irq(unsigned int ip)
94{
95 int ipnum = 0x100 << ip;
96
97 set_c0_status(ipnum);
98}
99
100static inline void disable_local_irq(unsigned int ip)
101{
102 int ipnum = 0x100 << ip;
103
104 clear_c0_status(ipnum);
105}
106
107static inline void ack_local_irq(unsigned int ip)
108{
109 int ipnum = 0x100 << ip;
110
111 clear_c0_cause(ipnum);
112}
113
114static void rb532_enable_irq(unsigned int irq_nr)
115{
116 int ip = irq_nr - GROUP0_IRQ_BASE;
117 unsigned int group, intr_bit;
118 volatile unsigned int *addr;
119
120 if (ip < 0)
121 enable_local_irq(irq_nr);
122 else {
123 group = ip >> 5;
124
125 ip &= (1 << 5) - 1;
126 intr_bit = 1 << ip;
127
128 enable_local_irq(group_to_ip(group));
129
130 addr = intr_group[group].base_addr;
131 WRITE_MASK(addr, READ_MASK(addr) & ~intr_bit);
132 }
133}
134
135static void rb532_disable_irq(unsigned int irq_nr)
136{
137 int ip = irq_nr - GROUP0_IRQ_BASE;
138 unsigned int group, intr_bit, mask;
139 volatile unsigned int *addr;
140
141 if (ip < 0) {
142 disable_local_irq(irq_nr);
143 } else {
144 group = ip >> 5;
145
146 ip &= (1 << 5) - 1;
147 intr_bit = 1 << ip;
148 addr = intr_group[group].base_addr;
149 mask = READ_MASK(addr);
150 mask |= intr_bit;
151 WRITE_MASK(addr, mask);
152
153 /*
154 * if there are no more interrupts enabled in this
155 * group, disable corresponding IP
156 */
157 if (mask == intr_group[group].mask)
158 disable_local_irq(group_to_ip(group));
159 }
160}
161
162static void rb532_mask_and_ack_irq(unsigned int irq_nr)
163{
164 rb532_disable_irq(irq_nr);
165 ack_local_irq(group_to_ip(irq_to_group(irq_nr)));
166}
167
168static struct irq_chip rc32434_irq_type = {
169 .name = "RB532",
170 .ack = rb532_disable_irq,
171 .mask = rb532_disable_irq,
172 .mask_ack = rb532_mask_and_ack_irq,
173 .unmask = rb532_enable_irq,
174};
175
176void __init arch_init_irq(void)
177{
178 int i;
179
180 pr_info("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS);
181
182 for (i = 0; i < RC32434_NR_IRQS; i++)
183 set_irq_chip_and_handler(i, &rc32434_irq_type,
184 handle_level_irq);
185}
186
187/* Main Interrupt dispatcher */
188asmlinkage void plat_irq_dispatch(void)
189{
190 unsigned int ip, pend, group;
191 volatile unsigned int *addr;
192 unsigned int cp0_cause = read_c0_cause() & read_c0_status();
193
194 if (cp0_cause & CAUSEF_IP7) {
195 do_IRQ(7);
196 } else {
197 ip = (cp0_cause & 0x7c00);
198 if (ip) {
199 group = 21 + (fls(ip) - 32);
200
201 addr = intr_group[group].base_addr;
202
203 pend = READ_PEND(addr);
204 pend &= ~READ_MASK(addr); /* only unmasked interrupts */
205 pend = 39 + (fls(pend) - 32);
206 do_IRQ((group << 5) + pend);
207 }
208 }
209}
diff --git a/arch/mips/rb532/prom.c b/arch/mips/rb532/prom.c
new file mode 100644
index 000000000000..1bc0af8febf4
--- /dev/null
+++ b/arch/mips/rb532/prom.c
@@ -0,0 +1,158 @@
1/*
2 * RouterBoard 500 specific prom routines
3 *
4 * Copyright (C) 2003, Peter Sadik <peter.sadik@idt.com>
5 * Copyright (C) 2005-2006, P.Christeas <p_christ@hol.gr>
6 * Copyright (C) 2007, Gabor Juhos <juhosg@openwrt.org>
7 * Felix Fietkau <nbd@openwrt.org>
8 * Florian Fainelli <florian@openwrt.org>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the
22 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 *
25 */
26
27#include <linux/init.h>
28#include <linux/mm.h>
29#include <linux/module.h>
30#include <linux/string.h>
31#include <linux/console.h>
32#include <linux/bootmem.h>
33#include <linux/ioport.h>
34#include <linux/blkdev.h>
35
36#include <asm/bootinfo.h>
37#include <asm/mach-rc32434/ddr.h>
38#include <asm/mach-rc32434/prom.h>
39
40extern void __init setup_serial_port(void);
41
42unsigned int idt_cpu_freq = 132000000;
43EXPORT_SYMBOL(idt_cpu_freq);
44unsigned int gpio_bootup_state;
45EXPORT_SYMBOL(gpio_bootup_state);
46
47static struct resource ddr_reg[] = {
48 {
49 .name = "ddr-reg",
50 .start = DDR0_PHYS_ADDR,
51 .end = DDR0_PHYS_ADDR + sizeof(struct ddr_ram),
52 .flags = IORESOURCE_MEM,
53 }
54};
55
56void __init prom_free_prom_memory(void)
57{
58 /* No prom memory to free */
59}
60
61static inline int match_tag(char *arg, const char *tag)
62{
63 return strncmp(arg, tag, strlen(tag)) == 0;
64}
65
66static inline unsigned long tag2ul(char *arg, const char *tag)
67{
68 char *num;
69
70 num = arg + strlen(tag);
71 return simple_strtoul(num, 0, 10);
72}
73
74void __init prom_setup_cmdline(void)
75{
76 char cmd_line[CL_SIZE];
77 char *cp, *board;
78 int prom_argc;
79 char **prom_argv, **prom_envp;
80 int i;
81
82 prom_argc = fw_arg0;
83 prom_argv = (char **) fw_arg1;
84 prom_envp = (char **) fw_arg2;
85
86 cp = cmd_line;
87 /* Note: it is common that parameters start
88 * at argv[1] and not argv[0],
89 * however, our elf loader starts at [0] */
90 for (i = 0; i < prom_argc; i++) {
91 if (match_tag(prom_argv[i], FREQ_TAG)) {
92 idt_cpu_freq = tag2ul(prom_argv[i], FREQ_TAG);
93 continue;
94 }
95#ifdef IGNORE_CMDLINE_MEM
96 /* parses out the "mem=xx" arg */
97 if (match_tag(prom_argv[i], MEM_TAG))
98 continue;
99#endif
100 if (i > 0)
101 *(cp++) = ' ';
102 if (match_tag(prom_argv[i], BOARD_TAG)) {
103 board = prom_argv[i] + strlen(BOARD_TAG);
104
105 if (match_tag(board, BOARD_RB532A))
106 mips_machtype = MACH_MIKROTIK_RB532A;
107 else
108 mips_machtype = MACH_MIKROTIK_RB532;
109 }
110
111 if (match_tag(prom_argv[i], GPIO_TAG))
112 gpio_bootup_state = tag2ul(prom_argv[i], GPIO_TAG);
113
114 strcpy(cp, prom_argv[i]);
115 cp += strlen(prom_argv[i]);
116 }
117 *(cp++) = ' ';
118
119 i = strlen(arcs_cmdline);
120 if (i > 0) {
121 *(cp++) = ' ';
122 strcpy(cp, arcs_cmdline);
123 cp += strlen(arcs_cmdline);
124 }
125 if (gpio_bootup_state & 0x02)
126 strcpy(cp, GPIO_INIT_NOBUTTON);
127 else
128 strcpy(cp, GPIO_INIT_BUTTON);
129
130 cmd_line[CL_SIZE-1] = '\0';
131
132 strcpy(arcs_cmdline, cmd_line);
133}
134
135void __init prom_init(void)
136{
137 struct ddr_ram __iomem *ddr;
138 phys_t memsize;
139 phys_t ddrbase;
140
141 ddr = ioremap_nocache(ddr_reg[0].start,
142 ddr_reg[0].end - ddr_reg[0].start);
143
144 if (!ddr) {
145 printk(KERN_ERR "Unable to remap DDR register\n");
146 return;
147 }
148
149 ddrbase = (phys_t)&ddr->ddrbase;
150 memsize = (phys_t)&ddr->ddrmask;
151 memsize = 0 - memsize;
152
153 prom_setup_cmdline();
154
155 /* give all RAM to boot allocator,
156 * except for the first 0x400 and the last 0x200 bytes */
157 add_memory_region(ddrbase + 0x400, memsize - 0x600, BOOT_MEM_RAM);
158}
diff --git a/arch/mips/rb532/serial.c b/arch/mips/rb532/serial.c
new file mode 100644
index 000000000000..1a05b5ddee09
--- /dev/null
+++ b/arch/mips/rb532/serial.c
@@ -0,0 +1,53 @@
1/*
2 * BRIEF MODULE DESCRIPTION
3 * Serial port initialisation.
4 *
5 * Copyright 2004 IDT Inc. (rischelp@idt.com)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
13 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
15 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
16 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
17 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
18 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28#include <linux/init.h>
29#include <linux/tty.h>
30#include <linux/serial_core.h>
31#include <linux/serial_8250.h>
32
33#include <asm/serial.h>
34#include <asm/mach-rc32434/rc32434.h>
35
36extern unsigned int idt_cpu_freq;
37
38static struct uart_port rb532_uart = {
39 .type = PORT_16550A,
40 .line = 0,
41 .irq = RC32434_UART0_IRQ,
42 .iotype = UPIO_MEM,
43 .membase = (char *)KSEG1ADDR(RC32434_UART0_BASE),
44 .regshift = 2
45};
46
47int __init setup_serial_port(void)
48{
49 rb532_uart.uartclk = idt_cpu_freq;
50
51 return early_serial_setup(&rb532_uart);
52}
53arch_initcall(setup_serial_port);
diff --git a/arch/mips/rb532/setup.c b/arch/mips/rb532/setup.c
new file mode 100644
index 000000000000..7aafa95ac20b
--- /dev/null
+++ b/arch/mips/rb532/setup.c
@@ -0,0 +1,79 @@
1/*
2 * setup.c - boot time setup code
3 */
4
5#include <linux/init.h>
6
7#include <asm/bootinfo.h>
8#include <asm/reboot.h>
9#include <asm/time.h>
10#include <linux/ioport.h>
11
12#include <asm/mach-rc32434/rc32434.h>
13#include <asm/mach-rc32434/pci.h>
14
15struct pci_reg __iomem *pci_reg;
16EXPORT_SYMBOL(pci_reg);
17
18static struct resource pci0_res[] = {
19 {
20 .name = "pci_reg0",
21 .start = PCI0_BASE_ADDR,
22 .end = PCI0_BASE_ADDR + sizeof(struct pci_reg),
23 .flags = IORESOURCE_MEM,
24 }
25};
26
27static void rb_machine_restart(char *command)
28{
29 /* just jump to the reset vector */
30 writel(0x80000001, (void *)KSEG1ADDR(RC32434_REG_BASE + RC32434_RST));
31 ((void (*)(void)) KSEG1ADDR(0x1FC00000u))();
32}
33
34static void rb_machine_halt(void)
35{
36 for (;;)
37 continue;
38}
39
40void __init plat_mem_setup(void)
41{
42 u32 val;
43
44 _machine_restart = rb_machine_restart;
45 _machine_halt = rb_machine_halt;
46 pm_power_off = rb_machine_halt;
47
48 set_io_port_base(KSEG1);
49
50 pci_reg = ioremap_nocache(pci0_res[0].start,
51 pci0_res[0].end - pci0_res[0].start);
52 if (!pci_reg) {
53 printk(KERN_ERR "Could not remap PCI registers\n");
54 return;
55 }
56
57 val = __raw_readl(&pci_reg->pcic);
58 val &= 0xFFFFFF7;
59 __raw_writel(val, (void *)&pci_reg->pcic);
60
61#ifdef CONFIG_PCI
62 /* Enable PCI interrupts in EPLD Mask register */
63 *epld_mask = 0x0;
64 *(epld_mask + 1) = 0x0;
65#endif
66 write_c0_wired(0);
67}
68
69const char *get_system_type(void)
70{
71 switch (mips_machtype) {
72 case MACH_MIKROTIK_RB532A:
73 return "Mikrotik RB532A";
74 break;
75 default:
76 return "Mikrotik RB532";
77 break;
78 }
79}
diff --git a/arch/mips/rb532/time.c b/arch/mips/rb532/time.c
new file mode 100644
index 000000000000..db74edf8cefb
--- /dev/null
+++ b/arch/mips/rb532/time.c
@@ -0,0 +1,67 @@
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/kernel_stat.h>
23#include <linux/ptrace.h>
24#include <linux/sched.h>
25#include <linux/spinlock.h>
26#include <linux/mc146818rtc.h>
27#include <linux/irq.h>
28#include <linux/timex.h>
29
30#include <asm/mipsregs.h>
31#include <asm/debug.h>
32#include <asm/time.h>
33#include <asm/mach-rc32434/rc32434.h>
34
35extern unsigned int idt_cpu_freq;
36
37/*
38 * Figure out the r4k offset, the amount to increment the compare
39 * register for each time tick. There is no RTC available.
40 *
41 * The RC32434 counts at half the CPU *core* speed.
42 */
43static unsigned long __init cal_r4koff(void)
44{
45 mips_hpt_frequency = idt_cpu_freq * IDT_CLOCK_MULT / 2;
46
47 return mips_hpt_frequency / HZ;
48}
49
50void __init plat_time_init(void)
51{
52 unsigned int est_freq, flags;
53 unsigned long r4k_offset;
54
55 local_irq_save(flags);
56
57 printk(KERN_INFO "calculating r4koff... ");
58 r4k_offset = cal_r4koff();
59 printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
60
61 est_freq = 2 * r4k_offset * HZ;
62 est_freq += 5000; /* round */
63 est_freq -= est_freq % 10000;
64 printk(KERN_INFO "CPU frequency %d.%02d MHz\n", est_freq / 1000000,
65 (est_freq % 1000000) * 100 / 1000000);
66 local_irq_restore(flags);
67}