1 /* $NetBSD: epclk.c,v 1.17 2009/10/23 00:39:30 snj Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Jesse Off 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Driver for the ep93xx clock tick. 31 * 32 * We use the 64Hz RTC interrupt as its the only thing that allows for timekeeping 33 * of a second (crystal error only). There are two general purpose timers 34 * on the ep93xx, but they run at a frequency that makes a perfect integer 35 * number of ticks per second impossible. Note that there was an errata with 36 * the ep93xx processor and many early boards (including the Cirrus eval board) have 37 * a broken crystal oscillator input that may make this 64Hz unreliable. However, 38 * not all boards are susceptible, the Technologic Systems TS-7200 is a notable 39 * exception that is immune to this errata. --joff 40 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: epclk.c,v 1.17 2009/10/23 00:39:30 snj Exp $"); 44 45 #include <sys/types.h> 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/kernel.h> 49 #include <sys/time.h> 50 #include <sys/timetc.h> 51 #include <sys/device.h> 52 53 #include <machine/bus.h> 54 #include <machine/intr.h> 55 56 #include <arm/cpufunc.h> 57 58 #include <arm/ep93xx/epsocvar.h> 59 #include <arm/ep93xx/epclkreg.h> 60 #include <arm/ep93xx/ep93xxreg.h> 61 #include <arm/ep93xx/ep93xxvar.h> 62 #include <dev/clock_subr.h> 63 64 #include "opt_hz.h" 65 66 #define TIMER_FREQ 983040 67 68 static int epclk_match(struct device *, struct cfdata *, void *); 69 static void epclk_attach(struct device *, struct device *, void *); 70 static u_int epclk_get_timecount(struct timecounter *); 71 72 void rtcinit(void); 73 74 /* callback functions for intr_functions */ 75 static int epclk_intr(void* arg); 76 77 struct epclk_softc { 78 struct device sc_dev; 79 bus_addr_t sc_baseaddr; 80 bus_space_tag_t sc_iot; 81 bus_space_handle_t sc_ioh; 82 #if defined(HZ) && (HZ == 64) 83 bus_space_handle_t sc_teoi_ioh; 84 #endif 85 int sc_intr; 86 }; 87 88 static struct timecounter epclk_timecounter = { 89 epclk_get_timecount, /* get_timecount */ 90 0, /* no poll_pps */ 91 ~0u, /* counter_mask */ 92 TIMER_FREQ, /* frequency */ 93 "epclk", /* name */ 94 100, /* quality */ 95 NULL, /* prev */ 96 NULL, /* next */ 97 }; 98 99 static struct epclk_softc *epclk_sc = NULL; 100 101 CFATTACH_DECL(epclk, sizeof(struct epclk_softc), 102 epclk_match, epclk_attach, NULL, NULL); 103 104 /* This is a quick ARM way to multiply by 983040/1000000 (w/o overflow) */ 105 #define US_TO_TIMER4VAL(x, y) { \ 106 u_int32_t hi, lo, scalar = 4222124650UL; \ 107 __asm volatile ( \ 108 "umull %0, %1, %2, %3;" \ 109 : "=&r"(lo), "=&r"(hi) \ 110 : "r"((x)), "r"(scalar) \ 111 ); \ 112 (y) = hi; \ 113 } 114 115 #define TIMER4VAL() (*(volatile u_int32_t *)(EP93XX_APB_VBASE + \ 116 EP93XX_APB_TIMERS + EP93XX_TIMERS_Timer4ValueLow)) 117 118 static int 119 epclk_match(struct device *parent, struct cfdata *match, void *aux) 120 { 121 122 return 2; 123 } 124 125 static void 126 epclk_attach(struct device *parent, struct device *self, void *aux) 127 { 128 struct epclk_softc *sc; 129 struct epsoc_attach_args *sa; 130 bool first_run; 131 132 printf("\n"); 133 134 sc = (struct epclk_softc*) self; 135 sa = aux; 136 sc->sc_iot = sa->sa_iot; 137 sc->sc_baseaddr = sa->sa_addr; 138 sc->sc_intr = sa->sa_intr; 139 140 if (epclk_sc == NULL) { 141 first_run = true; 142 epclk_sc = sc; 143 } 144 145 if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 146 0, &sc->sc_ioh)) 147 panic("%s: Cannot map registers", self->dv_xname); 148 #if defined(HZ) && (HZ == 64) 149 if (bus_space_map(sa->sa_iot, EP93XX_APB_HWBASE + EP93XX_APB_SYSCON + 150 EP93XX_SYSCON_TEOI, 4, 0, &sc->sc_teoi_ioh)) 151 panic("%s: Cannot map registers", self->dv_xname); 152 #endif 153 154 /* clear and start the debug timer (Timer4) */ 155 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EP93XX_TIMERS_Timer4Enable, 0); 156 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EP93XX_TIMERS_Timer4Enable, 0x100); 157 158 if (first_run) 159 tc_init(&epclk_timecounter); 160 } 161 162 /* 163 * epclk_intr: 164 * 165 * Handle the hardclock interrupt. 166 */ 167 static int 168 epclk_intr(void *arg) 169 { 170 struct epclk_softc* sc; 171 172 sc = epclk_sc; 173 174 #if defined(HZ) && (HZ == 64) 175 bus_space_write_4(sc->sc_iot, sc->sc_teoi_ioh, 0, 1); 176 #else 177 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EP93XX_TIMERS_Timer1Clear, 1); 178 #endif 179 hardclock((struct clockframe*) arg); 180 return (1); 181 } 182 183 /* 184 * setstatclockrate: 185 * 186 * Set the rate of the statistics clock. 187 * 188 * We assume that hz is either stathz or profhz, and that neither 189 * will change after being set by cpu_initclocks(). We could 190 * recalculate the intervals here, but that would be a pain. 191 */ 192 void 193 setstatclockrate(int newhz) 194 { 195 196 /* use hardclock */ 197 } 198 199 /* 200 * cpu_initclocks: 201 * 202 * Initialize the clock and get them going. 203 */ 204 void 205 cpu_initclocks(void) 206 { 207 struct epclk_softc* sc; 208 209 sc = epclk_sc; 210 stathz = profhz = 0; 211 212 #if defined(HZ) && (HZ == 64) 213 if (hz != 64) panic("HZ must be 64!"); 214 215 /* clear 64Hz interrupt status */ 216 bus_space_write_4(sc->sc_iot, sc->sc_teoi_ioh, 0, 1); 217 #else 218 #define CLOCK_SOURCE_RATE 14745600UL 219 #define CLOCK_TICK_DIV 29 220 #define CLOCK_TICK_RATE \ 221 (((CLOCK_SOURCE_RATE+(CLOCK_TICK_DIV*hz-1))/(CLOCK_TICK_DIV*hz))*hz) 222 #define LATCH ((CLOCK_TICK_RATE + hz/2) / hz) 223 /* setup and start the 16bit timer (Timer1) */ 224 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 225 EP93XX_TIMERS_Timer1Control, 226 (TimerControl_MODE)|(TimerControl_CLKSEL)); 227 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 228 EP93XX_TIMERS_Timer1Load, LATCH-1); 229 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 230 EP93XX_TIMERS_Timer1Control, 231 (TimerControl_ENABLE)|(TimerControl_MODE)|(TimerControl_CLKSEL)); 232 #endif 233 234 ep93xx_intr_establish(sc->sc_intr, IPL_CLOCK, epclk_intr, NULL); 235 } 236 237 /* 238 * delay: 239 * 240 * Delay for at least N microseconds. 241 */ 242 void 243 delay(unsigned int n) 244 { 245 unsigned int cur_tick, initial_tick; 246 int remaining; 247 248 #ifdef DEBUG 249 if (epclk_sc == NULL) { 250 printf("delay: called before start epclk\n"); 251 return; 252 } 253 #endif 254 255 /* 256 * Read the counter first, so that the rest of the setup overhead is 257 * counted. 258 */ 259 initial_tick = TIMER4VAL(); 260 261 US_TO_TIMER4VAL(n, remaining); 262 263 while (remaining > 0) { 264 cur_tick = TIMER4VAL(); 265 if (cur_tick >= initial_tick) 266 remaining -= cur_tick - initial_tick; 267 else 268 remaining -= UINT_MAX - initial_tick + cur_tick + 1; 269 initial_tick = cur_tick; 270 } 271 } 272 273 static u_int 274 epclk_get_timecount(struct timecounter *tc) 275 { 276 return TIMER4VAL(); 277 } 278