/*
* 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
};
{ /* 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