xref: /openbmc/linux/arch/mips/ar7/platform.c (revision 7dd65feb)
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 #include <linux/phy.h>
36 #include <linux/phy_fixed.h>
37 
38 #include <asm/addrspace.h>
39 #include <asm/mach-ar7/ar7.h>
40 #include <asm/mach-ar7/gpio.h>
41 #include <asm/mach-ar7/prom.h>
42 
43 struct plat_vlynq_data {
44 	struct plat_vlynq_ops ops;
45 	int gpio_bit;
46 	int reset_bit;
47 };
48 
49 
50 static int vlynq_on(struct vlynq_device *dev)
51 {
52 	int result;
53 	struct plat_vlynq_data *pdata = dev->dev.platform_data;
54 
55 	result = gpio_request(pdata->gpio_bit, "vlynq");
56 	if (result)
57 		goto out;
58 
59 	ar7_device_reset(pdata->reset_bit);
60 
61 	result = ar7_gpio_disable(pdata->gpio_bit);
62 	if (result)
63 		goto out_enabled;
64 
65 	result = ar7_gpio_enable(pdata->gpio_bit);
66 	if (result)
67 		goto out_enabled;
68 
69 	result = gpio_direction_output(pdata->gpio_bit, 0);
70 	if (result)
71 		goto out_gpio_enabled;
72 
73 	msleep(50);
74 
75 	gpio_set_value(pdata->gpio_bit, 1);
76 	msleep(50);
77 
78 	return 0;
79 
80 out_gpio_enabled:
81 	ar7_gpio_disable(pdata->gpio_bit);
82 out_enabled:
83 	ar7_device_disable(pdata->reset_bit);
84 	gpio_free(pdata->gpio_bit);
85 out:
86 	return result;
87 }
88 
89 static void vlynq_off(struct vlynq_device *dev)
90 {
91 	struct plat_vlynq_data *pdata = dev->dev.platform_data;
92 	ar7_gpio_disable(pdata->gpio_bit);
93 	gpio_free(pdata->gpio_bit);
94 	ar7_device_disable(pdata->reset_bit);
95 }
96 
97 static struct resource physmap_flash_resource = {
98 	.name = "mem",
99 	.flags = IORESOURCE_MEM,
100 	.start = 0x10000000,
101 	.end = 0x107fffff,
102 };
103 
104 static struct resource cpmac_low_res[] = {
105 	{
106 		.name = "regs",
107 		.flags = IORESOURCE_MEM,
108 		.start = AR7_REGS_MAC0,
109 		.end = AR7_REGS_MAC0 + 0x7ff,
110 	},
111 	{
112 		.name = "irq",
113 		.flags = IORESOURCE_IRQ,
114 		.start = 27,
115 		.end = 27,
116 	},
117 };
118 
119 static struct resource cpmac_high_res[] = {
120 	{
121 		.name = "regs",
122 		.flags = IORESOURCE_MEM,
123 		.start = AR7_REGS_MAC1,
124 		.end = AR7_REGS_MAC1 + 0x7ff,
125 	},
126 	{
127 		.name = "irq",
128 		.flags = IORESOURCE_IRQ,
129 		.start = 41,
130 		.end = 41,
131 	},
132 };
133 
134 static struct resource vlynq_low_res[] = {
135 	{
136 		.name = "regs",
137 		.flags = IORESOURCE_MEM,
138 		.start = AR7_REGS_VLYNQ0,
139 		.end = AR7_REGS_VLYNQ0 + 0xff,
140 	},
141 	{
142 		.name = "irq",
143 		.flags = IORESOURCE_IRQ,
144 		.start = 29,
145 		.end = 29,
146 	},
147 	{
148 		.name = "mem",
149 		.flags = IORESOURCE_MEM,
150 		.start = 0x04000000,
151 		.end = 0x04ffffff,
152 	},
153 	{
154 		.name = "devirq",
155 		.flags = IORESOURCE_IRQ,
156 		.start = 80,
157 		.end = 111,
158 	},
159 };
160 
161 static struct resource vlynq_high_res[] = {
162 	{
163 		.name = "regs",
164 		.flags = IORESOURCE_MEM,
165 		.start = AR7_REGS_VLYNQ1,
166 		.end = AR7_REGS_VLYNQ1 + 0xff,
167 	},
168 	{
169 		.name = "irq",
170 		.flags = IORESOURCE_IRQ,
171 		.start = 33,
172 		.end = 33,
173 	},
174 	{
175 		.name = "mem",
176 		.flags = IORESOURCE_MEM,
177 		.start = 0x0c000000,
178 		.end = 0x0cffffff,
179 	},
180 	{
181 		.name = "devirq",
182 		.flags = IORESOURCE_IRQ,
183 		.start = 112,
184 		.end = 143,
185 	},
186 };
187 
188 static struct resource usb_res[] = {
189 	{
190 		.name = "regs",
191 		.flags = IORESOURCE_MEM,
192 		.start = AR7_REGS_USB,
193 		.end = AR7_REGS_USB + 0xff,
194 	},
195 	{
196 		.name = "irq",
197 		.flags = IORESOURCE_IRQ,
198 		.start = 32,
199 		.end = 32,
200 	},
201 	{
202 		.name = "mem",
203 		.flags = IORESOURCE_MEM,
204 		.start = 0x03400000,
205 		.end = 0x034001fff,
206 	},
207 };
208 
209 static struct physmap_flash_data physmap_flash_data = {
210 	.width = 2,
211 };
212 
213 static struct fixed_phy_status fixed_phy_status __initdata = {
214 	.link = 1,
215 	.speed = 100,
216 	.duplex = 1,
217 };
218 
219 static struct plat_cpmac_data cpmac_low_data = {
220 	.reset_bit = 17,
221 	.power_bit = 20,
222 	.phy_mask = 0x80000000,
223 };
224 
225 static struct plat_cpmac_data cpmac_high_data = {
226 	.reset_bit = 21,
227 	.power_bit = 22,
228 	.phy_mask = 0x7fffffff,
229 };
230 
231 static struct plat_vlynq_data vlynq_low_data = {
232 	.ops.on = vlynq_on,
233 	.ops.off = vlynq_off,
234 	.reset_bit = 20,
235 	.gpio_bit = 18,
236 };
237 
238 static struct plat_vlynq_data vlynq_high_data = {
239 	.ops.on = vlynq_on,
240 	.ops.off = vlynq_off,
241 	.reset_bit = 16,
242 	.gpio_bit = 19,
243 };
244 
245 static struct platform_device physmap_flash = {
246 	.id = 0,
247 	.name = "physmap-flash",
248 	.dev.platform_data = &physmap_flash_data,
249 	.resource = &physmap_flash_resource,
250 	.num_resources = 1,
251 };
252 
253 static u64 cpmac_dma_mask = DMA_BIT_MASK(32);
254 static struct platform_device cpmac_low = {
255 	.id = 0,
256 	.name = "cpmac",
257 	.dev = {
258 		.dma_mask = &cpmac_dma_mask,
259 		.coherent_dma_mask = DMA_BIT_MASK(32),
260 		.platform_data = &cpmac_low_data,
261 	},
262 	.resource = cpmac_low_res,
263 	.num_resources = ARRAY_SIZE(cpmac_low_res),
264 };
265 
266 static struct platform_device cpmac_high = {
267 	.id = 1,
268 	.name = "cpmac",
269 	.dev = {
270 		.dma_mask = &cpmac_dma_mask,
271 		.coherent_dma_mask = DMA_BIT_MASK(32),
272 		.platform_data = &cpmac_high_data,
273 	},
274 	.resource = cpmac_high_res,
275 	.num_resources = ARRAY_SIZE(cpmac_high_res),
276 };
277 
278 static struct platform_device vlynq_low = {
279 	.id = 0,
280 	.name = "vlynq",
281 	.dev.platform_data = &vlynq_low_data,
282 	.resource = vlynq_low_res,
283 	.num_resources = ARRAY_SIZE(vlynq_low_res),
284 };
285 
286 static struct platform_device vlynq_high = {
287 	.id = 1,
288 	.name = "vlynq",
289 	.dev.platform_data = &vlynq_high_data,
290 	.resource = vlynq_high_res,
291 	.num_resources = ARRAY_SIZE(vlynq_high_res),
292 };
293 
294 
295 static struct gpio_led default_leds[] = {
296 	{
297 		.name = "status",
298 		.gpio = 8,
299 		.active_low = 1,
300 	},
301 };
302 
303 static struct gpio_led dsl502t_leds[] = {
304 	{
305 		.name = "status",
306 		.gpio = 9,
307 		.active_low = 1,
308 	},
309 	{
310 		.name = "ethernet",
311 		.gpio = 7,
312 		.active_low = 1,
313 	},
314 	{
315 		.name = "usb",
316 		.gpio = 12,
317 		.active_low = 1,
318 	},
319 };
320 
321 static struct gpio_led dg834g_leds[] = {
322 	{
323 		.name = "ppp",
324 		.gpio = 6,
325 		.active_low = 1,
326 	},
327 	{
328 		.name = "status",
329 		.gpio = 7,
330 		.active_low = 1,
331 	},
332 	{
333 		.name = "adsl",
334 		.gpio = 8,
335 		.active_low = 1,
336 	},
337 	{
338 		.name = "wifi",
339 		.gpio = 12,
340 		.active_low = 1,
341 	},
342 	{
343 		.name = "power",
344 		.gpio = 14,
345 		.active_low = 1,
346 		.default_trigger = "default-on",
347 	},
348 };
349 
350 static struct gpio_led fb_sl_leds[] = {
351 	{
352 		.name = "1",
353 		.gpio = 7,
354 	},
355 	{
356 		.name = "2",
357 		.gpio = 13,
358 		.active_low = 1,
359 	},
360 	{
361 		.name = "3",
362 		.gpio = 10,
363 		.active_low = 1,
364 	},
365 	{
366 		.name = "4",
367 		.gpio = 12,
368 		.active_low = 1,
369 	},
370 	{
371 		.name = "5",
372 		.gpio = 9,
373 		.active_low = 1,
374 	},
375 };
376 
377 static struct gpio_led fb_fon_leds[] = {
378 	{
379 		.name = "1",
380 		.gpio = 8,
381 	},
382 	{
383 		.name = "2",
384 		.gpio = 3,
385 		.active_low = 1,
386 	},
387 	{
388 		.name = "3",
389 		.gpio = 5,
390 	},
391 	{
392 		.name = "4",
393 		.gpio = 4,
394 		.active_low = 1,
395 	},
396 	{
397 		.name = "5",
398 		.gpio = 11,
399 		.active_low = 1,
400 	},
401 };
402 
403 static struct gpio_led_platform_data ar7_led_data;
404 
405 static struct platform_device ar7_gpio_leds = {
406 	.name = "leds-gpio",
407 	.id = -1,
408 	.dev = {
409 		.platform_data = &ar7_led_data,
410 	}
411 };
412 
413 static struct platform_device ar7_udc = {
414 	.id = -1,
415 	.name = "ar7_udc",
416 	.resource = usb_res,
417 	.num_resources = ARRAY_SIZE(usb_res),
418 };
419 
420 static struct resource ar7_wdt_res = {
421 	.name = "regs",
422 	.start = -1, /* Filled at runtime */
423 	.end = -1, /* Filled at runtime */
424 	.flags = IORESOURCE_MEM,
425 };
426 
427 static struct platform_device ar7_wdt = {
428 	.id = -1,
429 	.name  = "ar7_wdt",
430 	.resource = &ar7_wdt_res,
431 	.num_resources = 1,
432 };
433 
434 static inline unsigned char char2hex(char h)
435 {
436 	switch (h) {
437 	case '0': case '1': case '2': case '3': case '4':
438 	case '5': case '6': case '7': case '8': case '9':
439 		return h - '0';
440 	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
441 		return h - 'A' + 10;
442 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
443 		return h - 'a' + 10;
444 	default:
445 		return 0;
446 	}
447 }
448 
449 static void cpmac_get_mac(int instance, unsigned char *dev_addr)
450 {
451 	int i;
452 	char name[5], default_mac[ETH_ALEN], *mac;
453 
454 	mac = NULL;
455 	sprintf(name, "mac%c", 'a' + instance);
456 	mac = prom_getenv(name);
457 	if (!mac) {
458 		sprintf(name, "mac%c", 'a');
459 		mac = prom_getenv(name);
460 	}
461 	if (!mac) {
462 		random_ether_addr(default_mac);
463 		mac = default_mac;
464 	}
465 	for (i = 0; i < 6; i++)
466 		dev_addr[i] = (char2hex(mac[i * 3]) << 4) +
467 			char2hex(mac[i * 3 + 1]);
468 }
469 
470 static void __init detect_leds(void)
471 {
472 	char *prid, *usb_prod;
473 
474 	/* Default LEDs	*/
475 	ar7_led_data.num_leds = ARRAY_SIZE(default_leds);
476 	ar7_led_data.leds = default_leds;
477 
478 	/* FIXME: the whole thing is unreliable */
479 	prid = prom_getenv("ProductID");
480 	usb_prod = prom_getenv("usb_prod");
481 
482 	/* If we can't get the product id from PROM, use the default LEDs */
483 	if (!prid)
484 		return;
485 
486 	if (strstr(prid, "Fritz_Box_FON")) {
487 		ar7_led_data.num_leds = ARRAY_SIZE(fb_fon_leds);
488 		ar7_led_data.leds = fb_fon_leds;
489 	} else if (strstr(prid, "Fritz_Box_")) {
490 		ar7_led_data.num_leds = ARRAY_SIZE(fb_sl_leds);
491 		ar7_led_data.leds = fb_sl_leds;
492 	} else if ((!strcmp(prid, "AR7RD") || !strcmp(prid, "AR7DB"))
493 		&& usb_prod != NULL && strstr(usb_prod, "DSL-502T")) {
494 		ar7_led_data.num_leds = ARRAY_SIZE(dsl502t_leds);
495 		ar7_led_data.leds = dsl502t_leds;
496 	} else if (strstr(prid, "DG834")) {
497 		ar7_led_data.num_leds = ARRAY_SIZE(dg834g_leds);
498 		ar7_led_data.leds = dg834g_leds;
499 	}
500 }
501 
502 static int __init ar7_register_devices(void)
503 {
504 	u16 chip_id;
505 	int res;
506 	u32 *bootcr, val;
507 #ifdef CONFIG_SERIAL_8250
508 	static struct uart_port uart_port[2] __initdata;
509 
510 	memset(uart_port, 0, sizeof(struct uart_port) * 2);
511 
512 	uart_port[0].type = PORT_16550A;
513 	uart_port[0].line = 0;
514 	uart_port[0].irq = AR7_IRQ_UART0;
515 	uart_port[0].uartclk = ar7_bus_freq() / 2;
516 	uart_port[0].iotype = UPIO_MEM32;
517 	uart_port[0].mapbase = AR7_REGS_UART0;
518 	uart_port[0].membase = ioremap(uart_port[0].mapbase, 256);
519 	uart_port[0].regshift = 2;
520 	res = early_serial_setup(&uart_port[0]);
521 	if (res)
522 		return res;
523 
524 
525 	/* Only TNETD73xx have a second serial port */
526 	if (ar7_has_second_uart()) {
527 		uart_port[1].type = PORT_16550A;
528 		uart_port[1].line = 1;
529 		uart_port[1].irq = AR7_IRQ_UART1;
530 		uart_port[1].uartclk = ar7_bus_freq() / 2;
531 		uart_port[1].iotype = UPIO_MEM32;
532 		uart_port[1].mapbase = UR8_REGS_UART1;
533 		uart_port[1].membase = ioremap(uart_port[1].mapbase, 256);
534 		uart_port[1].regshift = 2;
535 		res = early_serial_setup(&uart_port[1]);
536 		if (res)
537 			return res;
538 	}
539 #endif /* CONFIG_SERIAL_8250 */
540 	res = platform_device_register(&physmap_flash);
541 	if (res)
542 		return res;
543 
544 	ar7_device_disable(vlynq_low_data.reset_bit);
545 	res = platform_device_register(&vlynq_low);
546 	if (res)
547 		return res;
548 
549 	if (ar7_has_high_vlynq()) {
550 		ar7_device_disable(vlynq_high_data.reset_bit);
551 		res = platform_device_register(&vlynq_high);
552 		if (res)
553 			return res;
554 	}
555 
556 	if (ar7_has_high_cpmac()) {
557 		res = fixed_phy_add(PHY_POLL, cpmac_high.id, &fixed_phy_status);
558 		if (res && res != -ENODEV)
559 			return res;
560 		cpmac_get_mac(1, cpmac_high_data.dev_addr);
561 		res = platform_device_register(&cpmac_high);
562 		if (res)
563 			return res;
564 	} else {
565 		cpmac_low_data.phy_mask = 0xffffffff;
566 	}
567 
568 	res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status);
569 	if (res && res != -ENODEV)
570 		return res;
571 
572 	cpmac_get_mac(0, cpmac_low_data.dev_addr);
573 	res = platform_device_register(&cpmac_low);
574 	if (res)
575 		return res;
576 
577 	detect_leds();
578 	res = platform_device_register(&ar7_gpio_leds);
579 	if (res)
580 		return res;
581 
582 	res = platform_device_register(&ar7_udc);
583 
584 	chip_id = ar7_chip_id();
585 	switch (chip_id) {
586 	case AR7_CHIP_7100:
587 	case AR7_CHIP_7200:
588 		ar7_wdt_res.start = AR7_REGS_WDT;
589 		break;
590 	case AR7_CHIP_7300:
591 		ar7_wdt_res.start = UR8_REGS_WDT;
592 		break;
593 	default:
594 		break;
595 	}
596 
597 	ar7_wdt_res.end = ar7_wdt_res.start + 0x20;
598 
599 	bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4);
600 	val = *bootcr;
601 	iounmap(bootcr);
602 
603 	/* Register watchdog only if enabled in hardware */
604 	if (val & AR7_WDT_HW_ENA)
605 		res = platform_device_register(&ar7_wdt);
606 
607 	return res;
608 }
609 arch_initcall(ar7_register_devices);
610