linux/arch/powerpc/platforms/52xx/mpc52xx_pic.c
<<
>>
Prefs
   1/*
   2 *
   3 * Programmable Interrupt Controller functions for the Freescale MPC52xx.
   4 *
   5 * Copyright (C) 2008 Secret Lab Technologies Ltd.
   6 * Copyright (C) 2006 bplan GmbH
   7 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
   8 * Copyright (C) 2003 Montavista Software, Inc
   9 *
  10 * Based on the code from the 2.4 kernel by
  11 * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
  12 *
  13 * This file is licensed under the terms of the GNU General Public License
  14 * version 2. This program is licensed "as is" without any warranty of any
  15 * kind, whether express or implied.
  16 *
  17 */
  18
  19/*
  20 * This is the device driver for the MPC5200 interrupt controller.
  21 *
  22 * hardware overview
  23 * -----------------
  24 * The MPC5200 interrupt controller groups the all interrupt sources into
  25 * three groups called 'critical', 'main', and 'peripheral'.  The critical
  26 * group has 3 irqs, External IRQ0, slice timer 0 irq, and wake from deep
  27 * sleep.  Main group include the other 3 external IRQs, slice timer 1, RTC,
  28 * gpios, and the general purpose timers.  Peripheral group contains the
  29 * remaining irq sources from all of the on-chip peripherals (PSCs, Ethernet,
  30 * USB, DMA, etc).
  31 *
  32 * virqs
  33 * -----
  34 * The Linux IRQ subsystem requires that each irq source be assigned a
  35 * system wide unique IRQ number starting at 1 (0 means no irq).  Since
  36 * systems can have multiple interrupt controllers, the virtual IRQ (virq)
  37 * infrastructure lets each interrupt controller to define a local set
  38 * of IRQ numbers and the virq infrastructure maps those numbers into
  39 * a unique range of the global IRQ# space.
  40 *
  41 * To define a range of virq numbers for this controller, this driver first
  42 * assigns a number to each of the irq groups (called the level 1 or L1
  43 * value).  Within each group individual irq sources are also assigned a
  44 * number, as defined by the MPC5200 user guide, and refers to it as the
  45 * level 2 or L2 value.  The virq number is determined by shifting up the
  46 * L1 value by MPC52xx_IRQ_L1_OFFSET and ORing it with the L2 value.
  47 *
  48 * For example, the TMR0 interrupt is irq 9 in the main group.  The
  49 * virq for TMR0 is calculated by ((1 << MPC52xx_IRQ_L1_OFFSET) | 9).
  50 *
  51 * The observant reader will also notice that this driver defines a 4th
  52 * interrupt group called 'bestcomm'.  The bestcomm group isn't physically
  53 * part of the MPC5200 interrupt controller, but it is used here to assign
  54 * a separate virq number for each bestcomm task (since any of the 16
  55 * bestcomm tasks can cause the bestcomm interrupt to be raised).  When a
  56 * bestcomm interrupt occurs (peripheral group, irq 0) this driver determines
  57 * which task needs servicing and returns the irq number for that task.  This
  58 * allows drivers which use bestcomm to define their own interrupt handlers.
  59 *
  60 * irq_chip structures
  61 * -------------------
  62 * For actually manipulating IRQs (masking, enabling, clearing, etc) this
  63 * driver defines four separate 'irq_chip' structures, one for the main
  64 * group, one for the peripherals group, one for the bestcomm group and one
  65 * for external interrupts.  The irq_chip structures provide the hooks needed
  66 * to manipulate each IRQ source, and since each group is has a separate set
  67 * of registers for controlling the irq, it makes sense to divide up the
  68 * hooks along those lines.
  69 *
  70 * You'll notice that there is not an irq_chip for the critical group and
  71 * you'll also notice that there is an irq_chip defined for external
  72 * interrupts even though there is no external interrupt group.  The reason
  73 * for this is that the four external interrupts are all managed with the same
  74 * register even though one of the external IRQs is in the critical group and
  75 * the other three are in the main group.  For this reason it makes sense for
  76 * the 4 external irqs to be managed using a separate set of hooks.  The
  77 * reason there is no crit irq_chip is that of the 3 irqs in the critical
  78 * group, only external interrupt is actually support at this time by this
  79 * driver and since external interrupt is the only one used, it can just
  80 * be directed to make use of the external irq irq_chip.
  81 *
  82 * device tree bindings
  83 * --------------------
  84 * The device tree bindings for this controller reflect the two level
  85 * organization of irqs in the device.  #interrupt-cells = <3> where the
  86 * first cell is the group number [0..3], the second cell is the irq
  87 * number in the group, and the third cell is the sense type (level/edge).
  88 * For reference, the following is a list of the interrupt property values
  89 * associated with external interrupt sources on the MPC5200 (just because
  90 * it is non-obvious to determine what the interrupts property should be
  91 * when reading the mpc5200 manual and it is a frequently asked question).
  92 *
  93 * External interrupts:
  94 * <0 0 n>      external irq0, n is sense       (n=0: level high,
  95 * <1 1 n>      external irq1, n is sense        n=1: edge rising,
  96 * <1 2 n>      external irq2, n is sense        n=2: edge falling,
  97 * <1 3 n>      external irq3, n is sense        n=3: level low)
  98 */
  99#undef DEBUG
 100
 101#include <linux/interrupt.h>
 102#include <linux/irq.h>
 103#include <linux/of.h>
 104#include <asm/io.h>
 105#include <asm/prom.h>
 106#include <asm/mpc52xx.h>
 107
 108/* HW IRQ mapping */
 109#define MPC52xx_IRQ_L1_CRIT     (0)
 110#define MPC52xx_IRQ_L1_MAIN     (1)
 111#define MPC52xx_IRQ_L1_PERP     (2)
 112#define MPC52xx_IRQ_L1_SDMA     (3)
 113
 114#define MPC52xx_IRQ_L1_OFFSET   (6)
 115#define MPC52xx_IRQ_L1_MASK     (0x00c0)
 116#define MPC52xx_IRQ_L2_MASK     (0x003f)
 117
 118#define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0)
 119
 120
 121/* MPC5200 device tree match tables */
 122static const struct of_device_id mpc52xx_pic_ids[] __initconst = {
 123        { .compatible = "fsl,mpc5200-pic", },
 124        { .compatible = "mpc5200-pic", },
 125        {}
 126};
 127static const struct of_device_id mpc52xx_sdma_ids[] __initconst = {
 128        { .compatible = "fsl,mpc5200-bestcomm", },
 129        { .compatible = "mpc5200-bestcomm", },
 130        {}
 131};
 132
 133static struct mpc52xx_intr __iomem *intr;
 134static struct mpc52xx_sdma __iomem *sdma;
 135static struct irq_domain *mpc52xx_irqhost = NULL;
 136
 137static unsigned char mpc52xx_map_senses[4] = {
 138        IRQ_TYPE_LEVEL_HIGH,
 139        IRQ_TYPE_EDGE_RISING,
 140        IRQ_TYPE_EDGE_FALLING,
 141        IRQ_TYPE_LEVEL_LOW,
 142};
 143
 144/* Utility functions */
 145static inline void io_be_setbit(u32 __iomem *addr, int bitno)
 146{
 147        out_be32(addr, in_be32(addr) | (1 << bitno));
 148}
 149
 150static inline void io_be_clrbit(u32 __iomem *addr, int bitno)
 151{
 152        out_be32(addr, in_be32(addr) & ~(1 << bitno));
 153}
 154
 155/*
 156 * IRQ[0-3] interrupt irq_chip
 157 */
 158static void mpc52xx_extirq_mask(struct irq_data *d)
 159{
 160        int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
 161        io_be_clrbit(&intr->ctrl, 11 - l2irq);
 162}
 163
 164static void mpc52xx_extirq_unmask(struct irq_data *d)
 165{
 166        int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
 167        io_be_setbit(&intr->ctrl, 11 - l2irq);
 168}
 169
 170static void mpc52xx_extirq_ack(struct irq_data *d)
 171{
 172        int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
 173        io_be_setbit(&intr->ctrl, 27-l2irq);
 174}
 175
 176static int mpc52xx_extirq_set_type(struct irq_data *d, unsigned int flow_type)
 177{
 178        u32 ctrl_reg, type;
 179        int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
 180        void *handler = handle_level_irq;
 181
 182        pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__,
 183                (int) irqd_to_hwirq(d), l2irq, flow_type);
 184
 185        switch (flow_type) {
 186        case IRQF_TRIGGER_HIGH: type = 0; break;
 187        case IRQF_TRIGGER_RISING: type = 1; handler = handle_edge_irq; break;
 188        case IRQF_TRIGGER_FALLING: type = 2; handler = handle_edge_irq; break;
 189        case IRQF_TRIGGER_LOW: type = 3; break;
 190        default:
 191                type = 0;
 192        }
 193
 194        ctrl_reg = in_be32(&intr->ctrl);
 195        ctrl_reg &= ~(0x3 << (22 - (l2irq * 2)));
 196        ctrl_reg |= (type << (22 - (l2irq * 2)));
 197        out_be32(&intr->ctrl, ctrl_reg);
 198
 199        irq_set_handler_locked(d, handler);
 200
 201        return 0;
 202}
 203
 204static struct irq_chip mpc52xx_extirq_irqchip = {
 205        .name = "MPC52xx External",
 206        .irq_mask = mpc52xx_extirq_mask,
 207        .irq_unmask = mpc52xx_extirq_unmask,
 208        .irq_ack = mpc52xx_extirq_ack,
 209        .irq_set_type = mpc52xx_extirq_set_type,
 210};
 211
 212/*
 213 * Main interrupt irq_chip
 214 */
 215static int mpc52xx_null_set_type(struct irq_data *d, unsigned int flow_type)
 216{
 217        return 0; /* Do nothing so that the sense mask will get updated */
 218}
 219
 220static void mpc52xx_main_mask(struct irq_data *d)
 221{
 222        int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
 223        io_be_setbit(&intr->main_mask, 16 - l2irq);
 224}
 225
 226static void mpc52xx_main_unmask(struct irq_data *d)
 227{
 228        int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
 229        io_be_clrbit(&intr->main_mask, 16 - l2irq);
 230}
 231
 232static struct irq_chip mpc52xx_main_irqchip = {
 233        .name = "MPC52xx Main",
 234        .irq_mask = mpc52xx_main_mask,
 235        .irq_mask_ack = mpc52xx_main_mask,
 236        .irq_unmask = mpc52xx_main_unmask,
 237        .irq_set_type = mpc52xx_null_set_type,
 238};
 239
 240/*
 241 * Peripherals interrupt irq_chip
 242 */
 243static void mpc52xx_periph_mask(struct irq_data *d)
 244{
 245        int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
 246        io_be_setbit(&intr->per_mask, 31 - l2irq);
 247}
 248
 249static void mpc52xx_periph_unmask(struct irq_data *d)
 250{
 251        int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
 252        io_be_clrbit(&intr->per_mask, 31 - l2irq);
 253}
 254
 255static struct irq_chip mpc52xx_periph_irqchip = {
 256        .name = "MPC52xx Peripherals",
 257        .irq_mask = mpc52xx_periph_mask,
 258        .irq_mask_ack = mpc52xx_periph_mask,
 259        .irq_unmask = mpc52xx_periph_unmask,
 260        .irq_set_type = mpc52xx_null_set_type,
 261};
 262
 263/*
 264 * SDMA interrupt irq_chip
 265 */
 266static void mpc52xx_sdma_mask(struct irq_data *d)
 267{
 268        int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
 269        io_be_setbit(&sdma->IntMask, l2irq);
 270}
 271
 272static void mpc52xx_sdma_unmask(struct irq_data *d)
 273{
 274        int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
 275        io_be_clrbit(&sdma->IntMask, l2irq);
 276}
 277
 278static void mpc52xx_sdma_ack(struct irq_data *d)
 279{
 280        int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
 281        out_be32(&sdma->IntPend, 1 << l2irq);
 282}
 283
 284static struct irq_chip mpc52xx_sdma_irqchip = {
 285        .name = "MPC52xx SDMA",
 286        .irq_mask = mpc52xx_sdma_mask,
 287        .irq_unmask = mpc52xx_sdma_unmask,
 288        .irq_ack = mpc52xx_sdma_ack,
 289        .irq_set_type = mpc52xx_null_set_type,
 290};
 291
 292/**
 293 * mpc52xx_is_extirq - Returns true if hwirq number is for an external IRQ
 294 */
 295static int mpc52xx_is_extirq(int l1, int l2)
 296{
 297        return ((l1 == 0) && (l2 == 0)) ||
 298               ((l1 == 1) && (l2 >= 1) && (l2 <= 3));
 299}
 300
 301/**
 302 * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property
 303 */
 304static int mpc52xx_irqhost_xlate(struct irq_domain *h, struct device_node *ct,
 305                                 const u32 *intspec, unsigned int intsize,
 306                                 irq_hw_number_t *out_hwirq,
 307                                 unsigned int *out_flags)
 308{
 309        int intrvect_l1;
 310        int intrvect_l2;
 311        int intrvect_type;
 312        int intrvect_linux;
 313
 314        if (intsize != 3)
 315                return -1;
 316
 317        intrvect_l1 = (int)intspec[0];
 318        intrvect_l2 = (int)intspec[1];
 319        intrvect_type = (int)intspec[2] & 0x3;
 320
 321        intrvect_linux = (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) &
 322                         MPC52xx_IRQ_L1_MASK;
 323        intrvect_linux |= intrvect_l2 & MPC52xx_IRQ_L2_MASK;
 324
 325        *out_hwirq = intrvect_linux;
 326        *out_flags = IRQ_TYPE_LEVEL_LOW;
 327        if (mpc52xx_is_extirq(intrvect_l1, intrvect_l2))
 328                *out_flags = mpc52xx_map_senses[intrvect_type];
 329
 330        pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
 331                 intrvect_l2);
 332        return 0;
 333}
 334
 335/**
 336 * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure
 337 */
 338static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq,
 339                               irq_hw_number_t irq)
 340{
 341        int l1irq;
 342        int l2irq;
 343        struct irq_chip *irqchip;
 344        void *hndlr;
 345        int type;
 346        u32 reg;
 347
 348        l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
 349        l2irq = irq & MPC52xx_IRQ_L2_MASK;
 350
 351        /*
 352         * External IRQs are handled differently by the hardware so they are
 353         * handled by a dedicated irq_chip structure.
 354         */
 355        if (mpc52xx_is_extirq(l1irq, l2irq)) {
 356                reg = in_be32(&intr->ctrl);
 357                type = mpc52xx_map_senses[(reg >> (22 - l2irq * 2)) & 0x3];
 358                if ((type == IRQ_TYPE_EDGE_FALLING) ||
 359                    (type == IRQ_TYPE_EDGE_RISING))
 360                        hndlr = handle_edge_irq;
 361                else
 362                        hndlr = handle_level_irq;
 363
 364                irq_set_chip_and_handler(virq, &mpc52xx_extirq_irqchip, hndlr);
 365                pr_debug("%s: External IRQ%i virq=%x, hw=%x. type=%x\n",
 366                         __func__, l2irq, virq, (int)irq, type);
 367                return 0;
 368        }
 369
 370        /* It is an internal SOC irq.  Choose the correct irq_chip */
 371        switch (l1irq) {
 372        case MPC52xx_IRQ_L1_MAIN: irqchip = &mpc52xx_main_irqchip; break;
 373        case MPC52xx_IRQ_L1_PERP: irqchip = &mpc52xx_periph_irqchip; break;
 374        case MPC52xx_IRQ_L1_SDMA: irqchip = &mpc52xx_sdma_irqchip; break;
 375        case MPC52xx_IRQ_L1_CRIT:
 376                pr_warn("%s: Critical IRQ #%d is unsupported! Nopping it.\n",
 377                        __func__, l2irq);
 378                irq_set_chip(virq, &no_irq_chip);
 379                return 0;
 380        }
 381
 382        irq_set_chip_and_handler(virq, irqchip, handle_level_irq);
 383        pr_debug("%s: virq=%x, l1=%i, l2=%i\n", __func__, virq, l1irq, l2irq);
 384
 385        return 0;
 386}
 387
 388static const struct irq_domain_ops mpc52xx_irqhost_ops = {
 389        .xlate = mpc52xx_irqhost_xlate,
 390        .map = mpc52xx_irqhost_map,
 391};
 392
 393/**
 394 * mpc52xx_init_irq - Initialize and register with the virq subsystem
 395 *
 396 * Hook for setting up IRQs on an mpc5200 system.  A pointer to this function
 397 * is to be put into the machine definition structure.
 398 *
 399 * This function searches the device tree for an MPC5200 interrupt controller,
 400 * initializes it, and registers it with the virq subsystem.
 401 */
 402void __init mpc52xx_init_irq(void)
 403{
 404        u32 intr_ctrl;
 405        struct device_node *picnode;
 406        struct device_node *np;
 407
 408        /* Remap the necessary zones */
 409        picnode = of_find_matching_node(NULL, mpc52xx_pic_ids);
 410        intr = of_iomap(picnode, 0);
 411        if (!intr)
 412                panic(__FILE__  ": find_and_map failed on 'mpc5200-pic'. "
 413                                "Check node !");
 414
 415        np = of_find_matching_node(NULL, mpc52xx_sdma_ids);
 416        sdma = of_iomap(np, 0);
 417        of_node_put(np);
 418        if (!sdma)
 419                panic(__FILE__  ": find_and_map failed on 'mpc5200-bestcomm'. "
 420                                "Check node !");
 421
 422        pr_debug("MPC5200 IRQ controller mapped to 0x%p\n", intr);
 423
 424        /* Disable all interrupt sources. */
 425        out_be32(&sdma->IntPend, 0xffffffff);   /* 1 means clear pending */
 426        out_be32(&sdma->IntMask, 0xffffffff);   /* 1 means disabled */
 427        out_be32(&intr->per_mask, 0x7ffffc00);  /* 1 means disabled */
 428        out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
 429        intr_ctrl = in_be32(&intr->ctrl);
 430        intr_ctrl &= 0x00ff0000;        /* Keeps IRQ[0-3] config */
 431        intr_ctrl |=    0x0f000000 |    /* clear IRQ 0-3 */
 432                        0x00001000 |    /* MEE master external enable */
 433                        0x00000000 |    /* 0 means disable IRQ 0-3 */
 434                        0x00000001;     /* CEb route critical normally */
 435        out_be32(&intr->ctrl, intr_ctrl);
 436
 437        /* Zero a bunch of the priority settings. */
 438        out_be32(&intr->per_pri1, 0);
 439        out_be32(&intr->per_pri2, 0);
 440        out_be32(&intr->per_pri3, 0);
 441        out_be32(&intr->main_pri1, 0);
 442        out_be32(&intr->main_pri2, 0);
 443
 444        /*
 445         * As last step, add an irq host to translate the real
 446         * hw irq information provided by the ofw to linux virq
 447         */
 448        mpc52xx_irqhost = irq_domain_add_linear(picnode,
 449                                         MPC52xx_IRQ_HIGHTESTHWIRQ,
 450                                         &mpc52xx_irqhost_ops, NULL);
 451
 452        if (!mpc52xx_irqhost)
 453                panic(__FILE__ ": Cannot allocate the IRQ host\n");
 454
 455        irq_set_default_host(mpc52xx_irqhost);
 456
 457        pr_info("MPC52xx PIC is up and running!\n");
 458}
 459
 460/**
 461 * mpc52xx_get_irq - Get pending interrupt number hook function
 462 *
 463 * Called by the interrupt handler to determine what IRQ handler needs to be
 464 * executed.
 465 *
 466 * Status of pending interrupts is determined by reading the encoded status
 467 * register.  The encoded status register has three fields; one for each of the
 468 * types of interrupts defined by the controller - 'critical', 'main' and
 469 * 'peripheral'.  This function reads the status register and returns the IRQ
 470 * number associated with the highest priority pending interrupt.  'Critical'
 471 * interrupts have the highest priority, followed by 'main' interrupts, and
 472 * then 'peripheral'.
 473 *
 474 * The mpc5200 interrupt controller can be configured to boost the priority
 475 * of individual 'peripheral' interrupts.  If this is the case then a special
 476 * value will appear in either the crit or main fields indicating a high
 477 * or medium priority peripheral irq has occurred.
 478 *
 479 * This function checks each of the 3 irq request fields and returns the
 480 * first pending interrupt that it finds.
 481 *
 482 * This function also identifies a 4th type of interrupt; 'bestcomm'.  Each
 483 * bestcomm DMA task can raise the bestcomm peripheral interrupt.  When this
 484 * occurs at task-specific IRQ# is decoded so that each task can have its
 485 * own IRQ handler.
 486 */
 487unsigned int mpc52xx_get_irq(void)
 488{
 489        u32 status;
 490        int irq;
 491
 492        status = in_be32(&intr->enc_status);
 493        if (status & 0x00000400) {      /* critical */
 494                irq = (status >> 8) & 0x3;
 495                if (irq == 2)   /* high priority peripheral */
 496                        goto peripheral;
 497                irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET);
 498        } else if (status & 0x00200000) {       /* main */
 499                irq = (status >> 16) & 0x1f;
 500                if (irq == 4)   /* low priority peripheral */
 501                        goto peripheral;
 502                irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET);
 503        } else if (status & 0x20000000) {       /* peripheral */
 504              peripheral:
 505                irq = (status >> 24) & 0x1f;
 506                if (irq == 0) { /* bestcomm */
 507                        status = in_be32(&sdma->IntPend);
 508                        irq = ffs(status) - 1;
 509                        irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET);
 510                } else {
 511                        irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET);
 512                }
 513        } else {
 514                return 0;
 515        }
 516
 517        return irq_linear_revmap(mpc52xx_irqhost, irq);
 518}
 519