Annotation of sys/arch/arm/xscale/pxa2x0_clock.c, Revision 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