FreeBSD/Linux Kernel Cross Reference
sys/arm/at91/at91_st.c
1 /*-
2 * Copyright (c) 2005 Olivier Houchard. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25 #include <sys/cdefs.h>
26 __FBSDID("$FreeBSD: releng/6.2/sys/arm/at91/at91_st.c 160480 2006-07-18 21:55:36Z imp $");
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/module.h>
32 #include <sys/time.h>
33 #include <sys/bus.h>
34 #include <sys/resource.h>
35 #include <sys/rman.h>
36 #include <sys/timetc.h>
37
38 #include <machine/bus.h>
39 #include <machine/cpu.h>
40 #include <machine/cpufunc.h>
41 #include <machine/resource.h>
42 #include <machine/frame.h>
43 #include <machine/intr.h>
44 #include <arm/at91/at91rm92reg.h>
45 #include <arm/at91/at91var.h>
46 #include <arm/at91/at91_streg.h>
47
48 static struct at91st_softc {
49 bus_space_tag_t sc_st;
50 bus_space_handle_t sc_sh;
51 device_t dev;
52 } *timer_softc;
53
54 #define RD4(off) \
55 bus_space_read_4(timer_softc->sc_st, timer_softc->sc_sh, (off))
56 #define WR4(off, val) \
57 bus_space_write_4(timer_softc->sc_st, timer_softc->sc_sh, (off), (val))
58
59 static inline int
60 st_crtr(void)
61 {
62 int cur1, cur2;
63 do {
64 cur1 = RD4(ST_CRTR);
65 cur2 = RD4(ST_CRTR);
66 } while (cur1 != cur2);
67 return (cur1);
68 }
69
70 static unsigned at91st_get_timecount(struct timecounter *tc);
71
72 static struct timecounter at91st_timecounter = {
73 at91st_get_timecount, /* get_timecount */
74 NULL, /* no poll_pps */
75 #ifdef SKYEYE_WORKAROUNDS
76 0xffffffffu, /* counter_mask */
77 #else
78 0xfffffu, /* counter_mask */
79 #endif
80 32768, /* frequency */
81 "AT91RM9200 timer", /* name */
82 1000 /* quality */
83 };
84
85 static int
86 at91st_probe(device_t dev)
87 {
88
89 device_set_desc(dev, "ST");
90 return (0);
91 }
92
93 static int
94 at91st_attach(device_t dev)
95 {
96 struct at91_softc *sc = device_get_softc(device_get_parent(dev));
97
98 timer_softc = device_get_softc(dev);
99 timer_softc->sc_st = sc->sc_st;
100 timer_softc->dev = dev;
101 if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_ST_BASE,
102 AT91RM92_ST_SIZE, &timer_softc->sc_sh) != 0)
103 panic("couldn't subregion timer registers");
104 /*
105 * Real time counter increments every clock cycle, need to set before
106 * initializing clocks so that DELAY works.
107 */
108 WR4(ST_RTMR, 1);
109 /* Disable all interrupts */
110 WR4(ST_IDR, 0xffffffff);
111 return (0);
112 }
113
114 static device_method_t at91st_methods[] = {
115 DEVMETHOD(device_probe, at91st_probe),
116 DEVMETHOD(device_attach, at91st_attach),
117 {0, 0},
118 };
119
120 static driver_t at91st_driver = {
121 "at91_st",
122 at91st_methods,
123 sizeof(struct at91st_softc),
124 };
125 static devclass_t at91st_devclass;
126
127 DRIVER_MODULE(at91_st, atmelarm, at91st_driver, at91st_devclass, 0, 0);
128
129 #ifdef SKYEYE_WORKAROUNDS
130 static unsigned long tot_count = 0;
131 #endif
132
133 static unsigned
134 at91st_get_timecount(struct timecounter *tc)
135 {
136 #ifdef SKYEYE_WORKAROUNDS
137 return (tot_count);
138 #else
139 return (st_crtr());
140 #endif
141 }
142
143 static void
144 clock_intr(void *arg)
145 {
146 struct clockframe *fp = arg;
147
148 /* The interrupt is shared, so we have to make sure it's for us. */
149 if (RD4(ST_SR) & ST_SR_PITS) {
150 #ifdef SKYEYE_WORKAROUNDS
151 tot_count += 32768 / hz;
152 #endif
153 hardclock(fp);
154 }
155 }
156
157 void
158 cpu_initclocks(void)
159 {
160 int rel_value;
161 struct resource *irq;
162 int rid = 0;
163 void *ih;
164 device_t dev = timer_softc->dev;
165
166 if (32768 % hz) {
167 printf("Cannot get %d Hz clock; using 128Hz\n", hz);
168 hz = 128;
169 }
170 rel_value = 32768 / hz;
171 /* Disable all interrupts. */
172 WR4(ST_IDR, 0xffffffff);
173 /* The system timer shares the system irq (1) */
174 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 1, 1, 1,
175 RF_ACTIVE | RF_SHAREABLE);
176 if (!irq)
177 panic("Unable to allocate irq for the system timer");
178 else
179 bus_setup_intr(dev, irq, INTR_TYPE_CLK | INTR_FAST,
180 clock_intr, NULL, &ih);
181
182 WR4(ST_PIMR, rel_value);
183
184 /* Enable PITS interrupts. */
185 WR4(ST_IER, ST_SR_PITS);
186 tc_init(&at91st_timecounter);
187 }
188
189 void
190 DELAY(int n)
191 {
192 uint32_t start, end, cur;
193
194 start = st_crtr();
195 n = (n * 1000) / 32768;
196 if (n <= 0)
197 n = 1;
198 end = (start + n) & ST_CRTR_MASK;
199 cur = start;
200 if (start > end) {
201 while (cur >= start || cur < end)
202 cur = st_crtr();
203 } else {
204 while (cur < end)
205 cur = st_crtr();
206 }
207 }
208
209 void
210 cpu_reset(void)
211 {
212 /*
213 * Reset the CPU by programmig the watchdog timer to reset the
214 * CPU after 128 'slow' clocks, or about ~4ms. Loop until
215 * the reset happens for safety.
216 */
217 WR4(ST_WDMR, ST_WDMR_RSTEN | 2);
218 WR4(ST_CR, ST_CR_WDRST);
219 while (1)
220 continue;
221 }
222
223 void
224 cpu_startprofclock(void)
225 {
226 }
227
228 void
229 cpu_stopprofclock(void)
230 {
231 }
232
Cache object: b810e78b68ba2b562e2c4c37c8ce45b2
|