1 /*
2 * xen/arch/arm/platforms/sunxi.c
3 *
4 * SUNXI (Allwinner ARM SoCs) specific settings
5 *
6 * Copyright (c) 2013 Citrix Systems.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19 #include <xen/mm.h>
20 #include <xen/vmap.h>
21 #include <asm/platform.h>
22 #include <asm/io.h>
23
24 /* Watchdog constants: */
25 #define SUNXI_WDT_MODE_REG 0x04
26 #define SUNXI_WDT_MODE_EN (1 << 0)
27 #define SUNXI_WDT_MODE_RST_EN (1 << 1)
28
29 #define SUNXI_WDT_CONFIG_SYSTEM_RESET (1 << 0)
30 #define SUNXI_WDOG0_CFG_REG 0x14
31 #define SUNXI_WDOG0_MODE_REG 0x18
32
sunxi_map_watchdog(bool * new_wdt)33 static void __iomem *sunxi_map_watchdog(bool *new_wdt)
34 {
35 void __iomem *wdt;
36 struct dt_device_node *node;
37 paddr_t wdt_start, wdt_len;
38 bool _new_wdt = false;
39 int ret;
40
41 node = dt_find_compatible_node(NULL, NULL, "allwinner,sun6i-a31-wdt");
42 if ( node )
43 _new_wdt = true;
44 else
45 node = dt_find_compatible_node(NULL, NULL, "allwinner,sun4i-a10-wdt");
46
47 if ( !node )
48 {
49 dprintk(XENLOG_ERR, "Cannot find matching watchdog node in DT\n");
50 return NULL;
51 }
52
53 ret = dt_device_get_address(node, 0, &wdt_start, &wdt_len);
54 if ( ret )
55 {
56 dprintk(XENLOG_ERR, "Cannot read watchdog register address\n");
57 return NULL;
58 }
59
60 wdt = ioremap_nocache(wdt_start & PAGE_MASK, PAGE_SIZE);
61 if ( !wdt )
62 {
63 dprintk(XENLOG_ERR, "Unable to map watchdog register!\n");
64 return NULL;
65 }
66
67 if ( new_wdt )
68 *new_wdt = _new_wdt;
69
70 return wdt + (wdt_start & ~PAGE_MASK);
71 }
72
73 /* Enable watchdog to trigger a reset after 500 ms */
sunxi_old_wdt_reset(void __iomem * wdt)74 static void sunxi_old_wdt_reset(void __iomem *wdt)
75 {
76 writel(SUNXI_WDT_MODE_EN | SUNXI_WDT_MODE_RST_EN,
77 wdt + SUNXI_WDT_MODE_REG);
78 }
79
sunxi_new_wdt_reset(void __iomem * wdt)80 static void sunxi_new_wdt_reset(void __iomem *wdt)
81 {
82 writel(SUNXI_WDT_CONFIG_SYSTEM_RESET, wdt + SUNXI_WDOG0_CFG_REG);
83 writel(SUNXI_WDT_MODE_EN, wdt + SUNXI_WDOG0_MODE_REG);
84 }
85
sunxi_reset(void)86 static void sunxi_reset(void)
87 {
88 void __iomem *wdt;
89 bool is_new_wdt;
90
91 wdt = sunxi_map_watchdog(&is_new_wdt);
92 if ( !wdt )
93 return;
94
95 if ( is_new_wdt )
96 sunxi_new_wdt_reset(wdt);
97 else
98 sunxi_old_wdt_reset(wdt);
99
100 iounmap(wdt);
101
102 for (;;)
103 wfi();
104 }
105
106 static const char * const sunxi_v7_dt_compat[] __initconst =
107 {
108 "allwinner,sun6i-a31",
109 "allwinner,sun6i-a31s",
110 "allwinner,sun7i-a20",
111 "allwinner,sun8i-a23",
112 "allwinner,sun8i-a33",
113 "allwinner,sun8i-h2-plus",
114 "allwinner,sun8i-h3",
115 NULL
116 };
117
118 static const char * const sunxi_v8_dt_compat[] __initconst =
119 {
120 "allwinner,sun50i-a64",
121 "allwinner,sun50i-h5",
122 NULL
123 };
124
125 static const struct dt_device_match sunxi_blacklist_dev[] __initconst =
126 {
127 /*
128 * The UARTs share a page which runs the risk of mapping the Xen console
129 * UART to dom0, so don't map any of them.
130 */
131 DT_MATCH_COMPATIBLE("snps,dw-apb-uart"),
132 { /* sentinel */ },
133 };
134
135 PLATFORM_START(sunxi_v7, "Allwinner ARMv7")
136 .compatible = sunxi_v7_dt_compat,
137 .blacklist_dev = sunxi_blacklist_dev,
138 .reset = sunxi_reset,
139 PLATFORM_END
140
141 PLATFORM_START(sunxi_v8, "Allwinner ARMv8")
142 .compatible = sunxi_v8_dt_compat,
143 .blacklist_dev = sunxi_blacklist_dev,
144 PLATFORM_END
145
146 /*
147 * Local variables:
148 * mode: C
149 * c-file-style: "BSD"
150 * c-basic-offset: 4
151 * indent-tabs-mode: nil
152 * End:
153 */
154