dns323-setup.c revision f93e4159b14c5edbaae9916d42ad685aa2f927d1
1/*
2 * arch/arm/mach-orion5x/dns323-setup.c
3 *
4 * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 */
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/platform_device.h>
16#include <linux/pci.h>
17#include <linux/irq.h>
18#include <linux/mtd/physmap.h>
19#include <linux/mv643xx_eth.h>
20#include <linux/leds.h>
21#include <linux/gpio_keys.h>
22#include <linux/input.h>
23#include <linux/i2c.h>
24#include <linux/ata_platform.h>
25#include <asm/mach-types.h>
26#include <asm/gpio.h>
27#include <asm/mach/arch.h>
28#include <asm/mach/pci.h>
29#include <mach/orion5x.h>
30#include "common.h"
31#include "mpp.h"
32
33#define DNS323_GPIO_LED_RIGHT_AMBER	1
34#define DNS323_GPIO_LED_LEFT_AMBER	2
35#define DNS323_GPIO_LED_POWER		5
36#define DNS323_GPIO_OVERTEMP		6
37#define DNS323_GPIO_RTC			7
38#define DNS323_GPIO_POWER_OFF		8
39#define DNS323_GPIO_KEY_POWER		9
40#define DNS323_GPIO_KEY_RESET		10
41
42/****************************************************************************
43 * PCI setup
44 */
45
46static int __init dns323_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
47{
48	int irq;
49
50	/*
51	 * Check for devices with hard-wired IRQs.
52	 */
53	irq = orion5x_pci_map_irq(dev, slot, pin);
54	if (irq != -1)
55		return irq;
56
57	return -1;
58}
59
60static struct hw_pci dns323_pci __initdata = {
61	.nr_controllers = 2,
62	.swizzle	= pci_std_swizzle,
63	.setup		= orion5x_pci_sys_setup,
64	.scan		= orion5x_pci_sys_scan_bus,
65	.map_irq	= dns323_pci_map_irq,
66};
67
68static int __init dns323_dev_id(void)
69{
70	u32 dev, rev;
71
72	orion5x_pcie_id(&dev, &rev);
73
74	return dev;
75}
76
77static int __init dns323_pci_init(void)
78{
79	/* The 5182 doesn't really use it's PCI bus, and initialising PCI
80	 * gets in the way of initialising the SATA controller.
81	 */
82	if (machine_is_dns323() && dns323_dev_id() != MV88F5182_DEV_ID)
83		pci_common_init(&dns323_pci);
84
85	return 0;
86}
87
88subsys_initcall(dns323_pci_init);
89
90/****************************************************************************
91 * 8MiB NOR flash (Spansion S29GL064M90TFIR4)
92 *
93 * Layout as used by D-Link:
94 *  0x00000000-0x00010000 : "MTD1"
95 *  0x00010000-0x00020000 : "MTD2"
96 *  0x00020000-0x001a0000 : "Linux Kernel"
97 *  0x001a0000-0x007d0000 : "File System"
98 *  0x007d0000-0x00800000 : "u-boot"
99 */
100
101#define DNS323_NOR_BOOT_BASE 0xf4000000
102#define DNS323_NOR_BOOT_SIZE SZ_8M
103
104static struct mtd_partition dns323_partitions[] = {
105	{
106		.name	= "MTD1",
107		.size	= 0x00010000,
108		.offset	= 0,
109	}, {
110		.name	= "MTD2",
111		.size	= 0x00010000,
112		.offset = 0x00010000,
113	}, {
114		.name	= "Linux Kernel",
115		.size	= 0x00180000,
116		.offset	= 0x00020000,
117	}, {
118		.name	= "File System",
119		.size	= 0x00630000,
120		.offset	= 0x001A0000,
121	}, {
122		.name	= "u-boot",
123		.size	= 0x00030000,
124		.offset	= 0x007d0000,
125	},
126};
127
128static struct physmap_flash_data dns323_nor_flash_data = {
129	.width		= 1,
130	.parts		= dns323_partitions,
131	.nr_parts	= ARRAY_SIZE(dns323_partitions)
132};
133
134static struct resource dns323_nor_flash_resource = {
135	.flags		= IORESOURCE_MEM,
136	.start		= DNS323_NOR_BOOT_BASE,
137	.end		= DNS323_NOR_BOOT_BASE + DNS323_NOR_BOOT_SIZE - 1,
138};
139
140static struct platform_device dns323_nor_flash = {
141	.name		= "physmap-flash",
142	.id		= 0,
143	.dev		= {
144		.platform_data	= &dns323_nor_flash_data,
145	},
146	.resource	= &dns323_nor_flash_resource,
147	.num_resources	= 1,
148};
149
150/****************************************************************************
151 * Ethernet
152 */
153
154static struct mv643xx_eth_platform_data dns323_eth_data = {
155	.phy_addr = MV643XX_ETH_PHY_ADDR(8),
156};
157
158/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these
159 * functions be kept somewhere?
160 */
161static int __init dns323_parse_hex_nibble(char n)
162{
163	if (n >= '0' && n <= '9')
164		return n - '0';
165
166	if (n >= 'A' && n <= 'F')
167		return n - 'A' + 10;
168
169	if (n >= 'a' && n <= 'f')
170		return n - 'a' + 10;
171
172	return -1;
173}
174
175static int __init dns323_parse_hex_byte(const char *b)
176{
177	int hi;
178	int lo;
179
180	hi = dns323_parse_hex_nibble(b[0]);
181	lo = dns323_parse_hex_nibble(b[1]);
182
183	if (hi < 0 || lo < 0)
184		return -1;
185
186	return (hi << 4) | lo;
187}
188
189static int __init dns323_read_mac_addr(void)
190{
191	u_int8_t addr[6];
192	int i;
193	char *mac_page;
194
195	/* MAC address is stored as a regular ol' string in /dev/mtdblock4
196	 * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80).
197	 */
198	mac_page = ioremap(DNS323_NOR_BOOT_BASE + 0x7d0000 + 196480, 1024);
199	if (!mac_page)
200		return -ENOMEM;
201
202	/* Sanity check the string we're looking at */
203	for (i = 0; i < 5; i++) {
204		if (*(mac_page + (i * 3) + 2) != ':') {
205			goto error_fail;
206		}
207	}
208
209	for (i = 0; i < 6; i++)	{
210		int byte;
211
212		byte = dns323_parse_hex_byte(mac_page + (i * 3));
213		if (byte < 0) {
214			goto error_fail;
215		}
216
217		addr[i] = byte;
218	}
219
220	iounmap(mac_page);
221	printk("DNS323: Found ethernet MAC address: ");
222	for (i = 0; i < 6; i++)
223		printk("%.2x%s", addr[i], (i < 5) ? ":" : ".\n");
224
225	memcpy(dns323_eth_data.mac_addr, addr, 6);
226
227	return 0;
228
229error_fail:
230	iounmap(mac_page);
231	return -EINVAL;
232}
233
234/****************************************************************************
235 * GPIO LEDs (simple - doesn't use hardware blinking support)
236 */
237
238static struct gpio_led dns323_leds[] = {
239	{
240		.name = "power:blue",
241		.gpio = DNS323_GPIO_LED_POWER,
242		.active_low = 1,
243	}, {
244		.name = "right:amber",
245		.gpio = DNS323_GPIO_LED_RIGHT_AMBER,
246		.active_low = 1,
247	}, {
248		.name = "left:amber",
249		.gpio = DNS323_GPIO_LED_LEFT_AMBER,
250		.active_low = 1,
251	},
252};
253
254static struct gpio_led_platform_data dns323_led_data = {
255	.num_leds	= ARRAY_SIZE(dns323_leds),
256	.leds		= dns323_leds,
257};
258
259static struct platform_device dns323_gpio_leds = {
260	.name		= "leds-gpio",
261	.id		= -1,
262	.dev		= {
263		.platform_data	= &dns323_led_data,
264	},
265};
266
267/****************************************************************************
268 * GPIO Attached Keys
269 */
270
271static struct gpio_keys_button dns323_buttons[] = {
272	{
273		.code		= KEY_RESTART,
274		.gpio		= DNS323_GPIO_KEY_RESET,
275		.desc		= "Reset Button",
276		.active_low	= 1,
277	}, {
278		.code		= KEY_POWER,
279		.gpio		= DNS323_GPIO_KEY_POWER,
280		.desc		= "Power Button",
281		.active_low	= 1,
282	},
283};
284
285static struct gpio_keys_platform_data dns323_button_data = {
286	.buttons	= dns323_buttons,
287	.nbuttons	= ARRAY_SIZE(dns323_buttons),
288};
289
290static struct platform_device dns323_button_device = {
291	.name		= "gpio-keys",
292	.id		= -1,
293	.num_resources	= 0,
294	.dev		= {
295		.platform_data	= &dns323_button_data,
296	},
297};
298
299/*****************************************************************************
300 * SATA
301 */
302static struct mv_sata_platform_data dns323_sata_data = {
303       .n_ports        = 2,
304};
305
306/****************************************************************************
307 * General Setup
308 */
309static struct orion5x_mpp_mode dns323_mv88f5181_mpp_modes[] __initdata = {
310	{  0, MPP_PCIE_RST_OUTn },
311	{  1, MPP_GPIO },		/* right amber LED (sata ch0) */
312	{  2, MPP_GPIO },		/* left amber LED (sata ch1) */
313	{  3, MPP_UNUSED },
314	{  4, MPP_GPIO },		/* power button LED */
315	{  5, MPP_GPIO },		/* power button LED */
316	{  6, MPP_GPIO },		/* GMT G751-2f overtemp */
317	{  7, MPP_GPIO },		/* M41T80 nIRQ/OUT/SQW */
318	{  8, MPP_GPIO },		/* triggers power off */
319	{  9, MPP_GPIO },		/* power button switch */
320	{ 10, MPP_GPIO },		/* reset button switch */
321	{ 11, MPP_UNUSED },
322	{ 12, MPP_UNUSED },
323	{ 13, MPP_UNUSED },
324	{ 14, MPP_UNUSED },
325	{ 15, MPP_UNUSED },
326	{ 16, MPP_UNUSED },
327	{ 17, MPP_UNUSED },
328	{ 18, MPP_UNUSED },
329	{ 19, MPP_UNUSED },
330	{ -1 },
331};
332
333static struct orion5x_mpp_mode dns323_mv88f5182_mpp_modes[] __initdata = {
334	{  0, MPP_UNUSED },
335	{  1, MPP_GPIO },		/* right amber LED (sata ch0) */
336	{  2, MPP_GPIO },		/* left amber LED (sata ch1) */
337	{  3, MPP_UNUSED },
338	{  4, MPP_GPIO },		/* power button LED */
339	{  5, MPP_GPIO },		/* power button LED */
340	{  6, MPP_GPIO },		/* GMT G751-2f overtemp */
341	{  7, MPP_GPIO },		/* M41T80 nIRQ/OUT/SQW */
342	{  8, MPP_GPIO },		/* triggers power off */
343	{  9, MPP_GPIO },		/* power button switch */
344	{ 10, MPP_GPIO },		/* reset button switch */
345	{ 11, MPP_UNUSED },
346	{ 12, MPP_SATA_LED },
347	{ 13, MPP_SATA_LED },
348	{ 14, MPP_SATA_LED },
349	{ 15, MPP_SATA_LED },
350	{ 16, MPP_UNUSED },
351	{ 17, MPP_UNUSED },
352	{ 18, MPP_UNUSED },
353	{ 19, MPP_UNUSED },
354	{ -1 },
355};
356
357/*
358 * On the DNS-323 the following devices are attached via I2C:
359 *
360 *  i2c addr | chip        | description
361 *  0x3e     | GMT G760Af  | fan speed PWM controller
362 *  0x48     | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible)
363 *  0x68     | ST M41T80   | RTC w/ alarm
364 */
365static struct i2c_board_info __initdata dns323_i2c_devices[] = {
366	{
367		I2C_BOARD_INFO("g760a", 0x3e),
368	}, {
369		I2C_BOARD_INFO("lm75", 0x48),
370	}, {
371		I2C_BOARD_INFO("m41t80", 0x68),
372	},
373};
374
375/* DNS-323 specific power off method */
376static void dns323_power_off(void)
377{
378	pr_info("%s: triggering power-off...\n", __func__);
379	gpio_set_value(DNS323_GPIO_POWER_OFF, 1);
380}
381
382static void __init dns323_init(void)
383{
384	/* Setup basic Orion functions. Need to be called early. */
385	orion5x_init();
386
387	/* Just to be tricky, the 5182 has a completely different
388	 * set of MPP modes to the 5181.
389	 */
390	if (dns323_dev_id() == MV88F5182_DEV_ID)
391		orion5x_mpp_conf(dns323_mv88f5182_mpp_modes);
392	else {
393		orion5x_mpp_conf(dns323_mv88f5181_mpp_modes);
394		writel(0, MPP_DEV_CTRL);		/* DEV_D[31:16] */
395	}
396
397	/* setup flash mapping
398	 * CS3 holds a 8 MB Spansion S29GL064M90TFIR4
399	 */
400	orion5x_setup_dev_boot_win(DNS323_NOR_BOOT_BASE, DNS323_NOR_BOOT_SIZE);
401	platform_device_register(&dns323_nor_flash);
402
403	platform_device_register(&dns323_gpio_leds);
404
405	platform_device_register(&dns323_button_device);
406
407	i2c_register_board_info(0, dns323_i2c_devices,
408				ARRAY_SIZE(dns323_i2c_devices));
409
410	/*
411	 * Configure peripherals.
412	 */
413	if (dns323_read_mac_addr() < 0)
414		printk("DNS323: Failed to read MAC address\n");
415
416	orion5x_ehci0_init();
417	orion5x_eth_init(&dns323_eth_data);
418	orion5x_i2c_init();
419	orion5x_uart0_init();
420
421	/* The 5182 has it's SATA controller on-chip, and needs it's own little
422	 * init routine.
423	 */
424	if (dns323_dev_id() == MV88F5182_DEV_ID)
425		orion5x_sata_init(&dns323_sata_data);
426
427	/* register dns323 specific power-off method */
428	if (gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0 ||
429	    gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0)
430		pr_err("DNS323: failed to setup power-off GPIO\n");
431	pm_power_off = dns323_power_off;
432}
433
434/* Warning: D-Link uses a wrong mach-type (=526) in their bootloader */
435MACHINE_START(DNS323, "D-Link DNS-323")
436	/* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
437	.phys_io	= ORION5X_REGS_PHYS_BASE,
438	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
439	.boot_params	= 0x00000100,
440	.init_machine	= dns323_init,
441	.map_io		= orion5x_map_io,
442	.init_irq	= orion5x_init_irq,
443	.timer		= &orion5x_timer,
444	.fixup		= tag_fixup_mem32,
445MACHINE_END
446