1205354Simp/* $NetBSD: s3c24x0_clk.c,v 1.6 2005/12/24 20:06:52 perry Exp $ */ 2205354Simp 3205354Simp/* 4205354Simp * Copyright (c) 2003 Genetec corporation. All rights reserved. 5205354Simp * Written by Hiroyuki Bessho for Genetec corporation. 6205354Simp * 7205354Simp * Redistribution and use in source and binary forms, with or without 8205354Simp * modification, are permitted provided that the following conditions 9205354Simp * are met: 10205354Simp * 1. Redistributions of source code must retain the above copyright 11205354Simp * notice, this list of conditions and the following disclaimer. 12205354Simp * 2. Redistributions in binary form must reproduce the above copyright 13205354Simp * notice, this list of conditions and the following disclaimer in the 14205354Simp * documentation and/or other materials provided with the distribution. 15205354Simp * 3. The name of Genetec corporation may not be used to endorse 16205354Simp * or promote products derived from this software without specific prior 17205354Simp * written permission. 18205354Simp * 19205354Simp * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND 20205354Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21205354Simp * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22205354Simp * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORP. 23205354Simp * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24205354Simp * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25205354Simp * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26205354Simp * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27205354Simp * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28205354Simp * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29205354Simp * POSSIBILITY OF SUCH DAMAGE. 30205354Simp */ 31205354Simp 32205354Simp#include <sys/cdefs.h> 33205354Simp__FBSDID("$FreeBSD$"); 34205354Simp 35205354Simp#include <sys/param.h> 36205354Simp#include <sys/systm.h> 37205354Simp#include <sys/kernel.h> 38205354Simp#include <sys/module.h> 39205354Simp#include <sys/time.h> 40205354Simp#include <sys/bus.h> 41205354Simp#include <sys/resource.h> 42205354Simp#include <sys/rman.h> 43205354Simp#include <sys/timetc.h> 44205354Simp 45205354Simp#include <machine/bus.h> 46205354Simp#include <machine/cpu.h> 47205354Simp#include <machine/cpufunc.h> 48205354Simp#include <machine/frame.h> 49205354Simp#include <machine/resource.h> 50205354Simp#include <machine/intr.h> 51272103Sgavin#include <arm/samsung/s3c2xx0/s3c24x0reg.h> 52272103Sgavin#include <arm/samsung/s3c2xx0/s3c24x0var.h> 53205354Simp 54205354Simpstruct s3c24x0_timer_softc { 55205354Simp device_t dev; 56205354Simp} timer_softc; 57205354Simp 58205354Simpstatic unsigned s3c24x0_timer_get_timecount(struct timecounter *tc); 59205354Simp 60205354Simpstatic struct timecounter s3c24x0_timer_timecounter = { 61205354Simp s3c24x0_timer_get_timecount, /* get_timecount */ 62205354Simp NULL, /* no poll_pps */ 63205354Simp ~0u, /* counter_mask */ 64205354Simp 3686400, /* frequency */ 65205354Simp "s3c24x0 timer", /* name */ 66205354Simp 1000 /* quality */ 67205354Simp}; 68205354Simp 69205354Simpstatic int 70205354Simps3c24x0_timer_probe(device_t dev) 71205354Simp{ 72205354Simp 73205354Simp device_set_desc(dev, "s3c24x0 timer"); 74205354Simp return (0); 75205354Simp} 76205354Simp 77205354Simpstatic int 78205354Simps3c24x0_timer_attach(device_t dev) 79205354Simp{ 80205354Simp timer_softc.dev = dev; 81205354Simp 82205354Simp /* We need to do this here for devices that expect DELAY to work */ 83205354Simp return (0); 84205354Simp} 85205354Simp 86205354Simpstatic device_method_t s3c24x0_timer_methods[] = { 87205354Simp DEVMETHOD(device_probe, s3c24x0_timer_probe), 88205354Simp DEVMETHOD(device_attach, s3c24x0_timer_attach), 89205354Simp {0, 0}, 90205354Simp}; 91205354Simp 92205354Simpstatic driver_t s3c24x0_timer_driver = { 93205354Simp "timer", 94205354Simp s3c24x0_timer_methods, 95205354Simp sizeof(struct s3c24x0_timer_softc), 96205354Simp}; 97205354Simpstatic devclass_t s3c24x0_timer_devclass; 98205354Simp 99205354SimpDRIVER_MODULE(s3c24x0timer, s3c24x0, s3c24x0_timer_driver, 100205354Simp s3c24x0_timer_devclass, 0, 0); 101205354Simp 102205354Simp#define TIMER_FREQUENCY(pclk) ((pclk)/16) /* divider=1/16 */ 103205354Simp 104205354Simpstatic unsigned int timer4_reload_value; 105205354Simpstatic unsigned int timer4_prescaler; 106205354Simpstatic unsigned int timer4_mseccount; 107205354Simpstatic volatile uint32_t s3c24x0_base; 108205354Simp 109205354Simp#define usec_to_counter(t) \ 110205354Simp ((timer4_mseccount*(t))/1000) 111205354Simp 112205354Simp#define counter_to_usec(c,pclk) \ 113205354Simp (((c)*timer4_prescaler*1000)/(TIMER_FREQUENCY(pclk)/1000)) 114205354Simp 115205354Simpstatic inline int 116205354Simpread_timer(struct s3c24x0_softc *sc) 117205354Simp{ 118205354Simp int count; 119205354Simp 120205354Simp do { 121205354Simp count = bus_space_read_2(sc->sc_sx.sc_iot, sc->sc_timer_ioh, 122205354Simp TIMER_TCNTO(4)); 123205354Simp } while ( __predict_false(count > timer4_reload_value) ); 124205354Simp 125205354Simp return count; 126205354Simp} 127205354Simp 128205354Simpstatic unsigned 129205354Simps3c24x0_timer_get_timecount(struct timecounter *tc) 130205354Simp{ 131205354Simp struct s3c24x0_softc *sc = (struct s3c24x0_softc *)s3c2xx0_softc; 132205354Simp int value; 133205354Simp 134205354Simp value = bus_space_read_2(sc->sc_sx.sc_iot, sc->sc_timer_ioh, 135205354Simp TIMER_TCNTO(4)); 136205354Simp return (s3c24x0_base - value); 137205354Simp} 138205354Simp 139205354Simpstatic int 140205354Simpclock_intr(void *arg) 141205354Simp{ 142205354Simp struct trapframe *fp = arg; 143205354Simp 144205354Simp atomic_add_32(&s3c24x0_base, timer4_reload_value); 145205354Simp 146205354Simp hardclock(TRAPF_USERMODE(fp), TRAPF_PC(fp)); 147205354Simp return (FILTER_HANDLED); 148205354Simp} 149205354Simp 150205354Simpvoid 151205354Simpcpu_initclocks(void) 152205354Simp{ 153205354Simp struct s3c24x0_softc *sc = (struct s3c24x0_softc *)s3c2xx0_softc; 154205354Simp long tc; 155205354Simp struct resource *irq; 156205354Simp int rid = 0; 157205354Simp void *ihl; 158205354Simp int err, prescaler; 159205354Simp int pclk = s3c2xx0_softc->sc_pclk; 160205354Simp bus_space_tag_t iot = sc->sc_sx.sc_iot; 161205354Simp bus_space_handle_t ioh = sc->sc_timer_ioh; 162205354Simp uint32_t reg; 163205354Simp device_t dev = timer_softc.dev; 164205354Simp 165205354Simp /* We have already been initialized */ 166205354Simp if (timer4_reload_value != 0) 167205354Simp return; 168205354Simp 169205354Simp#define time_constant(hz) (TIMER_FREQUENCY(pclk) /(hz)/ prescaler) 170205354Simp#define calc_time_constant(hz) \ 171205354Simp do { \ 172205354Simp prescaler = 1; \ 173205354Simp do { \ 174205354Simp ++prescaler; \ 175205354Simp tc = time_constant(hz); \ 176205354Simp } while( tc > 65536 ); \ 177205354Simp } while(0) 178205354Simp 179205354Simp 180205354Simp /* Use the channels 4 and 3 for hardclock and statclock, respectively */ 181205354Simp 182205354Simp /* stop all timers */ 183205354Simp bus_space_write_4(iot, ioh, TIMER_TCON, 0); 184205354Simp 185205354Simp /* calc suitable prescaler value */ 186205354Simp calc_time_constant(hz); 187205354Simp 188205354Simp timer4_prescaler = prescaler; 189205354Simp timer4_reload_value = TIMER_FREQUENCY(pclk) / hz / prescaler; 190205354Simp timer4_mseccount = TIMER_FREQUENCY(pclk)/timer4_prescaler/1000 ; 191205354Simp 192205354Simp bus_space_write_4(iot, ioh, TIMER_TCNTB(4), 193205354Simp ((prescaler - 1) << 16) | (timer4_reload_value - 1)); 194205354Simp 195205354Simp printf("clock: hz=%d PCLK=%d prescaler=%d tc=%ld\n", 196205354Simp hz, pclk, prescaler, tc); 197205354Simp 198205354Simp irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, S3C24X0_INT_TIMER4, 199205354Simp S3C24X0_INT_TIMER4, 1, RF_ACTIVE); 200205354Simp if (!irq) 201205354Simp panic("Unable to allocate the clock irq handler.\n"); 202205354Simp 203217072Sjhb err = bus_setup_intr(dev, irq, INTR_TYPE_CLK, 204205354Simp clock_intr, NULL, NULL, &ihl); 205205354Simp if (err != 0) 206205354Simp panic("Unable to setup the clock irq handler.\n"); 207205354Simp 208205354Simp /* set prescaler1 */ 209205354Simp reg = bus_space_read_4(iot, ioh, TIMER_TCFG0); 210205354Simp bus_space_write_4(iot, ioh, TIMER_TCFG0, 211205354Simp (reg & ~0xff00) | ((prescaler-1) << 8)); 212205354Simp 213205354Simp /* divider 1/16 for ch #4 */ 214205354Simp reg = bus_space_read_4(iot, ioh, TIMER_TCFG1); 215205354Simp bus_space_write_4(iot, ioh, TIMER_TCFG1, 216205354Simp (reg & ~(TCFG1_MUX_MASK(4))) | 217205354Simp (TCFG1_MUX_DIV16 << TCFG1_MUX_SHIFT(4)) ); 218205354Simp 219205354Simp 220205354Simp /* start timers */ 221205354Simp reg = bus_space_read_4(iot, ioh, TIMER_TCON); 222205354Simp reg &= ~(TCON_MASK(4)); 223205354Simp 224205354Simp /* load the time constant */ 225205354Simp bus_space_write_4(iot, ioh, TIMER_TCON, reg | TCON_MANUALUPDATE(4)); 226205354Simp /* set auto reload and start */ 227205354Simp bus_space_write_4(iot, ioh, TIMER_TCON, reg | 228205354Simp TCON_AUTORELOAD(4) | TCON_START(4) ); 229205354Simp 230205354Simp s3c24x0_timer_timecounter.tc_frequency = TIMER_FREQUENCY(pclk) / 231205354Simp timer4_prescaler; 232205354Simp tc_init(&s3c24x0_timer_timecounter); 233205354Simp} 234205354Simp 235205354Simp/* 236205354Simp * DELAY: 237205354Simp * 238205354Simp * Delay for at least N microseconds. 239205354Simp */ 240205354Simpvoid 241205354SimpDELAY(int n) 242205354Simp{ 243205354Simp struct s3c24x0_softc *sc = (struct s3c24x0_softc *) s3c2xx0_softc; 244205354Simp int v0, v1, delta; 245205354Simp u_int ucnt; 246205354Simp 247205354Simp if (timer4_reload_value == 0) { 248205354Simp /* not initialized yet */ 249205354Simp while ( n-- > 0 ){ 250205354Simp int m; 251205354Simp 252205354Simp for (m = 0; m < 100; ++m ) 253205354Simp ; 254205354Simp } 255205354Simp return; 256205354Simp } 257205354Simp 258205354Simp /* read down counter */ 259205354Simp v0 = read_timer(sc); 260205354Simp 261205354Simp ucnt = usec_to_counter(n); 262205354Simp 263205354Simp while( ucnt > 0 ) { 264205354Simp v1 = read_timer(sc); 265205354Simp delta = v0 - v1; 266205354Simp if ( delta < 0 ) 267205354Simp delta += timer4_reload_value; 268205354Simp 269205354Simp if((u_int)delta < ucnt){ 270205354Simp ucnt -= (u_int)delta; 271205354Simp v0 = v1; 272205354Simp } 273205354Simp else { 274205354Simp ucnt = 0; 275205354Simp } 276205354Simp } 277205354Simp} 278205354Simp 279205354Simpvoid 280205354Simpcpu_startprofclock(void) 281205354Simp{ 282205354Simp} 283205354Simp 284205354Simpvoid 285205354Simpcpu_stopprofclock(void) 286205354Simp{ 287205354Simp} 288