From f17d2cd2ffeda70aba8788910e9d088415562c8b Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sat, 7 Oct 2017 01:06:40 +0100 Subject: [PATCH] ARM: sunxi: support more Allwinner SoCs 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 Signed-off-by: Stefano Stabellini Reviewed-by: Stefano Stabellini --- xen/arch/arm/platforms/Makefile | 2 +- xen/arch/arm/platforms/sunxi.c | 96 ++++++++++++++++++++++++++++----- 2 files changed, 85 insertions(+), 13 deletions(-) diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile index 49fa683780..53a47e48d2 100644 --- a/xen/arch/arm/platforms/Makefile +++ b/xen/arch/arm/platforms/Makefile @@ -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 diff --git a/xen/arch/arm/platforms/sunxi.c b/xen/arch/arm/platforms/sunxi.c index 0ba7b3d9b4..55705b15b2 100644 --- a/xen/arch/arm/platforms/sunxi.c +++ b/xen/arch/arm/platforms/sunxi.c @@ -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. * @@ -22,36 +22,103 @@ #include /* 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 -- 2.30.2