blob: 5206d2fbe0c68729d114244053800d936bb4d18a [file] [log] [blame]
Manuel Lauss27dd65a2009-10-04 14:55:28 +02001/*
Manuel Lauss7c4b24d2011-11-10 12:06:21 +00002 * DBAu1000/1500/1100 board support
Manuel Lauss27dd65a2009-10-04 14:55:28 +02003 *
Manuel Lauss7c4b24d2011-11-10 12:06:21 +00004 * Copyright 2000, 2008 MontaVista Software Inc.
5 * Author: MontaVista Software, Inc. <source@mvista.com>
Manuel Lauss27dd65a2009-10-04 14:55:28 +02006 *
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 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
Manuel Lauss7c4b24d2011-11-10 12:06:21 +000022#include <linux/dma-mapping.h>
23#include <linux/gpio.h>
Manuel Lauss27dd65a2009-10-04 14:55:28 +020024#include <linux/init.h>
Manuel Laussb2ce3052011-07-25 13:44:46 +020025#include <linux/interrupt.h>
Manuel Laussc9af5142011-11-10 12:06:22 +000026#include <linux/leds.h>
27#include <linux/mmc/host.h>
28#include <linux/module.h>
Manuel Lauss27dd65a2009-10-04 14:55:28 +020029#include <linux/platform_device.h>
Manuel Lauss7c4b24d2011-11-10 12:06:21 +000030#include <linux/pm.h>
Manuel Laussb2ce3052011-07-25 13:44:46 +020031#include <asm/mach-au1x00/au1000.h>
32#include <asm/mach-au1x00/au1000_dma.h>
Manuel Laussc9af5142011-11-10 12:06:22 +000033#include <asm/mach-au1x00/au1100_mmc.h>
Manuel Lauss206aa6c2009-10-19 12:53:37 +020034#include <asm/mach-db1x00/bcsr.h>
Manuel Lauss7c4b24d2011-11-10 12:06:21 +000035#include <asm/reboot.h>
36#include <prom.h>
37#include "platform.h"
Manuel Lauss27dd65a2009-10-04 14:55:28 +020038
Manuel Laussf59c8112011-11-10 12:06:22 +000039#define F_SWAPPED (bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT)
40
Manuel Lauss7517de32011-08-12 11:39:44 +020041struct pci_dev;
42
Manuel Laussf59c8112011-11-10 12:06:22 +000043static const char *board_type_str(void)
44{
45 switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
46 case BCSR_WHOAMI_DB1000:
47 return "DB1000";
48 case BCSR_WHOAMI_DB1500:
49 return "DB1500";
50 case BCSR_WHOAMI_DB1100:
51 return "DB1100";
52 default:
53 return "(unknown)";
54 }
55}
56
Manuel Lauss7c4b24d2011-11-10 12:06:21 +000057const char *get_system_type(void)
58{
Manuel Laussf59c8112011-11-10 12:06:22 +000059 return board_type_str();
Manuel Lauss7c4b24d2011-11-10 12:06:21 +000060}
61
62void __init board_setup(void)
63{
Manuel Lauss7c4b24d2011-11-10 12:06:21 +000064 /* initialize board register space */
65 bcsr_init(DB1000_BCSR_PHYS_ADDR,
66 DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
67
Manuel Laussf59c8112011-11-10 12:06:22 +000068 printk(KERN_INFO "AMD Alchemy %s Board\n", board_type_str());
Manuel Lauss7c4b24d2011-11-10 12:06:21 +000069}
70
Manuel Lauss27dd65a2009-10-04 14:55:28 +020071
Manuel Laussf869d422011-11-10 12:06:16 +000072static int db1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
Manuel Lauss7517de32011-08-12 11:39:44 +020073{
74 if ((slot < 12) || (slot > 13) || pin == 0)
75 return -1;
76 if (slot == 12)
77 return (pin == 1) ? AU1500_PCI_INTA : 0xff;
78 if (slot == 13) {
79 switch (pin) {
80 case 1: return AU1500_PCI_INTA;
81 case 2: return AU1500_PCI_INTB;
82 case 3: return AU1500_PCI_INTC;
83 case 4: return AU1500_PCI_INTD;
84 }
85 }
86 return -1;
87}
Manuel Lauss7517de32011-08-12 11:39:44 +020088
Manuel Lauss7517de32011-08-12 11:39:44 +020089static struct resource alchemy_pci_host_res[] = {
90 [0] = {
91 .start = AU1500_PCI_PHYS_ADDR,
92 .end = AU1500_PCI_PHYS_ADDR + 0xfff,
93 .flags = IORESOURCE_MEM,
94 },
95};
96
Manuel Laussf869d422011-11-10 12:06:16 +000097static struct alchemy_pci_platdata db1500_pci_pd = {
98 .board_map_irq = db1500_map_pci_irq,
Manuel Lauss7517de32011-08-12 11:39:44 +020099};
100
Manuel Laussf869d422011-11-10 12:06:16 +0000101static struct platform_device db1500_pci_host_dev = {
102 .dev.platform_data = &db1500_pci_pd,
Manuel Lauss7517de32011-08-12 11:39:44 +0200103 .name = "alchemy-pci",
104 .id = 0,
105 .num_resources = ARRAY_SIZE(alchemy_pci_host_res),
106 .resource = alchemy_pci_host_res,
107};
108
Manuel Laussf869d422011-11-10 12:06:16 +0000109static int __init db1500_pci_init(void)
Manuel Lauss7517de32011-08-12 11:39:44 +0200110{
Manuel Laussf59c8112011-11-10 12:06:22 +0000111 if (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) == BCSR_WHOAMI_DB1500)
112 return platform_device_register(&db1500_pci_host_dev);
113 return 0;
Manuel Lauss7517de32011-08-12 11:39:44 +0200114}
115/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */
Manuel Laussf869d422011-11-10 12:06:16 +0000116arch_initcall(db1500_pci_init);
Manuel Lauss7517de32011-08-12 11:39:44 +0200117
Manuel Laussf59c8112011-11-10 12:06:22 +0000118
Manuel Lauss3766386032011-08-12 11:39:45 +0200119static struct resource au1100_lcd_resources[] = {
120 [0] = {
121 .start = AU1100_LCD_PHYS_ADDR,
122 .end = AU1100_LCD_PHYS_ADDR + 0x800 - 1,
123 .flags = IORESOURCE_MEM,
124 },
125 [1] = {
126 .start = AU1100_LCD_INT,
127 .end = AU1100_LCD_INT,
128 .flags = IORESOURCE_IRQ,
129 }
130};
131
132static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32);
133
134static struct platform_device au1100_lcd_device = {
135 .name = "au1100-lcd",
136 .id = 0,
137 .dev = {
138 .dma_mask = &au1100_lcd_dmamask,
139 .coherent_dma_mask = DMA_BIT_MASK(32),
140 },
141 .num_resources = ARRAY_SIZE(au1100_lcd_resources),
142 .resource = au1100_lcd_resources,
143};
Manuel Lauss3766386032011-08-12 11:39:45 +0200144
Manuel Laussb2ce3052011-07-25 13:44:46 +0200145static struct resource alchemy_ac97c_res[] = {
146 [0] = {
147 .start = AU1000_AC97_PHYS_ADDR,
148 .end = AU1000_AC97_PHYS_ADDR + 0xfff,
149 .flags = IORESOURCE_MEM,
150 },
151 [1] = {
152 .start = DMA_ID_AC97C_TX,
153 .end = DMA_ID_AC97C_TX,
154 .flags = IORESOURCE_DMA,
155 },
156 [2] = {
157 .start = DMA_ID_AC97C_RX,
158 .end = DMA_ID_AC97C_RX,
159 .flags = IORESOURCE_DMA,
160 },
161};
162
163static struct platform_device alchemy_ac97c_dev = {
164 .name = "alchemy-ac97c",
165 .id = -1,
166 .resource = alchemy_ac97c_res,
167 .num_resources = ARRAY_SIZE(alchemy_ac97c_res),
168};
169
170static struct platform_device alchemy_ac97c_dma_dev = {
171 .name = "alchemy-pcm-dma",
172 .id = 0,
173};
174
175static struct platform_device db1x00_codec_dev = {
176 .name = "ac97-codec",
177 .id = -1,
178};
179
180static struct platform_device db1x00_audio_dev = {
181 .name = "db1000-audio",
182};
183
Manuel Laussc9af5142011-11-10 12:06:22 +0000184/******************************************************************************/
185
186static irqreturn_t db1100_mmc_cd(int irq, void *ptr)
187{
188 void (*mmc_cd)(struct mmc_host *, unsigned long);
189 /* link against CONFIG_MMC=m */
190 mmc_cd = symbol_get(mmc_detect_change);
191 mmc_cd(ptr, msecs_to_jiffies(500));
192 symbol_put(mmc_detect_change);
193
194 return IRQ_HANDLED;
195}
196
197static int db1100_mmc_cd_setup(void *mmc_host, int en)
198{
199 int ret = 0;
200
201 if (en) {
202 irq_set_irq_type(AU1100_GPIO19_INT, IRQ_TYPE_EDGE_BOTH);
203 ret = request_irq(AU1100_GPIO19_INT, db1100_mmc_cd, 0,
204 "sd0_cd", mmc_host);
205 } else
206 free_irq(AU1100_GPIO19_INT, mmc_host);
207 return ret;
208}
209
210static int db1100_mmc1_cd_setup(void *mmc_host, int en)
211{
212 int ret = 0;
213
214 if (en) {
215 irq_set_irq_type(AU1100_GPIO20_INT, IRQ_TYPE_EDGE_BOTH);
216 ret = request_irq(AU1100_GPIO20_INT, db1100_mmc_cd, 0,
217 "sd1_cd", mmc_host);
218 } else
219 free_irq(AU1100_GPIO20_INT, mmc_host);
220 return ret;
221}
222
223static int db1100_mmc_card_readonly(void *mmc_host)
224{
225 /* testing suggests that this bit is inverted */
226 return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 0 : 1;
227}
228
229static int db1100_mmc_card_inserted(void *mmc_host)
230{
231 return !alchemy_gpio_get_value(19);
232}
233
234static void db1100_mmc_set_power(void *mmc_host, int state)
235{
236 if (state) {
237 bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD0PWR);
238 msleep(400); /* stabilization time */
239 } else
240 bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD0PWR, 0);
241}
242
243static void db1100_mmcled_set(struct led_classdev *led, enum led_brightness b)
244{
245 if (b != LED_OFF)
246 bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0);
247 else
248 bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0);
249}
250
251static struct led_classdev db1100_mmc_led = {
252 .brightness_set = db1100_mmcled_set,
253};
254
255static int db1100_mmc1_card_readonly(void *mmc_host)
256{
257 return (bcsr_read(BCSR_BOARD) & BCSR_BOARD_SD1WP) ? 1 : 0;
258}
259
260static int db1100_mmc1_card_inserted(void *mmc_host)
261{
262 return !alchemy_gpio_get_value(20);
263}
264
265static void db1100_mmc1_set_power(void *mmc_host, int state)
266{
267 if (state) {
268 bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR);
269 msleep(400); /* stabilization time */
270 } else
271 bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0);
272}
273
274static void db1100_mmc1led_set(struct led_classdev *led, enum led_brightness b)
275{
276 if (b != LED_OFF)
277 bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0);
278 else
279 bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1);
280}
281
282static struct led_classdev db1100_mmc1_led = {
283 .brightness_set = db1100_mmc1led_set,
284};
285
286static struct au1xmmc_platform_data db1100_mmc_platdata[2] = {
287 [0] = {
288 .cd_setup = db1100_mmc_cd_setup,
289 .set_power = db1100_mmc_set_power,
290 .card_inserted = db1100_mmc_card_inserted,
291 .card_readonly = db1100_mmc_card_readonly,
292 .led = &db1100_mmc_led,
293 },
294 [1] = {
295 .cd_setup = db1100_mmc1_cd_setup,
296 .set_power = db1100_mmc1_set_power,
297 .card_inserted = db1100_mmc1_card_inserted,
298 .card_readonly = db1100_mmc1_card_readonly,
299 .led = &db1100_mmc1_led,
300 },
301};
302
303static struct resource au1100_mmc0_resources[] = {
304 [0] = {
305 .start = AU1100_SD0_PHYS_ADDR,
306 .end = AU1100_SD0_PHYS_ADDR + 0xfff,
307 .flags = IORESOURCE_MEM,
308 },
309 [1] = {
310 .start = AU1100_SD_INT,
311 .end = AU1100_SD_INT,
312 .flags = IORESOURCE_IRQ,
313 },
314 [2] = {
315 .start = DMA_ID_SD0_TX,
316 .end = DMA_ID_SD0_TX,
317 .flags = IORESOURCE_DMA,
318 },
319 [3] = {
320 .start = DMA_ID_SD0_RX,
321 .end = DMA_ID_SD0_RX,
322 .flags = IORESOURCE_DMA,
323 }
324};
325
326static u64 au1xxx_mmc_dmamask = DMA_BIT_MASK(32);
327
328static struct platform_device db1100_mmc0_dev = {
329 .name = "au1xxx-mmc",
330 .id = 0,
331 .dev = {
332 .dma_mask = &au1xxx_mmc_dmamask,
333 .coherent_dma_mask = DMA_BIT_MASK(32),
334 .platform_data = &db1100_mmc_platdata[0],
335 },
336 .num_resources = ARRAY_SIZE(au1100_mmc0_resources),
337 .resource = au1100_mmc0_resources,
338};
339
340static struct resource au1100_mmc1_res[] = {
341 [0] = {
342 .start = AU1100_SD1_PHYS_ADDR,
343 .end = AU1100_SD1_PHYS_ADDR + 0xfff,
344 .flags = IORESOURCE_MEM,
345 },
346 [1] = {
347 .start = AU1100_SD_INT,
348 .end = AU1100_SD_INT,
349 .flags = IORESOURCE_IRQ,
350 },
351 [2] = {
352 .start = DMA_ID_SD1_TX,
353 .end = DMA_ID_SD1_TX,
354 .flags = IORESOURCE_DMA,
355 },
356 [3] = {
357 .start = DMA_ID_SD1_RX,
358 .end = DMA_ID_SD1_RX,
359 .flags = IORESOURCE_DMA,
360 }
361};
362
363static struct platform_device db1100_mmc1_dev = {
364 .name = "au1xxx-mmc",
365 .id = 1,
366 .dev = {
367 .dma_mask = &au1xxx_mmc_dmamask,
368 .coherent_dma_mask = DMA_BIT_MASK(32),
369 .platform_data = &db1100_mmc_platdata[1],
370 },
371 .num_resources = ARRAY_SIZE(au1100_mmc1_res),
372 .resource = au1100_mmc1_res,
373};
374
Manuel Lausse734ae12011-12-08 10:42:15 +0000375/******************************************************************************/
376
377static void db1000_irda_set_phy_mode(int mode)
378{
379 unsigned short mask = BCSR_RESETS_IRDA_MODE_MASK | BCSR_RESETS_FIR_SEL;
380
381 switch (mode) {
382 case AU1000_IRDA_PHY_MODE_OFF:
383 bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_OFF);
384 break;
385 case AU1000_IRDA_PHY_MODE_SIR:
386 bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_FULL);
387 break;
388 case AU1000_IRDA_PHY_MODE_FIR:
389 bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_FULL |
390 BCSR_RESETS_FIR_SEL);
391 break;
392 }
393}
394
395static struct au1k_irda_platform_data db1000_irda_platdata = {
396 .set_phy_mode = db1000_irda_set_phy_mode,
397};
398
399static struct resource au1000_irda_res[] = {
400 [0] = {
401 .start = AU1000_IRDA_PHYS_ADDR,
402 .end = AU1000_IRDA_PHYS_ADDR + 0x0fff,
403 .flags = IORESOURCE_MEM,
404 },
405 [1] = {
406 .start = AU1000_IRDA_TX_INT,
407 .end = AU1000_IRDA_TX_INT,
408 .flags = IORESOURCE_IRQ,
409 },
410 [2] = {
411 .start = AU1000_IRDA_RX_INT,
412 .end = AU1000_IRDA_RX_INT,
413 .flags = IORESOURCE_IRQ,
414 },
415};
416
417static struct platform_device db1000_irda_dev = {
418 .name = "au1000-irda",
419 .id = -1,
420 .dev = {
421 .platform_data = &db1000_irda_platdata,
422 },
423 .resource = au1000_irda_res,
424 .num_resources = ARRAY_SIZE(au1000_irda_res),
425};
Manuel Laussc9af5142011-11-10 12:06:22 +0000426
Manuel Laussf59c8112011-11-10 12:06:22 +0000427static struct platform_device *db1x00_devs[] = {
428 &db1x00_codec_dev,
429 &alchemy_ac97c_dma_dev,
430 &alchemy_ac97c_dev,
431 &db1x00_audio_dev,
432};
433
Manuel Lausse734ae12011-12-08 10:42:15 +0000434static struct platform_device *db1000_devs[] = {
435 &db1000_irda_dev,
436};
437
Manuel Laussf59c8112011-11-10 12:06:22 +0000438static struct platform_device *db1100_devs[] = {
439 &au1100_lcd_device,
Manuel Laussc9af5142011-11-10 12:06:22 +0000440 &db1100_mmc0_dev,
441 &db1100_mmc1_dev,
Manuel Lausse734ae12011-12-08 10:42:15 +0000442 &db1000_irda_dev,
Manuel Laussf59c8112011-11-10 12:06:22 +0000443};
444
445static int __init db1000_dev_init(void)
Manuel Lauss27dd65a2009-10-04 14:55:28 +0200446{
Manuel Laussf59c8112011-11-10 12:06:22 +0000447 int board = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
448 int c0, c1, d0, d1, s0, s1;
449
450 if (board == BCSR_WHOAMI_DB1500) {
451 c0 = AU1500_GPIO2_INT;
452 c1 = AU1500_GPIO5_INT;
453 d0 = AU1500_GPIO0_INT;
454 d1 = AU1500_GPIO3_INT;
455 s0 = AU1500_GPIO1_INT;
456 s1 = AU1500_GPIO4_INT;
457 } else if (board == BCSR_WHOAMI_DB1100) {
458 c0 = AU1100_GPIO2_INT;
459 c1 = AU1100_GPIO5_INT;
460 d0 = AU1100_GPIO0_INT;
461 d1 = AU1100_GPIO3_INT;
462 s0 = AU1100_GPIO1_INT;
463 s1 = AU1100_GPIO4_INT;
Manuel Laussc9af5142011-11-10 12:06:22 +0000464
465 gpio_direction_input(19); /* sd0 cd# */
466 gpio_direction_input(20); /* sd1 cd# */
467
Manuel Laussf59c8112011-11-10 12:06:22 +0000468 platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs));
469 } else if (board == BCSR_WHOAMI_DB1000) {
470 c0 = AU1000_GPIO2_INT;
471 c1 = AU1000_GPIO5_INT;
472 d0 = AU1000_GPIO0_INT;
473 d1 = AU1000_GPIO3_INT;
474 s0 = AU1000_GPIO1_INT;
475 s1 = AU1000_GPIO4_INT;
Manuel Lausse734ae12011-12-08 10:42:15 +0000476 platform_add_devices(db1000_devs, ARRAY_SIZE(db1000_devs));
Manuel Laussf59c8112011-11-10 12:06:22 +0000477 } else
478 return 0; /* unknown board, no further dev setup to do */
479
480 irq_set_irq_type(d0, IRQ_TYPE_EDGE_BOTH);
481 irq_set_irq_type(d1, IRQ_TYPE_EDGE_BOTH);
482 irq_set_irq_type(c0, IRQ_TYPE_LEVEL_LOW);
483 irq_set_irq_type(c1, IRQ_TYPE_LEVEL_LOW);
484 irq_set_irq_type(s0, IRQ_TYPE_LEVEL_LOW);
485 irq_set_irq_type(s1, IRQ_TYPE_LEVEL_LOW);
Manuel Lauss7c4b24d2011-11-10 12:06:21 +0000486
Manuel Lauss7cc2e272011-08-12 11:39:40 +0200487 db1x_register_pcmcia_socket(
488 AU1000_PCMCIA_ATTR_PHYS_ADDR,
489 AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
490 AU1000_PCMCIA_MEM_PHYS_ADDR,
491 AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
492 AU1000_PCMCIA_IO_PHYS_ADDR,
493 AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1,
Manuel Laussf59c8112011-11-10 12:06:22 +0000494 c0, d0, /*s0*/0, 0, 0);
Manuel Lauss27dd65a2009-10-04 14:55:28 +0200495
Manuel Lauss7cc2e272011-08-12 11:39:40 +0200496 db1x_register_pcmcia_socket(
497 AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
498 AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
499 AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004000000,
500 AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1,
501 AU1000_PCMCIA_IO_PHYS_ADDR + 0x004000000,
502 AU1000_PCMCIA_IO_PHYS_ADDR + 0x004010000 - 1,
Manuel Laussf59c8112011-11-10 12:06:22 +0000503 c1, d1, /*s1*/0, 0, 1);
Manuel Laussb2ce3052011-07-25 13:44:46 +0200504
Manuel Laussf59c8112011-11-10 12:06:22 +0000505 platform_add_devices(db1x00_devs, ARRAY_SIZE(db1x00_devs));
Manuel Lauss7c4b24d2011-11-10 12:06:21 +0000506 db1x_register_norflash(32 << 20, 4 /* 32bit */, F_SWAPPED);
Manuel Lauss27dd65a2009-10-04 14:55:28 +0200507 return 0;
508}
Manuel Laussf59c8112011-11-10 12:06:22 +0000509device_initcall(db1000_dev_init);