]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * arch/arm/mach-ixp4xx/common.c | |
3 | * | |
4 | * Generic code shared across all IXP4XX platforms | |
5 | * | |
6 | * Maintainer: Deepak Saxena <dsaxena@plexity.net> | |
7 | * | |
8 | * Copyright 2002 (c) Intel Corporation | |
9 | * Copyright 2003-2004 (c) MontaVista, Software, Inc. | |
10 | * | |
11 | * This file is licensed under the terms of the GNU General Public | |
12 | * License version 2. This program is licensed "as is" without any | |
13 | * warranty of any kind, whether express or implied. | |
14 | */ | |
15 | ||
1da177e4 LT |
16 | #include <linux/kernel.h> |
17 | #include <linux/mm.h> | |
18 | #include <linux/init.h> | |
19 | #include <linux/serial.h> | |
1da177e4 | 20 | #include <linux/tty.h> |
d052d1be | 21 | #include <linux/platform_device.h> |
1da177e4 | 22 | #include <linux/serial_core.h> |
1da177e4 LT |
23 | #include <linux/interrupt.h> |
24 | #include <linux/bitops.h> | |
fced80c7 | 25 | #include <linux/io.h> |
dc28094b | 26 | #include <linux/export.h> |
f7b861b7 | 27 | #include <linux/cpu.h> |
00e1b3a3 | 28 | #include <linux/pci.h> |
38ff87f7 | 29 | #include <linux/sched_clock.h> |
98ac0cc2 | 30 | #include <linux/bitops.h> |
55ec465e | 31 | #include <linux/irqchip/irq-ixp4xx.h> |
65af6667 | 32 | #include <linux/platform_data/timer-ixp4xx.h> |
a09e64fb RK |
33 | #include <mach/udc.h> |
34 | #include <mach/hardware.h> | |
f449588c | 35 | #include <mach/io.h> |
7c0f6ba6 | 36 | #include <linux/uaccess.h> |
1da177e4 LT |
37 | #include <asm/pgtable.h> |
38 | #include <asm/page.h> | |
98ac0cc2 | 39 | #include <asm/exception.h> |
1da177e4 | 40 | #include <asm/irq.h> |
86dfe446 | 41 | #include <asm/system_misc.h> |
1da177e4 LT |
42 | #include <asm/mach/map.h> |
43 | #include <asm/mach/irq.h> | |
44 | #include <asm/mach/time.h> | |
45 | ||
dc8ef8cd LW |
46 | #include "irqs.h" |
47 | ||
f0402f9b | 48 | #define IXP4XX_TIMER_FREQ 66666000 |
fb3174e4 | 49 | |
1da177e4 LT |
50 | /************************************************************************* |
51 | * IXP4xx chipset I/O mapping | |
52 | *************************************************************************/ | |
53 | static struct map_desc ixp4xx_io_desc[] __initdata = { | |
54 | { /* UART, Interrupt ctrl, GPIO, timers, NPEs, MACs, USB .... */ | |
13ec32f4 | 55 | .virtual = (unsigned long)IXP4XX_PERIPHERAL_BASE_VIRT, |
87fe04bd | 56 | .pfn = __phys_to_pfn(IXP4XX_PERIPHERAL_BASE_PHYS), |
1da177e4 LT |
57 | .length = IXP4XX_PERIPHERAL_REGION_SIZE, |
58 | .type = MT_DEVICE | |
59 | }, { /* Expansion Bus Config Registers */ | |
13ec32f4 | 60 | .virtual = (unsigned long)IXP4XX_EXP_CFG_BASE_VIRT, |
87fe04bd | 61 | .pfn = __phys_to_pfn(IXP4XX_EXP_CFG_BASE_PHYS), |
1da177e4 LT |
62 | .length = IXP4XX_EXP_CFG_REGION_SIZE, |
63 | .type = MT_DEVICE | |
64 | }, { /* PCI Registers */ | |
13ec32f4 | 65 | .virtual = (unsigned long)IXP4XX_PCI_CFG_BASE_VIRT, |
87fe04bd | 66 | .pfn = __phys_to_pfn(IXP4XX_PCI_CFG_BASE_PHYS), |
1da177e4 LT |
67 | .length = IXP4XX_PCI_CFG_REGION_SIZE, |
68 | .type = MT_DEVICE | |
f0cdb153 KH |
69 | }, { /* Queue Manager */ |
70 | .virtual = (unsigned long)IXP4XX_QMGR_BASE_VIRT, | |
71 | .pfn = __phys_to_pfn(IXP4XX_QMGR_BASE_PHYS), | |
72 | .length = IXP4XX_QMGR_REGION_SIZE, | |
73 | .type = MT_DEVICE | |
5932ae3f | 74 | }, |
1da177e4 LT |
75 | }; |
76 | ||
77 | void __init ixp4xx_map_io(void) | |
78 | { | |
79 | iotable_init(ixp4xx_io_desc, ARRAY_SIZE(ixp4xx_io_desc)); | |
80 | } | |
81 | ||
1da177e4 LT |
82 | void __init ixp4xx_init_irq(void) |
83 | { | |
12d2b4e5 NP |
84 | /* |
85 | * ixp4xx does not implement the XScale PWRMODE register | |
86 | * so it must not call cpu_do_idle(). | |
87 | */ | |
f7b861b7 | 88 | cpu_idle_poll_ctrl(true); |
12d2b4e5 | 89 | |
55ec465e LW |
90 | ixp4xx_irq_init(IXP4XX_INTC_BASE_PHYS, |
91 | (cpu_is_ixp46x() || cpu_is_ixp43x())); | |
1da177e4 LT |
92 | } |
93 | ||
435c5da0 | 94 | void __init ixp4xx_timer_init(void) |
1da177e4 | 95 | { |
65af6667 LW |
96 | return ixp4xx_timer_setup(IXP4XX_TIMER_BASE_PHYS, |
97 | IRQ_IXP4XX_TIMER1, | |
98 | IXP4XX_TIMER_FREQ); | |
1da177e4 LT |
99 | } |
100 | ||
e520a36d MS |
101 | static struct pxa2xx_udc_mach_info ixp4xx_udc_info; |
102 | ||
103 | void __init ixp4xx_set_udc_info(struct pxa2xx_udc_mach_info *info) | |
104 | { | |
105 | memcpy(&ixp4xx_udc_info, info, sizeof *info); | |
106 | } | |
107 | ||
108 | static struct resource ixp4xx_udc_resources[] = { | |
109 | [0] = { | |
110 | .start = 0xc800b000, | |
111 | .end = 0xc800bfff, | |
112 | .flags = IORESOURCE_MEM, | |
113 | }, | |
114 | [1] = { | |
115 | .start = IRQ_IXP4XX_USB, | |
116 | .end = IRQ_IXP4XX_USB, | |
117 | .flags = IORESOURCE_IRQ, | |
118 | }, | |
119 | }; | |
120 | ||
55ec465e LW |
121 | static struct resource ixp4xx_gpio_resource[] = { |
122 | { | |
123 | .start = IXP4XX_GPIO_BASE_PHYS, | |
124 | .end = IXP4XX_GPIO_BASE_PHYS + 0xfff, | |
125 | .flags = IORESOURCE_MEM, | |
126 | }, | |
127 | }; | |
128 | ||
129 | static struct platform_device ixp4xx_gpio_device = { | |
130 | .name = "ixp4xx-gpio", | |
131 | .id = -1, | |
132 | .dev = { | |
133 | .coherent_dma_mask = DMA_BIT_MASK(32), | |
134 | }, | |
135 | .resource = ixp4xx_gpio_resource, | |
136 | .num_resources = ARRAY_SIZE(ixp4xx_gpio_resource), | |
137 | }; | |
138 | ||
e520a36d | 139 | /* |
7a857620 | 140 | * USB device controller. The IXP4xx uses the same controller as PXA25X, |
e520a36d MS |
141 | * so we just use the same device. |
142 | */ | |
143 | static struct platform_device ixp4xx_udc_device = { | |
7a857620 | 144 | .name = "pxa25x-udc", |
e520a36d MS |
145 | .id = -1, |
146 | .num_resources = 2, | |
147 | .resource = ixp4xx_udc_resources, | |
148 | .dev = { | |
149 | .platform_data = &ixp4xx_udc_info, | |
150 | }, | |
151 | }; | |
152 | ||
0b458d7b LW |
153 | static struct resource ixp4xx_npe_resources[] = { |
154 | { | |
155 | .start = IXP4XX_NPEA_BASE_PHYS, | |
156 | .end = IXP4XX_NPEA_BASE_PHYS + 0xfff, | |
157 | .flags = IORESOURCE_MEM, | |
158 | }, | |
159 | { | |
160 | .start = IXP4XX_NPEB_BASE_PHYS, | |
161 | .end = IXP4XX_NPEB_BASE_PHYS + 0xfff, | |
162 | .flags = IORESOURCE_MEM, | |
163 | }, | |
164 | { | |
165 | .start = IXP4XX_NPEC_BASE_PHYS, | |
166 | .end = IXP4XX_NPEC_BASE_PHYS + 0xfff, | |
167 | .flags = IORESOURCE_MEM, | |
168 | }, | |
169 | ||
170 | }; | |
171 | ||
bc4d7eaf LW |
172 | static struct platform_device ixp4xx_npe_device = { |
173 | .name = "ixp4xx-npe", | |
174 | .id = -1, | |
0b458d7b LW |
175 | .num_resources = ARRAY_SIZE(ixp4xx_npe_resources), |
176 | .resource = ixp4xx_npe_resources, | |
bc4d7eaf LW |
177 | }; |
178 | ||
81bca32f LW |
179 | static struct platform_device ixp4xx_qmgr_device = { |
180 | .name = "ixp4xx-qmgr", | |
181 | .id = -1, | |
182 | }; | |
183 | ||
e520a36d | 184 | static struct platform_device *ixp4xx_devices[] __initdata = { |
bc4d7eaf | 185 | &ixp4xx_npe_device, |
81bca32f | 186 | &ixp4xx_qmgr_device, |
55ec465e | 187 | &ixp4xx_gpio_device, |
e520a36d MS |
188 | &ixp4xx_udc_device, |
189 | }; | |
190 | ||
1da177e4 LT |
191 | static struct resource ixp46x_i2c_resources[] = { |
192 | [0] = { | |
193 | .start = 0xc8011000, | |
194 | .end = 0xc801101c, | |
195 | .flags = IORESOURCE_MEM, | |
196 | }, | |
197 | [1] = { | |
198 | .start = IRQ_IXP4XX_I2C, | |
199 | .end = IRQ_IXP4XX_I2C, | |
200 | .flags = IORESOURCE_IRQ | |
201 | } | |
202 | }; | |
203 | ||
204 | /* | |
205 | * I2C controller. The IXP46x uses the same block as the IOP3xx, so | |
206 | * we just use the same device name. | |
207 | */ | |
208 | static struct platform_device ixp46x_i2c_controller = { | |
209 | .name = "IOP3xx-I2C", | |
210 | .id = 0, | |
211 | .num_resources = 2, | |
212 | .resource = ixp46x_i2c_resources | |
213 | }; | |
214 | ||
215 | static struct platform_device *ixp46x_devices[] __initdata = { | |
216 | &ixp46x_i2c_controller | |
217 | }; | |
218 | ||
54e269ea | 219 | unsigned long ixp4xx_exp_bus_size; |
1e74c891 | 220 | EXPORT_SYMBOL(ixp4xx_exp_bus_size); |
54e269ea | 221 | |
1da177e4 LT |
222 | void __init ixp4xx_sys_init(void) |
223 | { | |
54e269ea DS |
224 | ixp4xx_exp_bus_size = SZ_16M; |
225 | ||
e520a36d MS |
226 | platform_add_devices(ixp4xx_devices, ARRAY_SIZE(ixp4xx_devices)); |
227 | ||
1da177e4 | 228 | if (cpu_is_ixp46x()) { |
54e269ea DS |
229 | int region; |
230 | ||
1da177e4 LT |
231 | platform_add_devices(ixp46x_devices, |
232 | ARRAY_SIZE(ixp46x_devices)); | |
54e269ea DS |
233 | |
234 | for (region = 0; region < 7; region++) { | |
235 | if((*(IXP4XX_EXP_REG(0x4 * region)) & 0x200)) { | |
236 | ixp4xx_exp_bus_size = SZ_32M; | |
237 | break; | |
238 | } | |
239 | } | |
1da177e4 | 240 | } |
54e269ea | 241 | |
1e74c891 | 242 | printk("IXP4xx: Using %luMiB expansion bus window size\n", |
54e269ea | 243 | ixp4xx_exp_bus_size >> 20); |
1da177e4 LT |
244 | } |
245 | ||
e66a022a | 246 | unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ; |
5dbc4650 | 247 | EXPORT_SYMBOL(ixp4xx_timer_freq); |
d1b860fb | 248 | |
7b6d864b | 249 | void ixp4xx_restart(enum reboot_mode mode, const char *cmd) |
d1b860fb | 250 | { |
97e81acd | 251 | if (mode == REBOOT_SOFT) { |
d1b860fb RK |
252 | /* Jump into ROM at address 0 */ |
253 | soft_restart(0); | |
254 | } else { | |
255 | /* Use on-chip reset capability */ | |
256 | ||
257 | /* set the "key" register to enable access to | |
258 | * "timer" and "enable" registers | |
259 | */ | |
260 | *IXP4XX_OSWK = IXP4XX_WDT_KEY; | |
261 | ||
262 | /* write 0 to the timer register for an immediate reset */ | |
263 | *IXP4XX_OSWT = 0; | |
264 | ||
265 | *IXP4XX_OSWE = IXP4XX_WDT_RESET_ENABLE | IXP4XX_WDT_COUNT_ENABLE; | |
266 | } | |
267 | } | |
f449588c | 268 | |
00e1b3a3 KH |
269 | #ifdef CONFIG_PCI |
270 | static int ixp4xx_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) | |
271 | { | |
272 | return (dma_addr + size) > SZ_64M; | |
273 | } | |
274 | ||
275 | static int ixp4xx_platform_notify_remove(struct device *dev) | |
276 | { | |
277 | if (dev_is_pci(dev)) | |
278 | dmabounce_unregister_dev(dev); | |
279 | ||
280 | return 0; | |
281 | } | |
282 | #endif | |
283 | ||
284 | /* | |
285 | * Setup DMA mask to 64MB on PCI devices and 4 GB on all other things. | |
286 | */ | |
287 | static int ixp4xx_platform_notify(struct device *dev) | |
288 | { | |
289 | dev->dma_mask = &dev->coherent_dma_mask; | |
290 | ||
291 | #ifdef CONFIG_PCI | |
292 | if (dev_is_pci(dev)) { | |
293 | dev->coherent_dma_mask = DMA_BIT_MASK(28); /* 64 MB */ | |
294 | dmabounce_register_dev(dev, 2048, 4096, ixp4xx_needs_bounce); | |
295 | return 0; | |
296 | } | |
297 | #endif | |
298 | ||
299 | dev->coherent_dma_mask = DMA_BIT_MASK(32); | |
300 | return 0; | |
301 | } | |
302 | ||
303 | int dma_set_coherent_mask(struct device *dev, u64 mask) | |
304 | { | |
305 | if (dev_is_pci(dev)) | |
306 | mask &= DMA_BIT_MASK(28); /* 64 MB */ | |
307 | ||
308 | if ((mask & DMA_BIT_MASK(28)) == DMA_BIT_MASK(28)) { | |
309 | dev->coherent_dma_mask = mask; | |
310 | return 0; | |
311 | } | |
312 | ||
313 | return -EIO; /* device wanted sub-64MB mask */ | |
314 | } | |
315 | EXPORT_SYMBOL(dma_set_coherent_mask); | |
316 | ||
f449588c RH |
317 | #ifdef CONFIG_IXP4XX_INDIRECT_PCI |
318 | /* | |
319 | * In the case of using indirect PCI, we simply return the actual PCI | |
320 | * address and our read/write implementation use that to drive the | |
321 | * access registers. If something outside of PCI is ioremap'd, we | |
322 | * fallback to the default. | |
323 | */ | |
324 | ||
9b97173e | 325 | static void __iomem *ixp4xx_ioremap_caller(phys_addr_t addr, size_t size, |
f449588c RH |
326 | unsigned int mtype, void *caller) |
327 | { | |
328 | if (!is_pci_memory(addr)) | |
329 | return __arm_ioremap_caller(addr, size, mtype, caller); | |
330 | ||
331 | return (void __iomem *)addr; | |
332 | } | |
333 | ||
e43b21cb | 334 | static void ixp4xx_iounmap(volatile void __iomem *addr) |
f449588c RH |
335 | { |
336 | if (!is_pci_memory((__force u32)addr)) | |
337 | __iounmap(addr); | |
338 | } | |
00e1b3a3 | 339 | #endif |
f449588c RH |
340 | |
341 | void __init ixp4xx_init_early(void) | |
342 | { | |
00e1b3a3 KH |
343 | platform_notify = ixp4xx_platform_notify; |
344 | #ifdef CONFIG_PCI | |
345 | platform_notify_remove = ixp4xx_platform_notify_remove; | |
346 | #endif | |
347 | #ifdef CONFIG_IXP4XX_INDIRECT_PCI | |
f449588c RH |
348 | arch_ioremap_caller = ixp4xx_ioremap_caller; |
349 | arch_iounmap = ixp4xx_iounmap; | |
f449588c | 350 | #endif |
00e1b3a3 | 351 | } |