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