MIPS: Malta: Probe interrupt controllers via DT
Probe the CPU, GIC & i8259 interrupt controllers present in the Malta system using device tree. This enables interrupts to be provided to devices using device tree as they are moved over to being probed using it. Since Malta is very configurable it's unknown whether a GIC will be present at compile time. In order to support both cases the malta_dt_shim code is added in order to detect whether a GIC is present, adjusting the DT to route interrupts correctly and nop out the GIC node if no GIC is found. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: Masahiro Yamada <yamada.masahiro@socionext.com> Cc: Kees Cook <keescook@chromium.org> Cc: Rob Herring <robh+dt@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: devicetree@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14274/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Родитель
0051fc2e7b
Коммит
38ec82fe21
|
@ -479,6 +479,7 @@ config MIPS_MALTA
|
|||
select SYS_SUPPORTS_ZBOOT
|
||||
select SYS_SUPPORTS_RELOCATABLE
|
||||
select USE_OF
|
||||
select LIBFDT
|
||||
select ZONE_DMA32 if 64BIT
|
||||
select BUILTIN_DTB
|
||||
select LIBFDT
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/dts-v1/;
|
||||
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/mips-gic.h>
|
||||
|
||||
/memreserve/ 0x00000000 0x00001000; /* YAMON exception vectors */
|
||||
/memreserve/ 0x00001000 0x000ef000; /* YAMON */
|
||||
/memreserve/ 0x000f0000 0x00010000; /* PIIX4 ISA memory */
|
||||
|
@ -8,4 +11,42 @@
|
|||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "mti,malta";
|
||||
|
||||
cpu_intc: interrupt-controller {
|
||||
compatible = "mti,cpu-interrupt-controller";
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
|
||||
gic: interrupt-controller@1bdc0000 {
|
||||
compatible = "mti,gic";
|
||||
reg = <0x1bdc0000 0x20000>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <3>;
|
||||
|
||||
/*
|
||||
* Declare the interrupt-parent even though the mti,gic
|
||||
* binding doesn't require it, such that the kernel can
|
||||
* figure out that cpu_intc is the root interrupt
|
||||
* controller & should be probed first.
|
||||
*/
|
||||
interrupt-parent = <&cpu_intc>;
|
||||
|
||||
timer {
|
||||
compatible = "mti,gic-timer";
|
||||
interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
|
||||
};
|
||||
};
|
||||
|
||||
i8259: interrupt-controller@20 {
|
||||
compatible = "intel,i8259";
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include <asm/bootinfo.h>
|
||||
#include <asm/fw/fw.h>
|
||||
#include <asm/mips-boards/generic.h>
|
||||
#include <asm/mips-boards/malta.h>
|
||||
#include <asm/mips-cm.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#define ROCIT_REG_BASE 0x1f403000
|
||||
|
@ -226,6 +228,80 @@ static void __init append_memory(void *fdt, int root_off)
|
|||
panic("Unable to set linux,usable-memory property: %d", err);
|
||||
}
|
||||
|
||||
static void __init remove_gic(void *fdt)
|
||||
{
|
||||
int err, gic_off, i8259_off, cpu_off;
|
||||
void __iomem *biu_base;
|
||||
uint32_t cpu_phandle, sc_cfg;
|
||||
|
||||
/* if we have a CM which reports a GIC is present, leave the DT alone */
|
||||
err = mips_cm_probe();
|
||||
if (!err && (read_gcr_gic_status() & CM_GCR_GIC_STATUS_GICEX_MSK))
|
||||
return;
|
||||
|
||||
if (malta_scon() == MIPS_REVISION_SCON_ROCIT) {
|
||||
/*
|
||||
* On systems using the RocIT system controller a GIC may be
|
||||
* present without a CM. Detect whether that is the case.
|
||||
*/
|
||||
biu_base = ioremap_nocache(MSC01_BIU_REG_BASE,
|
||||
MSC01_BIU_ADDRSPACE_SZ);
|
||||
sc_cfg = __raw_readl(biu_base + MSC01_SC_CFG_OFS);
|
||||
if (sc_cfg & MSC01_SC_CFG_GICPRES_MSK) {
|
||||
/* enable the GIC at the system controller level */
|
||||
sc_cfg |= BIT(MSC01_SC_CFG_GICENA_SHF);
|
||||
__raw_writel(sc_cfg, biu_base + MSC01_SC_CFG_OFS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic");
|
||||
if (gic_off < 0) {
|
||||
pr_warn("malta-dtshim: unable to find DT GIC node: %d\n",
|
||||
gic_off);
|
||||
return;
|
||||
}
|
||||
|
||||
err = fdt_nop_node(fdt, gic_off);
|
||||
if (err)
|
||||
pr_warn("malta-dtshim: unable to nop GIC node\n");
|
||||
|
||||
i8259_off = fdt_node_offset_by_compatible(fdt, -1, "intel,i8259");
|
||||
if (i8259_off < 0) {
|
||||
pr_warn("malta-dtshim: unable to find DT i8259 node: %d\n",
|
||||
i8259_off);
|
||||
return;
|
||||
}
|
||||
|
||||
cpu_off = fdt_node_offset_by_compatible(fdt, -1,
|
||||
"mti,cpu-interrupt-controller");
|
||||
if (cpu_off < 0) {
|
||||
pr_warn("malta-dtshim: unable to find CPU intc node: %d\n",
|
||||
cpu_off);
|
||||
return;
|
||||
}
|
||||
|
||||
cpu_phandle = fdt_get_phandle(fdt, cpu_off);
|
||||
if (!cpu_phandle) {
|
||||
pr_warn("malta-dtshim: unable to get CPU intc phandle\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = fdt_setprop_u32(fdt, i8259_off, "interrupt-parent", cpu_phandle);
|
||||
if (err) {
|
||||
pr_warn("malta-dtshim: unable to set i8259 interrupt-parent: %d\n",
|
||||
err);
|
||||
return;
|
||||
}
|
||||
|
||||
err = fdt_setprop_u32(fdt, i8259_off, "interrupts", 2);
|
||||
if (err) {
|
||||
pr_warn("malta-dtshim: unable to set i8259 interrupts: %d\n",
|
||||
err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void __init *malta_dt_shim(void *fdt)
|
||||
{
|
||||
int root_off, len, err;
|
||||
|
@ -251,6 +327,7 @@ void __init *malta_dt_shim(void *fdt)
|
|||
return fdt;
|
||||
|
||||
append_memory(fdt_buf, root_off);
|
||||
remove_gic(fdt_buf);
|
||||
|
||||
err = fdt_pack(fdt_buf);
|
||||
if (err)
|
||||
|
|
|
@ -14,11 +14,13 @@
|
|||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqchip/mips-gic.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/random.h>
|
||||
|
@ -37,10 +39,6 @@
|
|||
#include <asm/setup.h>
|
||||
#include <asm/rtlx.h>
|
||||
|
||||
static void __iomem *_msc01_biu_base;
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(mips_irq_lock);
|
||||
|
||||
static inline int mips_pcibios_iack(void)
|
||||
{
|
||||
int irq;
|
||||
|
@ -85,49 +83,6 @@ static inline int mips_pcibios_iack(void)
|
|||
return irq;
|
||||
}
|
||||
|
||||
static inline int get_int(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int irq;
|
||||
raw_spin_lock_irqsave(&mips_irq_lock, flags);
|
||||
|
||||
irq = mips_pcibios_iack();
|
||||
|
||||
/*
|
||||
* The only way we can decide if an interrupt is spurious
|
||||
* is by checking the 8259 registers. This needs a spinlock
|
||||
* on an SMP system, so leave it up to the generic code...
|
||||
*/
|
||||
|
||||
raw_spin_unlock_irqrestore(&mips_irq_lock, flags);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
static void malta_hw0_irqdispatch(void)
|
||||
{
|
||||
int irq;
|
||||
|
||||
irq = get_int();
|
||||
if (irq < 0) {
|
||||
/* interrupt has already been cleared */
|
||||
return;
|
||||
}
|
||||
|
||||
do_IRQ(MALTA_INT_BASE + irq);
|
||||
|
||||
#ifdef CONFIG_MIPS_VPE_APSP_API_MT
|
||||
if (aprp_hook)
|
||||
aprp_hook();
|
||||
#endif
|
||||
}
|
||||
|
||||
static irqreturn_t i8259_handler(int irq, void *dev_id)
|
||||
{
|
||||
malta_hw0_irqdispatch();
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void corehi_irqdispatch(void)
|
||||
{
|
||||
unsigned int intedge, intsteer, pcicmd, pcibadaddr;
|
||||
|
@ -240,12 +195,6 @@ static struct irqaction irq_call = {
|
|||
};
|
||||
#endif /* CONFIG_MIPS_MT_SMP */
|
||||
|
||||
static struct irqaction i8259irq = {
|
||||
.handler = i8259_handler,
|
||||
.name = "XT-PIC cascade",
|
||||
.flags = IRQF_NO_THREAD,
|
||||
};
|
||||
|
||||
static struct irqaction corehi_irqaction = {
|
||||
.handler = corehi_handler,
|
||||
.name = "CoreHi",
|
||||
|
@ -281,28 +230,10 @@ void __init arch_init_ipiirq(int irq, struct irqaction *action)
|
|||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
int corehi_irq, i8259_irq;
|
||||
int corehi_irq;
|
||||
|
||||
init_i8259_irqs();
|
||||
|
||||
if (!cpu_has_veic)
|
||||
mips_cpu_irq_init();
|
||||
|
||||
if (mips_cm_present()) {
|
||||
write_gcr_gic_base(GIC_BASE_ADDR | CM_GCR_GIC_BASE_GICEN_MSK);
|
||||
gic_present = 1;
|
||||
} else {
|
||||
if (mips_revision_sconid == MIPS_REVISION_SCON_ROCIT) {
|
||||
_msc01_biu_base = ioremap_nocache(MSC01_BIU_REG_BASE,
|
||||
MSC01_BIU_ADDRSPACE_SZ);
|
||||
gic_present =
|
||||
(__raw_readl(_msc01_biu_base + MSC01_SC_CFG_OFS) &
|
||||
MSC01_SC_CFG_GICPRES_MSK) >>
|
||||
MSC01_SC_CFG_GICPRES_SHF;
|
||||
}
|
||||
}
|
||||
if (gic_present)
|
||||
pr_debug("GIC present\n");
|
||||
i8259_set_poll(mips_pcibios_iack);
|
||||
irqchip_init();
|
||||
|
||||
switch (mips_revision_sconid) {
|
||||
case MIPS_REVISION_SCON_SOCIT:
|
||||
|
@ -330,18 +261,6 @@ void __init arch_init_irq(void)
|
|||
}
|
||||
|
||||
if (gic_present) {
|
||||
int i;
|
||||
|
||||
gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, MIPSCPU_INT_GIC,
|
||||
MIPS_GIC_IRQ_BASE);
|
||||
if (!mips_cm_present()) {
|
||||
/* Enable the GIC */
|
||||
i = __raw_readl(_msc01_biu_base + MSC01_SC_CFG_OFS);
|
||||
__raw_writel(i | (0x1 << MSC01_SC_CFG_GICENA_SHF),
|
||||
_msc01_biu_base + MSC01_SC_CFG_OFS);
|
||||
pr_debug("GIC Enabled\n");
|
||||
}
|
||||
i8259_irq = MIPS_GIC_IRQ_BASE + GIC_INT_I8259A;
|
||||
corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
|
||||
} else {
|
||||
#if defined(CONFIG_MIPS_MT_SMP)
|
||||
|
@ -361,19 +280,14 @@ void __init arch_init_irq(void)
|
|||
arch_init_ipiirq(cpu_ipi_call_irq, &irq_call);
|
||||
#endif
|
||||
if (cpu_has_veic) {
|
||||
set_vi_handler(MSC01E_INT_I8259A,
|
||||
malta_hw0_irqdispatch);
|
||||
set_vi_handler(MSC01E_INT_COREHI,
|
||||
corehi_irqdispatch);
|
||||
i8259_irq = MSC01E_INT_BASE + MSC01E_INT_I8259A;
|
||||
corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI;
|
||||
} else {
|
||||
i8259_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_I8259A;
|
||||
corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
|
||||
}
|
||||
}
|
||||
|
||||
setup_irq(i8259_irq, &i8259irq);
|
||||
setup_irq(corehi_irq, &corehi_irqaction);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче