|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH WIP v1 05/10] WIP: xen: arm: intial platform support for Nvidia TK1
As used on the Jetson board.
This platform has a bunch of specific mappings and, more importantly, an
additional interrupt controller (which is used alongside the main GIC and
covers the same interrupts etc, so it is not a secondary or chained interrupt
controller) which dom0 really wants to poke at, I think for power gating
reasons. This is implemented as a whitelist derived from the set of interrupts
routed to dom0 (discovered by the new route_irq_to_guest platform hook).
Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
xen/arch/arm/platforms/Makefile | 1 +
xen/arch/arm/platforms/tegra.c | 395 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 396 insertions(+)
create mode 100644 xen/arch/arm/platforms/tegra.c
diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile
index e173fec..eb512ed 100644
--- a/xen/arch/arm/platforms/Makefile
+++ b/xen/arch/arm/platforms/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_ARM_32) += brcm.o
obj-$(CONFIG_ARM_32) += exynos5.o
obj-$(CONFIG_ARM_32) += midway.o
obj-$(CONFIG_ARM_32) += omap5.o
+obj-$(CONFIG_ARM_32) += tegra.o
obj-$(CONFIG_ARM_32) += sunxi.o
obj-$(CONFIG_ARM_32) += rcar2.o
obj-$(CONFIG_ARM_64) += seattle.o
diff --git a/xen/arch/arm/platforms/tegra.c b/xen/arch/arm/platforms/tegra.c
new file mode 100644
index 0000000..189ef44
--- /dev/null
+++ b/xen/arch/arm/platforms/tegra.c
@@ -0,0 +1,395 @@
+/*
+ * xen/arch/arm/platforms/tegra.c
+ *
+ * Nvidia Tegra specific settings
+ *
+ * Ian Campbell
+ * Copyright (c) 2014 Citrix Systems
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/config.h>
+#include <asm/platform.h>
+#include <xen/stdbool.h>
+#include <xen/vmap.h>
+#include <asm/io.h>
+#include <asm/gic.h>
+
+#define ICTLR_BASE 0x60004000
+#define ICTLR_SIZE 0x00001000
+
+#define ICTLR_CPU_IEP_VFIQ 0x08
+#define ICTLR_CPU_IEP_FIR 0x14
+#define ICTLR_CPU_IEP_FIR_SET 0x18
+#define ICTLR_CPU_IEP_FIR_CLR 0x1c
+
+#define ICTLR_CPU_IER 0x20
+#define ICTLR_CPU_IER_SET 0x24
+#define ICTLR_CPU_IER_CLR 0x28
+#define ICTLR_CPU_IEP_CLASS 0x2C
+
+#define ICTLR_COP_IER 0x30
+#define ICTLR_COP_IER_SET 0x34
+#define ICTLR_COP_IER_CLR 0x38
+#define ICTLR_COP_IEP_CLASS 0x3c
+
+static void __iomem *ictlr;
+
+struct {
+ uint32_t allow_dom0;
+} ictlr_info[5] = {
+ [0] = { 0x0 },
+ [1] = { 0x0 },
+ [2] = { 0x0 },
+ [3] = { 0x0 },
+ [4] = { 0x0 },
+};
+
+static int ictlr_read(struct vcpu *v, mmio_info_t *info)
+{
+ struct hsr_dabt dabt = info->dabt;
+ struct cpu_user_regs *regs = guest_cpu_user_regs();
+ register_t *r = select_user_reg(regs, dabt.reg);
+ uint32_t offs = info->gpa - ICTLR_BASE;
+ int ctlrnr = offs >> 8;
+ int reg = offs & 0xff;
+
+ uint32_t val;
+
+ if ( offs > 0x4ff )
+ {
+ printk("UNHANDLED READ FROM %"PRIpaddr"\n", info->gpa);
+ domain_crash_synchronous();
+ }
+ if ( offs & 0x3 )
+ {
+ printk("MISALIGNED READ FROM %"PRIpaddr"\n", info->gpa);
+ domain_crash_synchronous();
+ }
+ if ( dabt.size != DABT_WORD )
+ {
+ printk("NON-WORD READ FROM %"PRIpaddr"\n", info->gpa);
+ domain_crash_synchronous();
+ }
+
+ switch ( reg ) {
+ /* Read only */
+ case 0x00 ... 0x14:
+ case 0x20:
+ case 0x30:
+ case 0x60 ... 0x68:
+ case 0x78 ... 0x80:
+ case 0x90 ... 0x98:
+ /* Read/write */
+ case 0x2C:
+ case 0x3C:
+ case 0x74:
+ case 0x8C:
+ case 0xA4:
+ val = readl(ictlr + offs);
+ *r = val & ictlr_info[ctlrnr].allow_dom0;
+ if ( val != *r )
+ printk("TEGRA: ICTLR%d READ %x INTO r%d=%08"PRIregister"
(%08"PRIregister")\n",
+ ctlrnr+1, reg, dabt.reg, *r, val);
+ return 1;
+ /* Write only */
+ case 0x18 ... 0x1c:
+ case 0x24 ... 0x28:
+ case 0x34 ... 0x38:
+ case 0x6C ... 0x70:
+ case 0x84 ... 0x88:
+ case 0x9C ... 0xA0:
+ printk("READ FROM WO %"PRIpaddr"\n", info->gpa);
+ domain_crash_synchronous();
+ break;
+ case 0xa8 ... 0xff:
+ printk("READ FROM NON-EXISTENT %"PRIpaddr"\n", info->gpa);
+ domain_crash_synchronous();
+ break;
+ default:
+ BUG();
+ }
+}
+
+static int ictlr_write(struct vcpu *v, mmio_info_t *info)
+{
+ struct hsr_dabt dabt = info->dabt;
+ struct cpu_user_regs *regs = guest_cpu_user_regs();
+ register_t *r = select_user_reg(regs, dabt.reg);
+ uint32_t offs = info->gpa - ICTLR_BASE;
+ int ctlrnr = offs >> 8;
+ int reg = offs & 0xff;
+
+ uint32_t val = *r;
+
+ if ( offs > 0x4ff )
+ {
+ printk("UNHANDLED WRITE TO %"PRIpaddr"\n", info->gpa);
+ domain_crash_synchronous();
+ }
+ if ( offs & 0x3 )
+ {
+ printk("MISALIGNED WRITE TO %"PRIpaddr"\n", info->gpa);
+ domain_crash_synchronous();
+ }
+ if ( dabt.size != DABT_WORD )
+ {
+ printk("NON-WORD WRITE TO %"PRIpaddr"\n", info->gpa);
+ domain_crash_synchronous();
+ }
+
+ val &= ictlr_info[ctlrnr].allow_dom0;
+
+ switch ( reg ) {
+ /* Read only */
+ case 0x00 ... 0x14:
+ case 0x20:
+ case 0x30:
+ case 0x60 ... 0x68:
+ case 0x78 ... 0x80:
+ case 0x90 ... 0x98:
+ printk("WRITE TO RO %"PRIpaddr"\n", info->gpa);
+ domain_crash_synchronous();
+ /* Read/write */
+ case 0x2C:
+ case 0x3C:
+ case 0x74:
+ case 0x8C:
+ case 0xA4:
+ /* Write only */
+ case 0x18 ... 0x1c:
+ case 0x24 ... 0x28:
+ case 0x34 ... 0x38:
+ case 0x6C ... 0x70:
+ case 0x84 ... 0x88:
+ case 0x9C ... 0xA0:
+ if ( val != *r )
+ printk("TEGRA: ICTLR%d WRITE r%d=%08"PRIregister"
(%08"PRIregister") INTO %x\n",
+ ctlrnr+1, dabt.reg, val, *r, reg);
+ writel(val, ictlr + offs);
+ return 1;
+ case 0xa8 ... 0xff:
+ printk("READ FROM NON-EXISTENT %"PRIpaddr"\n", info->gpa);
+ domain_crash_synchronous();
+ break;
+ default:
+ BUG();
+ }
+}
+
+static struct mmio_handler_ops tegra_mmio_ictlr = {
+ .read_handler = ictlr_read,
+ .write_handler = ictlr_write,
+};
+
+static void tegra_route_irq_to_guest(struct domain *d, struct irq_desc *desc)
+{
+ int irq = desc->irq;
+ int ctlrnr;
+ uint32_t mask;
+
+ if ( irq < NR_LOCAL_IRQS )
+ return;
+
+ if ( d->domain_id )
+ return;
+
+ ctlrnr = ( irq - NR_LOCAL_IRQS ) / 32;
+ mask = BIT((irq - NR_LOCAL_IRQS) % 32);
+ printk("TEGRA: Routing IRQ%d to dom0, ICTLR%d, mask %#08x\n",
+ irq, ctlrnr, mask);
+ ictlr_info[ctlrnr].allow_dom0 |= mask;
+}
+
+static int map_one_mmio(struct domain *d, const char *what,
+ unsigned long start, unsigned long end)
+{
+ int ret;
+
+ printk("Additional MMIO %lx-%lx (%s)\n",
+ start, end, what);
+ ret = map_mmio_regions(d, start, end - start + 1, start);
+ if ( ret )
+ printk("Failed to map %s @ %lx to dom%d\n",
+ what, start, d->domain_id);
+ return ret;
+}
+
+static int map_one_spi(struct domain *d, const char *what,
+ unsigned int spi, unsigned int type)
+{
+ unsigned int irq;
+ int ret;
+
+ irq = spi + 32; /* SPIs start at IRQ 32 */
+
+ ret = irq_set_spi_type(irq, type);
+ if ( ret )
+ {
+ printk("Failed to set the type for IRQ%u\n", irq);
+ return ret;
+ }
+
+ printk("Additional IRQ %u (%s)\n", irq, what);
+
+ ret = route_irq_to_guest(d, irq, what);
+ if ( ret )
+ printk("Failed to route %s to dom%d\n", what, d->domain_id);
+
+ return ret;
+}
+
+/*
+ * Xen does not currently support mapping MMIO regions and interrupt
+ * for bus child devices (referenced via the "ranges" and
+ * "interrupt-map" properties to domain 0). Instead for now map the
+ * necessary resources manually.
+ */
+static int tegra_specific_mapping(struct domain *d)
+{
+ int ret;
+
+ ret = map_one_mmio(d, "IRAM", paddr_to_pfn(0x40000000),
+ paddr_to_pfn(0x40040000));
+ if ( ret )
+ goto err;
+
+ ret = map_one_mmio(d, "Display A", paddr_to_pfn(0x54200000),
+ paddr_to_pfn(0x54240000));
+ if ( ret )
+ goto err;
+
+ ret = map_one_mmio(d, "Display B", paddr_to_pfn(0x54240000),
+ paddr_to_pfn(0x54280000));
+ if ( ret )
+ goto err;
+
+ ret = map_one_mmio(d, "EXCEPTION VECTORS", paddr_to_pfn(0x6000f000),
+ paddr_to_pfn(0x60010000));
+ if ( ret )
+ goto err;
+
+ ret = map_one_mmio(d, "SYSREG", paddr_to_pfn(0x6000c000),
+ paddr_to_pfn(0x6000d000));
+ if ( ret )
+ goto err;
+
+ ret = map_one_mmio(d, "PCI CFG0", paddr_to_pfn(0x01000000),
+ paddr_to_pfn(0x01001000));
+ if ( ret )
+ goto err;
+ ret = map_one_mmio(d, "PCI CFG1", paddr_to_pfn(0x01001000),
+ paddr_to_pfn(0x01002000));
+ if ( ret )
+ goto err;
+ ret = map_one_mmio(d, "PCI IO", paddr_to_pfn(0x12000000),
+ paddr_to_pfn(0x12010000));
+ if ( ret )
+ goto err;
+ ret = map_one_mmio(d, "PCI MEM", paddr_to_pfn(0x13000000),
+ paddr_to_pfn(0x20000000));
+ if ( ret )
+ goto err;
+ ret = map_one_mmio(d, "PCI MEM (PREFETCH)", paddr_to_pfn(0x20000000),
+ paddr_to_pfn(0x40000000));
+ if ( ret )
+ goto err;
+
+ ret = map_one_spi(d, "DISPLAY", 73, DT_IRQ_TYPE_LEVEL_HIGH);
+ if ( ret )
+ goto err;
+
+ ret = map_one_spi(d, "DISPLAY B", 74, DT_IRQ_TYPE_LEVEL_HIGH);
+ if ( ret )
+ goto err;
+
+ register_mmio_handler(d, &tegra_mmio_ictlr, ICTLR_BASE, ICTLR_SIZE);
+
+ ret = 0;
+err:
+ return ret;
+}
+
+static void tegra_reset(void)
+{
+ void __iomem *addr;
+ u32 val;
+ addr = ioremap_nocache(0x7000e400, 4);
+
+ if ( !addr )
+ {
+ printk("Tegra: Unable to map tegra reset address, can not reset...\n");
+ return;
+ }
+
+ val = readl(addr);
+ val |= 0x10;
+ writel(val, addr);
+
+ iounmap(addr);
+}
+
+
+static int tegra_init(void)
+{
+ int i;
+
+ ictlr = ioremap_nocache(ICTLR_BASE, ICTLR_SIZE);
+ if ( !ictlr )
+ panic("Failed to map intc\n");
+
+ for (i = 0; i < ARRAY_SIZE(ictlr_info); i++) {
+ void __iomem *ictlr_n = ictlr + 0x100*i;
+ writel(~0, ictlr_n + ICTLR_CPU_IER_CLR);
+ writel(0, ictlr_n + ICTLR_CPU_IEP_CLASS);
+ }
+
+ return 0;
+}
+
+static const char * const tegra_dt_compat[] __initconst =
+{
+ "nvidia,tegra124",
+ NULL
+};
+
+static const struct dt_device_match tegra_blacklist_dev[] __initconst =
+{
+ /*
+ * The UARTs share a page which runs the risk of mapping the Xen console
+ * UART to dom0, so don't map any of them.
+ */
+ DT_MATCH_COMPATIBLE("nvidia,tegra20-uart"),
+ { /* sentinel */ },
+};
+
+PLATFORM_START(tegra, "TEGRA124")
+ .compatible = tegra_dt_compat,
+ .blacklist_dev = tegra_blacklist_dev,
+ .init = tegra_init,
+ .reset = tegra_reset,
+ .specific_mapping = tegra_specific_mapping,
+
+ .route_irq_to_guest = tegra_route_irq_to_guest,
+
+ .dom0_gnttab_start = 0x68000000,
+ .dom0_gnttab_size = 0x20000,
+PLATFORM_END
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
2.1.4
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |