diff options
| -rw-r--r-- | arch/microblaze/kernel/intc.c | 51 |
1 files changed, 41 insertions, 10 deletions
diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index 581451ad4687..15c7c12ea0e7 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c | |||
| @@ -32,6 +32,29 @@ static void __iomem *intc_baseaddr; | |||
| 32 | #define MER_ME (1<<0) | 32 | #define MER_ME (1<<0) |
| 33 | #define MER_HIE (1<<1) | 33 | #define MER_HIE (1<<1) |
| 34 | 34 | ||
| 35 | static unsigned int (*read_fn)(void __iomem *); | ||
| 36 | static void (*write_fn)(u32, void __iomem *); | ||
| 37 | |||
| 38 | static void intc_write32(u32 val, void __iomem *addr) | ||
| 39 | { | ||
| 40 | iowrite32(val, addr); | ||
| 41 | } | ||
| 42 | |||
| 43 | static unsigned int intc_read32(void __iomem *addr) | ||
| 44 | { | ||
| 45 | return ioread32(addr); | ||
| 46 | } | ||
| 47 | |||
| 48 | static void intc_write32_be(u32 val, void __iomem *addr) | ||
| 49 | { | ||
| 50 | iowrite32be(val, addr); | ||
| 51 | } | ||
| 52 | |||
| 53 | static unsigned int intc_read32_be(void __iomem *addr) | ||
| 54 | { | ||
| 55 | return ioread32be(addr); | ||
| 56 | } | ||
| 57 | |||
| 35 | static void intc_enable_or_unmask(struct irq_data *d) | 58 | static void intc_enable_or_unmask(struct irq_data *d) |
| 36 | { | 59 | { |
| 37 | unsigned long mask = 1 << d->hwirq; | 60 | unsigned long mask = 1 << d->hwirq; |
| @@ -43,21 +66,21 @@ static void intc_enable_or_unmask(struct irq_data *d) | |||
| 43 | * acks the irq before calling the interrupt handler | 66 | * acks the irq before calling the interrupt handler |
| 44 | */ | 67 | */ |
| 45 | if (irqd_is_level_type(d)) | 68 | if (irqd_is_level_type(d)) |
| 46 | out_be32(intc_baseaddr + IAR, mask); | 69 | write_fn(mask, intc_baseaddr + IAR); |
| 47 | 70 | ||
| 48 | out_be32(intc_baseaddr + SIE, mask); | 71 | write_fn(mask, intc_baseaddr + SIE); |
| 49 | } | 72 | } |
| 50 | 73 | ||
| 51 | static void intc_disable_or_mask(struct irq_data *d) | 74 | static void intc_disable_or_mask(struct irq_data *d) |
| 52 | { | 75 | { |
| 53 | pr_debug("disable: %ld\n", d->hwirq); | 76 | pr_debug("disable: %ld\n", d->hwirq); |
| 54 | out_be32(intc_baseaddr + CIE, 1 << d->hwirq); | 77 | write_fn(1 << d->hwirq, intc_baseaddr + CIE); |
| 55 | } | 78 | } |
| 56 | 79 | ||
| 57 | static void intc_ack(struct irq_data *d) | 80 | static void intc_ack(struct irq_data *d) |
| 58 | { | 81 | { |
| 59 | pr_debug("ack: %ld\n", d->hwirq); | 82 | pr_debug("ack: %ld\n", d->hwirq); |
| 60 | out_be32(intc_baseaddr + IAR, 1 << d->hwirq); | 83 | write_fn(1 << d->hwirq, intc_baseaddr + IAR); |
| 61 | } | 84 | } |
| 62 | 85 | ||
| 63 | static void intc_mask_ack(struct irq_data *d) | 86 | static void intc_mask_ack(struct irq_data *d) |
| @@ -65,8 +88,8 @@ static void intc_mask_ack(struct irq_data *d) | |||
| 65 | unsigned long mask = 1 << d->hwirq; | 88 | unsigned long mask = 1 << d->hwirq; |
| 66 | 89 | ||
| 67 | pr_debug("disable_and_ack: %ld\n", d->hwirq); | 90 | pr_debug("disable_and_ack: %ld\n", d->hwirq); |
| 68 | out_be32(intc_baseaddr + CIE, mask); | 91 | write_fn(mask, intc_baseaddr + CIE); |
| 69 | out_be32(intc_baseaddr + IAR, mask); | 92 | write_fn(mask, intc_baseaddr + IAR); |
| 70 | } | 93 | } |
| 71 | 94 | ||
| 72 | static struct irq_chip intc_dev = { | 95 | static struct irq_chip intc_dev = { |
| @@ -83,7 +106,7 @@ unsigned int get_irq(void) | |||
| 83 | { | 106 | { |
| 84 | unsigned int hwirq, irq = -1; | 107 | unsigned int hwirq, irq = -1; |
| 85 | 108 | ||
| 86 | hwirq = in_be32(intc_baseaddr + IVR); | 109 | hwirq = read_fn(intc_baseaddr + IVR); |
| 87 | if (hwirq != -1U) | 110 | if (hwirq != -1U) |
| 88 | irq = irq_find_mapping(root_domain, hwirq); | 111 | irq = irq_find_mapping(root_domain, hwirq); |
| 89 | 112 | ||
| @@ -140,17 +163,25 @@ static int __init xilinx_intc_of_init(struct device_node *intc, | |||
| 140 | pr_info("%s: num_irq=%d, edge=0x%x\n", | 163 | pr_info("%s: num_irq=%d, edge=0x%x\n", |
| 141 | intc->full_name, nr_irq, intr_mask); | 164 | intc->full_name, nr_irq, intr_mask); |
| 142 | 165 | ||
| 166 | write_fn = intc_write32; | ||
| 167 | read_fn = intc_read32; | ||
| 168 | |||
| 143 | /* | 169 | /* |
| 144 | * Disable all external interrupts until they are | 170 | * Disable all external interrupts until they are |
| 145 | * explicity requested. | 171 | * explicity requested. |
| 146 | */ | 172 | */ |
| 147 | out_be32(intc_baseaddr + IER, 0); | 173 | write_fn(0, intc_baseaddr + IER); |
| 148 | 174 | ||
| 149 | /* Acknowledge any pending interrupts just in case. */ | 175 | /* Acknowledge any pending interrupts just in case. */ |
| 150 | out_be32(intc_baseaddr + IAR, 0xffffffff); | 176 | write_fn(0xffffffff, intc_baseaddr + IAR); |
| 151 | 177 | ||
| 152 | /* Turn on the Master Enable. */ | 178 | /* Turn on the Master Enable. */ |
| 153 | out_be32(intc_baseaddr + MER, MER_HIE | MER_ME); | 179 | write_fn(MER_HIE | MER_ME, intc_baseaddr + MER); |
| 180 | if (!(read_fn(intc_baseaddr + MER) & (MER_HIE | MER_ME))) { | ||
| 181 | write_fn = intc_write32_be; | ||
| 182 | read_fn = intc_read32_be; | ||
| 183 | write_fn(MER_HIE | MER_ME, intc_baseaddr + MER); | ||
| 184 | } | ||
| 154 | 185 | ||
| 155 | /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm | 186 | /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm |
| 156 | * lazy and Michal can clean it up to something nicer when he tests | 187 | * lazy and Michal can clean it up to something nicer when he tests |
