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