0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #undef DEBUG
0019
0020 #include <linux/irq.h>
0021 #include <linux/interrupt.h>
0022 #include <linux/io.h>
0023 #include <linux/of_address.h>
0024 #include <linux/of_irq.h>
0025 #include <asm/time.h>
0026 #include <asm/machdep.h>
0027 #include <asm/mpc52xx.h>
0028
0029 static const struct of_device_id mpc5200_gpio_ids[] __initconst = {
0030 { .compatible = "fsl,mpc5200-gpio", },
0031 { .compatible = "mpc5200-gpio", },
0032 {}
0033 };
0034
0035
0036 #define MEDIA5200_IRQ_ENABLE (0x40c)
0037 #define MEDIA5200_IRQ_STATUS (0x410)
0038 #define MEDIA5200_NUM_IRQS (6)
0039 #define MEDIA5200_IRQ_SHIFT (32 - MEDIA5200_NUM_IRQS)
0040
0041 struct media5200_irq {
0042 void __iomem *regs;
0043 spinlock_t lock;
0044 struct irq_domain *irqhost;
0045 };
0046 struct media5200_irq media5200_irq;
0047
0048 static void media5200_irq_unmask(struct irq_data *d)
0049 {
0050 unsigned long flags;
0051 u32 val;
0052
0053 spin_lock_irqsave(&media5200_irq.lock, flags);
0054 val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
0055 val |= 1 << (MEDIA5200_IRQ_SHIFT + irqd_to_hwirq(d));
0056 out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
0057 spin_unlock_irqrestore(&media5200_irq.lock, flags);
0058 }
0059
0060 static void media5200_irq_mask(struct irq_data *d)
0061 {
0062 unsigned long flags;
0063 u32 val;
0064
0065 spin_lock_irqsave(&media5200_irq.lock, flags);
0066 val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
0067 val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irqd_to_hwirq(d)));
0068 out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
0069 spin_unlock_irqrestore(&media5200_irq.lock, flags);
0070 }
0071
0072 static struct irq_chip media5200_irq_chip = {
0073 .name = "Media5200 FPGA",
0074 .irq_unmask = media5200_irq_unmask,
0075 .irq_mask = media5200_irq_mask,
0076 .irq_mask_ack = media5200_irq_mask,
0077 };
0078
0079 static void media5200_irq_cascade(struct irq_desc *desc)
0080 {
0081 struct irq_chip *chip = irq_desc_get_chip(desc);
0082 int val;
0083 u32 status, enable;
0084
0085
0086 raw_spin_lock(&desc->lock);
0087 chip->irq_mask(&desc->irq_data);
0088 raw_spin_unlock(&desc->lock);
0089
0090
0091
0092 status = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
0093 enable = in_be32(media5200_irq.regs + MEDIA5200_IRQ_STATUS);
0094 val = ffs((status & enable) >> MEDIA5200_IRQ_SHIFT);
0095 if (val) {
0096 generic_handle_domain_irq(media5200_irq.irqhost, val - 1);
0097
0098
0099
0100 }
0101
0102
0103 raw_spin_lock(&desc->lock);
0104 chip->irq_ack(&desc->irq_data);
0105 if (!irqd_irq_disabled(&desc->irq_data))
0106 chip->irq_unmask(&desc->irq_data);
0107 raw_spin_unlock(&desc->lock);
0108 }
0109
0110 static int media5200_irq_map(struct irq_domain *h, unsigned int virq,
0111 irq_hw_number_t hw)
0112 {
0113 pr_debug("%s: h=%p, virq=%i, hwirq=%i\n", __func__, h, virq, (int)hw);
0114 irq_set_chip_data(virq, &media5200_irq);
0115 irq_set_chip_and_handler(virq, &media5200_irq_chip, handle_level_irq);
0116 irq_set_status_flags(virq, IRQ_LEVEL);
0117 return 0;
0118 }
0119
0120 static int media5200_irq_xlate(struct irq_domain *h, struct device_node *ct,
0121 const u32 *intspec, unsigned int intsize,
0122 irq_hw_number_t *out_hwirq,
0123 unsigned int *out_flags)
0124 {
0125 if (intsize != 2)
0126 return -1;
0127
0128 pr_debug("%s: bank=%i, number=%i\n", __func__, intspec[0], intspec[1]);
0129 *out_hwirq = intspec[1];
0130 *out_flags = IRQ_TYPE_NONE;
0131 return 0;
0132 }
0133
0134 static const struct irq_domain_ops media5200_irq_ops = {
0135 .map = media5200_irq_map,
0136 .xlate = media5200_irq_xlate,
0137 };
0138
0139
0140
0141
0142 static void __init media5200_init_irq(void)
0143 {
0144 struct device_node *fpga_np;
0145 int cascade_virq;
0146
0147
0148 mpc52xx_init_irq();
0149
0150
0151 fpga_np = of_find_compatible_node(NULL, NULL, "fsl,media5200-fpga");
0152 if (!fpga_np)
0153 goto out;
0154 pr_debug("%s: found fpga node: %pOF\n", __func__, fpga_np);
0155
0156 media5200_irq.regs = of_iomap(fpga_np, 0);
0157 if (!media5200_irq.regs)
0158 goto out;
0159 pr_debug("%s: mapped to %p\n", __func__, media5200_irq.regs);
0160
0161 cascade_virq = irq_of_parse_and_map(fpga_np, 0);
0162 if (!cascade_virq)
0163 goto out;
0164 pr_debug("%s: cascaded on virq=%i\n", __func__, cascade_virq);
0165
0166
0167 out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, 0);
0168
0169 spin_lock_init(&media5200_irq.lock);
0170
0171 media5200_irq.irqhost = irq_domain_add_linear(fpga_np,
0172 MEDIA5200_NUM_IRQS, &media5200_irq_ops, &media5200_irq);
0173 if (!media5200_irq.irqhost)
0174 goto out;
0175 pr_debug("%s: allocated irqhost\n", __func__);
0176
0177 irq_set_handler_data(cascade_virq, &media5200_irq);
0178 irq_set_chained_handler(cascade_virq, media5200_irq_cascade);
0179
0180 return;
0181
0182 out:
0183 pr_err("Could not find Media5200 FPGA; PCI interrupts will not work\n");
0184 }
0185
0186
0187
0188
0189 static void __init media5200_setup_arch(void)
0190 {
0191
0192 struct device_node *np;
0193 struct mpc52xx_gpio __iomem *gpio;
0194 u32 port_config;
0195
0196 if (ppc_md.progress)
0197 ppc_md.progress("media5200_setup_arch()", 0);
0198
0199
0200 mpc52xx_map_common_devices();
0201
0202
0203 mpc5200_setup_xlb_arbiter();
0204
0205 np = of_find_matching_node(NULL, mpc5200_gpio_ids);
0206 gpio = of_iomap(np, 0);
0207 of_node_put(np);
0208 if (!gpio) {
0209 printk(KERN_ERR "%s() failed. expect abnormal behavior\n",
0210 __func__);
0211 return;
0212 }
0213
0214
0215 port_config = in_be32(&gpio->port_config);
0216
0217 port_config &= ~0x03000000;
0218 port_config |= 0x01000000;
0219
0220 out_be32(&gpio->port_config, port_config);
0221
0222
0223 iounmap(gpio);
0224
0225 }
0226
0227
0228 static const char * const board[] __initconst = {
0229 "fsl,media5200",
0230 NULL
0231 };
0232
0233
0234
0235
0236 static int __init media5200_probe(void)
0237 {
0238 return of_device_compatible_match(of_root, board);
0239 }
0240
0241 define_machine(media5200_platform) {
0242 .name = "media5200-platform",
0243 .probe = media5200_probe,
0244 .setup_arch = media5200_setup_arch,
0245 .discover_phbs = mpc52xx_setup_pci,
0246 .init = mpc52xx_declare_of_platform_devices,
0247 .init_IRQ = media5200_init_irq,
0248 .get_irq = mpc52xx_get_irq,
0249 .restart = mpc52xx_restart,
0250 .calibrate_decr = generic_calibrate_decr,
0251 };