]> Pileus Git - ~andy/linux/blob - arch/arm/mach-ixp23xx/core.c
Merge tag 'split-asm_system_h-for-linus-20120328' of git://git.kernel.org/pub/scm...
[~andy/linux] / arch / arm / mach-ixp23xx / core.c
1 /*
2  * arch/arm/mach-ixp23xx/core.c
3  *
4  * Core routines for IXP23xx chips
5  *
6  * Author: Deepak Saxena <dsaxena@plexity.net>
7  *
8  * Copyright 2005 (c) MontaVista Software, Inc.
9  *
10  * Based on 2.4 code Copyright 2004 (c) Intel Corporation
11  *
12  * This file is licensed under the terms of the GNU General Public
13  * License version 2. This program is licensed "as is" without any
14  * warranty of any kind, whether express or implied.
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/init.h>
19 #include <linux/spinlock.h>
20 #include <linux/sched.h>
21 #include <linux/interrupt.h>
22 #include <linux/serial.h>
23 #include <linux/tty.h>
24 #include <linux/bitops.h>
25 #include <linux/serial_8250.h>
26 #include <linux/serial_core.h>
27 #include <linux/device.h>
28 #include <linux/mm.h>
29 #include <linux/time.h>
30 #include <linux/timex.h>
31
32 #include <asm/types.h>
33 #include <asm/setup.h>
34 #include <asm/memory.h>
35 #include <mach/hardware.h>
36 #include <asm/irq.h>
37 #include <asm/tlbflush.h>
38 #include <asm/pgtable.h>
39
40 #include <asm/mach/map.h>
41 #include <asm/mach/time.h>
42 #include <asm/mach/irq.h>
43 #include <asm/mach/arch.h>
44
45
46 /*************************************************************************
47  * Chip specific mappings shared by all IXP23xx systems
48  *************************************************************************/
49 static struct map_desc ixp23xx_io_desc[] __initdata = {
50         { /* XSI-CPP CSRs */
51                 .virtual        = IXP23XX_XSI2CPP_CSR_VIRT,
52                 .pfn            = __phys_to_pfn(IXP23XX_XSI2CPP_CSR_PHYS),
53                 .length         = IXP23XX_XSI2CPP_CSR_SIZE,
54                 .type           = MT_DEVICE,
55         }, { /* Expansion Bus Config */
56                 .virtual        = IXP23XX_EXP_CFG_VIRT,
57                 .pfn            = __phys_to_pfn(IXP23XX_EXP_CFG_PHYS),
58                 .length         = IXP23XX_EXP_CFG_SIZE,
59                 .type           = MT_DEVICE,
60         }, { /* UART, Interrupt ctrl, GPIO, timers, NPEs, MACS,.... */
61                 .virtual        = IXP23XX_PERIPHERAL_VIRT,
62                 .pfn            = __phys_to_pfn(IXP23XX_PERIPHERAL_PHYS),
63                 .length         = IXP23XX_PERIPHERAL_SIZE,
64                 .type           = MT_DEVICE,
65         }, { /* CAP CSRs */
66                 .virtual        = IXP23XX_CAP_CSR_VIRT,
67                 .pfn            = __phys_to_pfn(IXP23XX_CAP_CSR_PHYS),
68                 .length         = IXP23XX_CAP_CSR_SIZE,
69                 .type           = MT_DEVICE,
70         }, { /* MSF CSRs */
71                 .virtual        = IXP23XX_MSF_CSR_VIRT,
72                 .pfn            = __phys_to_pfn(IXP23XX_MSF_CSR_PHYS),
73                 .length         = IXP23XX_MSF_CSR_SIZE,
74                 .type           = MT_DEVICE,
75         }, { /* PCI I/O Space */
76                 .virtual        = IXP23XX_PCI_IO_VIRT,
77                 .pfn            = __phys_to_pfn(IXP23XX_PCI_IO_PHYS),
78                 .length         = IXP23XX_PCI_IO_SIZE,
79                 .type           = MT_DEVICE,
80         }, { /* PCI Config Space */
81                 .virtual        = IXP23XX_PCI_CFG_VIRT,
82                 .pfn            = __phys_to_pfn(IXP23XX_PCI_CFG_PHYS),
83                 .length         = IXP23XX_PCI_CFG_SIZE,
84                 .type           = MT_DEVICE,
85         }, { /* PCI local CFG CSRs */
86                 .virtual        = IXP23XX_PCI_CREG_VIRT,
87                 .pfn            = __phys_to_pfn(IXP23XX_PCI_CREG_PHYS),
88                 .length         = IXP23XX_PCI_CREG_SIZE,
89                 .type           = MT_DEVICE,
90         }, { /* PCI MEM Space */
91                 .virtual        = IXP23XX_PCI_MEM_VIRT,
92                 .pfn            = __phys_to_pfn(IXP23XX_PCI_MEM_PHYS),
93                 .length         = IXP23XX_PCI_MEM_SIZE,
94                 .type           = MT_DEVICE,
95         }
96 };
97
98 void __init ixp23xx_map_io(void)
99 {
100         iotable_init(ixp23xx_io_desc, ARRAY_SIZE(ixp23xx_io_desc));
101 }
102
103
104 /***************************************************************************
105  * IXP23xx Interrupt Handling
106  ***************************************************************************/
107 enum ixp23xx_irq_type {
108         IXP23XX_IRQ_LEVEL, IXP23XX_IRQ_EDGE
109 };
110
111 static void ixp23xx_config_irq(unsigned int, enum ixp23xx_irq_type);
112
113 static int ixp23xx_irq_set_type(struct irq_data *d, unsigned int type)
114 {
115         int line = d->irq - IRQ_IXP23XX_GPIO6 + 6;
116         u32 int_style;
117         enum ixp23xx_irq_type irq_type;
118         volatile u32 *int_reg;
119
120         /*
121          * Only GPIOs 6-15 are wired to interrupts on IXP23xx
122          */
123         if (line < 6 || line > 15)
124                 return -EINVAL;
125
126         switch (type) {
127         case IRQ_TYPE_EDGE_BOTH:
128                 int_style = IXP23XX_GPIO_STYLE_TRANSITIONAL;
129                 irq_type = IXP23XX_IRQ_EDGE;
130                 break;
131         case IRQ_TYPE_EDGE_RISING:
132                 int_style = IXP23XX_GPIO_STYLE_RISING_EDGE;
133                 irq_type = IXP23XX_IRQ_EDGE;
134                 break;
135         case IRQ_TYPE_EDGE_FALLING:
136                 int_style = IXP23XX_GPIO_STYLE_FALLING_EDGE;
137                 irq_type = IXP23XX_IRQ_EDGE;
138                 break;
139         case IRQ_TYPE_LEVEL_HIGH:
140                 int_style = IXP23XX_GPIO_STYLE_ACTIVE_HIGH;
141                 irq_type = IXP23XX_IRQ_LEVEL;
142                 break;
143         case IRQ_TYPE_LEVEL_LOW:
144                 int_style = IXP23XX_GPIO_STYLE_ACTIVE_LOW;
145                 irq_type = IXP23XX_IRQ_LEVEL;
146                 break;
147         default:
148                 return -EINVAL;
149         }
150
151         ixp23xx_config_irq(d->irq, irq_type);
152
153         if (line >= 8) {        /* pins 8-15 */
154                 line -= 8;
155                 int_reg = (volatile u32 *)IXP23XX_GPIO_GPIT2R;
156         } else {                /* pins 0-7 */
157                 int_reg = (volatile u32 *)IXP23XX_GPIO_GPIT1R;
158         }
159
160         /*
161          * Clear pending interrupts
162          */
163         *IXP23XX_GPIO_GPISR = (1 << line);
164
165         /* Clear the style for the appropriate pin */
166         *int_reg &= ~(IXP23XX_GPIO_STYLE_MASK <<
167                         (line * IXP23XX_GPIO_STYLE_SIZE));
168
169         /* Set the new style */
170         *int_reg |= (int_style << (line * IXP23XX_GPIO_STYLE_SIZE));
171
172         return 0;
173 }
174
175 static void ixp23xx_irq_mask(struct irq_data *d)
176 {
177         volatile unsigned long *intr_reg;
178         unsigned int irq = d->irq;
179
180         if (irq >= 56)
181                 irq += 8;
182
183         intr_reg = IXP23XX_INTR_EN1 + (irq / 32);
184         *intr_reg &= ~(1 << (irq % 32));
185 }
186
187 static void ixp23xx_irq_ack(struct irq_data *d)
188 {
189         int line = d->irq - IRQ_IXP23XX_GPIO6 + 6;
190
191         if ((line < 6) || (line > 15))
192                 return;
193
194         *IXP23XX_GPIO_GPISR = (1 << line);
195 }
196
197 /*
198  * Level triggered interrupts on GPIO lines can only be cleared when the
199  * interrupt condition disappears.
200  */
201 static void ixp23xx_irq_level_unmask(struct irq_data *d)
202 {
203         volatile unsigned long *intr_reg;
204         unsigned int irq = d->irq;
205
206         ixp23xx_irq_ack(d);
207
208         if (irq >= 56)
209                 irq += 8;
210
211         intr_reg = IXP23XX_INTR_EN1 + (irq / 32);
212         *intr_reg |= (1 << (irq % 32));
213 }
214
215 static void ixp23xx_irq_edge_unmask(struct irq_data *d)
216 {
217         volatile unsigned long *intr_reg;
218         unsigned int irq = d->irq;
219
220         if (irq >= 56)
221                 irq += 8;
222
223         intr_reg = IXP23XX_INTR_EN1 + (irq / 32);
224         *intr_reg |= (1 << (irq % 32));
225 }
226
227 static struct irq_chip ixp23xx_irq_level_chip = {
228         .irq_ack        = ixp23xx_irq_mask,
229         .irq_mask       = ixp23xx_irq_mask,
230         .irq_unmask     = ixp23xx_irq_level_unmask,
231         .irq_set_type   = ixp23xx_irq_set_type
232 };
233
234 static struct irq_chip ixp23xx_irq_edge_chip = {
235         .irq_ack        = ixp23xx_irq_ack,
236         .irq_mask       = ixp23xx_irq_mask,
237         .irq_unmask     = ixp23xx_irq_edge_unmask,
238         .irq_set_type   = ixp23xx_irq_set_type
239 };
240
241 static void ixp23xx_pci_irq_mask(struct irq_data *d)
242 {
243         unsigned int irq = d->irq;
244
245         *IXP23XX_PCI_XSCALE_INT_ENABLE &= ~(1 << (IRQ_IXP23XX_INTA + 27 - irq));
246 }
247
248 static void ixp23xx_pci_irq_unmask(struct irq_data *d)
249 {
250         unsigned int irq = d->irq;
251
252         *IXP23XX_PCI_XSCALE_INT_ENABLE |= (1 << (IRQ_IXP23XX_INTA + 27 - irq));
253 }
254
255 /*
256  * TODO: Should this just be done at ASM level?
257  */
258 static void pci_handler(unsigned int irq, struct irq_desc *desc)
259 {
260         u32 pci_interrupt;
261         unsigned int irqno;
262
263         pci_interrupt = *IXP23XX_PCI_XSCALE_INT_STATUS;
264
265         desc->irq_data.chip->irq_ack(&desc->irq_data);
266
267         /* See which PCI_INTA, or PCI_INTB interrupted */
268         if (pci_interrupt & (1 << 26)) {
269                 irqno = IRQ_IXP23XX_INTB;
270         } else if (pci_interrupt & (1 << 27)) {
271                 irqno = IRQ_IXP23XX_INTA;
272         } else {
273                 BUG();
274         }
275
276         generic_handle_irq(irqno);
277
278         desc->irq_data.chip->irq_unmask(&desc->irq_data);
279 }
280
281 static struct irq_chip ixp23xx_pci_irq_chip = {
282         .irq_ack        = ixp23xx_pci_irq_mask,
283         .irq_mask       = ixp23xx_pci_irq_mask,
284         .irq_unmask     = ixp23xx_pci_irq_unmask
285 };
286
287 static void ixp23xx_config_irq(unsigned int irq, enum ixp23xx_irq_type type)
288 {
289         switch (type) {
290         case IXP23XX_IRQ_LEVEL:
291                 irq_set_chip_and_handler(irq, &ixp23xx_irq_level_chip,
292                                          handle_level_irq);
293                 break;
294         case IXP23XX_IRQ_EDGE:
295                 irq_set_chip_and_handler(irq, &ixp23xx_irq_edge_chip,
296                                          handle_edge_irq);
297                 break;
298         }
299         set_irq_flags(irq, IRQF_VALID);
300 }
301
302 void __init ixp23xx_init_irq(void)
303 {
304         int irq;
305
306         /* Route everything to IRQ */
307         *IXP23XX_INTR_SEL1 = 0x0;
308         *IXP23XX_INTR_SEL2 = 0x0;
309         *IXP23XX_INTR_SEL3 = 0x0;
310         *IXP23XX_INTR_SEL4 = 0x0;
311
312         /* Mask all sources */
313         *IXP23XX_INTR_EN1 = 0x0;
314         *IXP23XX_INTR_EN2 = 0x0;
315         *IXP23XX_INTR_EN3 = 0x0;
316         *IXP23XX_INTR_EN4 = 0x0;
317
318         /*
319          * Configure all IRQs for level-sensitive operation
320          */
321         for (irq = 0; irq <= NUM_IXP23XX_RAW_IRQS; irq++) {
322                 ixp23xx_config_irq(irq, IXP23XX_IRQ_LEVEL);
323         }
324
325         for (irq = IRQ_IXP23XX_INTA; irq <= IRQ_IXP23XX_INTB; irq++) {
326                 irq_set_chip_and_handler(irq, &ixp23xx_pci_irq_chip,
327                                          handle_level_irq);
328                 set_irq_flags(irq, IRQF_VALID);
329         }
330
331         irq_set_chained_handler(IRQ_IXP23XX_PCI_INT_RPH, pci_handler);
332 }
333
334
335 /*************************************************************************
336  * Timer-tick functions for IXP23xx
337  *************************************************************************/
338 #define CLOCK_TICKS_PER_USEC    (CLOCK_TICK_RATE / USEC_PER_SEC)
339
340 static unsigned long next_jiffy_time;
341
342 static unsigned long
343 ixp23xx_gettimeoffset(void)
344 {
345         unsigned long elapsed;
346
347         elapsed = *IXP23XX_TIMER_CONT - (next_jiffy_time - LATCH);
348
349         return elapsed / CLOCK_TICKS_PER_USEC;
350 }
351
352 static irqreturn_t
353 ixp23xx_timer_interrupt(int irq, void *dev_id)
354 {
355         /* Clear Pending Interrupt by writing '1' to it */
356         *IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND;
357         while ((signed long)(*IXP23XX_TIMER_CONT - next_jiffy_time) >= LATCH) {
358                 timer_tick();
359                 next_jiffy_time += LATCH;
360         }
361
362         return IRQ_HANDLED;
363 }
364
365 static struct irqaction ixp23xx_timer_irq = {
366         .name           = "IXP23xx Timer Tick",
367         .handler        = ixp23xx_timer_interrupt,
368         .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
369 };
370
371 void __init ixp23xx_init_timer(void)
372 {
373         /* Clear Pending Interrupt by writing '1' to it */
374         *IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND;
375
376         /* Setup the Timer counter value */
377         *IXP23XX_TIMER1_RELOAD =
378                 (LATCH & ~IXP23XX_TIMER_RELOAD_MASK) | IXP23XX_TIMER_ENABLE;
379
380         *IXP23XX_TIMER_CONT = 0;
381         next_jiffy_time = LATCH;
382
383         /* Connect the interrupt handler and enable the interrupt */
384         setup_irq(IRQ_IXP23XX_TIMER1, &ixp23xx_timer_irq);
385 }
386
387 struct sys_timer ixp23xx_timer = {
388         .init           = ixp23xx_init_timer,
389         .offset         = ixp23xx_gettimeoffset,
390 };
391
392
393 /*************************************************************************
394  * IXP23xx Platform Initialization
395  *************************************************************************/
396 static struct resource ixp23xx_uart_resources[] = {
397         {
398                 .start          = IXP23XX_UART1_PHYS,
399                 .end            = IXP23XX_UART1_PHYS + 0x0fff,
400                 .flags          = IORESOURCE_MEM
401         }, {
402                 .start          = IXP23XX_UART2_PHYS,
403                 .end            = IXP23XX_UART2_PHYS + 0x0fff,
404                 .flags          = IORESOURCE_MEM
405         }
406 };
407
408 static struct plat_serial8250_port ixp23xx_uart_data[] = {
409         {
410                 .mapbase        = IXP23XX_UART1_PHYS,
411                 .membase        = (char *)(IXP23XX_UART1_VIRT + 3),
412                 .irq            = IRQ_IXP23XX_UART1,
413                 .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
414                 .iotype         = UPIO_MEM,
415                 .regshift       = 2,
416                 .uartclk        = IXP23XX_UART_XTAL,
417         }, {
418                 .mapbase        = IXP23XX_UART2_PHYS,
419                 .membase        = (char *)(IXP23XX_UART2_VIRT + 3),
420                 .irq            = IRQ_IXP23XX_UART2,
421                 .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
422                 .iotype         = UPIO_MEM,
423                 .regshift       = 2,
424                 .uartclk        = IXP23XX_UART_XTAL,
425         },
426         { },
427 };
428
429 static struct platform_device ixp23xx_uart = {
430         .name                   = "serial8250",
431         .id                     = 0,
432         .dev.platform_data      = ixp23xx_uart_data,
433         .num_resources          = 2,
434         .resource               = ixp23xx_uart_resources,
435 };
436
437 static struct platform_device *ixp23xx_devices[] __initdata = {
438         &ixp23xx_uart,
439 };
440
441 void __init ixp23xx_sys_init(void)
442 {
443         /* by default, the idle code is disabled */
444         disable_hlt();
445
446         *IXP23XX_EXP_UNIT_FUSE |= 0xf;
447         platform_add_devices(ixp23xx_devices, ARRAY_SIZE(ixp23xx_devices));
448 }
449
450 void ixp23xx_restart(char mode, const char *cmd)
451 {
452         /* Use on-chip reset capability */
453         *IXP23XX_RESET0 |= IXP23XX_RST_ALL;
454 }