diff options
author | Michal Simek <michal.simek@xilinx.com> | 2014-02-24 08:56:32 -0500 |
---|---|---|
committer | Michal Simek <michal.simek@xilinx.com> | 2014-04-07 05:58:32 -0400 |
commit | 1aa1243c339d4c902c0f9c1ced45742729a86e6a (patch) | |
tree | 6d355c9ec0234982540e4b647f1b3c00abd70598 /arch/microblaze | |
parent | cff2ee046e063d887a3af432c23e7ec214b6d09d (diff) |
microblaze: Make intc driver endian aware
Detect endianess directly on the hardware and use
ioread/iowrite functions.
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Diffstat (limited to 'arch/microblaze')
-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 |