Commit 6525771f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'arc-5.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc

Pull ARC updates from Vineet Gupta:

 - support for Edge Triggered IRQs in ARC IDU intc

 - other fixes here and there

* tag 'arc-5.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc:
  arc: prefer __section from compiler_attributes.h
  dt-bindings: IDU-intc: Add support for edge-triggered interrupts
  dt-bindings: IDU-intc: Clean up documentation
  ARCv2: IDU-intc: Add support for edge-triggered interrupts
  ARC: unwind: Mark expected switch fall-throughs
  ARC: [plat-hsdk]: allow to switch between AXI DMAC port configurations
  ARC: fix typo in setup_dma_ops log message
  ARCv2: entry: early return from exception need not clear U & DE bits
parents 8d645408 2f029413
* ARC-HS Interrupt Distribution Unit
This optional 2nd level interrupt controller can be used in SMP configurations for
dynamic IRQ routing, load balancing of common/external IRQs towards core intc.
This optional 2nd level interrupt controller can be used in SMP configurations
for dynamic IRQ routing, load balancing of common/external IRQs towards core
intc.
Properties:
- compatible: "snps,archs-idu-intc"
- interrupt-controller: This is an interrupt controller.
- #interrupt-cells: Must be <1>.
Value of the cell specifies the "common" IRQ from peripheral to IDU. Number N
of the particular interrupt line of IDU corresponds to the line N+24 of the
core interrupt controller.
intc accessed via the special ARC AUX register interface, hence "reg" property
is not specified.
- #interrupt-cells: Must be <1> or <2>.
Value of the first cell specifies the "common" IRQ from peripheral to IDU.
Number N of the particular interrupt line of IDU corresponds to the line N+24
of the core interrupt controller.
The (optional) second cell specifies any of the following flags:
- bits[3:0] trigger type and level flags
1 = low-to-high edge triggered
2 = NOT SUPPORTED (high-to-low edge triggered)
4 = active high level-sensitive <<< DEFAULT
8 = NOT SUPPORTED (active low level-sensitive)
When no second cell is specified, the interrupt is assumed to be level
sensitive.
The interrupt controller is accessed via the special ARC AUX register
interface, hence "reg" property is not specified.
Example:
core_intc: core-interrupt-controller {
......
......@@ -12,3 +12,6 @@ dtb-y := $(builtindtb-y).dtb
# for CONFIG_OF_ALL_DTBS test
dtstree := $(srctree)/$(src)
dtb- := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts))
# board-specific dtc flags
DTC_FLAGS_hsdk += --pad 20
......@@ -256,7 +256,7 @@
.macro FAKE_RET_FROM_EXCPN
lr r9, [status32]
bic r9, r9, (STATUS_U_MASK|STATUS_DE_MASK|STATUS_AE_MASK)
bic r9, r9, STATUS_AE_MASK
or r9, r9, STATUS_IE_MASK
kflag r9
.endm
......
......@@ -62,15 +62,15 @@
#else /* !__ASSEMBLY__ */
#ifdef CONFIG_ARC_HAS_ICCM
#define __arcfp_code __attribute__((__section__(".text.arcfp")))
#define __arcfp_code __section(.text.arcfp)
#else
#define __arcfp_code __attribute__((__section__(".text")))
#define __arcfp_code __section(.text)
#endif
#ifdef CONFIG_ARC_HAS_DCCM
#define __arcfp_data __attribute__((__section__(".data.arcfp")))
#define __arcfp_data __section(.data.arcfp)
#else
#define __arcfp_data __attribute__((__section__(".data")))
#define __arcfp_data __section(.data)
#endif
#endif /* __ASSEMBLY__ */
......
......@@ -53,8 +53,7 @@ extern const struct machine_desc __arch_info_begin[], __arch_info_end[];
*/
#define MACHINE_START(_type, _name) \
static const struct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
__used __section(.arch.info.init) = { \
.name = _name,
#define MACHINE_END \
......
......@@ -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;
......@@ -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);
}
......@@ -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)
......@@ -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)
{
/*
......@@ -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
......@@ -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,
};
......
......@@ -826,7 +826,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
case DW_CFA_def_cfa:
state->cfa.reg = get_uleb128(&ptr.p8, end);
unw_debug("cfa_def_cfa: r%lu ", state->cfa.reg);
/*nobreak*/
/* fall through */
case DW_CFA_def_cfa_offset:
state->cfa.offs = get_uleb128(&ptr.p8, end);
unw_debug("cfa_def_cfa_offset: 0x%lx ",
......@@ -834,7 +834,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
break;
case DW_CFA_def_cfa_sf:
state->cfa.reg = get_uleb128(&ptr.p8, end);
/*nobreak */
/* fall through */
case DW_CFA_def_cfa_offset_sf:
state->cfa.offs = get_sleb128(&ptr.p8, end)
* state->dataAlign;
......
......@@ -101,7 +101,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
if (is_isa_arcv2() && ioc_enable && coherent)
dev->dma_coherent = true;
dev_info(dev, "use %sncoherent DMA ops\n",
dev_info(dev, "use %scoherent DMA ops\n",
dev->dma_coherent ? "" : "non");
}
......
......@@ -6,11 +6,15 @@
*/
#include <linux/init.h>
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
#include <linux/smp.h>
#include <asm/arcregs.h>
#include <asm/io.h>
#include <asm/mach_desc.h>
int arc_hsdk_axi_dmac_coherent __section(.data) = 0;
#define ARC_CCM_UNUSED_ADDR 0x60000000
static void __init hsdk_init_per_cpu(unsigned int cpu)
......@@ -97,6 +101,42 @@ static void __init hsdk_enable_gpio_intc_wire(void)
iowrite32(GPIO_INT_CONNECTED_MASK, (void __iomem *) GPIO_INTEN);
}
static int __init hsdk_tweak_node_coherency(const char *path, bool coherent)
{
void *fdt = initial_boot_params;
const void *prop;
int node, ret;
bool dt_coh_set;
node = fdt_path_offset(fdt, path);
if (node < 0)
goto tweak_fail;
prop = fdt_getprop(fdt, node, "dma-coherent", &ret);
if (!prop && ret != -FDT_ERR_NOTFOUND)
goto tweak_fail;
dt_coh_set = ret != -FDT_ERR_NOTFOUND;
ret = 0;
/* need to remove "dma-coherent" property */
if (dt_coh_set && !coherent)
ret = fdt_delprop(fdt, node, "dma-coherent");
/* need to set "dma-coherent" property */
if (!dt_coh_set && coherent)
ret = fdt_setprop(fdt, node, "dma-coherent", NULL, 0);
if (ret < 0)
goto tweak_fail;
return 0;
tweak_fail:
pr_err("failed to tweak %s to %scoherent\n", path, coherent ? "" : "non");
return -EFAULT;
}
enum hsdk_axi_masters {
M_HS_CORE = 0,
M_HS_RTT,
......@@ -162,6 +202,39 @@ enum hsdk_axi_masters {
#define CREG_PAE ((void __iomem *)(CREG_BASE + 0x180))
#define CREG_PAE_UPDT ((void __iomem *)(CREG_BASE + 0x194))
static void __init hsdk_init_memory_bridge_axi_dmac(void)
{
bool coherent = !!arc_hsdk_axi_dmac_coherent;
u32 axi_m_slv1, axi_m_oft1;
/*
* Don't tweak memory bridge configuration if we failed to tweak DTB
* as we will end up in a inconsistent state.
*/
if (hsdk_tweak_node_coherency("/soc/dmac@80000", coherent))
return;
if (coherent) {
axi_m_slv1 = 0x77999999;
axi_m_oft1 = 0x76DCBA98;
} else {
axi_m_slv1 = 0x77777777;
axi_m_oft1 = 0x76543210;
}
writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0));
writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0));
writel(axi_m_slv1, CREG_AXI_M_SLV1(M_DMAC_0));
writel(axi_m_oft1, CREG_AXI_M_OFT1(M_DMAC_0));
writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0));
writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1));
writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1));
writel(axi_m_slv1, CREG_AXI_M_SLV1(M_DMAC_1));
writel(axi_m_oft1, CREG_AXI_M_OFT1(M_DMAC_1));
writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1));
}
static void __init hsdk_init_memory_bridge(void)
{
u32 reg;
......@@ -227,24 +300,14 @@ static void __init hsdk_init_memory_bridge(void)
writel(0x76543210, CREG_AXI_M_OFT1(M_GPU));
writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_GPU));
writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0));
writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_0));
writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0));
writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_0));
writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0));
writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1));
writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_1));
writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1));
writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_1));
writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1));
writel(0x00000000, CREG_AXI_M_SLV0(M_DVFS));
writel(0x60000000, CREG_AXI_M_SLV1(M_DVFS));
writel(0x00000000, CREG_AXI_M_OFT0(M_DVFS));
writel(0x00000000, CREG_AXI_M_OFT1(M_DVFS));
writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DVFS));
hsdk_init_memory_bridge_axi_dmac();
/*
* PAE remapping for DMA clients does not work due to an RTL bug, so
* CREG_PAE register must be programmed to all zeroes, otherwise it
......
......@@ -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
......@@ -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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment