linux/arch/arc/kernel/intc-arcv2.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2014 Synopsys, Inc. (www.synopsys.com)
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 *
   8 */
   9
  10#include <linux/interrupt.h>
  11#include <linux/module.h>
  12#include <linux/of.h>
  13#include <linux/irqdomain.h>
  14#include <linux/irqchip.h>
  15#include <asm/irq.h>
  16
  17#define NR_EXCEPTIONS   16
  18
  19struct bcr_irq_arcv2 {
  20#ifdef CONFIG_CPU_BIG_ENDIAN
  21        unsigned int pad:3, firq:1, prio:4, exts:8, irqs:8, ver:8;
  22#else
  23        unsigned int ver:8, irqs:8, exts:8, prio:4, firq:1, pad:3;
  24#endif
  25};
  26
  27/*
  28 * Early Hardware specific Interrupt setup
  29 * -Called very early (start_kernel -> setup_arch -> setup_processor)
  30 * -Platform Independent (must for any ARC Core)
  31 * -Needed for each CPU (hence not foldable into init_IRQ)
  32 */
  33void arc_init_IRQ(void)
  34{
  35        unsigned int tmp, irq_prio, i;
  36        struct bcr_irq_arcv2 irq_bcr;
  37
  38        struct aux_irq_ctrl {
  39#ifdef CONFIG_CPU_BIG_ENDIAN
  40                unsigned int res3:18, save_idx_regs:1, res2:1,
  41                             save_u_to_u:1, save_lp_regs:1, save_blink:1,
  42                             res:4, save_nr_gpr_pairs:5;
  43#else
  44                unsigned int save_nr_gpr_pairs:5, res:4,
  45                             save_blink:1, save_lp_regs:1, save_u_to_u:1,
  46                             res2:1, save_idx_regs:1, res3:18;
  47#endif
  48        } ictrl;
  49
  50        *(unsigned int *)&ictrl = 0;
  51
  52        ictrl.save_nr_gpr_pairs = 6;    /* r0 to r11 (r12 saved manually) */
  53        ictrl.save_blink = 1;
  54        ictrl.save_lp_regs = 1;         /* LP_COUNT, LP_START, LP_END */
  55        ictrl.save_u_to_u = 0;          /* user ctxt saved on kernel stack */
  56        ictrl.save_idx_regs = 1;        /* JLI, LDI, EI */
  57
  58        WRITE_AUX(AUX_IRQ_CTRL, ictrl);
  59
  60        /*
  61         * ARCv2 core intc provides multiple interrupt priorities (upto 16).
  62         * Typical builds though have only two levels (0-high, 1-low)
  63         * Linux by default uses lower prio 1 for most irqs, reserving 0 for
  64         * NMI style interrupts in future (say perf)
  65         */
  66
  67        READ_BCR(ARC_REG_IRQ_BCR, irq_bcr);
  68
  69        irq_prio = irq_bcr.prio;        /* Encoded as N-1 for N levels */
  70        pr_info("archs-intc\t: %d priority levels (default %d)%s\n",
  71                irq_prio + 1, ARCV2_IRQ_DEF_PRIO,
  72                irq_bcr.firq ? " FIRQ (not used)":"");
  73
  74        /*
  75         * Set a default priority for all available interrupts to prevent
  76         * switching of register banks if Fast IRQ and multiple register banks
  77         * are supported by CPU.
  78         * Also disable private-per-core IRQ lines so faulty external HW won't
  79         * trigger interrupt that kernel is not ready to handle.
  80         */
  81        for (i = NR_EXCEPTIONS; i < irq_bcr.irqs + NR_EXCEPTIONS; i++) {
  82                write_aux_reg(AUX_IRQ_SELECT, i);
  83                write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO);
  84
  85                /*
  86                 * Only mask cpu private IRQs here.
  87                 * "common" interrupts are masked at IDU, otherwise it would
  88                 * need to be unmasked at each cpu, with IPIs
  89                 */
  90                if (i < FIRST_EXT_IRQ)
  91                        write_aux_reg(AUX_IRQ_ENABLE, 0);
  92        }
  93
  94        /* setup status32, don't enable intr yet as kernel doesn't want */
  95        tmp = read_aux_reg(ARC_REG_STATUS32);
  96        tmp |= STATUS_AD_MASK | (ARCV2_IRQ_DEF_PRIO << 1);
  97        tmp &= ~STATUS_IE_MASK;
  98        asm volatile("kflag %0  \n"::"r"(tmp));
  99}
 100
 101static void arcv2_irq_mask(struct irq_data *data)
 102{
 103        write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
 104        write_aux_reg(AUX_IRQ_ENABLE, 0);
 105}
 106
 107static void arcv2_irq_unmask(struct irq_data *data)
 108{
 109        write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
 110        write_aux_reg(AUX_IRQ_ENABLE, 1);
 111}
 112
 113void arcv2_irq_enable(struct irq_data *data)
 114{
 115        /* set default priority */
 116        write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
 117        write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO);
 118
 119        /*
 120         * hw auto enables (linux unmask) all by default
 121         * So no need to do IRQ_ENABLE here
 122         * XXX: However OSCI LAN need it
 123         */
 124        write_aux_reg(AUX_IRQ_ENABLE, 1);
 125}
 126
 127static struct irq_chip arcv2_irq_chip = {
 128        .name           = "ARCv2 core Intc",
 129        .irq_mask       = arcv2_irq_mask,
 130        .irq_unmask     = arcv2_irq_unmask,
 131        .irq_enable     = arcv2_irq_enable
 132};
 133
 134static int arcv2_irq_map(struct irq_domain *d, unsigned int irq,
 135                         irq_hw_number_t hw)
 136{
 137        /*
 138         * core intc IRQs [16, 23]:
 139         * Statically assigned always private-per-core (Timers, WDT, IPI, PCT)
 140         */
 141        if (hw < FIRST_EXT_IRQ) {
 142                /*
 143                 * A subsequent request_percpu_irq() fails if percpu_devid is
 144                 * not set. That in turns sets NOAUTOEN, meaning each core needs
 145                 * to call enable_percpu_irq()
 146                 */
 147                irq_set_percpu_devid(irq);
 148                irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_percpu_irq);
 149        } else {
 150                irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_level_irq);
 151        }
 152
 153        return 0;
 154}
 155
 156static const struct irq_domain_ops arcv2_irq_ops = {
 157        .xlate = irq_domain_xlate_onecell,
 158        .map = arcv2_irq_map,
 159};
 160
 161
 162static int __init
 163init_onchip_IRQ(struct device_node *intc, struct device_node *parent)
 164{
 165        struct irq_domain *root_domain;
 166        struct bcr_irq_arcv2 irq_bcr;
 167        unsigned int nr_cpu_irqs;
 168
 169        READ_BCR(ARC_REG_IRQ_BCR, irq_bcr);
 170        nr_cpu_irqs = irq_bcr.irqs + NR_EXCEPTIONS;
 171
 172        if (parent)
 173                panic("DeviceTree incore intc not a root irq controller\n");
 174
 175        root_domain = irq_domain_add_linear(intc, nr_cpu_irqs, &arcv2_irq_ops, NULL);
 176        if (!root_domain)
 177                panic("root irq domain not avail\n");
 178
 179        /*
 180         * Needed for primary domain lookup to succeed
 181         * This is a primary irqchip, and can never have a parent
 182         */
 183        irq_set_default_host(root_domain);
 184
 185#ifdef CONFIG_SMP
 186        irq_create_mapping(root_domain, IPI_IRQ);
 187#endif
 188        irq_create_mapping(root_domain, SOFTIRQ_IRQ);
 189
 190        return 0;
 191}
 192
 193IRQCHIP_DECLARE(arc_intc, "snps,archs-intc", init_onchip_IRQ);
 194