]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/at91/at91_rst.c
Merge clang trunk r321414 to contrib/llvm.
[FreeBSD/FreeBSD.git] / sys / arm / at91 / at91_rst.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2010 Greg Ansley.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include "opt_platform.h"
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #include <sys/rman.h>
38 #include <sys/systm.h>
39
40 #include <machine/bus.h>
41
42 #include <arm/at91/at91var.h>
43 #include <arm/at91/at91_rstreg.h>
44 #include <arm/at91/at91board.h>
45
46 #ifdef FDT
47 #include <dev/ofw/ofw_bus.h>
48 #include <dev/ofw/ofw_bus_subr.h>
49 #define FDT_HACKS 1
50 #endif
51
52 #define RST_TIMEOUT (5) /* Seconds to hold NRST for hard reset */
53 #define RST_TICK (20)   /* sample NRST at hz/RST_TICK intervals */
54
55 #ifndef FDT
56 static int at91_rst_intr(void *arg);
57 #endif
58
59 static struct at91_rst_softc {
60         struct resource *mem_res;       /* Memory resource */
61         struct resource *irq_res;       /* IRQ resource */
62         void            *intrhand;      /* Interrupt handle */
63         struct callout  tick_ch;        /* Tick callout */
64         device_t        sc_dev;
65         u_int           shutdown;       /* Shutdown in progress */
66 } *at91_rst_sc;
67
68 static inline uint32_t
69 RD4(struct at91_rst_softc *sc, bus_size_t off)
70 {
71
72         return (bus_read_4(sc->mem_res, off));
73 }
74
75 static inline void
76 WR4(struct at91_rst_softc *sc, bus_size_t off, uint32_t val)
77 {
78
79         bus_write_4(sc->mem_res, off, val);
80 }
81
82 void cpu_reset_sam9g20(void) __attribute__((weak));
83 void cpu_reset_sam9g20(void) {}
84
85 void
86 at91_rst_cpu_reset(void)
87 {
88
89         if (at91_rst_sc) {
90                 cpu_reset_sam9g20(); /* May be null */
91
92                 WR4(at91_rst_sc, RST_MR,
93                     RST_MR_ERSTL(0xd) | RST_MR_URSTEN | RST_MR_KEY);
94
95                 WR4(at91_rst_sc, RST_CR,
96                     RST_CR_PROCRST |
97                     RST_CR_PERRST  |
98                     RST_CR_EXTRST  |
99                     RST_CR_KEY);
100         }
101         while(1)
102                 continue;
103 }
104
105 static int
106 at91_rst_probe(device_t dev)
107 {
108 #ifdef FDT
109         if (!ofw_bus_is_compatible(dev, "atmel,at91sam9260-rstc"))
110                 return (ENXIO);
111 #endif
112
113         device_set_desc(dev, "AT91SAM9 Reset Controller");
114         return (0);
115 }
116
117 static int
118 at91_rst_attach(device_t dev)
119 {
120         struct at91_rst_softc *sc;
121         const char *cause;
122         int rid, err = 0;
123
124         at91_rst_sc = sc = device_get_softc(dev);
125         sc->sc_dev = dev;
126
127         callout_init(&sc->tick_ch, 0);
128
129         rid = 0;
130         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
131             RF_ACTIVE);
132         if (sc->mem_res == NULL) {
133                 device_printf(dev, "could not allocate memory resources.\n");
134                 err = ENOMEM;
135                 goto out;
136         }
137
138 #ifndef FDT_HACKS
139         rid = 0;
140         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
141             RF_ACTIVE | RF_SHAREABLE);
142         if (sc->irq_res == NULL) {
143                 device_printf(dev, "could not allocate interrupt resources.\n");
144                 err = ENOMEM;
145                 goto out;
146         }
147
148         /* Activate the interrupt. */
149         err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
150             at91_rst_intr, NULL, sc, &sc->intrhand);
151         if (err)
152                 device_printf(dev, "could not establish interrupt handler.\n");
153 #endif
154
155         WR4(at91_rst_sc, RST_MR, RST_MR_ERSTL(0xd) | RST_MR_URSIEN | RST_MR_KEY);
156
157         switch (RD4(sc, RST_SR) & RST_SR_RST_MASK) {
158                 case    RST_SR_RST_POW:
159                         cause = "Power On";
160                         break;
161                 case    RST_SR_RST_WAKE:
162                         cause = "Wake Up";
163                         break;
164                 case    RST_SR_RST_WDT:
165                         cause = "Watchdog";
166                         break;
167                 case    RST_SR_RST_SOFT:
168                         cause = "Software Request";
169                         break;
170                 case    RST_SR_RST_USR:
171                         cause = "External (User)";
172                         break;
173                 default:
174                         cause = "Unknown";
175                         break;
176         }
177
178         device_printf(dev, "Reset cause: %s.\n", cause);
179 out:
180         return (err);
181 }
182
183 #ifndef FDT_HACKS
184 static void
185 at91_rst_tick(void *argp)
186 {
187         struct at91_rst_softc *sc = argp;
188
189         if (sc->shutdown++ >= RST_TIMEOUT * RST_TICK) {
190                 /* User released the button in morre than RST_TIMEOUT */
191                 cpu_reset();
192         } else if ((RD4(sc, RST_SR) & RST_SR_NRSTL)) {
193                 /* User released the button in less than RST_TIMEOUT */
194                 sc->shutdown = 0;
195                 device_printf(sc->sc_dev, "shutting down...\n");
196                 shutdown_nice(0);
197         } else {
198                 callout_reset(&sc->tick_ch, hz/RST_TICK, at91_rst_tick, sc);
199         }
200 }
201
202 static int
203 at91_rst_intr(void *argp)
204 {
205         struct at91_rst_softc *sc = argp;
206
207         if (RD4(sc, RST_SR) & RST_SR_URSTS) {
208                 if (sc->shutdown == 0)
209                         callout_reset(&sc->tick_ch, hz/RST_TICK, at91_rst_tick, sc);
210                 return (FILTER_HANDLED);
211         }
212         return (FILTER_STRAY);
213 }
214 #endif
215
216 static device_method_t at91_rst_methods[] = {
217         DEVMETHOD(device_probe, at91_rst_probe),
218         DEVMETHOD(device_attach, at91_rst_attach),
219         DEVMETHOD_END
220 };
221
222 static driver_t at91_rst_driver = {
223         "at91_rst",
224         at91_rst_methods,
225         sizeof(struct at91_rst_softc),
226 };
227
228 static devclass_t at91_rst_devclass;
229
230 #ifdef FDT
231 DRIVER_MODULE(at91_rst, simplebus, at91_rst_driver, at91_rst_devclass, NULL,
232     NULL);
233 #else
234 DRIVER_MODULE(at91_rst, atmelarm, at91_rst_driver, at91_rst_devclass, NULL,
235     NULL);
236 #endif