1 /* $NetBSD: epclk.c,v 1.20 2012/11/12 18:00:36 skrll 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.20 2012/11/12 18:00:36 skrll 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 <sys/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(device_t, cfdata_t, void *); 69 static void epclk_attach(device_t, device_t, 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 bus_addr_t sc_baseaddr; 79 bus_space_tag_t sc_iot; 80 bus_space_handle_t sc_ioh; 81 #if defined(HZ) && (HZ == 64) 82 bus_space_handle_t sc_teoi_ioh; 83 #endif 84 int sc_intr; 85 }; 86 87 static struct timecounter epclk_timecounter = { 88 epclk_get_timecount, /* get_timecount */ 89 0, /* no poll_pps */ 90 ~0u, /* counter_mask */ 91 TIMER_FREQ, /* frequency */ 92 "epclk", /* name */ 93 100, /* quality */ 94 NULL, /* prev */ 95 NULL, /* next */ 96 }; 97 98 static struct epclk_softc *epclk_sc = NULL; 99 100 CFATTACH_DECL_NEW(epclk, sizeof(struct epclk_softc), 101 epclk_match, epclk_attach, NULL, NULL); 102 103 /* This is a quick ARM way to multiply by 983040/1000000 (w/o overflow) */ 104 #define US_TO_TIMER4VAL(x, y) { \ 105 uint32_t hi, lo, scalar = 4222124650UL; \ 106 __asm volatile ( \ 107 "umull %0, %1, %2, %3;" \ 108 : "=&r"(lo), "=&r"(hi) \ 109 : "r"((x)), "r"(scalar) \ 110 ); \ 111 (y) = hi; \ 112 } 113 114 #define TIMER4VAL() (*(volatile uint32_t *)(EP93XX_APB_VBASE + \ 115 EP93XX_APB_TIMERS + EP93XX_TIMERS_Timer4ValueLow)) 116 117 static int 118 epclk_match(device_t parent, cfdata_t match, void *aux) 119 { 120 121 return 2; 122 } 123 124 static void 125 epclk_attach(device_t parent, device_t self, void *aux) 126 { 127 struct epclk_softc *sc; 128 struct epsoc_attach_args *sa; 129 bool first_run; 130 131 printf("\n"); 132 133 sc = device_private(self); 134 sa = aux; 135 sc->sc_iot = sa->sa_iot; 136 sc->sc_baseaddr = sa->sa_addr; 137 sc->sc_intr = sa->sa_intr; 138 139 if (epclk_sc == NULL) { 140 first_run = true; 141 epclk_sc = sc; 142 } 143 144 if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 145 0, &sc->sc_ioh)) 146 panic("%s: Cannot map registers", device_xname(self)); 147 #if defined(HZ) && (HZ == 64) 148 if (bus_space_map(sa->sa_iot, EP93XX_APB_HWBASE + EP93XX_APB_SYSCON + 149 EP93XX_SYSCON_TEOI, 4, 0, &sc->sc_teoi_ioh)) 150 panic("%s: Cannot map registers", device_xname(self)); 151 #endif 152 153 /* clear and start the debug timer (Timer4) */ 154 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EP93XX_TIMERS_Timer4Enable, 0); 155 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EP93XX_TIMERS_Timer4Enable, 0x100); 156 157 if (first_run) 158 tc_init(&epclk_timecounter); 159 } 160 161 /* 162 * epclk_intr: 163 * 164 * Handle the hardclock interrupt. 165 */ 166 static int 167 epclk_intr(void *arg) 168 { 169 struct epclk_softc* sc; 170 171 sc = epclk_sc; 172 173 #if defined(HZ) && (HZ == 64) 174 bus_space_write_4(sc->sc_iot, sc->sc_teoi_ioh, 0, 1); 175 #else 176 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EP93XX_TIMERS_Timer1Clear, 1); 177 #endif 178 hardclock((struct clockframe*) arg); 179 return (1); 180 } 181 182 /* 183 * setstatclockrate: 184 * 185 * Set the rate of the statistics clock. 186 * 187 * We assume that hz is either stathz or profhz, and that neither 188 * will change after being set by cpu_initclocks(). We could 189 * recalculate the intervals here, but that would be a pain. 190 */ 191 void 192 setstatclockrate(int newhz) 193 { 194 195 /* use hardclock */ 196 } 197 198 /* 199 * cpu_initclocks: 200 * 201 * Initialize the clock and get them going. 202 */ 203 void 204 cpu_initclocks(void) 205 { 206 struct epclk_softc* sc; 207 208 sc = epclk_sc; 209 stathz = profhz = 0; 210 211 #if defined(HZ) && (HZ == 64) 212 if (hz != 64) panic("HZ must be 64!"); 213 214 /* clear 64Hz interrupt status */ 215 bus_space_write_4(sc->sc_iot, sc->sc_teoi_ioh, 0, 1); 216 #else 217 #define CLOCK_SOURCE_RATE 14745600UL 218 #define CLOCK_TICK_DIV 29 219 #define CLOCK_TICK_RATE \ 220 (((CLOCK_SOURCE_RATE+(CLOCK_TICK_DIV*hz-1))/(CLOCK_TICK_DIV*hz))*hz) 221 #define LATCH ((CLOCK_TICK_RATE + hz/2) / hz) 222 /* setup and start the 16bit timer (Timer1) */ 223 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 224 EP93XX_TIMERS_Timer1Control, 225 (TimerControl_MODE)|(TimerControl_CLKSEL)); 226 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 227 EP93XX_TIMERS_Timer1Load, LATCH-1); 228 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 229 EP93XX_TIMERS_Timer1Control, 230 (TimerControl_ENABLE)|(TimerControl_MODE)|(TimerControl_CLKSEL)); 231 #endif 232 233 ep93xx_intr_establish(sc->sc_intr, IPL_CLOCK, epclk_intr, NULL); 234 } 235 236 /* 237 * delay: 238 * 239 * Delay for at least N microseconds. 240 */ 241 void 242 delay(unsigned int n) 243 { 244 unsigned int cur_tick, initial_tick; 245 int remaining; 246 247 #ifdef DEBUG 248 if (epclk_sc == NULL) { 249 printf("delay: called before start epclk\n"); 250 return; 251 } 252 #endif 253 254 /* 255 * Read the counter first, so that the rest of the setup overhead is 256 * counted. 257 */ 258 initial_tick = TIMER4VAL(); 259 260 US_TO_TIMER4VAL(n, remaining); 261 262 while (remaining > 0) { 263 cur_tick = TIMER4VAL(); 264 if (cur_tick >= initial_tick) 265 remaining -= cur_tick - initial_tick; 266 else 267 remaining -= UINT_MAX - initial_tick + cur_tick + 1; 268 initial_tick = cur_tick; 269 } 270 } 271 272 static u_int 273 epclk_get_timecount(struct timecounter *tc) 274 { 275 return TIMER4VAL(); 276 } 277