1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2012 Freescale Semiconductor, Inc.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Author: Varun Sethi <varun.sethi@freescale.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/irq.h>
9*4882a593Smuzhiyun #include <linux/smp.h>
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <asm/io.h>
13*4882a593Smuzhiyun #include <asm/irq.h>
14*4882a593Smuzhiyun #include <asm/mpic.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include "mpic.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define MPIC_ERR_INT_BASE 0x3900
19*4882a593Smuzhiyun #define MPIC_ERR_INT_EISR 0x0000
20*4882a593Smuzhiyun #define MPIC_ERR_INT_EIMR 0x0010
21*4882a593Smuzhiyun
mpic_fsl_err_read(u32 __iomem * base,unsigned int err_reg)22*4882a593Smuzhiyun static inline u32 mpic_fsl_err_read(u32 __iomem *base, unsigned int err_reg)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun return in_be32(base + (err_reg >> 2));
25*4882a593Smuzhiyun }
26*4882a593Smuzhiyun
mpic_fsl_err_write(u32 __iomem * base,u32 value)27*4882a593Smuzhiyun static inline void mpic_fsl_err_write(u32 __iomem *base, u32 value)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun out_be32(base + (MPIC_ERR_INT_EIMR >> 2), value);
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun
fsl_mpic_mask_err(struct irq_data * d)32*4882a593Smuzhiyun static void fsl_mpic_mask_err(struct irq_data *d)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun u32 eimr;
35*4882a593Smuzhiyun struct mpic *mpic = irq_data_get_irq_chip_data(d);
36*4882a593Smuzhiyun unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
39*4882a593Smuzhiyun eimr |= (1 << (31 - src));
40*4882a593Smuzhiyun mpic_fsl_err_write(mpic->err_regs, eimr);
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
fsl_mpic_unmask_err(struct irq_data * d)43*4882a593Smuzhiyun static void fsl_mpic_unmask_err(struct irq_data *d)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun u32 eimr;
46*4882a593Smuzhiyun struct mpic *mpic = irq_data_get_irq_chip_data(d);
47*4882a593Smuzhiyun unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
50*4882a593Smuzhiyun eimr &= ~(1 << (31 - src));
51*4882a593Smuzhiyun mpic_fsl_err_write(mpic->err_regs, eimr);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun static struct irq_chip fsl_mpic_err_chip = {
55*4882a593Smuzhiyun .irq_disable = fsl_mpic_mask_err,
56*4882a593Smuzhiyun .irq_mask = fsl_mpic_mask_err,
57*4882a593Smuzhiyun .irq_unmask = fsl_mpic_unmask_err,
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun
mpic_setup_error_int(struct mpic * mpic,int intvec)60*4882a593Smuzhiyun int mpic_setup_error_int(struct mpic *mpic, int intvec)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun int i;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun mpic->err_regs = ioremap(mpic->paddr + MPIC_ERR_INT_BASE, 0x1000);
65*4882a593Smuzhiyun if (!mpic->err_regs) {
66*4882a593Smuzhiyun pr_err("could not map mpic error registers\n");
67*4882a593Smuzhiyun return -ENOMEM;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun mpic->hc_err = fsl_mpic_err_chip;
70*4882a593Smuzhiyun mpic->hc_err.name = mpic->name;
71*4882a593Smuzhiyun mpic->flags |= MPIC_FSL_HAS_EIMR;
72*4882a593Smuzhiyun /* allocate interrupt vectors for error interrupts */
73*4882a593Smuzhiyun for (i = MPIC_MAX_ERR - 1; i >= 0; i--)
74*4882a593Smuzhiyun mpic->err_int_vecs[i] = intvec--;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun return 0;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
mpic_map_error_int(struct mpic * mpic,unsigned int virq,irq_hw_number_t hw)79*4882a593Smuzhiyun int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun if ((mpic->flags & MPIC_FSL_HAS_EIMR) &&
82*4882a593Smuzhiyun (hw >= mpic->err_int_vecs[0] &&
83*4882a593Smuzhiyun hw <= mpic->err_int_vecs[MPIC_MAX_ERR - 1])) {
84*4882a593Smuzhiyun WARN_ON(mpic->flags & MPIC_SECONDARY);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun pr_debug("mpic: mapping as Error Interrupt\n");
87*4882a593Smuzhiyun irq_set_chip_data(virq, mpic);
88*4882a593Smuzhiyun irq_set_chip_and_handler(virq, &mpic->hc_err,
89*4882a593Smuzhiyun handle_level_irq);
90*4882a593Smuzhiyun return 1;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun return 0;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
fsl_error_int_handler(int irq,void * data)96*4882a593Smuzhiyun static irqreturn_t fsl_error_int_handler(int irq, void *data)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun struct mpic *mpic = (struct mpic *) data;
99*4882a593Smuzhiyun u32 eisr, eimr;
100*4882a593Smuzhiyun int errint;
101*4882a593Smuzhiyun unsigned int cascade_irq;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun eisr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EISR);
104*4882a593Smuzhiyun eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (!(eisr & ~eimr))
107*4882a593Smuzhiyun return IRQ_NONE;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun while (eisr) {
110*4882a593Smuzhiyun errint = __builtin_clz(eisr);
111*4882a593Smuzhiyun cascade_irq = irq_linear_revmap(mpic->irqhost,
112*4882a593Smuzhiyun mpic->err_int_vecs[errint]);
113*4882a593Smuzhiyun WARN_ON(!cascade_irq);
114*4882a593Smuzhiyun if (cascade_irq) {
115*4882a593Smuzhiyun generic_handle_irq(cascade_irq);
116*4882a593Smuzhiyun } else {
117*4882a593Smuzhiyun eimr |= 1 << (31 - errint);
118*4882a593Smuzhiyun mpic_fsl_err_write(mpic->err_regs, eimr);
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun eisr &= ~(1 << (31 - errint));
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun return IRQ_HANDLED;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
mpic_err_int_init(struct mpic * mpic,irq_hw_number_t irqnum)126*4882a593Smuzhiyun void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun unsigned int virq;
129*4882a593Smuzhiyun int ret;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun virq = irq_create_mapping(mpic->irqhost, irqnum);
132*4882a593Smuzhiyun if (!virq) {
133*4882a593Smuzhiyun pr_err("Error interrupt setup failed\n");
134*4882a593Smuzhiyun return;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun /* Mask all error interrupts */
138*4882a593Smuzhiyun mpic_fsl_err_write(mpic->err_regs, ~0);
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun ret = request_irq(virq, fsl_error_int_handler, IRQF_NO_THREAD,
141*4882a593Smuzhiyun "mpic-error-int", mpic);
142*4882a593Smuzhiyun if (ret)
143*4882a593Smuzhiyun pr_err("Failed to register error interrupt handler\n");
144*4882a593Smuzhiyun }
145