]> xenbits.xensource.com Git - xen.git/commitdiff
ARM: sunxi: support more Allwinner SoCs
authorAndre Przywara <andre.przywara@arm.com>
Sat, 7 Oct 2017 00:06:40 +0000 (01:06 +0100)
committerStefano Stabellini <sstabellini@kernel.org>
Wed, 11 Oct 2017 00:30:32 +0000 (17:30 -0700)
So far we only supported the Allwinner A20 SoC. Add support for most
of the other virtualization capable Allwinner SoCs by:
- supporting the watchdog in newer (sun8i) SoCs
- getting the watchdog address from DT
- adding compatible strings for other 32-bit SoCs
- adding compatible strings for 64-bit SoCs

As all 64-bit SoCs support system reset via PSCI, we don't use the
platform specific reset routine there. Should the 32-bit SoCs start to
properly support the PSCI 0.2 SYSTEM_RESET call, we will use it for them
automatically, as we try PSCI first, then fall back to platform reset.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
xen/arch/arm/platforms/Makefile
xen/arch/arm/platforms/sunxi.c

index 49fa6837808a5d700f1f965d7747596ff3e81f82..53a47e48d2c06f29aeb3366f59d6540e367ab111 100644 (file)
@@ -5,6 +5,6 @@ obj-$(CONFIG_ARM_32) += midway.o
 obj-$(CONFIG_ARM_32) += omap5.o
 obj-$(CONFIG_ARM_32) += rcar2.o
 obj-$(CONFIG_ARM_64) += seattle.o
-obj-$(CONFIG_ARM_32) += sunxi.o
+obj-y += sunxi.o
 obj-$(CONFIG_ARM_64) += xgene-storm.o
 obj-$(CONFIG_ARM_64) += xilinx-zynqmp.o
index 0ba7b3d9b476a95edb653e120b7b3900a47f7c06..55705b15b209837718b2c4c4b227620dbcd3e8e4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * xen/arch/arm/platforms/sunxi.c
  *
- * SUNXI (AllWinner A20/A31) specific settings
+ * SUNXI (Allwinner ARM SoCs) specific settings
  *
  * Copyright (c) 2013 Citrix Systems.
  *
 #include <asm/io.h>
 
 /* Watchdog constants: */
-#define SUNXI_WDT_BASE            0x01c20c90
-#define SUNXI_WDT_MODE            0x04
-#define SUNXI_WDT_MODEADDR        (SUNXI_WDT_BASE + SUNXI_WDT_MODE)
+#define SUNXI_WDT_MODE_REG        0x04
 #define SUNXI_WDT_MODE_EN         (1 << 0)
 #define SUNXI_WDT_MODE_RST_EN     (1 << 1)
 
+#define SUNXI_WDT_CONFIG_SYSTEM_RESET   (1 << 0)
+#define SUNXI_WDOG0_CFG_REG             0x14
+#define SUNXI_WDOG0_MODE_REG            0x18
 
-static void sunxi_reset(void)
+static void __iomem *sunxi_map_watchdog(bool *new_wdt)
 {
     void __iomem *wdt;
+    struct dt_device_node *node;
+    paddr_t wdt_start, wdt_len;
+    bool _new_wdt = false;
+    int ret;
+
+    node = dt_find_compatible_node(NULL, NULL, "allwinner,sun6i-a31-wdt");
+    if ( node )
+       _new_wdt = true;
+    else
+        node = dt_find_compatible_node(NULL, NULL, "allwinner,sun4i-a10-wdt");
+
+    if ( !node )
+    {
+        dprintk(XENLOG_ERR, "Cannot find matching watchdog node in DT\n");
+        return NULL;
+    }
 
-    wdt = ioremap_nocache(SUNXI_WDT_MODEADDR & PAGE_MASK, PAGE_SIZE);
+    ret = dt_device_get_address(node, 0, &wdt_start, &wdt_len);
+    if ( ret )
+    {
+        dprintk(XENLOG_ERR, "Cannot read watchdog register address\n");
+        return NULL;
+    }
+
+    wdt = ioremap_nocache(wdt_start & PAGE_MASK, PAGE_SIZE);
     if ( !wdt )
     {
         dprintk(XENLOG_ERR, "Unable to map watchdog register!\n");
-        return;
+        return NULL;
     }
 
-    /* Enable watchdog to trigger a reset after 500 ms: */
+    if ( new_wdt )
+        *new_wdt = _new_wdt;
+
+    return wdt + (wdt_start & ~PAGE_MASK);
+}
+
+/* Enable watchdog to trigger a reset after 500 ms */
+static void sunxi_old_wdt_reset(void __iomem *wdt)
+{
     writel(SUNXI_WDT_MODE_EN | SUNXI_WDT_MODE_RST_EN,
-      wdt + (SUNXI_WDT_MODEADDR & ~PAGE_MASK));
+           wdt + SUNXI_WDT_MODE_REG);
+}
+
+static void sunxi_new_wdt_reset(void __iomem *wdt)
+{
+    writel(SUNXI_WDT_CONFIG_SYSTEM_RESET, wdt + SUNXI_WDOG0_CFG_REG);
+    writel(SUNXI_WDT_MODE_EN, wdt + SUNXI_WDOG0_MODE_REG);
+}
+
+static void sunxi_reset(void)
+{
+    void __iomem *wdt;
+    bool is_new_wdt;
+
+    wdt = sunxi_map_watchdog(&is_new_wdt);
+    if ( !wdt )
+        return;
+
+    if ( is_new_wdt )
+        sunxi_new_wdt_reset(wdt);
+    else
+        sunxi_old_wdt_reset(wdt);
+
     iounmap(wdt);
 
     for (;;)
         wfi();
 }
 
-static const char * const sunxi_dt_compat[] __initconst =
+static const char * const sunxi_v7_dt_compat[] __initconst =
 {
+    "allwinner,sun6i-a31",
+    "allwinner,sun6i-a31s",
     "allwinner,sun7i-a20",
+    "allwinner,sun8i-a23",
+    "allwinner,sun8i-a33",
+    "allwinner,sun8i-h2-plus",
+    "allwinner,sun8i-h3",
+    NULL
+};
+
+static const char * const sunxi_v8_dt_compat[] __initconst =
+{
+    "allwinner,sun50i-a64",
+    "allwinner,sun50i-h5",
     NULL
 };
 
@@ -65,12 +132,17 @@ static const struct dt_device_match sunxi_blacklist_dev[] __initconst =
     { /* sentinel */ },
 };
 
-PLATFORM_START(sunxi, "Allwinner A20")
-    .compatible = sunxi_dt_compat,
+PLATFORM_START(sunxi_v7, "Allwinner ARMv7")
+    .compatible = sunxi_v7_dt_compat,
     .blacklist_dev = sunxi_blacklist_dev,
     .reset = sunxi_reset,
 PLATFORM_END
 
+PLATFORM_START(sunxi_v8, "Allwinner ARMv8")
+    .compatible = sunxi_v8_dt_compat,
+    .blacklist_dev = sunxi_blacklist_dev,
+PLATFORM_END
+
 /*
  * Local variables:
  * mode: C