1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2012 Freescale Semiconductor, Inc.
5 * Author: Varun Sethi <varun.sethi@freescale.com>
10 #include <linux/interrupt.h>
18 #define MPIC_ERR_INT_BASE 0x3900
19 #define MPIC_ERR_INT_EISR 0x0000
20 #define MPIC_ERR_INT_EIMR 0x0010
22 static inline u32
mpic_fsl_err_read(u32 __iomem
*base
, unsigned int err_reg
)
24 return in_be32(base
+ (err_reg
>> 2));
27 static inline void mpic_fsl_err_write(u32 __iomem
*base
, u32 value
)
29 out_be32(base
+ (MPIC_ERR_INT_EIMR
>> 2), value
);
32 static void fsl_mpic_mask_err(struct irq_data
*d
)
35 struct mpic
*mpic
= irq_data_get_irq_chip_data(d
);
36 unsigned int src
= virq_to_hw(d
->irq
) - mpic
->err_int_vecs
[0];
38 eimr
= mpic_fsl_err_read(mpic
->err_regs
, MPIC_ERR_INT_EIMR
);
39 eimr
|= (1 << (31 - src
));
40 mpic_fsl_err_write(mpic
->err_regs
, eimr
);
43 static void fsl_mpic_unmask_err(struct irq_data
*d
)
46 struct mpic
*mpic
= irq_data_get_irq_chip_data(d
);
47 unsigned int src
= virq_to_hw(d
->irq
) - mpic
->err_int_vecs
[0];
49 eimr
= mpic_fsl_err_read(mpic
->err_regs
, MPIC_ERR_INT_EIMR
);
50 eimr
&= ~(1 << (31 - src
));
51 mpic_fsl_err_write(mpic
->err_regs
, eimr
);
54 static struct irq_chip fsl_mpic_err_chip
= {
55 .irq_disable
= fsl_mpic_mask_err
,
56 .irq_mask
= fsl_mpic_mask_err
,
57 .irq_unmask
= fsl_mpic_unmask_err
,
60 int mpic_setup_error_int(struct mpic
*mpic
, int intvec
)
64 mpic
->err_regs
= ioremap(mpic
->paddr
+ MPIC_ERR_INT_BASE
, 0x1000);
65 if (!mpic
->err_regs
) {
66 pr_err("could not map mpic error registers\n");
69 mpic
->hc_err
= fsl_mpic_err_chip
;
70 mpic
->hc_err
.name
= mpic
->name
;
71 mpic
->flags
|= MPIC_FSL_HAS_EIMR
;
72 /* allocate interrupt vectors for error interrupts */
73 for (i
= MPIC_MAX_ERR
- 1; i
>= 0; i
--)
74 mpic
->err_int_vecs
[i
] = intvec
--;
79 int mpic_map_error_int(struct mpic
*mpic
, unsigned int virq
, irq_hw_number_t hw
)
81 if ((mpic
->flags
& MPIC_FSL_HAS_EIMR
) &&
82 (hw
>= mpic
->err_int_vecs
[0] &&
83 hw
<= mpic
->err_int_vecs
[MPIC_MAX_ERR
- 1])) {
84 WARN_ON(mpic
->flags
& MPIC_SECONDARY
);
86 pr_debug("mpic: mapping as Error Interrupt\n");
87 irq_set_chip_data(virq
, mpic
);
88 irq_set_chip_and_handler(virq
, &mpic
->hc_err
,
96 static irqreturn_t
fsl_error_int_handler(int irq
, void *data
)
98 struct mpic
*mpic
= (struct mpic
*) data
;
101 unsigned int cascade_irq
;
103 eisr
= mpic_fsl_err_read(mpic
->err_regs
, MPIC_ERR_INT_EISR
);
104 eimr
= mpic_fsl_err_read(mpic
->err_regs
, MPIC_ERR_INT_EIMR
);
110 errint
= __builtin_clz(eisr
);
111 cascade_irq
= irq_linear_revmap(mpic
->irqhost
,
112 mpic
->err_int_vecs
[errint
]);
113 WARN_ON(!cascade_irq
);
115 generic_handle_irq(cascade_irq
);
117 eimr
|= 1 << (31 - errint
);
118 mpic_fsl_err_write(mpic
->err_regs
, eimr
);
120 eisr
&= ~(1 << (31 - errint
));
126 void mpic_err_int_init(struct mpic
*mpic
, irq_hw_number_t irqnum
)
131 virq
= irq_create_mapping(mpic
->irqhost
, irqnum
);
133 pr_err("Error interrupt setup failed\n");
137 /* Mask all error interrupts */
138 mpic_fsl_err_write(mpic
->err_regs
, ~0);
140 ret
= request_irq(virq
, fsl_error_int_handler
, IRQF_NO_THREAD
,
141 "mpic-error-int", mpic
);
143 pr_err("Failed to register error interrupt handler\n");