[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.