linux/arch/mips/lantiq/irq.c
<<
>>
Prefs
   1/*
   2 *  This program is free software; you can redistribute it and/or modify it
   3 *  under the terms of the GNU General Public License version 2 as published
   4 *  by the Free Software Foundation.
   5 *
   6 * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
   7 * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
   8 */
   9
  10#include <linux/interrupt.h>
  11#include <linux/ioport.h>
  12#include <linux/sched.h>
  13#include <linux/irqdomain.h>
  14#include <linux/of_platform.h>
  15#include <linux/of_address.h>
  16#include <linux/of_irq.h>
  17
  18#include <asm/bootinfo.h>
  19#include <asm/irq_cpu.h>
  20
  21#include <lantiq_soc.h>
  22#include <irq.h>
  23
  24/* register definitions - internal irqs */
  25#define LTQ_ICU_IM0_ISR         0x0000
  26#define LTQ_ICU_IM0_IER         0x0008
  27#define LTQ_ICU_IM0_IOSR        0x0010
  28#define LTQ_ICU_IM0_IRSR        0x0018
  29#define LTQ_ICU_IM0_IMR         0x0020
  30#define LTQ_ICU_IM1_ISR         0x0028
  31#define LTQ_ICU_OFFSET          (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR)
  32
  33/* register definitions - external irqs */
  34#define LTQ_EIU_EXIN_C          0x0000
  35#define LTQ_EIU_EXIN_INIC       0x0004
  36#define LTQ_EIU_EXIN_INEN       0x000C
  37
  38/* irq numbers used by the external interrupt unit (EIU) */
  39#define LTQ_EIU_IR0             (INT_NUM_IM4_IRL0 + 30)
  40#define LTQ_EIU_IR1             (INT_NUM_IM3_IRL0 + 31)
  41#define LTQ_EIU_IR2             (INT_NUM_IM1_IRL0 + 26)
  42#define LTQ_EIU_IR3             INT_NUM_IM1_IRL0
  43#define LTQ_EIU_IR4             (INT_NUM_IM1_IRL0 + 1)
  44#define LTQ_EIU_IR5             (INT_NUM_IM1_IRL0 + 2)
  45#define LTQ_EIU_IR6             (INT_NUM_IM2_IRL0 + 30)
  46#define XWAY_EXIN_COUNT         3
  47#define MAX_EIU                 6
  48
  49/* the performance counter */
  50#define LTQ_PERF_IRQ            (INT_NUM_IM4_IRL0 + 31)
  51
  52/*
  53 * irqs generated by devices attached to the EBU need to be acked in
  54 * a special manner
  55 */
  56#define LTQ_ICU_EBU_IRQ         22
  57
  58#define ltq_icu_w32(m, x, y)    ltq_w32((x), ltq_icu_membase[m] + (y))
  59#define ltq_icu_r32(m, x)       ltq_r32(ltq_icu_membase[m] + (x))
  60
  61#define ltq_eiu_w32(x, y)       ltq_w32((x), ltq_eiu_membase + (y))
  62#define ltq_eiu_r32(x)          ltq_r32(ltq_eiu_membase + (x))
  63
  64/* our 2 ipi interrupts for VSMP */
  65#define MIPS_CPU_IPI_RESCHED_IRQ        0
  66#define MIPS_CPU_IPI_CALL_IRQ           1
  67
  68/* we have a cascade of 8 irqs */
  69#define MIPS_CPU_IRQ_CASCADE            8
  70
  71#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
  72int gic_present;
  73#endif
  74
  75static unsigned short ltq_eiu_irq[MAX_EIU] = {
  76        LTQ_EIU_IR0,
  77        LTQ_EIU_IR1,
  78        LTQ_EIU_IR2,
  79        LTQ_EIU_IR3,
  80        LTQ_EIU_IR4,
  81        LTQ_EIU_IR5,
  82};
  83
  84static int exin_avail;
  85static void __iomem *ltq_icu_membase[MAX_IM];
  86static void __iomem *ltq_eiu_membase;
  87static struct irq_domain *ltq_domain;
  88
  89void ltq_disable_irq(struct irq_data *d)
  90{
  91        u32 ier = LTQ_ICU_IM0_IER;
  92        int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
  93        int im = offset / INT_NUM_IM_OFFSET;
  94
  95        offset %= INT_NUM_IM_OFFSET;
  96        ltq_icu_w32(im, ltq_icu_r32(im, ier) & ~BIT(offset), ier);
  97}
  98
  99void ltq_mask_and_ack_irq(struct irq_data *d)
 100{
 101        u32 ier = LTQ_ICU_IM0_IER;
 102        u32 isr = LTQ_ICU_IM0_ISR;
 103        int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
 104        int im = offset / INT_NUM_IM_OFFSET;
 105
 106        offset %= INT_NUM_IM_OFFSET;
 107        ltq_icu_w32(im, ltq_icu_r32(im, ier) & ~BIT(offset), ier);
 108        ltq_icu_w32(im, BIT(offset), isr);
 109}
 110
 111static void ltq_ack_irq(struct irq_data *d)
 112{
 113        u32 isr = LTQ_ICU_IM0_ISR;
 114        int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
 115        int im = offset / INT_NUM_IM_OFFSET;
 116
 117        offset %= INT_NUM_IM_OFFSET;
 118        ltq_icu_w32(im, BIT(offset), isr);
 119}
 120
 121void ltq_enable_irq(struct irq_data *d)
 122{
 123        u32 ier = LTQ_ICU_IM0_IER;
 124        int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE;
 125        int im = offset / INT_NUM_IM_OFFSET;
 126
 127        offset %= INT_NUM_IM_OFFSET;
 128        ltq_icu_w32(im, ltq_icu_r32(im, ier) | BIT(offset), ier);
 129}
 130
 131static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
 132{
 133        int i;
 134
 135        ltq_enable_irq(d);
 136        for (i = 0; i < MAX_EIU; i++) {
 137                if (d->hwirq == ltq_eiu_irq[i]) {
 138                        /* low level - we should really handle set_type */
 139                        ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
 140                                (0x6 << (i * 4)), LTQ_EIU_EXIN_C);
 141                        /* clear all pending */
 142                        ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~BIT(i),
 143                                LTQ_EIU_EXIN_INIC);
 144                        /* enable */
 145                        ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i),
 146                                LTQ_EIU_EXIN_INEN);
 147                        break;
 148                }
 149        }
 150
 151        return 0;
 152}
 153
 154static void ltq_shutdown_eiu_irq(struct irq_data *d)
 155{
 156        int i;
 157
 158        ltq_disable_irq(d);
 159        for (i = 0; i < MAX_EIU; i++) {
 160                if (d->hwirq == ltq_eiu_irq[i]) {
 161                        /* disable */
 162                        ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i),
 163                                LTQ_EIU_EXIN_INEN);
 164                        break;
 165                }
 166        }
 167}
 168
 169static struct irq_chip ltq_irq_type = {
 170        "icu",
 171        .irq_enable = ltq_enable_irq,
 172        .irq_disable = ltq_disable_irq,
 173        .irq_unmask = ltq_enable_irq,
 174        .irq_ack = ltq_ack_irq,
 175        .irq_mask = ltq_disable_irq,
 176        .irq_mask_ack = ltq_mask_and_ack_irq,
 177};
 178
 179static struct irq_chip ltq_eiu_type = {
 180        "eiu",
 181        .irq_startup = ltq_startup_eiu_irq,
 182        .irq_shutdown = ltq_shutdown_eiu_irq,
 183        .irq_enable = ltq_enable_irq,
 184        .irq_disable = ltq_disable_irq,
 185        .irq_unmask = ltq_enable_irq,
 186        .irq_ack = ltq_ack_irq,
 187        .irq_mask = ltq_disable_irq,
 188        .irq_mask_ack = ltq_mask_and_ack_irq,
 189};
 190
 191static void ltq_hw_irqdispatch(int module)
 192{
 193        u32 irq;
 194
 195        irq = ltq_icu_r32(module, LTQ_ICU_IM0_IOSR);
 196        if (irq == 0)
 197                return;
 198
 199        /*
 200         * silicon bug causes only the msb set to 1 to be valid. all
 201         * other bits might be bogus
 202         */
 203        irq = __fls(irq);
 204        do_IRQ((int)irq + MIPS_CPU_IRQ_CASCADE + (INT_NUM_IM_OFFSET * module));
 205
 206        /* if this is a EBU irq, we need to ack it or get a deadlock */
 207        if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0) && LTQ_EBU_PCC_ISTAT)
 208                ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10,
 209                        LTQ_EBU_PCC_ISTAT);
 210}
 211
 212#define DEFINE_HWx_IRQDISPATCH(x)                                       \
 213        static void ltq_hw ## x ## _irqdispatch(void)                   \
 214        {                                                               \
 215                ltq_hw_irqdispatch(x);                                  \
 216        }
 217DEFINE_HWx_IRQDISPATCH(0)
 218DEFINE_HWx_IRQDISPATCH(1)
 219DEFINE_HWx_IRQDISPATCH(2)
 220DEFINE_HWx_IRQDISPATCH(3)
 221DEFINE_HWx_IRQDISPATCH(4)
 222
 223#if MIPS_CPU_TIMER_IRQ == 7
 224static void ltq_hw5_irqdispatch(void)
 225{
 226        do_IRQ(MIPS_CPU_TIMER_IRQ);
 227}
 228#else
 229DEFINE_HWx_IRQDISPATCH(5)
 230#endif
 231
 232#ifdef CONFIG_MIPS_MT_SMP
 233void __init arch_init_ipiirq(int irq, struct irqaction *action)
 234{
 235        setup_irq(irq, action);
 236        irq_set_handler(irq, handle_percpu_irq);
 237}
 238
 239static void ltq_sw0_irqdispatch(void)
 240{
 241        do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
 242}
 243
 244static void ltq_sw1_irqdispatch(void)
 245{
 246        do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
 247}
 248static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 249{
 250        scheduler_ipi();
 251        return IRQ_HANDLED;
 252}
 253
 254static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
 255{
 256        smp_call_function_interrupt();
 257        return IRQ_HANDLED;
 258}
 259
 260static struct irqaction irq_resched = {
 261        .handler        = ipi_resched_interrupt,
 262        .flags          = IRQF_PERCPU,
 263        .name           = "IPI_resched"
 264};
 265
 266static struct irqaction irq_call = {
 267        .handler        = ipi_call_interrupt,
 268        .flags          = IRQF_PERCPU,
 269        .name           = "IPI_call"
 270};
 271#endif
 272
 273asmlinkage void plat_irq_dispatch(void)
 274{
 275        unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
 276        unsigned int i;
 277
 278        if ((MIPS_CPU_TIMER_IRQ == 7) && (pending & CAUSEF_IP7)) {
 279                do_IRQ(MIPS_CPU_TIMER_IRQ);
 280                goto out;
 281        } else {
 282                for (i = 0; i < MAX_IM; i++) {
 283                        if (pending & (CAUSEF_IP2 << i)) {
 284                                ltq_hw_irqdispatch(i);
 285                                goto out;
 286                        }
 287                }
 288        }
 289        pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
 290
 291out:
 292        return;
 293}
 294
 295static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
 296{
 297        struct irq_chip *chip = &ltq_irq_type;
 298        int i;
 299
 300        if (hw < MIPS_CPU_IRQ_CASCADE)
 301                return 0;
 302
 303        for (i = 0; i < exin_avail; i++)
 304                if (hw == ltq_eiu_irq[i])
 305                        chip = &ltq_eiu_type;
 306
 307        irq_set_chip_and_handler(hw, chip, handle_level_irq);
 308
 309        return 0;
 310}
 311
 312static const struct irq_domain_ops irq_domain_ops = {
 313        .xlate = irq_domain_xlate_onetwocell,
 314        .map = icu_map,
 315};
 316
 317static struct irqaction cascade = {
 318        .handler = no_action,
 319        .name = "cascade",
 320};
 321
 322int __init icu_of_init(struct device_node *node, struct device_node *parent)
 323{
 324        struct device_node *eiu_node;
 325        struct resource res;
 326        int i;
 327
 328        for (i = 0; i < MAX_IM; i++) {
 329                if (of_address_to_resource(node, i, &res))
 330                        panic("Failed to get icu memory range");
 331
 332                if (request_mem_region(res.start, resource_size(&res),
 333                                        res.name) < 0)
 334                        pr_err("Failed to request icu memory");
 335
 336                ltq_icu_membase[i] = ioremap_nocache(res.start,
 337                                        resource_size(&res));
 338                if (!ltq_icu_membase[i])
 339                        panic("Failed to remap icu memory");
 340        }
 341
 342        /* the external interrupts are optional and xway only */
 343        eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu");
 344        if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) {
 345                /* find out how many external irq sources we have */
 346                const __be32 *count = of_get_property(node,
 347                                                        "lantiq,count", NULL);
 348
 349                if (count)
 350                        exin_avail = *count;
 351                if (exin_avail > MAX_EIU)
 352                        exin_avail = MAX_EIU;
 353
 354                if (request_mem_region(res.start, resource_size(&res),
 355                                                        res.name) < 0)
 356                        pr_err("Failed to request eiu memory");
 357
 358                ltq_eiu_membase = ioremap_nocache(res.start,
 359                                                        resource_size(&res));
 360                if (!ltq_eiu_membase)
 361                        panic("Failed to remap eiu memory");
 362        }
 363
 364        /* turn off all irqs by default */
 365        for (i = 0; i < MAX_IM; i++) {
 366                /* make sure all irqs are turned off by default */
 367                ltq_icu_w32(i, 0, LTQ_ICU_IM0_IER);
 368                /* clear all possibly pending interrupts */
 369                ltq_icu_w32(i, ~0, LTQ_ICU_IM0_ISR);
 370        }
 371
 372        mips_cpu_irq_init();
 373
 374        for (i = 0; i < MAX_IM; i++)
 375                setup_irq(i + 2, &cascade);
 376
 377        if (cpu_has_vint) {
 378                pr_info("Setting up vectored interrupts\n");
 379                set_vi_handler(2, ltq_hw0_irqdispatch);
 380                set_vi_handler(3, ltq_hw1_irqdispatch);
 381                set_vi_handler(4, ltq_hw2_irqdispatch);
 382                set_vi_handler(5, ltq_hw3_irqdispatch);
 383                set_vi_handler(6, ltq_hw4_irqdispatch);
 384                set_vi_handler(7, ltq_hw5_irqdispatch);
 385        }
 386
 387        ltq_domain = irq_domain_add_linear(node,
 388                (MAX_IM * INT_NUM_IM_OFFSET) + MIPS_CPU_IRQ_CASCADE,
 389                &irq_domain_ops, 0);
 390
 391#if defined(CONFIG_MIPS_MT_SMP)
 392        if (cpu_has_vint) {
 393                pr_info("Setting up IPI vectored interrupts\n");
 394                set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ltq_sw0_irqdispatch);
 395                set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ltq_sw1_irqdispatch);
 396        }
 397        arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ,
 398                &irq_resched);
 399        arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ, &irq_call);
 400#endif
 401
 402#if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
 403        set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 |
 404                IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
 405#else
 406        set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 |
 407                IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
 408#endif
 409
 410        /* tell oprofile which irq to use */
 411        cp0_perfcount_irq = LTQ_PERF_IRQ;
 412
 413        /*
 414         * if the timer irq is not one of the mips irqs we need to
 415         * create a mapping
 416         */
 417        if (MIPS_CPU_TIMER_IRQ != 7)
 418                irq_create_mapping(ltq_domain, MIPS_CPU_TIMER_IRQ);
 419
 420        return 0;
 421}
 422
 423unsigned int __cpuinit get_c0_compare_int(void)
 424{
 425        return MIPS_CPU_TIMER_IRQ;
 426}
 427
 428static struct of_device_id __initdata of_irq_ids[] = {
 429        { .compatible = "lantiq,icu", .data = icu_of_init },
 430        {},
 431};
 432
 433void __init arch_init_irq(void)
 434{
 435        of_irq_init(of_irq_ids);
 436}
 437