Skip to content

Commit

Permalink
ARCv2: IDU-intc: Add support for edge-triggered interrupts
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mischa Jonker authored and Vineet Gupta committed Aug 26, 2019
1 parent e86d94f commit 174ae4e
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 6 deletions.
60 changes: 54 additions & 6 deletions arch/arc/kernel/mcip.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ static void idu_set_dest(unsigned int cmn_irq, unsigned int cpu_mask)
__mcip_cmd_data(CMD_IDU_SET_DEST, cmn_irq, cpu_mask);
}

static void idu_set_mode(unsigned int cmn_irq, unsigned int lvl,
unsigned int distr)
static void idu_set_mode(unsigned int cmn_irq, bool set_lvl, unsigned int lvl,
bool set_distr, unsigned int distr)
{
union {
unsigned int word;
Expand All @@ -212,8 +212,11 @@ static void idu_set_mode(unsigned int cmn_irq, unsigned int lvl,
};
} data;

data.distr = distr;
data.lvl = lvl;
data.word = __mcip_cmd_read(CMD_IDU_READ_MODE, cmn_irq);
if (set_distr)
data.distr = distr;
if (set_lvl)
data.lvl = lvl;
__mcip_cmd_data(CMD_IDU_SET_MODE, cmn_irq, data.word);
}

Expand All @@ -240,6 +243,25 @@ static void idu_irq_unmask(struct irq_data *data)
raw_spin_unlock_irqrestore(&mcip_lock, flags);
}

static void idu_irq_ack(struct irq_data *data)
{
unsigned long flags;

raw_spin_lock_irqsave(&mcip_lock, flags);
__mcip_cmd(CMD_IDU_ACK_CIRQ, data->hwirq);
raw_spin_unlock_irqrestore(&mcip_lock, flags);
}

static void idu_irq_mask_ack(struct irq_data *data)
{
unsigned long flags;

raw_spin_lock_irqsave(&mcip_lock, flags);
__mcip_cmd_data(CMD_IDU_SET_MASK, data->hwirq, 1);
__mcip_cmd(CMD_IDU_ACK_CIRQ, data->hwirq);
raw_spin_unlock_irqrestore(&mcip_lock, flags);
}

static int
idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask,
bool force)
Expand All @@ -263,13 +285,36 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask,
else
distribution_mode = IDU_M_DISTRI_RR;

idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, distribution_mode);
idu_set_mode(data->hwirq, false, 0, true, distribution_mode);

raw_spin_unlock_irqrestore(&mcip_lock, flags);

return IRQ_SET_MASK_OK;
}

static int idu_irq_set_type(struct irq_data *data, u32 type)
{
unsigned long flags;

/*
* ARCv2 IDU HW does not support inverse polarity, so these are the
* only interrupt types supported.
*/
if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
return -EINVAL;

raw_spin_lock_irqsave(&mcip_lock, flags);

idu_set_mode(data->hwirq, true,
type & IRQ_TYPE_EDGE_RISING ? IDU_M_TRIG_EDGE :
IDU_M_TRIG_LEVEL,
false, 0);

raw_spin_unlock_irqrestore(&mcip_lock, flags);

return 0;
}

static void idu_irq_enable(struct irq_data *data)
{
/*
Expand All @@ -289,7 +334,10 @@ static struct irq_chip idu_irq_chip = {
.name = "MCIP IDU Intc",
.irq_mask = idu_irq_mask,
.irq_unmask = idu_irq_unmask,
.irq_ack = idu_irq_ack,
.irq_mask_ack = idu_irq_mask_ack,
.irq_enable = idu_irq_enable,
.irq_set_type = idu_irq_set_type,
#ifdef CONFIG_SMP
.irq_set_affinity = idu_irq_set_affinity,
#endif
Expand Down Expand Up @@ -317,7 +365,7 @@ static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t
}

static const struct irq_domain_ops idu_irq_ops = {
.xlate = irq_domain_xlate_onecell,
.xlate = irq_domain_xlate_onetwocell,
.map = idu_irq_map,
};

Expand Down
11 changes: 11 additions & 0 deletions include/soc/arc/mcip.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ struct mcip_cmd {
#define CMD_IDU_ENABLE 0x71
#define CMD_IDU_DISABLE 0x72
#define CMD_IDU_SET_MODE 0x74
#define CMD_IDU_READ_MODE 0x75
#define CMD_IDU_SET_DEST 0x76
#define CMD_IDU_ACK_CIRQ 0x79
#define CMD_IDU_SET_MASK 0x7C

#define IDU_M_TRIG_LEVEL 0x0
Expand Down Expand Up @@ -119,4 +121,13 @@ static inline void __mcip_cmd_data(unsigned int cmd, unsigned int param,
__mcip_cmd(cmd, param);
}

/*
* Read MCIP register
*/
static inline unsigned int __mcip_cmd_read(unsigned int cmd, unsigned int param)
{
__mcip_cmd(cmd, param);
return read_aux_reg(ARC_REG_MCIP_READBACK);
}

#endif

0 comments on commit 174ae4e

Please sign in to comment.