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