2 * Copyright (C) 2012 Freescale Semiconductor, Inc.
4 * Author: Varun Sethi <varun.sethi@freescale.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; version 2 of the
13 #include <linux/irq.h>
14 #include <linux/smp.h>
15 #include <linux/interrupt.h>
23 #define MPIC_ERR_INT_BASE 0x3900
24 #define MPIC_ERR_INT_EISR 0x0000
25 #define MPIC_ERR_INT_EIMR 0x0010
27 static inline u32
mpic_fsl_err_read(u32 __iomem
*base
, unsigned int err_reg
)
29 return in_be32(base
+ (err_reg
>> 2));
32 static inline void mpic_fsl_err_write(u32 __iomem
*base
, u32 value
)
34 out_be32(base
+ (MPIC_ERR_INT_EIMR
>> 2), value
);
37 static void fsl_mpic_mask_err(struct irq_data
*d
)
40 struct mpic
*mpic
= irq_data_get_irq_chip_data(d
);
41 unsigned int src
= virq_to_hw(d
->irq
) - mpic
->err_int_vecs
[0];
43 eimr
= mpic_fsl_err_read(mpic
->err_regs
, MPIC_ERR_INT_EIMR
);
44 eimr
|= (1 << (31 - src
));
45 mpic_fsl_err_write(mpic
->err_regs
, eimr
);
48 static void fsl_mpic_unmask_err(struct irq_data
*d
)
51 struct mpic
*mpic
= irq_data_get_irq_chip_data(d
);
52 unsigned int src
= virq_to_hw(d
->irq
) - mpic
->err_int_vecs
[0];
54 eimr
= mpic_fsl_err_read(mpic
->err_regs
, MPIC_ERR_INT_EIMR
);
55 eimr
&= ~(1 << (31 - src
));
56 mpic_fsl_err_write(mpic
->err_regs
, eimr
);
59 static struct irq_chip fsl_mpic_err_chip
= {
60 .irq_disable
= fsl_mpic_mask_err
,
61 .irq_mask
= fsl_mpic_mask_err
,
62 .irq_unmask
= fsl_mpic_unmask_err
,
65 int mpic_setup_error_int(struct mpic
*mpic
, int intvec
)
69 mpic
->err_regs
= ioremap(mpic
->paddr
+ MPIC_ERR_INT_BASE
, 0x1000);
70 if (!mpic
->err_regs
) {
71 pr_err("could not map mpic error registers\n");
74 mpic
->hc_err
= fsl_mpic_err_chip
;
75 mpic
->hc_err
.name
= mpic
->name
;
76 mpic
->flags
|= MPIC_FSL_HAS_EIMR
;
77 /* allocate interrupt vectors for error interrupts */
78 for (i
= MPIC_MAX_ERR
- 1; i
>= 0; i
--)
79 mpic
->err_int_vecs
[i
] = --intvec
;
84 int mpic_map_error_int(struct mpic
*mpic
, unsigned int virq
, irq_hw_number_t hw
)
86 if ((mpic
->flags
& MPIC_FSL_HAS_EIMR
) &&
87 (hw
>= mpic
->err_int_vecs
[0] &&
88 hw
<= mpic
->err_int_vecs
[MPIC_MAX_ERR
- 1])) {
89 WARN_ON(mpic
->flags
& MPIC_SECONDARY
);
91 pr_debug("mpic: mapping as Error Interrupt\n");
92 irq_set_chip_data(virq
, mpic
);
93 irq_set_chip_and_handler(virq
, &mpic
->hc_err
,
101 static irqreturn_t
fsl_error_int_handler(int irq
, void *data
)
103 struct mpic
*mpic
= (struct mpic
*) data
;
106 unsigned int cascade_irq
;
108 eisr
= mpic_fsl_err_read(mpic
->err_regs
, MPIC_ERR_INT_EISR
);
109 eimr
= mpic_fsl_err_read(mpic
->err_regs
, MPIC_ERR_INT_EIMR
);
115 errint
= __builtin_clz(eisr
);
116 cascade_irq
= irq_linear_revmap(mpic
->irqhost
,
117 mpic
->err_int_vecs
[errint
]);
118 WARN_ON(cascade_irq
== NO_IRQ
);
119 if (cascade_irq
!= NO_IRQ
) {
120 generic_handle_irq(cascade_irq
);
122 eimr
|= 1 << (31 - errint
);
123 mpic_fsl_err_write(mpic
->err_regs
, eimr
);
125 eisr
&= ~(1 << (31 - errint
));
131 void mpic_err_int_init(struct mpic
*mpic
, irq_hw_number_t irqnum
)
136 virq
= irq_create_mapping(mpic
->irqhost
, irqnum
);
137 if (virq
== NO_IRQ
) {
138 pr_err("Error interrupt setup failed\n");
142 /* Mask all error interrupts */
143 mpic_fsl_err_write(mpic
->err_regs
, ~0);
145 ret
= request_irq(virq
, fsl_error_int_handler
, IRQF_NO_THREAD
,
146 "mpic-error-int", mpic
);
148 pr_err("Failed to register error interrupt handler\n");