Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARCv2: IDU-intc: Add support for edge-triggered interrupts

This adds support for an optional extra interrupt cell to specify edge
vs level triggered. It is backward compatible with dts files with only
one cell, and will default to level-triggered in such a case.

Note that I had to make a change to idu_irq_set_affinity as well, as
this function was setting the interrupt type to "level" unconditionally,
since this was the only type supported previously.

Signed-off-by: Mischa Jonker <mischa.jonker@synopsys.com>
Reviewed-by: Vineet Gupta <vgupta@synopsys.com>
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>

authored by

Mischa Jonker and committed by
Vineet Gupta
174ae4e9 e86d94fd

+65 -6
+54 -6
arch/arc/kernel/mcip.c
··· 202 202 __mcip_cmd_data(CMD_IDU_SET_DEST, cmn_irq, cpu_mask); 203 203 } 204 204 205 - static void idu_set_mode(unsigned int cmn_irq, unsigned int lvl, 206 - unsigned int distr) 205 + static void idu_set_mode(unsigned int cmn_irq, bool set_lvl, unsigned int lvl, 206 + bool set_distr, unsigned int distr) 207 207 { 208 208 union { 209 209 unsigned int word; ··· 212 212 }; 213 213 } data; 214 214 215 - data.distr = distr; 216 - data.lvl = lvl; 215 + data.word = __mcip_cmd_read(CMD_IDU_READ_MODE, cmn_irq); 216 + if (set_distr) 217 + data.distr = distr; 218 + if (set_lvl) 219 + data.lvl = lvl; 217 220 __mcip_cmd_data(CMD_IDU_SET_MODE, cmn_irq, data.word); 218 221 } 219 222 ··· 243 240 raw_spin_unlock_irqrestore(&mcip_lock, flags); 244 241 } 245 242 243 + static void idu_irq_ack(struct irq_data *data) 244 + { 245 + unsigned long flags; 246 + 247 + raw_spin_lock_irqsave(&mcip_lock, flags); 248 + __mcip_cmd(CMD_IDU_ACK_CIRQ, data->hwirq); 249 + raw_spin_unlock_irqrestore(&mcip_lock, flags); 250 + } 251 + 252 + static void idu_irq_mask_ack(struct irq_data *data) 253 + { 254 + unsigned long flags; 255 + 256 + raw_spin_lock_irqsave(&mcip_lock, flags); 257 + __mcip_cmd_data(CMD_IDU_SET_MASK, data->hwirq, 1); 258 + __mcip_cmd(CMD_IDU_ACK_CIRQ, data->hwirq); 259 + raw_spin_unlock_irqrestore(&mcip_lock, flags); 260 + } 261 + 246 262 static int 247 263 idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, 248 264 bool force) ··· 285 263 else 286 264 distribution_mode = IDU_M_DISTRI_RR; 287 265 288 - idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, distribution_mode); 266 + idu_set_mode(data->hwirq, false, 0, true, distribution_mode); 289 267 290 268 raw_spin_unlock_irqrestore(&mcip_lock, flags); 291 269 292 270 return IRQ_SET_MASK_OK; 271 + } 272 + 273 + static int idu_irq_set_type(struct irq_data *data, u32 type) 274 + { 275 + unsigned long flags; 276 + 277 + /* 278 + * ARCv2 IDU HW does not support inverse polarity, so these are the 279 + * only interrupt types supported. 280 + */ 281 + if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH)) 282 + return -EINVAL; 283 + 284 + raw_spin_lock_irqsave(&mcip_lock, flags); 285 + 286 + idu_set_mode(data->hwirq, true, 287 + type & IRQ_TYPE_EDGE_RISING ? IDU_M_TRIG_EDGE : 288 + IDU_M_TRIG_LEVEL, 289 + false, 0); 290 + 291 + raw_spin_unlock_irqrestore(&mcip_lock, flags); 292 + 293 + return 0; 293 294 } 294 295 295 296 static void idu_irq_enable(struct irq_data *data) ··· 334 289 .name = "MCIP IDU Intc", 335 290 .irq_mask = idu_irq_mask, 336 291 .irq_unmask = idu_irq_unmask, 292 + .irq_ack = idu_irq_ack, 293 + .irq_mask_ack = idu_irq_mask_ack, 337 294 .irq_enable = idu_irq_enable, 295 + .irq_set_type = idu_irq_set_type, 338 296 #ifdef CONFIG_SMP 339 297 .irq_set_affinity = idu_irq_set_affinity, 340 298 #endif ··· 365 317 } 366 318 367 319 static const struct irq_domain_ops idu_irq_ops = { 368 - .xlate = irq_domain_xlate_onecell, 320 + .xlate = irq_domain_xlate_onetwocell, 369 321 .map = idu_irq_map, 370 322 }; 371 323
+11
include/soc/arc/mcip.h
··· 46 46 #define CMD_IDU_ENABLE 0x71 47 47 #define CMD_IDU_DISABLE 0x72 48 48 #define CMD_IDU_SET_MODE 0x74 49 + #define CMD_IDU_READ_MODE 0x75 49 50 #define CMD_IDU_SET_DEST 0x76 51 + #define CMD_IDU_ACK_CIRQ 0x79 50 52 #define CMD_IDU_SET_MASK 0x7C 51 53 52 54 #define IDU_M_TRIG_LEVEL 0x0 ··· 119 117 write_aux_reg(ARC_REG_MCIP_WDATA, data); 120 118 121 119 __mcip_cmd(cmd, param); 120 + } 121 + 122 + /* 123 + * Read MCIP register 124 + */ 125 + static inline unsigned int __mcip_cmd_read(unsigned int cmd, unsigned int param) 126 + { 127 + __mcip_cmd(cmd, param); 128 + return read_aux_reg(ARC_REG_MCIP_READBACK); 122 129 } 123 130 124 131 #endif