1/* $NetBSD: s3c24x0_clk.c,v 1.6 2005/12/24 20:06:52 perry Exp $ */ 2 3/* 4 * Copyright (c) 2003 Genetec corporation. All rights reserved. 5 * Written by Hiroyuki Bessho for Genetec corporation. 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 * 3. The name of Genetec corporation may not be used to endorse 16 * or promote products derived from this software without specific prior 17 * written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORP. 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD$"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/kernel.h> 38#include <sys/module.h> 39#include <sys/time.h> 40#include <sys/bus.h> 41#include <sys/resource.h> 42#include <sys/rman.h> 43#include <sys/timetc.h> 44 45#include <machine/bus.h> 46#include <machine/cpu.h> 47#include <machine/cpufunc.h> 48#include <machine/frame.h> 49#include <machine/resource.h> 50#include <machine/intr.h> 51#include <arm/samsung/s3c2xx0/s3c24x0reg.h> 52#include <arm/samsung/s3c2xx0/s3c24x0var.h> 53 54struct s3c24x0_timer_softc { 55 device_t dev; 56} timer_softc; 57 58static unsigned s3c24x0_timer_get_timecount(struct timecounter *tc); 59 60static struct timecounter s3c24x0_timer_timecounter = { 61 s3c24x0_timer_get_timecount, /* get_timecount */ 62 NULL, /* no poll_pps */ 63 ~0u, /* counter_mask */ 64 3686400, /* frequency */ 65 "s3c24x0 timer", /* name */ 66 1000 /* quality */ 67}; 68 69static int 70s3c24x0_timer_probe(device_t dev) 71{ 72 73 device_set_desc(dev, "s3c24x0 timer"); 74 return (0); 75} 76 77static int 78s3c24x0_timer_attach(device_t dev) 79{ 80 timer_softc.dev = dev; 81 82 /* We need to do this here for devices that expect DELAY to work */ 83 return (0); 84} 85 86static device_method_t s3c24x0_timer_methods[] = { 87 DEVMETHOD(device_probe, s3c24x0_timer_probe), 88 DEVMETHOD(device_attach, s3c24x0_timer_attach), 89 {0, 0}, 90}; 91 92static driver_t s3c24x0_timer_driver = { 93 "timer", 94 s3c24x0_timer_methods, 95 sizeof(struct s3c24x0_timer_softc), 96}; 97static devclass_t s3c24x0_timer_devclass; 98 99DRIVER_MODULE(s3c24x0timer, s3c24x0, s3c24x0_timer_driver, 100 s3c24x0_timer_devclass, 0, 0); 101 102#define TIMER_FREQUENCY(pclk) ((pclk)/16) /* divider=1/16 */ 103 104static unsigned int timer4_reload_value; 105static unsigned int timer4_prescaler; 106static unsigned int timer4_mseccount; 107static volatile uint32_t s3c24x0_base; 108 109#define usec_to_counter(t) \ 110 ((timer4_mseccount*(t))/1000) 111 112#define counter_to_usec(c,pclk) \ 113 (((c)*timer4_prescaler*1000)/(TIMER_FREQUENCY(pclk)/1000)) 114 115static inline int 116read_timer(struct s3c24x0_softc *sc) 117{ 118 int count; 119 120 do { 121 count = bus_space_read_2(sc->sc_sx.sc_iot, sc->sc_timer_ioh, 122 TIMER_TCNTO(4)); 123 } while ( __predict_false(count > timer4_reload_value) ); 124 125 return count; 126} 127 128static unsigned 129s3c24x0_timer_get_timecount(struct timecounter *tc) 130{ 131 struct s3c24x0_softc *sc = (struct s3c24x0_softc *)s3c2xx0_softc; 132 int value; 133 134 value = bus_space_read_2(sc->sc_sx.sc_iot, sc->sc_timer_ioh, 135 TIMER_TCNTO(4)); 136 return (s3c24x0_base - value); 137} 138 139static int 140clock_intr(void *arg) 141{ 142 struct trapframe *fp = arg; 143 144 atomic_add_32(&s3c24x0_base, timer4_reload_value); 145 146 hardclock(TRAPF_USERMODE(fp), TRAPF_PC(fp)); 147 return (FILTER_HANDLED); 148} 149 150void 151cpu_initclocks(void) 152{ 153 struct s3c24x0_softc *sc = (struct s3c24x0_softc *)s3c2xx0_softc; 154 long tc; 155 struct resource *irq; 156 int rid = 0; 157 void *ihl; 158 int err, prescaler; 159 int pclk = s3c2xx0_softc->sc_pclk; 160 bus_space_tag_t iot = sc->sc_sx.sc_iot; 161 bus_space_handle_t ioh = sc->sc_timer_ioh; 162 uint32_t reg; 163 device_t dev = timer_softc.dev; 164 165 /* We have already been initialized */ 166 if (timer4_reload_value != 0) 167 return; 168 169#define time_constant(hz) (TIMER_FREQUENCY(pclk) /(hz)/ prescaler) 170#define calc_time_constant(hz) \ 171 do { \ 172 prescaler = 1; \ 173 do { \ 174 ++prescaler; \ 175 tc = time_constant(hz); \ 176 } while( tc > 65536 ); \ 177 } while(0) 178 179 180 /* Use the channels 4 and 3 for hardclock and statclock, respectively */ 181 182 /* stop all timers */ 183 bus_space_write_4(iot, ioh, TIMER_TCON, 0); 184 185 /* calc suitable prescaler value */ 186 calc_time_constant(hz); 187 188 timer4_prescaler = prescaler; 189 timer4_reload_value = TIMER_FREQUENCY(pclk) / hz / prescaler; 190 timer4_mseccount = TIMER_FREQUENCY(pclk)/timer4_prescaler/1000 ; 191 192 bus_space_write_4(iot, ioh, TIMER_TCNTB(4), 193 ((prescaler - 1) << 16) | (timer4_reload_value - 1)); 194 195 printf("clock: hz=%d PCLK=%d prescaler=%d tc=%ld\n", 196 hz, pclk, prescaler, tc); 197 198 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, S3C24X0_INT_TIMER4, 199 S3C24X0_INT_TIMER4, 1, RF_ACTIVE); 200 if (!irq) 201 panic("Unable to allocate the clock irq handler.\n"); 202 203 err = bus_setup_intr(dev, irq, INTR_TYPE_CLK, 204 clock_intr, NULL, NULL, &ihl); 205 if (err != 0) 206 panic("Unable to setup the clock irq handler.\n"); 207 208 /* set prescaler1 */ 209 reg = bus_space_read_4(iot, ioh, TIMER_TCFG0); 210 bus_space_write_4(iot, ioh, TIMER_TCFG0, 211 (reg & ~0xff00) | ((prescaler-1) << 8)); 212 213 /* divider 1/16 for ch #4 */ 214 reg = bus_space_read_4(iot, ioh, TIMER_TCFG1); 215 bus_space_write_4(iot, ioh, TIMER_TCFG1, 216 (reg & ~(TCFG1_MUX_MASK(4))) | 217 (TCFG1_MUX_DIV16 << TCFG1_MUX_SHIFT(4)) ); 218 219 220 /* start timers */ 221 reg = bus_space_read_4(iot, ioh, TIMER_TCON); 222 reg &= ~(TCON_MASK(4)); 223 224 /* load the time constant */ 225 bus_space_write_4(iot, ioh, TIMER_TCON, reg | TCON_MANUALUPDATE(4)); 226 /* set auto reload and start */ 227 bus_space_write_4(iot, ioh, TIMER_TCON, reg | 228 TCON_AUTORELOAD(4) | TCON_START(4) ); 229 230 s3c24x0_timer_timecounter.tc_frequency = TIMER_FREQUENCY(pclk) / 231 timer4_prescaler; 232 tc_init(&s3c24x0_timer_timecounter); 233} 234 235/* 236 * DELAY: 237 * 238 * Delay for at least N microseconds. 239 */ 240void 241DELAY(int n) 242{ 243 struct s3c24x0_softc *sc = (struct s3c24x0_softc *) s3c2xx0_softc; 244 int v0, v1, delta; 245 u_int ucnt; 246 247 if (timer4_reload_value == 0) { 248 /* not initialized yet */ 249 while ( n-- > 0 ){ 250 int m; 251 252 for (m = 0; m < 100; ++m ) 253 ; 254 } 255 return; 256 } 257 258 /* read down counter */ 259 v0 = read_timer(sc); 260 261 ucnt = usec_to_counter(n); 262 263 while( ucnt > 0 ) { 264 v1 = read_timer(sc); 265 delta = v0 - v1; 266 if ( delta < 0 ) 267 delta += timer4_reload_value; 268 269 if((u_int)delta < ucnt){ 270 ucnt -= (u_int)delta; 271 v0 = v1; 272 } 273 else { 274 ucnt = 0; 275 } 276 } 277} 278 279void 280cpu_startprofclock(void) 281{ 282} 283 284void 285cpu_stopprofclock(void) 286{ 287} 288