root/arch/powerpc/platforms/52xx/media5200.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. media5200_irq_unmask
  2. media5200_irq_mask
  3. media5200_irq_cascade
  4. media5200_irq_map
  5. media5200_irq_xlate
  6. media5200_init_irq
  7. media5200_setup_arch
  8. media5200_probe
  9. define_machine

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Support for 'media5200-platform' compatible boards.
   4  *
   5  * Copyright (C) 2008 Secret Lab Technologies Ltd.
   6  *
   7  * Description:
   8  * This code implements support for the Freescape Media5200 platform
   9  * (built around the MPC5200 SoC).
  10  *
  11  * Notable characteristic of the Media5200 is the presence of an FPGA
  12  * that has all external IRQ lines routed through it.  This file implements
  13  * a cascaded interrupt controller driver which attaches itself to the
  14  * Virtual IRQ subsystem after the primary mpc5200 interrupt controller
  15  * is initialized.
  16  */
  17 
  18 #undef DEBUG
  19 
  20 #include <linux/irq.h>
  21 #include <linux/interrupt.h>
  22 #include <linux/io.h>
  23 #include <asm/time.h>
  24 #include <asm/prom.h>
  25 #include <asm/machdep.h>
  26 #include <asm/mpc52xx.h>
  27 
  28 static const struct of_device_id mpc5200_gpio_ids[] __initconst = {
  29         { .compatible = "fsl,mpc5200-gpio", },
  30         { .compatible = "mpc5200-gpio", },
  31         {}
  32 };
  33 
  34 /* FPGA register set */
  35 #define MEDIA5200_IRQ_ENABLE (0x40c)
  36 #define MEDIA5200_IRQ_STATUS (0x410)
  37 #define MEDIA5200_NUM_IRQS   (6)
  38 #define MEDIA5200_IRQ_SHIFT  (32 - MEDIA5200_NUM_IRQS)
  39 
  40 struct media5200_irq {
  41         void __iomem *regs;
  42         spinlock_t lock;
  43         struct irq_domain *irqhost;
  44 };
  45 struct media5200_irq media5200_irq;
  46 
  47 static void media5200_irq_unmask(struct irq_data *d)
  48 {
  49         unsigned long flags;
  50         u32 val;
  51 
  52         spin_lock_irqsave(&media5200_irq.lock, flags);
  53         val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
  54         val |= 1 << (MEDIA5200_IRQ_SHIFT + irqd_to_hwirq(d));
  55         out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
  56         spin_unlock_irqrestore(&media5200_irq.lock, flags);
  57 }
  58 
  59 static void media5200_irq_mask(struct irq_data *d)
  60 {
  61         unsigned long flags;
  62         u32 val;
  63 
  64         spin_lock_irqsave(&media5200_irq.lock, flags);
  65         val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
  66         val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irqd_to_hwirq(d)));
  67         out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
  68         spin_unlock_irqrestore(&media5200_irq.lock, flags);
  69 }
  70 
  71 static struct irq_chip media5200_irq_chip = {
  72         .name = "Media5200 FPGA",
  73         .irq_unmask = media5200_irq_unmask,
  74         .irq_mask = media5200_irq_mask,
  75         .irq_mask_ack = media5200_irq_mask,
  76 };
  77 
  78 static void media5200_irq_cascade(struct irq_desc *desc)
  79 {
  80         struct irq_chip *chip = irq_desc_get_chip(desc);
  81         int sub_virq, val;
  82         u32 status, enable;
  83 
  84         /* Mask off the cascaded IRQ */
  85         raw_spin_lock(&desc->lock);
  86         chip->irq_mask(&desc->irq_data);
  87         raw_spin_unlock(&desc->lock);
  88 
  89         /* Ask the FPGA for IRQ status.  If 'val' is 0, then no irqs
  90          * are pending.  'ffs()' is 1 based */
  91         status = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
  92         enable = in_be32(media5200_irq.regs + MEDIA5200_IRQ_STATUS);
  93         val = ffs((status & enable) >> MEDIA5200_IRQ_SHIFT);
  94         if (val) {
  95                 sub_virq = irq_linear_revmap(media5200_irq.irqhost, val - 1);
  96                 /* pr_debug("%s: virq=%i s=%.8x e=%.8x hwirq=%i subvirq=%i\n",
  97                  *          __func__, virq, status, enable, val - 1, sub_virq);
  98                  */
  99                 generic_handle_irq(sub_virq);
 100         }
 101 
 102         /* Processing done; can reenable the cascade now */
 103         raw_spin_lock(&desc->lock);
 104         chip->irq_ack(&desc->irq_data);
 105         if (!irqd_irq_disabled(&desc->irq_data))
 106                 chip->irq_unmask(&desc->irq_data);
 107         raw_spin_unlock(&desc->lock);
 108 }
 109 
 110 static int media5200_irq_map(struct irq_domain *h, unsigned int virq,
 111                              irq_hw_number_t hw)
 112 {
 113         pr_debug("%s: h=%p, virq=%i, hwirq=%i\n", __func__, h, virq, (int)hw);
 114         irq_set_chip_data(virq, &media5200_irq);
 115         irq_set_chip_and_handler(virq, &media5200_irq_chip, handle_level_irq);
 116         irq_set_status_flags(virq, IRQ_LEVEL);
 117         return 0;
 118 }
 119 
 120 static int media5200_irq_xlate(struct irq_domain *h, struct device_node *ct,
 121                                  const u32 *intspec, unsigned int intsize,
 122                                  irq_hw_number_t *out_hwirq,
 123                                  unsigned int *out_flags)
 124 {
 125         if (intsize != 2)
 126                 return -1;
 127 
 128         pr_debug("%s: bank=%i, number=%i\n", __func__, intspec[0], intspec[1]);
 129         *out_hwirq = intspec[1];
 130         *out_flags = IRQ_TYPE_NONE;
 131         return 0;
 132 }
 133 
 134 static const struct irq_domain_ops media5200_irq_ops = {
 135         .map = media5200_irq_map,
 136         .xlate = media5200_irq_xlate,
 137 };
 138 
 139 /*
 140  * Setup Media5200 IRQ mapping
 141  */
 142 static void __init media5200_init_irq(void)
 143 {
 144         struct device_node *fpga_np;
 145         int cascade_virq;
 146 
 147         /* First setup the regular MPC5200 interrupt controller */
 148         mpc52xx_init_irq();
 149 
 150         /* Now find the FPGA IRQ */
 151         fpga_np = of_find_compatible_node(NULL, NULL, "fsl,media5200-fpga");
 152         if (!fpga_np)
 153                 goto out;
 154         pr_debug("%s: found fpga node: %pOF\n", __func__, fpga_np);
 155 
 156         media5200_irq.regs = of_iomap(fpga_np, 0);
 157         if (!media5200_irq.regs)
 158                 goto out;
 159         pr_debug("%s: mapped to %p\n", __func__, media5200_irq.regs);
 160 
 161         cascade_virq = irq_of_parse_and_map(fpga_np, 0);
 162         if (!cascade_virq)
 163                 goto out;
 164         pr_debug("%s: cascaded on virq=%i\n", __func__, cascade_virq);
 165 
 166         /* Disable all FPGA IRQs */
 167         out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, 0);
 168 
 169         spin_lock_init(&media5200_irq.lock);
 170 
 171         media5200_irq.irqhost = irq_domain_add_linear(fpga_np,
 172                         MEDIA5200_NUM_IRQS, &media5200_irq_ops, &media5200_irq);
 173         if (!media5200_irq.irqhost)
 174                 goto out;
 175         pr_debug("%s: allocated irqhost\n", __func__);
 176 
 177         irq_set_handler_data(cascade_virq, &media5200_irq);
 178         irq_set_chained_handler(cascade_virq, media5200_irq_cascade);
 179 
 180         return;
 181 
 182  out:
 183         pr_err("Could not find Media5200 FPGA; PCI interrupts will not work\n");
 184 }
 185 
 186 /*
 187  * Setup the architecture
 188  */
 189 static void __init media5200_setup_arch(void)
 190 {
 191 
 192         struct device_node *np;
 193         struct mpc52xx_gpio __iomem *gpio;
 194         u32 port_config;
 195 
 196         if (ppc_md.progress)
 197                 ppc_md.progress("media5200_setup_arch()", 0);
 198 
 199         /* Map important registers from the internal memory map */
 200         mpc52xx_map_common_devices();
 201 
 202         /* Some mpc5200 & mpc5200b related configuration */
 203         mpc5200_setup_xlb_arbiter();
 204 
 205         mpc52xx_setup_pci();
 206 
 207         np = of_find_matching_node(NULL, mpc5200_gpio_ids);
 208         gpio = of_iomap(np, 0);
 209         of_node_put(np);
 210         if (!gpio) {
 211                 printk(KERN_ERR "%s() failed. expect abnormal behavior\n",
 212                        __func__);
 213                 return;
 214         }
 215 
 216         /* Set port config */
 217         port_config = in_be32(&gpio->port_config);
 218 
 219         port_config &= ~0x03000000;     /* ATA CS is on csb_4/5         */
 220         port_config |=  0x01000000;
 221 
 222         out_be32(&gpio->port_config, port_config);
 223 
 224         /* Unmap zone */
 225         iounmap(gpio);
 226 
 227 }
 228 
 229 /* list of the supported boards */
 230 static const char * const board[] __initconst = {
 231         "fsl,media5200",
 232         NULL
 233 };
 234 
 235 /*
 236  * Called very early, MMU is off, device-tree isn't unflattened
 237  */
 238 static int __init media5200_probe(void)
 239 {
 240         return of_device_compatible_match(of_root, board);
 241 }
 242 
 243 define_machine(media5200_platform) {
 244         .name           = "media5200-platform",
 245         .probe          = media5200_probe,
 246         .setup_arch     = media5200_setup_arch,
 247         .init           = mpc52xx_declare_of_platform_devices,
 248         .init_IRQ       = media5200_init_irq,
 249         .get_irq        = mpc52xx_get_irq,
 250         .restart        = mpc52xx_restart,
 251         .calibrate_decr = generic_calibrate_decr,
 252 };

/* [<][>][^][v][top][bottom][index][help] */