make atheros wifi cards used on arcaydian 4519 ifxmips based boards work
[10.03/openwrt.git] / target / linux / ifxmips / files / arch / mips / ifxmips / board.c
1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
15  *
16  *   Copyright (C) 2007 John Crispin <blogic@openwrt.org> 
17  */
18
19 #include <linux/autoconf.h>
20 #include <linux/init.h>
21 #include <linux/module.h>
22 #include <linux/types.h>
23 #include <linux/string.h>
24 #include <linux/mtd/physmap.h>
25 #include <linux/kernel.h>
26 #include <linux/reboot.h>
27 #include <linux/platform_device.h>
28 #include <asm/bootinfo.h>
29 #include <asm/reboot.h>
30 #include <asm/time.h>
31 #include <asm/irq.h>
32 #include <asm/io.h>
33 #include <linux/etherdevice.h>
34 #include <asm/ifxmips/ifxmips.h>
35 #include <linux/leds.h>
36
37 #define MAX_BOARD_NAME_LEN              32
38 #define MAX_IFXMIPS_DEVS                9
39
40 #define SYSTEM_DANUBE                   "Danube"
41 #define SYSTEM_DANUBE_CHIPID1   0x10129083
42 #define SYSTEM_DANUBE_CHIPID2   0x3012B083
43
44 #define SYSTEM_TWINPASS                 "Twinpass"
45 #define SYSTEM_TWINPASS_CHIPID  0x3012D083
46
47 extern int ifxmips_pci_external_clock;
48
49 static unsigned int chiprev;
50 static int cmdline_mac = 0;
51 char board_name[MAX_BOARD_NAME_LEN + 1] = { 0 };
52
53 struct ifxmips_board {
54         char name[32];
55         unsigned int system_type;
56         struct platform_device *devs[MAX_IFXMIPS_DEVS];
57         struct resource reset_resource;
58         struct resource gpiodev_resource;
59         int pci_external_clock;
60         int num_devs;
61 };
62
63 spinlock_t ebu_lock = SPIN_LOCK_UNLOCKED;
64 EXPORT_SYMBOL_GPL(ebu_lock);
65
66 static unsigned char ifxmips_mii_mac[6];
67 static int ifxmips_brn = 0;
68
69 static struct platform_device
70 ifxmips_led =
71 {
72         .id = 0,
73         .name = "ifxmips_led",
74 };
75
76 static struct platform_device
77 ifxmips_gpio =
78 {
79         .id = 0,
80         .name = "ifxmips_gpio",
81         .num_resources = 1,
82 };
83
84 static struct platform_device
85 ifxmips_mii =
86 {
87         .id = 0,
88         .name = "ifxmips_mii0",
89         .dev = {
90                 .platform_data = ifxmips_mii_mac,
91         }
92 };
93
94 static struct platform_device
95 ifxmips_wdt =
96 {
97         .id = 0,
98         .name = "ifxmips_wdt",
99 };
100
101 static struct resource
102 ifxmips_mtd_resource = {
103         .start  = IFXMIPS_FLASH_START,
104         .end    = IFXMIPS_FLASH_START + IFXMIPS_FLASH_MAX - 1,
105         .flags  = IORESOURCE_MEM,
106 };
107
108 static struct platform_device
109 ifxmips_mtd =
110 {
111         .id = 0,
112         .name = "ifxmips_mtd",
113         .num_resources  = 1,
114         .resource   = &ifxmips_mtd_resource,
115 };
116
117 static struct platform_device
118 ifxmips_gpio_dev = {
119         .name     = "GPIODEV",
120         .id     = -1,
121         .num_resources    =     1,
122 };
123
124 #ifdef CONFIG_LEDS_GPIO
125 static struct gpio_led arv4519_leds[] = {
126         { .name = "ifxmips:green:power0", .gpio = 3, .active_low = 0, },
127         { .name = "ifxmips:red:power1", .gpio = 7, .active_low = 1, },
128         { .name = "ifxmips:green:adsl", .gpio = 4, .active_low = 1, },
129         { .name = "ifxmips:green:internet0", .gpio = 5, .active_low = 0, },
130         { .name = "ifxmips:red:internet1", .gpio = 8, .active_low = 1, },
131         { .name = "ifxmips:green:wlan", .gpio = 6, .active_low = 1, },
132         { .name = "ifxmips:green:usb", .gpio = 19, .active_low = 1, },
133 };
134
135 static const struct gpio_led_platform_data arv4519_led_data = {
136         .num_leds = ARRAY_SIZE(arv4519_leds),
137         .leds = (void *) arv4519_leds,
138 };
139
140 static struct platform_device arv4519_gpio_leds = {
141         .name = "leds-gpio",
142         .id = -1,
143         .dev = {
144                 .platform_data = (void *) &arv4519_led_data,
145          }
146 };
147 #endif
148
149 const char*
150 get_system_type(void)
151 {
152         chiprev = ifxmips_r32(IFXMIPS_MPS_CHIPID);
153         switch(chiprev)
154         {
155         case SYSTEM_DANUBE_CHIPID1:
156         case SYSTEM_DANUBE_CHIPID2:
157                 return SYSTEM_DANUBE;
158
159         case SYSTEM_TWINPASS_CHIPID:
160                 return SYSTEM_TWINPASS;
161         }
162
163         return BOARD_SYSTEM_TYPE;
164 }
165
166 static int __init
167 ifxmips_set_board_type(char *str)
168 {
169         str = strchr(str, '=');
170         if(!str)
171                 goto out;
172         str++;
173         if(strlen(str) > MAX_BOARD_NAME_LEN)
174                 goto out;
175         strncpy(board_name, str, MAX_BOARD_NAME_LEN);
176         printk("bootloader told us, that this is a %s board\n", board_name);
177 out:
178         return 1;
179 }
180 __setup("ifxmips_board", ifxmips_set_board_type);
181
182 #define IS_HEX(x) \
183         (((x >='0' && x <= '9') || (x >='a' && x <= 'f') || (x >='A' && x <= 'F'))?(1):(0))
184
185 static int __init
186 ifxmips_set_mii0_mac(char *str)
187 {
188         int i;
189         str = strchr(str, '=');
190         if(!str)
191                 goto out;
192         str++;
193         if(strlen(str) != 17)
194                 goto out;
195         for(i = 0; i < 6; i++)
196         {
197                 if(!IS_HEX(str[3 * i]) || !IS_HEX(str[(3 * i) + 1]))
198                         goto out;
199                 if((i != 5) && (str[(3 * i) + 2] != ':'))
200                         goto out;
201                 ifxmips_mii_mac[i] = simple_strtoul(&str[3 * i], NULL, 16);
202         }
203         if(is_valid_ether_addr(ifxmips_mii_mac))
204                 cmdline_mac = 1;
205 out:
206         return 1;
207 }
208 __setup("mii0_mac", ifxmips_set_mii0_mac);
209
210
211 static struct ifxmips_board boards[] =
212 {
213         {
214                 .name = "EASY50712",
215                 .system_type = SYSTEM_DANUBE_CHIPID1,
216                 .devs =
217                 {
218                         &ifxmips_led, &ifxmips_gpio, &ifxmips_mii,
219                         &ifxmips_mtd, &ifxmips_wdt, &ifxmips_gpio_dev,
220                 },
221                 .reset_resource =
222                 {
223                         .name = "reset",
224                         .start = 1,
225                         .end = 15,
226                 },
227                 .gpiodev_resource =
228                 {
229                         .name = "gpio",
230                         .start = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) |
231                                         (1 << 4) | (1 << 5) | (1 << 8) | (1 << 9) | (1 << 12),
232                         .end = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) |
233                                         (1 << 4) | (1 << 5) | (1 << 8) | (1 << 9) | (1 << 12),
234                 },
235                 .num_devs = 6,
236         }, {
237                 .name = "EASY4010",
238                 .system_type = SYSTEM_TWINPASS_CHIPID,
239                 .devs =
240                 {
241                         &ifxmips_led, &ifxmips_gpio, &ifxmips_mii,
242                         &ifxmips_mtd, &ifxmips_wdt, &ifxmips_gpio_dev,
243                 },
244                 .reset_resource =
245                 {
246                         .name = "reset",
247                         .start = 1,
248                         .end = 15,
249                 },
250                 .gpiodev_resource =
251                 {
252                         .name = "gpio",
253                         .start = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) |
254                                         (1 << 4) | (1 << 5) | (1 << 8) | (1 << 9) | (1 << 12),
255                         .end = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) |
256                                         (1 << 4) | (1 << 5) | (1 << 8) | (1 << 9) | (1 << 12),
257                 },
258                 .num_devs = 6,
259         }, {
260                 .name = "ARV4519",
261                 .system_type = SYSTEM_DANUBE_CHIPID2,
262                 .devs =
263                 {
264                         &ifxmips_gpio, &ifxmips_mii,
265                         &ifxmips_mtd, &ifxmips_wdt, &ifxmips_gpio_dev,
266 #ifdef CONFIG_LEDS_GPIO
267                         &arv4519_gpio_leds,
268 #endif
269                 },
270                 .reset_resource =
271                 {
272                         .name = "reset",
273                         .start = 1,
274                         .end = 12,
275                 },
276                 .gpiodev_resource =
277                 {
278                         .name = "gpio",
279                         .start = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) |
280                                         (1 << 4) | (1 << 5) | (1 << 8) | (1 << 9) | (1 << 12),
281                         .end = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) |
282                                         (1 << 4) | (1 << 5) | (1 << 8) | (1 << 9) | (1 << 12),
283                 },
284                 .pci_external_clock = 1,
285                 .num_devs = 6,
286         },
287 };
288
289 int
290 ifxmips_find_brn_block(void){
291         unsigned char temp[8];
292         memcpy_fromio(temp, (void*)KSEG1ADDR(IFXMIPS_FLASH_START + 0x800000 - 0x10000), 8);
293         if(memcmp(temp, "BRN-BOOT", 8) == 0)
294         {
295                 if(!cmdline_mac)
296                         memcpy_fromio(ifxmips_mii_mac, (void*)KSEG1ADDR(IFXMIPS_FLASH_START + 0x800000 - 0x10000 + 0x16), 6);
297                 cmdline_mac = 1;
298                 return 1;
299         } else {
300                 return 0;
301         }
302 }
303
304 int
305 ifxmips_has_brn_block(void)
306 {
307         return ifxmips_brn;
308 }
309 EXPORT_SYMBOL(ifxmips_has_brn_block);
310
311 struct ifxmips_board*
312 ifxmips_find_board(void)
313 {
314         int i;
315         if(!*board_name)
316                 return 0;
317         for(i = 0; i < ARRAY_SIZE(boards); i++)
318                 if((boards[i].system_type == chiprev) && (!strcmp(boards[i].name, board_name)))
319                         return &boards[i];
320         return 0;
321 }
322
323 int __init
324 ifxmips_init_devices(void)
325 {
326         struct ifxmips_board *board = ifxmips_find_board();
327
328         chiprev = ifxmips_r32(IFXMIPS_MPS_CHIPID);
329         ifxmips_brn = ifxmips_find_brn_block();
330
331         if(!cmdline_mac)
332                 random_ether_addr(ifxmips_mii_mac);
333
334         if(!board)
335         {
336                 switch(chiprev)
337                 {
338                 case SYSTEM_DANUBE_CHIPID1:
339                 case SYSTEM_DANUBE_CHIPID2:
340                         board = &boards[0];
341                         break;
342                 case SYSTEM_TWINPASS_CHIPID:
343                         board = &boards[1];
344                         break;
345                 }
346         }
347         ifxmips_gpio.resource = &board->reset_resource;
348         ifxmips_gpio_dev.resource = &board->gpiodev_resource;
349         if(board->pci_external_clock)
350                 ifxmips_pci_external_clock = 1;
351         printk("using board definition %s\n", board->name);
352         return platform_add_devices(board->devs, board->num_devs);
353 }
354
355 arch_initcall(ifxmips_init_devices);