xref: /OK3568_Linux_fs/kernel/arch/powerpc/sysdev/fsl_mpic_err.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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