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>
11 #include <linux/irqdomain.h>
19 #define MPIC_ERR_INT_BASE 0x3900
20 #define MPIC_ERR_INT_EISR 0x0000
21 #define MPIC_ERR_INT_EIMR 0x0010
23 static inline u32
mpic_fsl_err_read(u32 __iomem
*base
, unsigned int err_reg
)
25 return in_be32(base
+ (err_reg
>> 2));
28 static inline void mpic_fsl_err_write(u32 __iomem
*base
, u32 value
)
30 out_be32(base
+ (MPIC_ERR_INT_EIMR
>> 2), value
);
33 static void fsl_mpic_mask_err(struct irq_data
*d
)
36 struct mpic
*mpic
= irq_data_get_irq_chip_data(d
);
37 unsigned int src
= virq_to_hw(d
->irq
) - mpic
->err_int_vecs
[0];
39 eimr
= mpic_fsl_err_read(mpic
->err_regs
, MPIC_ERR_INT_EIMR
);
40 eimr
|= (1 << (31 - src
));
41 mpic_fsl_err_write(mpic
->err_regs
, eimr
);
44 static void fsl_mpic_unmask_err(struct irq_data
*d
)
47 struct mpic
*mpic
= irq_data_get_irq_chip_data(d
);
48 unsigned int src
= virq_to_hw(d
->irq
) - mpic
->err_int_vecs
[0];
50 eimr
= mpic_fsl_err_read(mpic
->err_regs
, MPIC_ERR_INT_EIMR
);
51 eimr
&= ~(1 << (31 - src
));
52 mpic_fsl_err_write(mpic
->err_regs
, eimr
);
55 static struct irq_chip fsl_mpic_err_chip
= {
56 .irq_disable
= fsl_mpic_mask_err
,
57 .irq_mask
= fsl_mpic_mask_err
,
58 .irq_unmask
= fsl_mpic_unmask_err
,
61 int __init
mpic_setup_error_int(struct mpic
*mpic
, int intvec
)
65 mpic
->err_regs
= ioremap(mpic
->paddr
+ MPIC_ERR_INT_BASE
, 0x1000);
66 if (!mpic
->err_regs
) {
67 pr_err("could not map mpic error registers\n");
70 mpic
->hc_err
= fsl_mpic_err_chip
;
71 mpic
->hc_err
.name
= mpic
->name
;
72 mpic
->flags
|= MPIC_FSL_HAS_EIMR
;
73 /* allocate interrupt vectors for error interrupts */
74 for (i
= MPIC_MAX_ERR
- 1; i
>= 0; i
--)
75 mpic
->err_int_vecs
[i
] = intvec
--;
80 int mpic_map_error_int(struct mpic
*mpic
, unsigned int virq
, irq_hw_number_t hw
)
82 if ((mpic
->flags
& MPIC_FSL_HAS_EIMR
) &&
83 (hw
>= mpic
->err_int_vecs
[0] &&
84 hw
<= mpic
->err_int_vecs
[MPIC_MAX_ERR
- 1])) {
85 WARN_ON(mpic
->flags
& MPIC_SECONDARY
);
87 pr_debug("mpic: mapping as Error Interrupt\n");
88 irq_set_chip_data(virq
, mpic
);
89 irq_set_chip_and_handler(virq
, &mpic
->hc_err
,
97 static irqreturn_t
fsl_error_int_handler(int irq
, void *data
)
99 struct mpic
*mpic
= (struct mpic
*) data
;
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
);
111 errint
= __builtin_clz(eisr
);
112 ret
= generic_handle_domain_irq(mpic
->irqhost
,
113 mpic
->err_int_vecs
[errint
]);
115 eimr
|= 1 << (31 - errint
);
116 mpic_fsl_err_write(mpic
->err_regs
, eimr
);
118 eisr
&= ~(1 << (31 - errint
));
124 void __init
mpic_err_int_init(struct mpic
*mpic
, irq_hw_number_t irqnum
)
129 virq
= irq_create_mapping(mpic
->irqhost
, irqnum
);
131 pr_err("Error interrupt setup failed\n");
135 /* Mask all error interrupts */
136 mpic_fsl_err_write(mpic
->err_regs
, ~0);
138 ret
= request_irq(virq
, fsl_error_int_handler
, IRQF_NO_THREAD
,
139 "mpic-error-int", mpic
);
141 pr_err("Failed to register error interrupt handler\n");