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