Annotation of sys/arch/arm/xscale/pxa2x0_clock.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pxa2x0_clock.c,v 1.5 2007/01/11 07:24:52 robert Exp $ */
2:
3: /*
4: * Copyright (c) 2005 Dale Rahn <drahn@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20: #include <sys/param.h>
21: #include <sys/systm.h>
22: #include <sys/kernel.h>
23: #include <sys/time.h>
24: #include <sys/device.h>
25:
26: #include <machine/bus.h>
27: #include <machine/intr.h>
28:
29: #include <arm/cpufunc.h>
30:
31: #include <arm/sa11x0/sa11x0_reg.h>
32: #include <arm/sa11x0/sa11x0_var.h>
33: #include <arm/sa11x0/sa11x0_ostreg.h>
34: #include <arm/xscale/pxa2x0reg.h>
35:
36: int pxaost_match(struct device *, void *, void *);
37: void pxaost_attach(struct device *, struct device *, void *);
38:
39: int doclockintr(void *);
40: int clockintr(void *);
41: int statintr(void *);
42: void rtcinit(void);
43:
44: struct pxaost_softc {
45: struct device sc_dev;
46: bus_space_tag_t sc_iot;
47: bus_space_handle_t sc_ioh;
48:
49: u_int32_t sc_clock_count;
50: u_int32_t sc_statclock_count;
51: u_int32_t sc_statclock_step;
52: u_int32_t sc_clock_step;
53: u_int32_t sc_clock_step_err_cnt;
54: u_int32_t sc_clock_step_error;
55: };
56:
57: static struct pxaost_softc *pxaost_sc = NULL;
58:
59: #define CLK4_TIMER_FREQUENCY 32768 /* 32.768KHz */
60:
61: #define CLK0_TIMER_FREQUENCY 3250000 /* 3.2500MHz */
62:
63: #ifndef STATHZ
64: #define STATHZ 64
65: #endif
66:
67: struct cfattach pxaost_ca = {
68: sizeof (struct pxaost_softc), pxaost_match, pxaost_attach
69: };
70:
71: struct cfdriver pxaost_cd = {
72: NULL, "pxaost", DV_DULL
73: };
74:
75: int
76: pxaost_match(parent, match, aux)
77: struct device *parent;
78: void *match;
79: void *aux;
80: {
81: return (1);
82: }
83:
84: void
85: pxaost_attach(parent, self, aux)
86: struct device *parent;
87: struct device *self;
88: void *aux;
89: {
90: struct pxaost_softc *sc = (struct pxaost_softc*)self;
91: struct sa11x0_attach_args *sa = aux;
92:
93: printf("\n");
94:
95: sc->sc_iot = sa->sa_iot;
96:
97: pxaost_sc = sc;
98:
99: if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0,
100: &sc->sc_ioh))
101: panic("%s: Cannot map registers", self->dv_xname);
102:
103: /* disable all channel and clear interrupt status */
104: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_IR, 0);
105: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_SR, 0x3f);
106:
107: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OMCR4, 0xc1);
108: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OMCR5, 0x41);
109:
110: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR4,
111: pxaost_sc->sc_clock_count);
112: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR5,
113: pxaost_sc->sc_statclock_count);
114:
115: /* Zero the counter value */
116: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSCR4, 0);
117:
118: }
119:
120: int
121: clockintr(arg)
122: void *arg;
123: {
124: struct clockframe *frame = arg;
125: u_int32_t oscr, match;
126: u_int32_t match_error;
127:
128: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_SR, 0x10);
129:
130: match = pxaost_sc->sc_clock_count;
131:
132: do {
133: match += pxaost_sc->sc_clock_step;
134: pxaost_sc->sc_clock_step_error +=
135: pxaost_sc->sc_clock_step_err_cnt;
136: if (pxaost_sc->sc_clock_count > hz) {
137: match_error = pxaost_sc->sc_clock_step_error / hz;
138: pxaost_sc->sc_clock_step_error -= (match_error * hz);
139: match += match_error;
140: }
141: pxaost_sc->sc_clock_count = match;
142: hardclock(frame);
143:
144: oscr = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh,
145: OST_OSCR4);
146:
147: } while ((signed)(oscr - match) > 0);
148:
149: /* prevent missed interrupts */
150: if (oscr - match < 5)
151: match += 5;
152:
153: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR4,
154: match);
155:
156: return(1);
157: }
158:
159: int
160: statintr(arg)
161: void *arg;
162: {
163: struct clockframe *frame = arg;
164: u_int32_t oscr, match;
165:
166: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_SR, 0x20);
167:
168: /* schedule next clock intr */
169: match = pxaost_sc->sc_statclock_count;
170: do {
171: match += pxaost_sc->sc_statclock_step;
172: pxaost_sc->sc_statclock_count = match;
173: statclock(frame);
174:
175: oscr = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh,
176: OST_OSCR4);
177:
178: } while ((signed)(oscr - match) > 0);
179:
180: /* prevent missed interrupts */
181: if (oscr - match < 5)
182: match += 5;
183: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR5,
184: match);
185:
186: return(1);
187: }
188:
189: void
190: setstatclockrate(int newstathz)
191: {
192: u_int32_t count;
193: pxaost_sc->sc_statclock_step = CLK4_TIMER_FREQUENCY / newstathz;
194: count = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSCR4);
195: count += pxaost_sc->sc_statclock_step;
196: pxaost_sc->sc_statclock_count = count;
197: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh,
198: OST_OSMR5, count);
199: }
200:
201: int
202: doclockintr(void *arg)
203: {
204: u_int32_t status;
205: int result = 0;
206:
207: status = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_SR);
208: if (status & 0x10)
209: result |= clockintr(arg);
210: if (status & 0x20)
211: result |= statintr(arg);
212:
213: return (result);
214: }
215:
216: void
217: cpu_initclocks()
218: {
219: u_int32_t clk;
220:
221: stathz = STATHZ;
222: profhz = stathz;
223: pxaost_sc->sc_statclock_step = CLK4_TIMER_FREQUENCY / stathz;
224: pxaost_sc->sc_clock_step = CLK4_TIMER_FREQUENCY / hz;
225: pxaost_sc->sc_clock_step_err_cnt = CLK4_TIMER_FREQUENCY % hz;
226: pxaost_sc->sc_clock_step_error = 0;
227:
228: /* Use the channels 0 and 1 for hardclock and statclock, respectively */
229: pxaost_sc->sc_clock_count = pxaost_sc->sc_clock_step;
230: pxaost_sc->sc_statclock_count = CLK4_TIMER_FREQUENCY / stathz;
231:
232: pxa2x0_intr_establish(PXA2X0_INT_OST, IPL_CLOCK, doclockintr, 0, "clock");
233:
234: clk = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSCR4);
235:
236: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_SR, 0x3f);
237: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_IR, 0x30);
238: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR4,
239: clk + pxaost_sc->sc_clock_count);
240: bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR5,
241: clk + pxaost_sc->sc_statclock_count);
242: }
243:
244: void
245: microtime(tvp)
246: register struct timeval *tvp;
247: {
248: int s, deltacnt;
249: u_int32_t counter, expected;
250:
251: if (pxaost_sc == NULL) {
252: tvp->tv_sec = 0;
253: tvp->tv_usec = 0;
254: return;
255: }
256:
257: s = splhigh();
258: counter = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh,
259: OST_OSCR4);
260: expected = pxaost_sc->sc_clock_count;
261:
262: *tvp = time;
263: splx(s);
264:
265: /* number of CLK4_TIMER_FREQUENCY ticks past time */
266: deltacnt = counter - expected + pxaost_sc->sc_clock_step;
267:
268: tvp->tv_usec += deltacnt * 1000000ULL / CLK4_TIMER_FREQUENCY;
269:
270: while (tvp->tv_usec >= 1000000) {
271: tvp->tv_sec++;
272: tvp->tv_usec -= 1000000;
273: }
274: }
275:
276: void
277: delay(usecs)
278: u_int usecs;
279: {
280: u_int32_t clock, oclock, delta, delaycnt;
281: volatile int j;
282: int csec, usec;
283:
284: if (usecs > (0x80000000 / (CLK4_TIMER_FREQUENCY))) {
285: csec = usecs / 10000;
286: usec = usecs % 10000;
287:
288: delaycnt = (CLK4_TIMER_FREQUENCY / 100) * csec +
289: (CLK4_TIMER_FREQUENCY / 100) * usec / 10000;
290: } else {
291: delaycnt = CLK4_TIMER_FREQUENCY * usecs / 1000000;
292: }
293:
294: if (delaycnt <= 1)
295: for (j = 100; j > 0; j--)
296: ;
297:
298: if (!pxaost_sc) {
299: /* clock isn't initialized yet */
300: for (; usecs > 0; usecs--)
301: for (j = 100; j > 0; j--)
302: ;
303: return;
304: }
305:
306: oclock = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh,
307: OST_OSCR4);
308:
309: while (1) {
310: for (j = 100; j > 0; j--)
311: ;
312: clock = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh,
313: OST_OSCR4);
314: delta = clock - oclock;
315: if (delta > delaycnt)
316: break;
317: }
318: }
CVSweb