Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-ixp2000/core.c
10817 views
1
/*
2
* arch/arm/mach-ixp2000/core.c
3
*
4
* Common routines used by all IXP2400/2800 based platforms.
5
*
6
* Author: Deepak Saxena <[email protected]>
7
*
8
* Copyright 2004 (C) MontaVista Software, Inc.
9
*
10
* Based on work Copyright (C) 2002-2003 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/irq.h>
23
#include <linux/serial.h>
24
#include <linux/tty.h>
25
#include <linux/bitops.h>
26
#include <linux/serial_8250.h>
27
#include <linux/mm.h>
28
29
#include <asm/types.h>
30
#include <asm/setup.h>
31
#include <asm/memory.h>
32
#include <mach/hardware.h>
33
#include <asm/irq.h>
34
#include <asm/system.h>
35
#include <asm/tlbflush.h>
36
#include <asm/pgtable.h>
37
38
#include <asm/mach/map.h>
39
#include <asm/mach/time.h>
40
#include <asm/mach/irq.h>
41
42
#include <mach/gpio.h>
43
44
static DEFINE_SPINLOCK(ixp2000_slowport_lock);
45
static unsigned long ixp2000_slowport_irq_flags;
46
47
/*************************************************************************
48
* Slowport access routines
49
*************************************************************************/
50
void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg)
51
{
52
spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags);
53
54
old_cfg->CCR = *IXP2000_SLOWPORT_CCR;
55
old_cfg->WTC = *IXP2000_SLOWPORT_WTC2;
56
old_cfg->RTC = *IXP2000_SLOWPORT_RTC2;
57
old_cfg->PCR = *IXP2000_SLOWPORT_PCR;
58
old_cfg->ADC = *IXP2000_SLOWPORT_ADC;
59
60
ixp2000_reg_write(IXP2000_SLOWPORT_CCR, new_cfg->CCR);
61
ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC);
62
ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC);
63
ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR);
64
ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, new_cfg->ADC);
65
}
66
67
void ixp2000_release_slowport(struct slowport_cfg *old_cfg)
68
{
69
ixp2000_reg_write(IXP2000_SLOWPORT_CCR, old_cfg->CCR);
70
ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC);
71
ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC);
72
ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR);
73
ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, old_cfg->ADC);
74
75
spin_unlock_irqrestore(&ixp2000_slowport_lock,
76
ixp2000_slowport_irq_flags);
77
}
78
79
/*************************************************************************
80
* Chip specific mappings shared by all IXP2000 systems
81
*************************************************************************/
82
static struct map_desc ixp2000_io_desc[] __initdata = {
83
{
84
.virtual = IXP2000_CAP_VIRT_BASE,
85
.pfn = __phys_to_pfn(IXP2000_CAP_PHYS_BASE),
86
.length = IXP2000_CAP_SIZE,
87
.type = MT_DEVICE,
88
}, {
89
.virtual = IXP2000_INTCTL_VIRT_BASE,
90
.pfn = __phys_to_pfn(IXP2000_INTCTL_PHYS_BASE),
91
.length = IXP2000_INTCTL_SIZE,
92
.type = MT_DEVICE,
93
}, {
94
.virtual = IXP2000_PCI_CREG_VIRT_BASE,
95
.pfn = __phys_to_pfn(IXP2000_PCI_CREG_PHYS_BASE),
96
.length = IXP2000_PCI_CREG_SIZE,
97
.type = MT_DEVICE,
98
}, {
99
.virtual = IXP2000_PCI_CSR_VIRT_BASE,
100
.pfn = __phys_to_pfn(IXP2000_PCI_CSR_PHYS_BASE),
101
.length = IXP2000_PCI_CSR_SIZE,
102
.type = MT_DEVICE,
103
}, {
104
.virtual = IXP2000_MSF_VIRT_BASE,
105
.pfn = __phys_to_pfn(IXP2000_MSF_PHYS_BASE),
106
.length = IXP2000_MSF_SIZE,
107
.type = MT_DEVICE,
108
}, {
109
.virtual = IXP2000_SCRATCH_RING_VIRT_BASE,
110
.pfn = __phys_to_pfn(IXP2000_SCRATCH_RING_PHYS_BASE),
111
.length = IXP2000_SCRATCH_RING_SIZE,
112
.type = MT_DEVICE,
113
}, {
114
.virtual = IXP2000_SRAM0_VIRT_BASE,
115
.pfn = __phys_to_pfn(IXP2000_SRAM0_PHYS_BASE),
116
.length = IXP2000_SRAM0_SIZE,
117
.type = MT_DEVICE,
118
}, {
119
.virtual = IXP2000_PCI_IO_VIRT_BASE,
120
.pfn = __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE),
121
.length = IXP2000_PCI_IO_SIZE,
122
.type = MT_DEVICE,
123
}, {
124
.virtual = IXP2000_PCI_CFG0_VIRT_BASE,
125
.pfn = __phys_to_pfn(IXP2000_PCI_CFG0_PHYS_BASE),
126
.length = IXP2000_PCI_CFG0_SIZE,
127
.type = MT_DEVICE,
128
}, {
129
.virtual = IXP2000_PCI_CFG1_VIRT_BASE,
130
.pfn = __phys_to_pfn(IXP2000_PCI_CFG1_PHYS_BASE),
131
.length = IXP2000_PCI_CFG1_SIZE,
132
.type = MT_DEVICE,
133
}
134
};
135
136
void __init ixp2000_map_io(void)
137
{
138
iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc));
139
140
/* Set slowport to 8-bit mode. */
141
ixp2000_reg_wrb(IXP2000_SLOWPORT_FRM, 1);
142
}
143
144
145
/*************************************************************************
146
* Serial port support for IXP2000
147
*************************************************************************/
148
static struct plat_serial8250_port ixp2000_serial_port[] = {
149
{
150
.mapbase = IXP2000_UART_PHYS_BASE,
151
.membase = (char *)(IXP2000_UART_VIRT_BASE + 3),
152
.irq = IRQ_IXP2000_UART,
153
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
154
.iotype = UPIO_MEM,
155
.regshift = 2,
156
.uartclk = 50000000,
157
},
158
{ },
159
};
160
161
static struct resource ixp2000_uart_resource = {
162
.start = IXP2000_UART_PHYS_BASE,
163
.end = IXP2000_UART_PHYS_BASE + 0x1f,
164
.flags = IORESOURCE_MEM,
165
};
166
167
static struct platform_device ixp2000_serial_device = {
168
.name = "serial8250",
169
.id = PLAT8250_DEV_PLATFORM,
170
.dev = {
171
.platform_data = ixp2000_serial_port,
172
},
173
.num_resources = 1,
174
.resource = &ixp2000_uart_resource,
175
};
176
177
void __init ixp2000_uart_init(void)
178
{
179
platform_device_register(&ixp2000_serial_device);
180
}
181
182
183
/*************************************************************************
184
* Timer-tick functions for IXP2000
185
*************************************************************************/
186
static unsigned ticks_per_jiffy;
187
static unsigned ticks_per_usec;
188
static unsigned next_jiffy_time;
189
static volatile unsigned long *missing_jiffy_timer_csr;
190
191
unsigned long ixp2000_gettimeoffset (void)
192
{
193
unsigned long offset;
194
195
offset = next_jiffy_time - *missing_jiffy_timer_csr;
196
197
return offset / ticks_per_usec;
198
}
199
200
static irqreturn_t ixp2000_timer_interrupt(int irq, void *dev_id)
201
{
202
/* clear timer 1 */
203
ixp2000_reg_wrb(IXP2000_T1_CLR, 1);
204
205
while ((signed long)(next_jiffy_time - *missing_jiffy_timer_csr)
206
>= ticks_per_jiffy) {
207
timer_tick();
208
next_jiffy_time -= ticks_per_jiffy;
209
}
210
211
return IRQ_HANDLED;
212
}
213
214
static struct irqaction ixp2000_timer_irq = {
215
.name = "IXP2000 Timer Tick",
216
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
217
.handler = ixp2000_timer_interrupt,
218
};
219
220
void __init ixp2000_init_time(unsigned long tick_rate)
221
{
222
ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
223
ticks_per_usec = tick_rate / 1000000;
224
225
/*
226
* We use timer 1 as our timer interrupt.
227
*/
228
ixp2000_reg_write(IXP2000_T1_CLR, 0);
229
ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1);
230
ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7));
231
232
/*
233
* We use a second timer as a monotonic counter for tracking
234
* missed jiffies. The IXP2000 has four timers, but if we're
235
* on an A-step IXP2800, timer 2 and 3 don't work, so on those
236
* chips we use timer 4. Timer 4 is the only timer that can
237
* be used for the watchdog, so we use timer 2 if we're on a
238
* non-buggy chip.
239
*/
240
if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
241
printk(KERN_INFO "Enabling IXP2800 erratum #25 workaround\n");
242
243
ixp2000_reg_write(IXP2000_T4_CLR, 0);
244
ixp2000_reg_write(IXP2000_T4_CLD, -1);
245
ixp2000_reg_wrb(IXP2000_T4_CTL, (1 << 7));
246
missing_jiffy_timer_csr = IXP2000_T4_CSR;
247
} else {
248
ixp2000_reg_write(IXP2000_T2_CLR, 0);
249
ixp2000_reg_write(IXP2000_T2_CLD, -1);
250
ixp2000_reg_wrb(IXP2000_T2_CTL, (1 << 7));
251
missing_jiffy_timer_csr = IXP2000_T2_CSR;
252
}
253
next_jiffy_time = 0xffffffff;
254
255
/* register for interrupt */
256
setup_irq(IRQ_IXP2000_TIMER1, &ixp2000_timer_irq);
257
}
258
259
/*************************************************************************
260
* GPIO helpers
261
*************************************************************************/
262
static unsigned long GPIO_IRQ_falling_edge;
263
static unsigned long GPIO_IRQ_rising_edge;
264
static unsigned long GPIO_IRQ_level_low;
265
static unsigned long GPIO_IRQ_level_high;
266
267
static void update_gpio_int_csrs(void)
268
{
269
ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
270
ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
271
ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
272
ixp2000_reg_wrb(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
273
}
274
275
void gpio_line_config(int line, int direction)
276
{
277
unsigned long flags;
278
279
local_irq_save(flags);
280
if (direction == GPIO_OUT) {
281
/* if it's an output, it ain't an interrupt anymore */
282
GPIO_IRQ_falling_edge &= ~(1 << line);
283
GPIO_IRQ_rising_edge &= ~(1 << line);
284
GPIO_IRQ_level_low &= ~(1 << line);
285
GPIO_IRQ_level_high &= ~(1 << line);
286
update_gpio_int_csrs();
287
288
ixp2000_reg_wrb(IXP2000_GPIO_PDSR, 1 << line);
289
} else if (direction == GPIO_IN) {
290
ixp2000_reg_wrb(IXP2000_GPIO_PDCR, 1 << line);
291
}
292
local_irq_restore(flags);
293
}
294
EXPORT_SYMBOL(gpio_line_config);
295
296
297
/*************************************************************************
298
* IRQ handling IXP2000
299
*************************************************************************/
300
static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irq_desc *desc)
301
{
302
int i;
303
unsigned long status = *IXP2000_GPIO_INST;
304
305
for (i = 0; i <= 7; i++) {
306
if (status & (1<<i)) {
307
generic_handle_irq(i + IRQ_IXP2000_GPIO0);
308
}
309
}
310
}
311
312
static int ixp2000_GPIO_irq_type(struct irq_data *d, unsigned int type)
313
{
314
int line = d->irq - IRQ_IXP2000_GPIO0;
315
316
/*
317
* First, configure this GPIO line as an input.
318
*/
319
ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
320
321
/*
322
* Then, set the proper trigger type.
323
*/
324
if (type & IRQ_TYPE_EDGE_FALLING)
325
GPIO_IRQ_falling_edge |= 1 << line;
326
else
327
GPIO_IRQ_falling_edge &= ~(1 << line);
328
if (type & IRQ_TYPE_EDGE_RISING)
329
GPIO_IRQ_rising_edge |= 1 << line;
330
else
331
GPIO_IRQ_rising_edge &= ~(1 << line);
332
if (type & IRQ_TYPE_LEVEL_LOW)
333
GPIO_IRQ_level_low |= 1 << line;
334
else
335
GPIO_IRQ_level_low &= ~(1 << line);
336
if (type & IRQ_TYPE_LEVEL_HIGH)
337
GPIO_IRQ_level_high |= 1 << line;
338
else
339
GPIO_IRQ_level_high &= ~(1 << line);
340
update_gpio_int_csrs();
341
342
return 0;
343
}
344
345
static void ixp2000_GPIO_irq_mask_ack(struct irq_data *d)
346
{
347
unsigned int irq = d->irq;
348
349
ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
350
351
ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
352
ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
353
ixp2000_reg_wrb(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
354
}
355
356
static void ixp2000_GPIO_irq_mask(struct irq_data *d)
357
{
358
unsigned int irq = d->irq;
359
360
ixp2000_reg_wrb(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
361
}
362
363
static void ixp2000_GPIO_irq_unmask(struct irq_data *d)
364
{
365
unsigned int irq = d->irq;
366
367
ixp2000_reg_write(IXP2000_GPIO_INSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
368
}
369
370
static struct irq_chip ixp2000_GPIO_irq_chip = {
371
.irq_ack = ixp2000_GPIO_irq_mask_ack,
372
.irq_mask = ixp2000_GPIO_irq_mask,
373
.irq_unmask = ixp2000_GPIO_irq_unmask,
374
.irq_set_type = ixp2000_GPIO_irq_type,
375
};
376
377
static void ixp2000_pci_irq_mask(struct irq_data *d)
378
{
379
unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
380
if (d->irq == IRQ_IXP2000_PCIA)
381
ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26)));
382
else if (d->irq == IRQ_IXP2000_PCIB)
383
ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27)));
384
}
385
386
static void ixp2000_pci_irq_unmask(struct irq_data *d)
387
{
388
unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
389
if (d->irq == IRQ_IXP2000_PCIA)
390
ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 26)));
391
else if (d->irq == IRQ_IXP2000_PCIB)
392
ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 27)));
393
}
394
395
/*
396
* Error interrupts. These are used extensively by the microengine drivers
397
*/
398
static void ixp2000_err_irq_handler(unsigned int irq, struct irq_desc *desc)
399
{
400
int i;
401
unsigned long status = *IXP2000_IRQ_ERR_STATUS;
402
403
for(i = 31; i >= 0; i--) {
404
if(status & (1 << i)) {
405
generic_handle_irq(IRQ_IXP2000_DRAM0_MIN_ERR + i);
406
}
407
}
408
}
409
410
static void ixp2000_err_irq_mask(struct irq_data *d)
411
{
412
ixp2000_reg_write(IXP2000_IRQ_ERR_ENABLE_CLR,
413
(1 << (d->irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
414
}
415
416
static void ixp2000_err_irq_unmask(struct irq_data *d)
417
{
418
ixp2000_reg_write(IXP2000_IRQ_ERR_ENABLE_SET,
419
(1 << (d->irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
420
}
421
422
static struct irq_chip ixp2000_err_irq_chip = {
423
.irq_ack = ixp2000_err_irq_mask,
424
.irq_mask = ixp2000_err_irq_mask,
425
.irq_unmask = ixp2000_err_irq_unmask
426
};
427
428
static struct irq_chip ixp2000_pci_irq_chip = {
429
.irq_ack = ixp2000_pci_irq_mask,
430
.irq_mask = ixp2000_pci_irq_mask,
431
.irq_unmask = ixp2000_pci_irq_unmask
432
};
433
434
static void ixp2000_irq_mask(struct irq_data *d)
435
{
436
ixp2000_reg_wrb(IXP2000_IRQ_ENABLE_CLR, (1 << d->irq));
437
}
438
439
static void ixp2000_irq_unmask(struct irq_data *d)
440
{
441
ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << d->irq));
442
}
443
444
static struct irq_chip ixp2000_irq_chip = {
445
.irq_ack = ixp2000_irq_mask,
446
.irq_mask = ixp2000_irq_mask,
447
.irq_unmask = ixp2000_irq_unmask
448
};
449
450
void __init ixp2000_init_irq(void)
451
{
452
int irq;
453
454
/*
455
* Mask all sources
456
*/
457
ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, 0xffffffff);
458
ixp2000_reg_write(IXP2000_FIQ_ENABLE_CLR, 0xffffffff);
459
460
/* clear all GPIO edge/level detects */
461
ixp2000_reg_write(IXP2000_GPIO_REDR, 0);
462
ixp2000_reg_write(IXP2000_GPIO_FEDR, 0);
463
ixp2000_reg_write(IXP2000_GPIO_LSHR, 0);
464
ixp2000_reg_write(IXP2000_GPIO_LSLR, 0);
465
ixp2000_reg_write(IXP2000_GPIO_INCR, -1);
466
467
/* clear PCI interrupt sources */
468
ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, 0);
469
470
/*
471
* Certain bits in the IRQ status register of the
472
* IXP2000 are reserved. Instead of trying to map
473
* things non 1:1 from bit position to IRQ number,
474
* we mark the reserved IRQs as invalid. This makes
475
* our mask/unmask code much simpler.
476
*/
477
for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) {
478
if ((1 << irq) & IXP2000_VALID_IRQ_MASK) {
479
irq_set_chip_and_handler(irq, &ixp2000_irq_chip,
480
handle_level_irq);
481
set_irq_flags(irq, IRQF_VALID);
482
} else set_irq_flags(irq, 0);
483
}
484
485
for (irq = IRQ_IXP2000_DRAM0_MIN_ERR; irq <= IRQ_IXP2000_SP_INT; irq++) {
486
if((1 << (irq - IRQ_IXP2000_DRAM0_MIN_ERR)) &
487
IXP2000_VALID_ERR_IRQ_MASK) {
488
irq_set_chip_and_handler(irq, &ixp2000_err_irq_chip,
489
handle_level_irq);
490
set_irq_flags(irq, IRQF_VALID);
491
}
492
else
493
set_irq_flags(irq, 0);
494
}
495
irq_set_chained_handler(IRQ_IXP2000_ERRSUM, ixp2000_err_irq_handler);
496
497
for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) {
498
irq_set_chip_and_handler(irq, &ixp2000_GPIO_irq_chip,
499
handle_level_irq);
500
set_irq_flags(irq, IRQF_VALID);
501
}
502
irq_set_chained_handler(IRQ_IXP2000_GPIO, ixp2000_GPIO_irq_handler);
503
504
/*
505
* Enable PCI irqs. The actual PCI[AB] decoding is done in
506
* entry-macro.S, so we don't need a chained handler for the
507
* PCI interrupt source.
508
*/
509
ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << IRQ_IXP2000_PCI));
510
for (irq = IRQ_IXP2000_PCIA; irq <= IRQ_IXP2000_PCIB; irq++) {
511
irq_set_chip_and_handler(irq, &ixp2000_pci_irq_chip,
512
handle_level_irq);
513
set_irq_flags(irq, IRQF_VALID);
514
}
515
}
516
517
518