ixp425_timer.c revision 278613
1158115Sume/* $NetBSD: ixp425_timer.c,v 1.11 2006/04/10 03:36:03 simonb Exp $ */ 2158115Sume 3158115Sume/* 4158115Sume * Copyright (c) 2003 5158115Sume * Ichiro FUKUHARA <ichiro@ichiro.org>. 6158115Sume * All rights reserved. 7158115Sume * 8158115Sume * Redistribution and use in source and binary forms, with or without 9158115Sume * modification, are permitted provided that the following conditions 10158115Sume * are met: 11158115Sume * 1. Redistributions of source code must retain the above copyright 12158115Sume * notice, this list of conditions and the following disclaimer. 13158115Sume * 2. Redistributions in binary form must reproduce the above copyright 14158115Sume * notice, this list of conditions and the following disclaimer in the 15158115Sume * documentation and/or other materials provided with the distribution. 16158115Sume * 3. All advertising materials mentioning features or use of this software 17158115Sume * must display the following acknowledgement: 18158115Sume * This product includes software developed by Ichiro FUKUHARA. 19158115Sume * 4. The name of the company nor the name of the author may be used to 20158115Sume * endorse or promote products derived from this software without specific 21158115Sume * prior written permission. 22158115Sume * 23158115Sume * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``AS IS'' AND ANY EXPRESS OR 24158115Sume * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25158115Sume * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26158115Sume * IN NO EVENT SHALL ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR 27158115Sume * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28158115Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29171795Sbushman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30171795Sbushman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31158115Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32158115Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33158115Sume * SUCH DAMAGE. 34158115Sume */ 35158115Sume 36158115Sume#include <sys/cdefs.h> 37158115Sume__FBSDID("$FreeBSD: stable/10/sys/arm/xscale/ixp425/ixp425_timer.c 278613 2015-02-12 03:50:33Z ian $"); 38158115Sume 39158115Sume#include <sys/param.h> 40158115Sume#include <sys/systm.h> 41158115Sume#include <sys/kernel.h> 42158115Sume#include <sys/module.h> 43158115Sume#include <sys/time.h> 44158115Sume#include <sys/bus.h> 45158115Sume#include <sys/resource.h> 46158115Sume#include <sys/rman.h> 47158115Sume#include <sys/timetc.h> 48158115Sume 49158115Sume#include <machine/armreg.h> 50158115Sume#include <machine/bus.h> 51158115Sume#include <machine/cpu.h> 52158115Sume#include <machine/cpufunc.h> 53158115Sume#include <machine/frame.h> 54158115Sume#include <machine/resource.h> 55158115Sume#include <machine/intr.h> 56158115Sume#include <arm/xscale/ixp425/ixp425reg.h> 57158115Sume#include <arm/xscale/ixp425/ixp425var.h> 58158115Sume 59158115Sumestatic uint32_t counts_per_hz; 60158115Sume 61158115Sume/* callback functions for intr_functions */ 62158115Sumeint ixpclk_intr(void *); 63158115Sume 64158115Sumestruct ixpclk_softc { 65158115Sume device_t sc_dev; 66158115Sume bus_addr_t sc_baseaddr; 67158115Sume bus_space_tag_t sc_iot; 68158115Sume bus_space_handle_t sc_ioh; 69158115Sume}; 70158115Sume 71158115Sumestatic unsigned ixp425_timer_get_timecount(struct timecounter *tc); 72158115Sume 73158115Sume#ifndef IXP425_CLOCK_FREQ 74158115Sume#define COUNTS_PER_SEC 66666600 /* 66MHz */ 75158115Sume#else 76158115Sume#define COUNTS_PER_SEC IXP425_CLOCK_FREQ 77158115Sume#endif 78158115Sume#define COUNTS_PER_USEC ((COUNTS_PER_SEC / 1000000) + 1) 79158115Sume 80158115Sumestatic struct ixpclk_softc *ixpclk_sc = NULL; 81158115Sume 82158115Sume#define GET_TS_VALUE(sc) (*(volatile u_int32_t *) \ 83158115Sume (IXP425_TIMER_VBASE + IXP425_OST_TS)) 84158115Sume 85158115Sumestatic struct timecounter ixp425_timer_timecounter = { 86158115Sume ixp425_timer_get_timecount, /* get_timecount */ 87158115Sume NULL, /* no poll_pps */ 88158115Sume ~0u, /* counter_mask */ 89158115Sume COUNTS_PER_SEC, /* frequency */ 90158115Sume "IXP4XX Timer", /* name */ 91158115Sume 1000, /* quality */ 92158115Sume}; 93158115Sume 94158115Sumestatic int 95158115Sumeixpclk_probe(device_t dev) 96158115Sume{ 97158115Sume device_set_desc(dev, "IXP4XX Timer"); 98158115Sume return (0); 99158115Sume} 100158115Sume 101158115Sumestatic int 102158115Sumeixpclk_attach(device_t dev) 103158115Sume{ 104158115Sume struct ixpclk_softc *sc = device_get_softc(dev); 105158115Sume struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); 106158115Sume 107158115Sume ixpclk_sc = sc; 108158115Sume 109158115Sume sc->sc_dev = dev; 110158115Sume sc->sc_iot = sa->sc_iot; 111158115Sume sc->sc_baseaddr = IXP425_TIMER_HWBASE; 112158115Sume 113158115Sume if (bus_space_map(sc->sc_iot, sc->sc_baseaddr, 8, 0, 114158115Sume &sc->sc_ioh)) 115158115Sume panic("%s: Cannot map registers", device_get_name(dev)); 116158115Sume 117158115Sume return (0); 118158115Sume} 119158115Sume 120158115Sumestatic device_method_t ixpclk_methods[] = { 121158115Sume DEVMETHOD(device_probe, ixpclk_probe), 122158115Sume DEVMETHOD(device_attach, ixpclk_attach), 123158115Sume {0, 0}, 124158115Sume}; 125158115Sume 126158115Sumestatic driver_t ixpclk_driver = { 127158115Sume "ixpclk", 128158115Sume ixpclk_methods, 129158115Sume sizeof(struct ixpclk_softc), 130158115Sume}; 131158115Sumestatic devclass_t ixpclk_devclass; 132158115Sume 133158115SumeDRIVER_MODULE(ixpclk, ixp, ixpclk_driver, ixpclk_devclass, 0, 0); 134158115Sumestatic unsigned 135158115Sumeixp425_timer_get_timecount(struct timecounter *tc) 136158115Sume{ 137158115Sume uint32_t ret; 138158115Sume 139158115Sume ret = GET_TS_VALUE(sc); 140158115Sume return (ret); 141158115Sume} 142158115Sume 143158115Sume/* 144158115Sume * cpu_initclocks: 145158115Sume * 146158115Sume * Initialize the clock and get them going. 147158115Sume */ 148158115Sumevoid 149158115Sumecpu_initclocks(void) 150158115Sume{ 151158115Sume struct ixpclk_softc* sc = ixpclk_sc; 152158115Sume struct resource *irq; 153158115Sume device_t dev = sc->sc_dev; 154158115Sume u_int oldirqstate; 155158115Sume int rid = 0; 156158115Sume void *ihl; 157158115Sume 158158115Sume if (hz < 50 || COUNTS_PER_SEC % hz) { 159158115Sume printf("Cannot get %d Hz clock; using 100 Hz\n", hz); 160158115Sume hz = 100; 161158115Sume } 162158115Sume tick = 1000000 / hz; /* number of microseconds between interrupts */ 163158115Sume 164158115Sume /* 165158115Sume * We only have one timer available; stathz and profhz are 166158115Sume * always left as 0 (the upper-layer clock code deals with 167158115Sume * this situation). 168158115Sume */ 169158115Sume if (stathz != 0) 170158115Sume printf("Cannot get %d Hz statclock\n", stathz); 171158115Sume stathz = 0; 172158115Sume 173158115Sume if (profhz != 0) 174158115Sume printf("Cannot get %d Hz profclock\n", profhz); 175158115Sume profhz = 0; 176158115Sume 177158115Sume /* Report the clock frequency. */ 178158115Sume 179158115Sume oldirqstate = disable_interrupts(PSR_I); 180158115Sume 181158115Sume irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, IXP425_INT_TMR0, 182158115Sume IXP425_INT_TMR0, 1, RF_ACTIVE); 183158115Sume if (!irq) 184158115Sume panic("Unable to setup the clock irq handler.\n"); 185158115Sume else 186158115Sume bus_setup_intr(dev, irq, INTR_TYPE_CLK, ixpclk_intr, NULL, 187158115Sume NULL, &ihl); 188158115Sume 189158115Sume /* Set up the new clock parameters. */ 190158115Sume 191158115Sume /* clear interrupt */ 192158115Sume bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_STATUS, 193158115Sume OST_WARM_RESET | OST_WDOG_INT | OST_TS_INT | 194158115Sume OST_TIM1_INT | OST_TIM0_INT); 195158115Sume 196158115Sume counts_per_hz = COUNTS_PER_SEC / hz; 197158115Sume 198158115Sume /* reload value & Timer enable */ 199158115Sume bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_TIM0_RELOAD, 200158115Sume (counts_per_hz & TIMERRELOAD_MASK) | OST_TIMER_EN); 201158115Sume 202158115Sume tc_init(&ixp425_timer_timecounter); 203158115Sume restore_interrupts(oldirqstate); 204158115Sume rid = 0; 205158115Sume} 206158115Sume 207158115Sume 208158115Sume/* 209158115Sume * DELAY: 210158115Sume * 211158115Sume * Delay for at least N microseconds. 212158115Sume */ 213158115Sumevoid 214158115SumeDELAY(int n) 215158115Sume{ 216158115Sume u_int32_t first, last; 217158115Sume int usecs; 218158115Sume 219158115Sume if (n == 0) 220158115Sume return; 221158115Sume 222158115Sume /* 223158115Sume * Clamp the timeout at a maximum value (about 32 seconds with 224158115Sume * a 66MHz clock). *Nobody* should be delay()ing for anywhere 225158115Sume * near that length of time and if they are, they should be hung 226158115Sume * out to dry. 227158115Sume */ 228158115Sume if (n >= (0x80000000U / COUNTS_PER_USEC)) 229158115Sume usecs = (0x80000000U / COUNTS_PER_USEC) - 1; 230158115Sume else 231158115Sume usecs = n * COUNTS_PER_USEC; 232158115Sume 233158115Sume /* Note: Timestamp timer counts *up*, unlike the other timers */ 234158115Sume first = GET_TS_VALUE(); 235158115Sume 236158115Sume while (usecs > 0) { 237158115Sume last = GET_TS_VALUE(); 238158115Sume usecs -= (int)(last - first); 239158115Sume first = last; 240158115Sume } 241158115Sume} 242158115Sume 243158115Sume/* 244158115Sume * ixpclk_intr: 245158115Sume * 246158115Sume * Handle the hardclock interrupt. 247158115Sume */ 248158115Sumeint 249158115Sumeixpclk_intr(void *arg) 250158115Sume{ 251158115Sume struct ixpclk_softc* sc = ixpclk_sc; 252158115Sume struct trapframe *frame = arg; 253158115Sume 254158115Sume bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_STATUS, 255158115Sume OST_TIM0_INT); 256158115Sume 257158115Sume hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); 258158115Sume return (FILTER_HANDLED); 259158115Sume} 260158115Sume 261158115Sumevoid 262158115Sumecpu_startprofclock(void) 263158115Sume{ 264158115Sume} 265158115Sume 266void 267cpu_stopprofclock(void) 268{ 269} 270