diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2008-07-16 11:12:25 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2008-07-20 09:38:18 -0400 |
commit | 73b4390fb23456964201abda79f1210fe337d01a (patch) | |
tree | bc613dfa0a3926bd889025cebbc28ae034b8c854 /arch/mips/rb532 | |
parent | 36a0a3cd45b49ceff78ac28efef1cbeec413d8c2 (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/Makefile | 7 | ||||
-rw-r--r-- | arch/mips/rb532/devices.c | 331 | ||||
-rw-r--r-- | arch/mips/rb532/gpio.c | 220 | ||||
-rw-r--r-- | arch/mips/rb532/irq.c | 209 | ||||
-rw-r--r-- | arch/mips/rb532/prom.c | 158 | ||||
-rw-r--r-- | arch/mips/rb532/serial.c | 53 | ||||
-rw-r--r-- | arch/mips/rb532/setup.c | 79 | ||||
-rw-r--r-- | arch/mips/rb532/time.c | 67 |
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 | |||
5 | obj-y += irq.o time.o setup.o serial.o prom.o gpio.o devices.o | ||
6 | |||
7 | EXTRA_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 | |||
52 | extern char *board_type; | ||
53 | |||
54 | static 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 | |||
93 | static struct korina_device korina_dev0_data = { | ||
94 | .name = "korina0", | ||
95 | .mac = {0xde, 0xca, 0xff, 0xc0, 0xff, 0xee} | ||
96 | }; | ||
97 | |||
98 | static 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 | |||
108 | static 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 | |||
120 | static struct cf_device cf_slot0_data = { | ||
121 | .gpio_pin = 13 | ||
122 | }; | ||
123 | |||
124 | static 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 */ | ||
133 | static int rb532_dev_ready(struct mtd_info *mtd) | ||
134 | { | ||
135 | return readl(IDT434_REG_BASE + GPIOD) & GPIO_RDY; | ||
136 | } | ||
137 | |||
138 | static 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 | |||
156 | static struct resource nand_slot0_res[] = { | ||
157 | [0] = { | ||
158 | .name = "nand_membase", | ||
159 | .flags = IORESOURCE_MEM | ||
160 | } | ||
161 | }; | ||
162 | |||
163 | static struct platform_nand_data rb532_nand_data = { | ||
164 | .ctrl.dev_ready = rb532_dev_ready, | ||
165 | .ctrl.cmd_ctrl = rb532_cmd_ctrl, | ||
166 | }; | ||
167 | |||
168 | static 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 | |||
176 | static 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 | |||
188 | static struct platform_device rb532_led = { | ||
189 | .name = "rb532-led", | ||
190 | .id = 0, | ||
191 | }; | ||
192 | |||
193 | static 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 | |||
202 | static struct gpio_keys_platform_data rb532_gpio_btn_data = { | ||
203 | .buttons = rb532_gpio_btn, | ||
204 | .nbuttons = ARRAY_SIZE(rb532_gpio_btn), | ||
205 | }; | ||
206 | |||
207 | static struct platform_device rb532_button = { | ||
208 | .name = "gpio-keys", | ||
209 | .id = -1, | ||
210 | .dev = { | ||
211 | .platform_data = &rb532_gpio_btn_data, | ||
212 | } | ||
213 | }; | ||
214 | |||
215 | static 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 | |||
224 | static 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 | |||
231 | static 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 | |||
240 | static 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 | |||
279 | static 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 | |||
301 | static 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 | |||
322 | static 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 | |||
331 | arch_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 | |||
42 | struct rb532_gpio_reg __iomem *rb532_gpio_reg0; | ||
43 | EXPORT_SYMBOL(rb532_gpio_reg0); | ||
44 | |||
45 | struct mpmc_device dev3; | ||
46 | |||
47 | static 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 | |||
56 | static 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 | |||
65 | void 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 | } | ||
83 | EXPORT_SYMBOL(set_434_reg); | ||
84 | |||
85 | unsigned get_434_reg(unsigned reg_offs) | ||
86 | { | ||
87 | return readl(IDT434_REG_BASE + reg_offs); | ||
88 | } | ||
89 | EXPORT_SYMBOL(get_434_reg); | ||
90 | |||
91 | void 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 | } | ||
102 | EXPORT_SYMBOL(set_latch_u5); | ||
103 | |||
104 | unsigned char get_latch_u5(void) | ||
105 | { | ||
106 | return dev3.state; | ||
107 | } | ||
108 | EXPORT_SYMBOL(get_latch_u5); | ||
109 | |||
110 | int rb532_gpio_get_value(unsigned gpio) | ||
111 | { | ||
112 | return readl(&rb532_gpio_reg0->gpiod) & (1 << gpio); | ||
113 | } | ||
114 | EXPORT_SYMBOL(rb532_gpio_get_value); | ||
115 | |||
116 | void 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 | } | ||
126 | EXPORT_SYMBOL(rb532_gpio_set_value); | ||
127 | |||
128 | int 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 | } | ||
135 | EXPORT_SYMBOL(rb532_gpio_direction_input); | ||
136 | |||
137 | int 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 | } | ||
145 | EXPORT_SYMBOL(rb532_gpio_direction_output); | ||
146 | |||
147 | void 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 | } | ||
156 | EXPORT_SYMBOL(rb532_gpio_set_int_level); | ||
157 | |||
158 | int rb532_gpio_get_int_level(unsigned gpio) | ||
159 | { | ||
160 | return readl(&rb532_gpio_reg0->gpioilevel) & (1 << gpio); | ||
161 | } | ||
162 | EXPORT_SYMBOL(rb532_gpio_get_int_level); | ||
163 | |||
164 | void 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 | } | ||
173 | EXPORT_SYMBOL(rb532_gpio_set_int_status); | ||
174 | |||
175 | int rb532_gpio_get_int_status(unsigned gpio) | ||
176 | { | ||
177 | return readl(&rb532_gpio_reg0->gpioistat) & (1 << gpio); | ||
178 | } | ||
179 | EXPORT_SYMBOL(rb532_gpio_get_int_status); | ||
180 | |||
181 | void 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 | } | ||
190 | EXPORT_SYMBOL(rb532_gpio_set_func); | ||
191 | |||
192 | int rb532_gpio_get_func(unsigned gpio) | ||
193 | { | ||
194 | return readl(&rb532_gpio_reg0->gpiofunc) & (1 << gpio); | ||
195 | } | ||
196 | EXPORT_SYMBOL(rb532_gpio_get_func); | ||
197 | |||
198 | int __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 | } | ||
220 | arch_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 | |||
50 | struct 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 | |||
61 | static 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 | |||
83 | static inline int irq_to_group(unsigned int irq_nr) | ||
84 | { | ||
85 | return (irq_nr - GROUP0_IRQ_BASE) >> 5; | ||
86 | } | ||
87 | |||
88 | static inline int group_to_ip(unsigned int group) | ||
89 | { | ||
90 | return group + 2; | ||
91 | } | ||
92 | |||
93 | static inline void enable_local_irq(unsigned int ip) | ||
94 | { | ||
95 | int ipnum = 0x100 << ip; | ||
96 | |||
97 | set_c0_status(ipnum); | ||
98 | } | ||
99 | |||
100 | static inline void disable_local_irq(unsigned int ip) | ||
101 | { | ||
102 | int ipnum = 0x100 << ip; | ||
103 | |||
104 | clear_c0_status(ipnum); | ||
105 | } | ||
106 | |||
107 | static inline void ack_local_irq(unsigned int ip) | ||
108 | { | ||
109 | int ipnum = 0x100 << ip; | ||
110 | |||
111 | clear_c0_cause(ipnum); | ||
112 | } | ||
113 | |||
114 | static 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 | |||
135 | static 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 | |||
162 | static 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 | |||
168 | static 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 | |||
176 | void __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 */ | ||
188 | asmlinkage 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 | |||
40 | extern void __init setup_serial_port(void); | ||
41 | |||
42 | unsigned int idt_cpu_freq = 132000000; | ||
43 | EXPORT_SYMBOL(idt_cpu_freq); | ||
44 | unsigned int gpio_bootup_state; | ||
45 | EXPORT_SYMBOL(gpio_bootup_state); | ||
46 | |||
47 | static 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 | |||
56 | void __init prom_free_prom_memory(void) | ||
57 | { | ||
58 | /* No prom memory to free */ | ||
59 | } | ||
60 | |||
61 | static inline int match_tag(char *arg, const char *tag) | ||
62 | { | ||
63 | return strncmp(arg, tag, strlen(tag)) == 0; | ||
64 | } | ||
65 | |||
66 | static 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 | |||
74 | void __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 | |||
135 | void __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 | |||
36 | extern unsigned int idt_cpu_freq; | ||
37 | |||
38 | static 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 | |||
47 | int __init setup_serial_port(void) | ||
48 | { | ||
49 | rb532_uart.uartclk = idt_cpu_freq; | ||
50 | |||
51 | return early_serial_setup(&rb532_uart); | ||
52 | } | ||
53 | arch_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 | |||
15 | struct pci_reg __iomem *pci_reg; | ||
16 | EXPORT_SYMBOL(pci_reg); | ||
17 | |||
18 | static 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 | |||
27 | static 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 | |||
34 | static void rb_machine_halt(void) | ||
35 | { | ||
36 | for (;;) | ||
37 | continue; | ||
38 | } | ||
39 | |||
40 | void __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 | |||
69 | const 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 | |||
35 | extern 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 | */ | ||
43 | static 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 | |||
50 | void __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 | } | ||