diff options
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r-- | arch/powerpc/sysdev/fsl_soc.c | 46 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 16 | ||||
-rw-r--r-- | arch/powerpc/sysdev/xilinx_intc.c | 117 |
3 files changed, 116 insertions, 63 deletions
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index afe8dbc964aa..5c64ccd402e2 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
@@ -208,52 +208,6 @@ static int __init of_add_fixed_phys(void) | |||
208 | arch_initcall(of_add_fixed_phys); | 208 | arch_initcall(of_add_fixed_phys); |
209 | #endif /* CONFIG_FIXED_PHY */ | 209 | #endif /* CONFIG_FIXED_PHY */ |
210 | 210 | ||
211 | #ifdef CONFIG_PPC_83xx | ||
212 | static int __init mpc83xx_wdt_init(void) | ||
213 | { | ||
214 | struct resource r; | ||
215 | struct device_node *np; | ||
216 | struct platform_device *dev; | ||
217 | u32 freq = fsl_get_sys_freq(); | ||
218 | int ret; | ||
219 | |||
220 | np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt"); | ||
221 | |||
222 | if (!np) { | ||
223 | ret = -ENODEV; | ||
224 | goto nodev; | ||
225 | } | ||
226 | |||
227 | memset(&r, 0, sizeof(r)); | ||
228 | |||
229 | ret = of_address_to_resource(np, 0, &r); | ||
230 | if (ret) | ||
231 | goto err; | ||
232 | |||
233 | dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1); | ||
234 | if (IS_ERR(dev)) { | ||
235 | ret = PTR_ERR(dev); | ||
236 | goto err; | ||
237 | } | ||
238 | |||
239 | ret = platform_device_add_data(dev, &freq, sizeof(freq)); | ||
240 | if (ret) | ||
241 | goto unreg; | ||
242 | |||
243 | of_node_put(np); | ||
244 | return 0; | ||
245 | |||
246 | unreg: | ||
247 | platform_device_unregister(dev); | ||
248 | err: | ||
249 | of_node_put(np); | ||
250 | nodev: | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | arch_initcall(mpc83xx_wdt_init); | ||
255 | #endif | ||
256 | |||
257 | static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) | 211 | static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) |
258 | { | 212 | { |
259 | if (!phy_type) | 213 | if (!phy_type) |
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 21b956701596..0efc12d1a3d7 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -1057,13 +1057,6 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1057 | memset(mpic, 0, sizeof(struct mpic)); | 1057 | memset(mpic, 0, sizeof(struct mpic)); |
1058 | mpic->name = name; | 1058 | mpic->name = name; |
1059 | 1059 | ||
1060 | mpic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, | ||
1061 | isu_size, &mpic_host_ops, | ||
1062 | flags & MPIC_LARGE_VECTORS ? 2048 : 256); | ||
1063 | if (mpic->irqhost == NULL) | ||
1064 | return NULL; | ||
1065 | |||
1066 | mpic->irqhost->host_data = mpic; | ||
1067 | mpic->hc_irq = mpic_irq_chip; | 1060 | mpic->hc_irq = mpic_irq_chip; |
1068 | mpic->hc_irq.typename = name; | 1061 | mpic->hc_irq.typename = name; |
1069 | if (flags & MPIC_PRIMARY) | 1062 | if (flags & MPIC_PRIMARY) |
@@ -1213,6 +1206,15 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1213 | mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); | 1206 | mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); |
1214 | mpic->isu_mask = (1 << mpic->isu_shift) - 1; | 1207 | mpic->isu_mask = (1 << mpic->isu_shift) - 1; |
1215 | 1208 | ||
1209 | mpic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, | ||
1210 | isu_size ? isu_size : mpic->num_sources, | ||
1211 | &mpic_host_ops, | ||
1212 | flags & MPIC_LARGE_VECTORS ? 2048 : 256); | ||
1213 | if (mpic->irqhost == NULL) | ||
1214 | return NULL; | ||
1215 | |||
1216 | mpic->irqhost->host_data = mpic; | ||
1217 | |||
1216 | /* Display version */ | 1218 | /* Display version */ |
1217 | switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) { | 1219 | switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) { |
1218 | case 1: | 1220 | case 1: |
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index a22e1a2df1af..c658b413c9b4 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c | |||
@@ -41,8 +41,32 @@ | |||
41 | 41 | ||
42 | static struct irq_host *master_irqhost; | 42 | static struct irq_host *master_irqhost; |
43 | 43 | ||
44 | #define XILINX_INTC_MAXIRQS (32) | ||
45 | |||
46 | /* The following table allows the interrupt type, edge or level, | ||
47 | * to be cached after being read from the device tree until the interrupt | ||
48 | * is mapped | ||
49 | */ | ||
50 | static int xilinx_intc_typetable[XILINX_INTC_MAXIRQS]; | ||
51 | |||
52 | /* Map the interrupt type from the device tree to the interrupt types | ||
53 | * used by the interrupt subsystem | ||
54 | */ | ||
55 | static unsigned char xilinx_intc_map_senses[] = { | ||
56 | IRQ_TYPE_EDGE_RISING, | ||
57 | IRQ_TYPE_EDGE_FALLING, | ||
58 | IRQ_TYPE_LEVEL_HIGH, | ||
59 | IRQ_TYPE_LEVEL_LOW, | ||
60 | }; | ||
61 | |||
44 | /* | 62 | /* |
45 | * IRQ Chip operations | 63 | * The interrupt controller is setup such that it doesn't work well with |
64 | * the level interrupt handler in the kernel because the handler acks the | ||
65 | * interrupt before calling the application interrupt handler. To deal with | ||
66 | * that, we use 2 different irq chips so that different functions can be | ||
67 | * used for level and edge type interrupts. | ||
68 | * | ||
69 | * IRQ Chip common (across level and edge) operations | ||
46 | */ | 70 | */ |
47 | static void xilinx_intc_mask(unsigned int virq) | 71 | static void xilinx_intc_mask(unsigned int virq) |
48 | { | 72 | { |
@@ -52,15 +76,54 @@ static void xilinx_intc_mask(unsigned int virq) | |||
52 | out_be32(regs + XINTC_CIE, 1 << irq); | 76 | out_be32(regs + XINTC_CIE, 1 << irq); |
53 | } | 77 | } |
54 | 78 | ||
55 | static void xilinx_intc_unmask(unsigned int virq) | 79 | static int xilinx_intc_set_type(unsigned int virq, unsigned int flow_type) |
80 | { | ||
81 | struct irq_desc *desc = get_irq_desc(virq); | ||
82 | |||
83 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | ||
84 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; | ||
85 | if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) | ||
86 | desc->status |= IRQ_LEVEL; | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * IRQ Chip level operations | ||
92 | */ | ||
93 | static void xilinx_intc_level_unmask(unsigned int virq) | ||
56 | { | 94 | { |
57 | int irq = virq_to_hw(virq); | 95 | int irq = virq_to_hw(virq); |
58 | void * regs = get_irq_chip_data(virq); | 96 | void * regs = get_irq_chip_data(virq); |
59 | pr_debug("unmask: %d\n", irq); | 97 | pr_debug("unmask: %d\n", irq); |
60 | out_be32(regs + XINTC_SIE, 1 << irq); | 98 | out_be32(regs + XINTC_SIE, 1 << irq); |
99 | |||
100 | /* ack level irqs because they can't be acked during | ||
101 | * ack function since the handle_level_irq function | ||
102 | * acks the irq before calling the inerrupt handler | ||
103 | */ | ||
104 | out_be32(regs + XINTC_IAR, 1 << irq); | ||
61 | } | 105 | } |
62 | 106 | ||
63 | static void xilinx_intc_ack(unsigned int virq) | 107 | static struct irq_chip xilinx_intc_level_irqchip = { |
108 | .typename = "Xilinx Level INTC", | ||
109 | .mask = xilinx_intc_mask, | ||
110 | .mask_ack = xilinx_intc_mask, | ||
111 | .unmask = xilinx_intc_level_unmask, | ||
112 | .set_type = xilinx_intc_set_type, | ||
113 | }; | ||
114 | |||
115 | /* | ||
116 | * IRQ Chip edge operations | ||
117 | */ | ||
118 | static void xilinx_intc_edge_unmask(unsigned int virq) | ||
119 | { | ||
120 | int irq = virq_to_hw(virq); | ||
121 | void *regs = get_irq_chip_data(virq); | ||
122 | pr_debug("unmask: %d\n", irq); | ||
123 | out_be32(regs + XINTC_SIE, 1 << irq); | ||
124 | } | ||
125 | |||
126 | static void xilinx_intc_edge_ack(unsigned int virq) | ||
64 | { | 127 | { |
65 | int irq = virq_to_hw(virq); | 128 | int irq = virq_to_hw(virq); |
66 | void * regs = get_irq_chip_data(virq); | 129 | void * regs = get_irq_chip_data(virq); |
@@ -68,27 +131,60 @@ static void xilinx_intc_ack(unsigned int virq) | |||
68 | out_be32(regs + XINTC_IAR, 1 << irq); | 131 | out_be32(regs + XINTC_IAR, 1 << irq); |
69 | } | 132 | } |
70 | 133 | ||
71 | static struct irq_chip xilinx_intc_irqchip = { | 134 | static struct irq_chip xilinx_intc_edge_irqchip = { |
72 | .typename = "Xilinx INTC", | 135 | .typename = "Xilinx Edge INTC", |
73 | .mask = xilinx_intc_mask, | 136 | .mask = xilinx_intc_mask, |
74 | .unmask = xilinx_intc_unmask, | 137 | .unmask = xilinx_intc_edge_unmask, |
75 | .ack = xilinx_intc_ack, | 138 | .ack = xilinx_intc_edge_ack, |
139 | .set_type = xilinx_intc_set_type, | ||
76 | }; | 140 | }; |
77 | 141 | ||
78 | /* | 142 | /* |
79 | * IRQ Host operations | 143 | * IRQ Host operations |
80 | */ | 144 | */ |
145 | |||
146 | /** | ||
147 | * xilinx_intc_xlate - translate virq# from device tree interrupts property | ||
148 | */ | ||
149 | static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct, | ||
150 | u32 *intspec, unsigned int intsize, | ||
151 | irq_hw_number_t *out_hwirq, | ||
152 | unsigned int *out_flags) | ||
153 | { | ||
154 | if ((intsize < 2) || (intspec[0] >= XILINX_INTC_MAXIRQS)) | ||
155 | return -EINVAL; | ||
156 | |||
157 | /* keep a copy of the interrupt type til the interrupt is mapped | ||
158 | */ | ||
159 | xilinx_intc_typetable[intspec[0]] = xilinx_intc_map_senses[intspec[1]]; | ||
160 | |||
161 | /* Xilinx uses 2 interrupt entries, the 1st being the h/w | ||
162 | * interrupt number, the 2nd being the interrupt type, edge or level | ||
163 | */ | ||
164 | *out_hwirq = intspec[0]; | ||
165 | *out_flags = xilinx_intc_map_senses[intspec[1]]; | ||
166 | |||
167 | return 0; | ||
168 | } | ||
81 | static int xilinx_intc_map(struct irq_host *h, unsigned int virq, | 169 | static int xilinx_intc_map(struct irq_host *h, unsigned int virq, |
82 | irq_hw_number_t irq) | 170 | irq_hw_number_t irq) |
83 | { | 171 | { |
84 | set_irq_chip_data(virq, h->host_data); | 172 | set_irq_chip_data(virq, h->host_data); |
85 | set_irq_chip_and_handler(virq, &xilinx_intc_irqchip, handle_level_irq); | 173 | |
86 | set_irq_type(virq, IRQ_TYPE_NONE); | 174 | if (xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_HIGH || |
175 | xilinx_intc_typetable[irq] == IRQ_TYPE_LEVEL_LOW) { | ||
176 | set_irq_chip_and_handler(virq, &xilinx_intc_level_irqchip, | ||
177 | handle_level_irq); | ||
178 | } else { | ||
179 | set_irq_chip_and_handler(virq, &xilinx_intc_edge_irqchip, | ||
180 | handle_edge_irq); | ||
181 | } | ||
87 | return 0; | 182 | return 0; |
88 | } | 183 | } |
89 | 184 | ||
90 | static struct irq_host_ops xilinx_intc_ops = { | 185 | static struct irq_host_ops xilinx_intc_ops = { |
91 | .map = xilinx_intc_map, | 186 | .map = xilinx_intc_map, |
187 | .xlate = xilinx_intc_xlate, | ||
92 | }; | 188 | }; |
93 | 189 | ||
94 | struct irq_host * __init | 190 | struct irq_host * __init |
@@ -116,7 +212,8 @@ xilinx_intc_init(struct device_node *np) | |||
116 | out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */ | 212 | out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */ |
117 | 213 | ||
118 | /* Allocate and initialize an irq_host structure. */ | 214 | /* Allocate and initialize an irq_host structure. */ |
119 | irq = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 32, &xilinx_intc_ops, -1); | 215 | irq = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, XILINX_INTC_MAXIRQS, |
216 | &xilinx_intc_ops, -1); | ||
120 | if (!irq) | 217 | if (!irq) |
121 | panic(__FILE__ ": Cannot allocate IRQ host\n"); | 218 | panic(__FILE__ ": Cannot allocate IRQ host\n"); |
122 | irq->host_data = regs; | 219 | irq->host_data = regs; |