xref: /openbmc/linux/arch/mips/ar7/platform.c (revision 3b23dc52)
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/delay.h>
23 #include <linux/dma-mapping.h>
24 #include <linux/platform_device.h>
25 #include <linux/mtd/physmap.h>
26 #include <linux/serial.h>
27 #include <linux/serial_8250.h>
28 #include <linux/ioport.h>
29 #include <linux/io.h>
30 #include <linux/vlynq.h>
31 #include <linux/leds.h>
32 #include <linux/string.h>
33 #include <linux/etherdevice.h>
34 #include <linux/phy.h>
35 #include <linux/phy_fixed.h>
36 #include <linux/gpio.h>
37 #include <linux/clk.h>
38 
39 #include <asm/addrspace.h>
40 #include <asm/mach-ar7/ar7.h>
41 #include <asm/mach-ar7/prom.h>
42 
43 /*****************************************************************************
44  * VLYNQ Bus
45  ****************************************************************************/
46 struct plat_vlynq_data {
47 	struct plat_vlynq_ops ops;
48 	int gpio_bit;
49 	int reset_bit;
50 };
51 
52 static int vlynq_on(struct vlynq_device *dev)
53 {
54 	int ret;
55 	struct plat_vlynq_data *pdata = dev->dev.platform_data;
56 
57 	ret = gpio_request(pdata->gpio_bit, "vlynq");
58 	if (ret)
59 		goto out;
60 
61 	ar7_device_reset(pdata->reset_bit);
62 
63 	ret = ar7_gpio_disable(pdata->gpio_bit);
64 	if (ret)
65 		goto out_enabled;
66 
67 	ret = ar7_gpio_enable(pdata->gpio_bit);
68 	if (ret)
69 		goto out_enabled;
70 
71 	ret = gpio_direction_output(pdata->gpio_bit, 0);
72 	if (ret)
73 		goto out_gpio_enabled;
74 
75 	msleep(50);
76 
77 	gpio_set_value(pdata->gpio_bit, 1);
78 
79 	msleep(50);
80 
81 	return 0;
82 
83 out_gpio_enabled:
84 	ar7_gpio_disable(pdata->gpio_bit);
85 out_enabled:
86 	ar7_device_disable(pdata->reset_bit);
87 	gpio_free(pdata->gpio_bit);
88 out:
89 	return ret;
90 }
91 
92 static void vlynq_off(struct vlynq_device *dev)
93 {
94 	struct plat_vlynq_data *pdata = dev->dev.platform_data;
95 
96 	ar7_gpio_disable(pdata->gpio_bit);
97 	gpio_free(pdata->gpio_bit);
98 	ar7_device_disable(pdata->reset_bit);
99 }
100 
101 static struct resource vlynq_low_res[] = {
102 	{
103 		.name	= "regs",
104 		.flags	= IORESOURCE_MEM,
105 		.start	= AR7_REGS_VLYNQ0,
106 		.end	= AR7_REGS_VLYNQ0 + 0xff,
107 	},
108 	{
109 		.name	= "irq",
110 		.flags	= IORESOURCE_IRQ,
111 		.start	= 29,
112 		.end	= 29,
113 	},
114 	{
115 		.name	= "mem",
116 		.flags	= IORESOURCE_MEM,
117 		.start	= 0x04000000,
118 		.end	= 0x04ffffff,
119 	},
120 	{
121 		.name	= "devirq",
122 		.flags	= IORESOURCE_IRQ,
123 		.start	= 80,
124 		.end	= 111,
125 	},
126 };
127 
128 static struct resource vlynq_high_res[] = {
129 	{
130 		.name	= "regs",
131 		.flags	= IORESOURCE_MEM,
132 		.start	= AR7_REGS_VLYNQ1,
133 		.end	= AR7_REGS_VLYNQ1 + 0xff,
134 	},
135 	{
136 		.name	= "irq",
137 		.flags	= IORESOURCE_IRQ,
138 		.start	= 33,
139 		.end	= 33,
140 	},
141 	{
142 		.name	= "mem",
143 		.flags	= IORESOURCE_MEM,
144 		.start	= 0x0c000000,
145 		.end	= 0x0cffffff,
146 	},
147 	{
148 		.name	= "devirq",
149 		.flags	= IORESOURCE_IRQ,
150 		.start	= 112,
151 		.end	= 143,
152 	},
153 };
154 
155 static struct plat_vlynq_data vlynq_low_data = {
156 	.ops = {
157 		.on	= vlynq_on,
158 		.off	= vlynq_off,
159 	},
160 	.reset_bit	= 20,
161 	.gpio_bit	= 18,
162 };
163 
164 static struct plat_vlynq_data vlynq_high_data = {
165 	.ops = {
166 		.on	= vlynq_on,
167 		.off	= vlynq_off,
168 	},
169 	.reset_bit	= 16,
170 	.gpio_bit	= 19,
171 };
172 
173 static struct platform_device vlynq_low = {
174 	.id		= 0,
175 	.name		= "vlynq",
176 	.dev = {
177 		.platform_data	= &vlynq_low_data,
178 	},
179 	.resource	= vlynq_low_res,
180 	.num_resources	= ARRAY_SIZE(vlynq_low_res),
181 };
182 
183 static struct platform_device vlynq_high = {
184 	.id		= 1,
185 	.name		= "vlynq",
186 	.dev = {
187 		.platform_data	= &vlynq_high_data,
188 	},
189 	.resource	= vlynq_high_res,
190 	.num_resources	= ARRAY_SIZE(vlynq_high_res),
191 };
192 
193 /*****************************************************************************
194  * Flash
195  ****************************************************************************/
196 static struct resource physmap_flash_resource = {
197 	.name	= "mem",
198 	.flags	= IORESOURCE_MEM,
199 	.start	= 0x10000000,
200 	.end	= 0x107fffff,
201 };
202 
203 static const char *ar7_probe_types[] = { "ar7part", NULL };
204 
205 static struct physmap_flash_data physmap_flash_data = {
206 	.width	= 2,
207 	.part_probe_types = ar7_probe_types,
208 };
209 
210 static struct platform_device physmap_flash = {
211 	.name		= "physmap-flash",
212 	.dev = {
213 		.platform_data	= &physmap_flash_data,
214 	},
215 	.resource	= &physmap_flash_resource,
216 	.num_resources	= 1,
217 };
218 
219 /*****************************************************************************
220  * Ethernet
221  ****************************************************************************/
222 static struct resource cpmac_low_res[] = {
223 	{
224 		.name	= "regs",
225 		.flags	= IORESOURCE_MEM,
226 		.start	= AR7_REGS_MAC0,
227 		.end	= AR7_REGS_MAC0 + 0x7ff,
228 	},
229 	{
230 		.name	= "irq",
231 		.flags	= IORESOURCE_IRQ,
232 		.start	= 27,
233 		.end	= 27,
234 	},
235 };
236 
237 static struct resource cpmac_high_res[] = {
238 	{
239 		.name	= "regs",
240 		.flags	= IORESOURCE_MEM,
241 		.start	= AR7_REGS_MAC1,
242 		.end	= AR7_REGS_MAC1 + 0x7ff,
243 	},
244 	{
245 		.name	= "irq",
246 		.flags	= IORESOURCE_IRQ,
247 		.start	= 41,
248 		.end	= 41,
249 	},
250 };
251 
252 static struct fixed_phy_status fixed_phy_status __initdata = {
253 	.link		= 1,
254 	.speed		= 100,
255 	.duplex		= 1,
256 };
257 
258 static struct plat_cpmac_data cpmac_low_data = {
259 	.reset_bit	= 17,
260 	.power_bit	= 20,
261 	.phy_mask	= 0x80000000,
262 };
263 
264 static struct plat_cpmac_data cpmac_high_data = {
265 	.reset_bit	= 21,
266 	.power_bit	= 22,
267 	.phy_mask	= 0x7fffffff,
268 };
269 
270 static u64 cpmac_dma_mask = DMA_BIT_MASK(32);
271 
272 static struct platform_device cpmac_low = {
273 	.id		= 0,
274 	.name		= "cpmac",
275 	.dev = {
276 		.dma_mask		= &cpmac_dma_mask,
277 		.coherent_dma_mask	= DMA_BIT_MASK(32),
278 		.platform_data		= &cpmac_low_data,
279 	},
280 	.resource	= cpmac_low_res,
281 	.num_resources	= ARRAY_SIZE(cpmac_low_res),
282 };
283 
284 static struct platform_device cpmac_high = {
285 	.id		= 1,
286 	.name		= "cpmac",
287 	.dev = {
288 		.dma_mask		= &cpmac_dma_mask,
289 		.coherent_dma_mask	= DMA_BIT_MASK(32),
290 		.platform_data		= &cpmac_high_data,
291 	},
292 	.resource	= cpmac_high_res,
293 	.num_resources	= ARRAY_SIZE(cpmac_high_res),
294 };
295 
296 static void __init cpmac_get_mac(int instance, unsigned char *dev_addr)
297 {
298 	char name[5], *mac;
299 
300 	sprintf(name, "mac%c", 'a' + instance);
301 	mac = prom_getenv(name);
302 	if (!mac && instance) {
303 		sprintf(name, "mac%c", 'a');
304 		mac = prom_getenv(name);
305 	}
306 
307 	if (mac) {
308 		if (!mac_pton(mac, dev_addr)) {
309 			pr_warn("cannot parse mac address, using random address\n");
310 			eth_random_addr(dev_addr);
311 		}
312 	} else
313 		eth_random_addr(dev_addr);
314 }
315 
316 /*****************************************************************************
317  * USB
318  ****************************************************************************/
319 static struct resource usb_res[] = {
320 	{
321 		.name	= "regs",
322 		.flags	= IORESOURCE_MEM,
323 		.start	= AR7_REGS_USB,
324 		.end	= AR7_REGS_USB + 0xff,
325 	},
326 	{
327 		.name	= "irq",
328 		.flags	= IORESOURCE_IRQ,
329 		.start	= 32,
330 		.end	= 32,
331 	},
332 	{
333 		.name	= "mem",
334 		.flags	= IORESOURCE_MEM,
335 		.start	= 0x03400000,
336 		.end	= 0x03401fff,
337 	},
338 };
339 
340 static struct platform_device ar7_udc = {
341 	.name		= "ar7_udc",
342 	.resource	= usb_res,
343 	.num_resources	= ARRAY_SIZE(usb_res),
344 };
345 
346 /*****************************************************************************
347  * LEDs
348  ****************************************************************************/
349 static const struct gpio_led default_leds[] = {
350 	{
351 		.name			= "status",
352 		.gpio			= 8,
353 		.active_low		= 1,
354 	},
355 };
356 
357 static const struct gpio_led titan_leds[] = {
358 	{ .name = "status", .gpio = 8, .active_low = 1, },
359 	{ .name = "wifi", .gpio = 13, .active_low = 1, },
360 };
361 
362 static const struct gpio_led dsl502t_leds[] = {
363 	{
364 		.name			= "status",
365 		.gpio			= 9,
366 		.active_low		= 1,
367 	},
368 	{
369 		.name			= "ethernet",
370 		.gpio			= 7,
371 		.active_low		= 1,
372 	},
373 	{
374 		.name			= "usb",
375 		.gpio			= 12,
376 		.active_low		= 1,
377 	},
378 };
379 
380 static const struct gpio_led dg834g_leds[] = {
381 	{
382 		.name			= "ppp",
383 		.gpio			= 6,
384 		.active_low		= 1,
385 	},
386 	{
387 		.name			= "status",
388 		.gpio			= 7,
389 		.active_low		= 1,
390 	},
391 	{
392 		.name			= "adsl",
393 		.gpio			= 8,
394 		.active_low		= 1,
395 	},
396 	{
397 		.name			= "wifi",
398 		.gpio			= 12,
399 		.active_low		= 1,
400 	},
401 	{
402 		.name			= "power",
403 		.gpio			= 14,
404 		.active_low		= 1,
405 		.default_trigger	= "default-on",
406 	},
407 };
408 
409 static const struct gpio_led fb_sl_leds[] = {
410 	{
411 		.name			= "1",
412 		.gpio			= 7,
413 	},
414 	{
415 		.name			= "2",
416 		.gpio			= 13,
417 		.active_low		= 1,
418 	},
419 	{
420 		.name			= "3",
421 		.gpio			= 10,
422 		.active_low		= 1,
423 	},
424 	{
425 		.name			= "4",
426 		.gpio			= 12,
427 		.active_low		= 1,
428 	},
429 	{
430 		.name			= "5",
431 		.gpio			= 9,
432 		.active_low		= 1,
433 	},
434 };
435 
436 static const struct gpio_led fb_fon_leds[] = {
437 	{
438 		.name			= "1",
439 		.gpio			= 8,
440 	},
441 	{
442 		.name			= "2",
443 		.gpio			= 3,
444 		.active_low		= 1,
445 	},
446 	{
447 		.name			= "3",
448 		.gpio			= 5,
449 	},
450 	{
451 		.name			= "4",
452 		.gpio			= 4,
453 		.active_low		= 1,
454 	},
455 	{
456 		.name			= "5",
457 		.gpio			= 11,
458 		.active_low		= 1,
459 	},
460 };
461 
462 static const struct gpio_led gt701_leds[] = {
463 	{
464 		.name			= "inet:green",
465 		.gpio			= 13,
466 		.active_low		= 1,
467 	},
468 	{
469 		.name			= "usb",
470 		.gpio			= 12,
471 		.active_low		= 1,
472 	},
473 	{
474 		.name			= "inet:red",
475 		.gpio			= 9,
476 		.active_low		= 1,
477 	},
478 	{
479 		.name			= "power:red",
480 		.gpio			= 7,
481 		.active_low		= 1,
482 	},
483 	{
484 		.name			= "power:green",
485 		.gpio			= 8,
486 		.active_low		= 1,
487 		.default_trigger	= "default-on",
488 	},
489 	{
490 		.name			= "ethernet",
491 		.gpio			= 10,
492 		.active_low		= 1,
493 	},
494 };
495 
496 static struct gpio_led_platform_data ar7_led_data;
497 
498 static struct platform_device ar7_gpio_leds = {
499 	.name = "leds-gpio",
500 	.dev = {
501 		.platform_data = &ar7_led_data,
502 	}
503 };
504 
505 static void __init detect_leds(void)
506 {
507 	char *prid, *usb_prod;
508 
509 	/* Default LEDs */
510 	ar7_led_data.num_leds = ARRAY_SIZE(default_leds);
511 	ar7_led_data.leds = default_leds;
512 
513 	/* FIXME: the whole thing is unreliable */
514 	prid = prom_getenv("ProductID");
515 	usb_prod = prom_getenv("usb_prod");
516 
517 	/* If we can't get the product id from PROM, use the default LEDs */
518 	if (!prid)
519 		return;
520 
521 	if (strstr(prid, "Fritz_Box_FON")) {
522 		ar7_led_data.num_leds = ARRAY_SIZE(fb_fon_leds);
523 		ar7_led_data.leds = fb_fon_leds;
524 	} else if (strstr(prid, "Fritz_Box_")) {
525 		ar7_led_data.num_leds = ARRAY_SIZE(fb_sl_leds);
526 		ar7_led_data.leds = fb_sl_leds;
527 	} else if ((!strcmp(prid, "AR7RD") || !strcmp(prid, "AR7DB"))
528 		&& usb_prod != NULL && strstr(usb_prod, "DSL-502T")) {
529 		ar7_led_data.num_leds = ARRAY_SIZE(dsl502t_leds);
530 		ar7_led_data.leds = dsl502t_leds;
531 	} else if (strstr(prid, "DG834")) {
532 		ar7_led_data.num_leds = ARRAY_SIZE(dg834g_leds);
533 		ar7_led_data.leds = dg834g_leds;
534 	} else if (strstr(prid, "CYWM") || strstr(prid, "CYWL")) {
535 		ar7_led_data.num_leds = ARRAY_SIZE(titan_leds);
536 		ar7_led_data.leds = titan_leds;
537 	} else if (strstr(prid, "GT701")) {
538 		ar7_led_data.num_leds = ARRAY_SIZE(gt701_leds);
539 		ar7_led_data.leds = gt701_leds;
540 	}
541 }
542 
543 /*****************************************************************************
544  * Watchdog
545  ****************************************************************************/
546 static struct resource ar7_wdt_res = {
547 	.name		= "regs",
548 	.flags		= IORESOURCE_MEM,
549 	.start		= -1,	/* Filled at runtime */
550 	.end		= -1,	/* Filled at runtime */
551 };
552 
553 static struct platform_device ar7_wdt = {
554 	.name		= "ar7_wdt",
555 	.resource	= &ar7_wdt_res,
556 	.num_resources	= 1,
557 };
558 
559 /*****************************************************************************
560  * Init
561  ****************************************************************************/
562 static int __init ar7_register_uarts(void)
563 {
564 #ifdef CONFIG_SERIAL_8250
565 	static struct uart_port uart_port __initdata;
566 	struct clk *bus_clk;
567 	int res;
568 
569 	memset(&uart_port, 0, sizeof(struct uart_port));
570 
571 	bus_clk = clk_get(NULL, "bus");
572 	if (IS_ERR(bus_clk))
573 		panic("unable to get bus clk");
574 
575 	uart_port.type		= PORT_AR7;
576 	uart_port.uartclk	= clk_get_rate(bus_clk) / 2;
577 	uart_port.iotype	= UPIO_MEM32;
578 	uart_port.flags		= UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF;
579 	uart_port.regshift	= 2;
580 
581 	uart_port.line		= 0;
582 	uart_port.irq		= AR7_IRQ_UART0;
583 	uart_port.mapbase	= AR7_REGS_UART0;
584 	uart_port.membase	= ioremap(uart_port.mapbase, 256);
585 
586 	res = early_serial_setup(&uart_port);
587 	if (res)
588 		return res;
589 
590 	/* Only TNETD73xx have a second serial port */
591 	if (ar7_has_second_uart()) {
592 		uart_port.line		= 1;
593 		uart_port.irq		= AR7_IRQ_UART1;
594 		uart_port.mapbase	= UR8_REGS_UART1;
595 		uart_port.membase	= ioremap(uart_port.mapbase, 256);
596 
597 		res = early_serial_setup(&uart_port);
598 		if (res)
599 			return res;
600 	}
601 #endif
602 
603 	return 0;
604 }
605 
606 static void __init titan_fixup_devices(void)
607 {
608 	/* Set vlynq0 data */
609 	vlynq_low_data.reset_bit = 15;
610 	vlynq_low_data.gpio_bit = 14;
611 
612 	/* Set vlynq1 data */
613 	vlynq_high_data.reset_bit = 16;
614 	vlynq_high_data.gpio_bit = 7;
615 
616 	/* Set vlynq0 resources */
617 	vlynq_low_res[0].start = TITAN_REGS_VLYNQ0;
618 	vlynq_low_res[0].end = TITAN_REGS_VLYNQ0 + 0xff;
619 	vlynq_low_res[1].start = 33;
620 	vlynq_low_res[1].end = 33;
621 	vlynq_low_res[2].start = 0x0c000000;
622 	vlynq_low_res[2].end = 0x0fffffff;
623 	vlynq_low_res[3].start = 80;
624 	vlynq_low_res[3].end = 111;
625 
626 	/* Set vlynq1 resources */
627 	vlynq_high_res[0].start = TITAN_REGS_VLYNQ1;
628 	vlynq_high_res[0].end = TITAN_REGS_VLYNQ1 + 0xff;
629 	vlynq_high_res[1].start = 34;
630 	vlynq_high_res[1].end = 34;
631 	vlynq_high_res[2].start = 0x40000000;
632 	vlynq_high_res[2].end = 0x43ffffff;
633 	vlynq_high_res[3].start = 112;
634 	vlynq_high_res[3].end = 143;
635 
636 	/* Set cpmac0 data */
637 	cpmac_low_data.phy_mask = 0x40000000;
638 
639 	/* Set cpmac1 data */
640 	cpmac_high_data.phy_mask = 0x80000000;
641 
642 	/* Set cpmac0 resources */
643 	cpmac_low_res[0].start = TITAN_REGS_MAC0;
644 	cpmac_low_res[0].end = TITAN_REGS_MAC0 + 0x7ff;
645 
646 	/* Set cpmac1 resources */
647 	cpmac_high_res[0].start = TITAN_REGS_MAC1;
648 	cpmac_high_res[0].end = TITAN_REGS_MAC1 + 0x7ff;
649 }
650 
651 static int __init ar7_register_devices(void)
652 {
653 	void __iomem *bootcr;
654 	u32 val;
655 	int res;
656 
657 	res = ar7_gpio_init();
658 	if (res)
659 		pr_warn("unable to register gpios: %d\n", res);
660 
661 	res = ar7_register_uarts();
662 	if (res)
663 		pr_err("unable to setup uart(s): %d\n", res);
664 
665 	res = platform_device_register(&physmap_flash);
666 	if (res)
667 		pr_warn("unable to register physmap-flash: %d\n", res);
668 
669 	if (ar7_is_titan())
670 		titan_fixup_devices();
671 
672 	ar7_device_disable(vlynq_low_data.reset_bit);
673 	res = platform_device_register(&vlynq_low);
674 	if (res)
675 		pr_warn("unable to register vlynq-low: %d\n", res);
676 
677 	if (ar7_has_high_vlynq()) {
678 		ar7_device_disable(vlynq_high_data.reset_bit);
679 		res = platform_device_register(&vlynq_high);
680 		if (res)
681 			pr_warn("unable to register vlynq-high: %d\n", res);
682 	}
683 
684 	if (ar7_has_high_cpmac()) {
685 		res = fixed_phy_add(PHY_POLL, cpmac_high.id,
686 				    &fixed_phy_status, -1);
687 		if (!res) {
688 			cpmac_get_mac(1, cpmac_high_data.dev_addr);
689 
690 			res = platform_device_register(&cpmac_high);
691 			if (res)
692 				pr_warn("unable to register cpmac-high: %d\n",
693 					res);
694 		} else
695 			pr_warn("unable to add cpmac-high phy: %d\n", res);
696 	} else
697 		cpmac_low_data.phy_mask = 0xffffffff;
698 
699 	res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status, -1);
700 	if (!res) {
701 		cpmac_get_mac(0, cpmac_low_data.dev_addr);
702 		res = platform_device_register(&cpmac_low);
703 		if (res)
704 			pr_warn("unable to register cpmac-low: %d\n", res);
705 	} else
706 		pr_warn("unable to add cpmac-low phy: %d\n", res);
707 
708 	detect_leds();
709 	res = platform_device_register(&ar7_gpio_leds);
710 	if (res)
711 		pr_warn("unable to register leds: %d\n", res);
712 
713 	res = platform_device_register(&ar7_udc);
714 	if (res)
715 		pr_warn("unable to register usb slave: %d\n", res);
716 
717 	/* Register watchdog only if enabled in hardware */
718 	bootcr = ioremap_nocache(AR7_REGS_DCL, 4);
719 	val = readl(bootcr);
720 	iounmap(bootcr);
721 	if (val & AR7_WDT_HW_ENA) {
722 		if (ar7_has_high_vlynq())
723 			ar7_wdt_res.start = UR8_REGS_WDT;
724 		else
725 			ar7_wdt_res.start = AR7_REGS_WDT;
726 
727 		ar7_wdt_res.end = ar7_wdt_res.start + 0x20;
728 		res = platform_device_register(&ar7_wdt);
729 		if (res)
730 			pr_warn("unable to register watchdog: %d\n", res);
731 	}
732 
733 	return 0;
734 }
735 device_initcall(ar7_register_devices);
736