]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* arch/arm/mach-lh7a40x/arch-lpd7a40x.c |
2 | * | |
3 | * Copyright (C) 2004 Logic Product Development | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU General Public License | |
7 | * version 2 as published by the Free Software Foundation. | |
8 | * | |
9 | */ | |
10 | ||
11 | #include <linux/tty.h> | |
12 | #include <linux/init.h> | |
13 | #include <linux/device.h> | |
14 | #include <linux/interrupt.h> | |
15 | ||
16 | #include <asm/hardware.h> | |
17 | #include <asm/setup.h> | |
18 | #include <asm/mach-types.h> | |
19 | #include <asm/mach/arch.h> | |
20 | #include <asm/irq.h> | |
21 | #include <asm/mach/irq.h> | |
22 | #include <asm/mach/map.h> | |
23 | ||
24 | #include "common.h" | |
25 | ||
26 | static struct resource smc91x_resources[] = { | |
27 | [0] = { | |
28 | .start = CPLD00_PHYS, | |
29 | .end = CPLD00_PHYS + CPLD00_SIZE - 1, /* Only needs 16B */ | |
30 | .flags = IORESOURCE_MEM, | |
31 | }, | |
32 | ||
33 | [1] = { | |
34 | .start = IRQ_LPD7A40X_ETH_INT, | |
35 | .end = IRQ_LPD7A40X_ETH_INT, | |
36 | .flags = IORESOURCE_IRQ, | |
37 | }, | |
38 | ||
39 | }; | |
40 | ||
41 | static struct platform_device smc91x_device = { | |
42 | .name = "smc91x", | |
43 | .id = 0, | |
44 | .num_resources = ARRAY_SIZE(smc91x_resources), | |
45 | .resource = smc91x_resources, | |
46 | }; | |
47 | ||
48 | static struct resource lh7a40x_usbclient_resources[] = { | |
49 | [0] = { | |
50 | .start = USB_PHYS, | |
51 | .end = (USB_PHYS + 0xFF), | |
52 | .flags = IORESOURCE_MEM, | |
53 | }, | |
54 | [1] = { | |
55 | .start = IRQ_USBINTR, | |
56 | .end = IRQ_USBINTR, | |
57 | .flags = IORESOURCE_IRQ, | |
58 | }, | |
59 | }; | |
60 | ||
61 | static u64 lh7a40x_usbclient_dma_mask = 0xffffffffUL; | |
62 | ||
63 | static struct platform_device lh7a40x_usbclient_device = { | |
64 | .name = "lh7a40x_udc", | |
65 | .id = 0, | |
66 | .dev = { | |
67 | .dma_mask = &lh7a40x_usbclient_dma_mask, | |
68 | .coherent_dma_mask = 0xffffffffUL, | |
69 | }, | |
70 | .num_resources = ARRAY_SIZE (lh7a40x_usbclient_resources), | |
71 | .resource = lh7a40x_usbclient_resources, | |
72 | }; | |
73 | ||
74 | #if defined (CONFIG_ARCH_LH7A404) | |
75 | ||
76 | static struct resource lh7a404_usbhost_resources [] = { | |
77 | [0] = { | |
78 | .start = USBH_PHYS, | |
79 | .end = (USBH_PHYS + 0xFF), | |
80 | .flags = IORESOURCE_MEM, | |
81 | }, | |
82 | [1] = { | |
83 | .start = IRQ_USHINTR, | |
84 | .end = IRQ_USHINTR, | |
85 | .flags = IORESOURCE_IRQ, | |
86 | }, | |
87 | }; | |
88 | ||
89 | static u64 lh7a404_usbhost_dma_mask = 0xffffffffUL; | |
90 | ||
91 | static struct platform_device lh7a404_usbhost_device = { | |
92 | .name = "lh7a404-ohci", | |
93 | .id = 0, | |
94 | .dev = { | |
95 | .dma_mask = &lh7a404_usbhost_dma_mask, | |
96 | .coherent_dma_mask = 0xffffffffUL, | |
97 | }, | |
98 | .num_resources = ARRAY_SIZE (lh7a404_usbhost_resources), | |
99 | .resource = lh7a404_usbhost_resources, | |
100 | }; | |
101 | ||
102 | #endif | |
103 | ||
104 | static struct platform_device *lpd7a40x_devs[] __initdata = { | |
105 | &smc91x_device, | |
106 | &lh7a40x_usbclient_device, | |
107 | #if defined (CONFIG_ARCH_LH7A404) | |
108 | &lh7a404_usbhost_device, | |
109 | #endif | |
110 | }; | |
111 | ||
112 | extern void lpd7a400_map_io (void); | |
113 | ||
114 | static void __init lpd7a40x_init (void) | |
115 | { | |
116 | CPLD_CONTROL |= (1<<6); /* Mask USB1 connection IRQ */ | |
117 | CPLD_CONTROL &= ~(0 | |
118 | | (1<<1) /* Disable LCD */ | |
119 | | (1<<0) /* Enable WLAN */ | |
120 | ); | |
121 | ||
122 | platform_add_devices (lpd7a40x_devs, ARRAY_SIZE (lpd7a40x_devs)); | |
123 | } | |
124 | ||
125 | static void lh7a40x_ack_cpld_irq (u32 irq) | |
126 | { | |
127 | /* CPLD doesn't have ack capability */ | |
128 | } | |
129 | ||
130 | static void lh7a40x_mask_cpld_irq (u32 irq) | |
131 | { | |
132 | switch (irq) { | |
133 | case IRQ_LPD7A40X_ETH_INT: | |
134 | CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x4; | |
135 | break; | |
136 | case IRQ_LPD7A400_TS: | |
137 | CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x8; | |
138 | break; | |
139 | } | |
140 | } | |
141 | ||
142 | static void lh7a40x_unmask_cpld_irq (u32 irq) | |
143 | { | |
144 | switch (irq) { | |
145 | case IRQ_LPD7A40X_ETH_INT: | |
146 | CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x4; | |
147 | break; | |
148 | case IRQ_LPD7A400_TS: | |
149 | CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x8; | |
150 | break; | |
151 | } | |
152 | } | |
153 | ||
154 | static struct irqchip lpd7a40x_cpld_chip = { | |
155 | .ack = lh7a40x_ack_cpld_irq, | |
156 | .mask = lh7a40x_mask_cpld_irq, | |
157 | .unmask = lh7a40x_unmask_cpld_irq, | |
158 | }; | |
159 | ||
160 | static void lpd7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc, | |
161 | struct pt_regs *regs) | |
162 | { | |
163 | unsigned int mask = CPLD_INTERRUPTS; | |
164 | ||
165 | desc->chip->ack (irq); | |
166 | ||
167 | if ((mask & 0x1) == 0) /* WLAN */ | |
168 | IRQ_DISPATCH (IRQ_LPD7A40X_ETH_INT); | |
169 | ||
170 | if ((mask & 0x2) == 0) /* Touch */ | |
171 | IRQ_DISPATCH (IRQ_LPD7A400_TS); | |
172 | ||
173 | desc->chip->unmask (irq); /* Level-triggered need this */ | |
174 | } | |
175 | ||
176 | ||
177 | void __init lh7a40x_init_board_irq (void) | |
178 | { | |
179 | int irq; | |
180 | ||
181 | /* Rev A (v2.8): PF0, PF1, PF2, and PF3 are available IRQs. | |
182 | PF7 supports the CPLD. | |
183 | Rev B (v3.4): PF0, PF1, and PF2 are available IRQs. | |
184 | PF3 supports the CPLD. | |
185 | (Some) LPD7A404 prerelease boards report a version | |
186 | number of 0x16, but we force an override since the | |
187 | hardware is of the newer variety. | |
188 | */ | |
189 | ||
190 | unsigned char cpld_version = CPLD_REVISION; | |
191 | int pinCPLD = (cpld_version == 0x28) ? 7 : 3; | |
192 | ||
193 | #if defined CONFIG_MACH_LPD7A404 | |
194 | cpld_version = 0x34; /* Coerce LPD7A404 to RevB */ | |
195 | #endif | |
196 | ||
197 | /* First, configure user controlled GPIOF interrupts */ | |
198 | ||
199 | GPIO_PFDD &= ~0x0f; /* PF0-3 are inputs */ | |
200 | GPIO_INTTYPE1 &= ~0x0f; /* PF0-3 are level triggered */ | |
201 | GPIO_INTTYPE2 &= ~0x0f; /* PF0-3 are active low */ | |
202 | barrier (); | |
203 | GPIO_GPIOFINTEN |= 0x0f; /* Enable PF0, PF1, PF2, and PF3 IRQs */ | |
204 | ||
205 | /* Then, configure CPLD interrupt */ | |
206 | ||
207 | CPLD_INTERRUPTS = 0x9c; /* Disable all CPLD interrupts */ | |
208 | GPIO_PFDD &= ~(1 << pinCPLD); /* Make input */ | |
209 | GPIO_INTTYPE1 |= (1 << pinCPLD); /* Edge triggered */ | |
210 | GPIO_INTTYPE2 &= ~(1 << pinCPLD); /* Active low */ | |
211 | barrier (); | |
212 | GPIO_GPIOFINTEN |= (1 << pinCPLD); /* Enable */ | |
213 | ||
214 | /* Cascade CPLD interrupts */ | |
215 | ||
216 | for (irq = IRQ_BOARD_START; | |
217 | irq < IRQ_BOARD_START + NR_IRQ_BOARD; ++irq) { | |
218 | set_irq_chip (irq, &lpd7a40x_cpld_chip); | |
219 | set_irq_handler (irq, do_edge_IRQ); | |
220 | set_irq_flags (irq, IRQF_VALID); | |
221 | } | |
222 | ||
223 | set_irq_chained_handler ((cpld_version == 0x28) | |
224 | ? IRQ_CPLD_V28 | |
225 | : IRQ_CPLD_V34, | |
226 | lpd7a40x_cpld_handler); | |
227 | } | |
228 | ||
229 | static struct map_desc lpd7a400_io_desc[] __initdata = { | |
230 | { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE }, | |
231 | /* Mapping added to work around chip select problems */ | |
232 | { IOBARRIER_VIRT, IOBARRIER_PHYS, IOBARRIER_SIZE, MT_DEVICE }, | |
233 | { CF_VIRT, CF_PHYS, CF_SIZE, MT_DEVICE }, | |
234 | /* This mapping is redundant since the smc driver performs another. */ | |
235 | /* { CPLD00_VIRT, CPLD00_PHYS, CPLD00_SIZE, MT_DEVICE }, */ | |
236 | { CPLD02_VIRT, CPLD02_PHYS, CPLD02_SIZE, MT_DEVICE }, | |
237 | { CPLD06_VIRT, CPLD06_PHYS, CPLD06_SIZE, MT_DEVICE }, | |
238 | { CPLD08_VIRT, CPLD08_PHYS, CPLD08_SIZE, MT_DEVICE }, | |
239 | { CPLD0C_VIRT, CPLD0C_PHYS, CPLD0C_SIZE, MT_DEVICE }, | |
240 | { CPLD0E_VIRT, CPLD0E_PHYS, CPLD0E_SIZE, MT_DEVICE }, | |
241 | { CPLD10_VIRT, CPLD10_PHYS, CPLD10_SIZE, MT_DEVICE }, | |
242 | { CPLD12_VIRT, CPLD12_PHYS, CPLD12_SIZE, MT_DEVICE }, | |
243 | { CPLD14_VIRT, CPLD14_PHYS, CPLD14_SIZE, MT_DEVICE }, | |
244 | { CPLD16_VIRT, CPLD16_PHYS, CPLD16_SIZE, MT_DEVICE }, | |
245 | { CPLD18_VIRT, CPLD18_PHYS, CPLD18_SIZE, MT_DEVICE }, | |
246 | { CPLD1A_VIRT, CPLD1A_PHYS, CPLD1A_SIZE, MT_DEVICE }, | |
247 | }; | |
248 | ||
249 | void __init | |
250 | lpd7a400_map_io(void) | |
251 | { | |
252 | iotable_init (lpd7a400_io_desc, ARRAY_SIZE (lpd7a400_io_desc)); | |
253 | ||
254 | /* Fixup (improve) Static Memory Controller settings */ | |
255 | SMC_BCR0 = 0x200039af; /* Boot Flash */ | |
256 | SMC_BCR6 = 0x1000fbe0; /* CPLD */ | |
257 | SMC_BCR7 = 0x1000b2c2; /* Compact Flash */ | |
258 | } | |
259 | ||
260 | #ifdef CONFIG_MACH_LPD7A400 | |
261 | ||
262 | MACHINE_START (LPD7A400, "Logic Product Development LPD7A400-10") | |
e9dea0c6 RK |
263 | /* Maintainer: Marc Singer */ |
264 | .phys_ram = 0xc0000000, | |
265 | .phys_io = 0x80000000, | |
266 | .io_pg_offst = ((io_p2v (0x80000000))>>18) & 0xfffc, | |
267 | .boot_params = 0xc0000100, | |
268 | .map_io = lpd7a400_map_io, | |
269 | .init_irq = lh7a400_init_irq, | |
1da177e4 | 270 | .timer = &lh7a40x_timer, |
e9dea0c6 | 271 | .init_machine = lpd7a40x_init, |
1da177e4 LT |
272 | MACHINE_END |
273 | ||
274 | #endif | |
275 | ||
276 | #ifdef CONFIG_MACH_LPD7A404 | |
277 | ||
278 | MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10") | |
e9dea0c6 RK |
279 | /* Maintainer: Marc Singer */ |
280 | .phys_ram = 0xc0000000, | |
281 | .phys_io = 0x80000000, | |
282 | .io_pg_offst = ((io_p2v (0x80000000))>>18) & 0xfffc, | |
283 | .boot_params = 0xc0000100, | |
284 | .map_io = lpd7a400_map_io, | |
285 | .init_irq = lh7a404_init_irq, | |
1da177e4 | 286 | .timer = &lh7a40x_timer, |
e9dea0c6 | 287 | .init_machine = lpd7a40x_init, |
1da177e4 LT |
288 | MACHINE_END |
289 | ||
290 | #endif |