1179595Sbenno/*- 2179595Sbenno * Copyright (c) 2006 Benno Rice. All rights reserved. 3179595Sbenno * 4179595Sbenno * Redistribution and use in source and binary forms, with or without 5179595Sbenno * modification, are permitted provided that the following conditions 6179595Sbenno * are met: 7179595Sbenno * 1. Redistributions of source code must retain the above copyright 8179595Sbenno * notice, this list of conditions and the following disclaimer. 9179595Sbenno * 2. Redistributions in binary form must reproduce the above copyright 10179595Sbenno * notice, this list of conditions and the following disclaimer in the 11179595Sbenno * documentation and/or other materials provided with the distribution. 12179595Sbenno * 13179595Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14179595Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15179595Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16179595Sbenno * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17179595Sbenno * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18179595Sbenno * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19179595Sbenno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20179595Sbenno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21179595Sbenno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22179595Sbenno * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23179595Sbenno */ 24179595Sbenno 25179595Sbenno#include <sys/cdefs.h> 26179595Sbenno__FBSDID("$FreeBSD$"); 27179595Sbenno 28179595Sbenno#include <sys/param.h> 29179595Sbenno#include <sys/systm.h> 30179595Sbenno#include <sys/bus.h> 31179595Sbenno#include <sys/kernel.h> 32179595Sbenno#include <sys/module.h> 33179595Sbenno#include <sys/malloc.h> 34179595Sbenno#include <sys/rman.h> 35179595Sbenno#include <sys/timetc.h> 36278613Sian#include <machine/armreg.h> 37179595Sbenno#include <machine/bus.h> 38179595Sbenno#include <machine/cpu.h> 39179595Sbenno#include <machine/frame.h> 40179595Sbenno#include <machine/intr.h> 41179595Sbenno 42179595Sbenno#include <arm/xscale/pxa/pxavar.h> 43179595Sbenno#include <arm/xscale/pxa/pxareg.h> 44179595Sbenno 45179595Sbenno#define PXA_TIMER_FREQUENCY 3686400 46179595Sbenno#define PXA_TIMER_TICK (PXA_TIMER_FREQUENCY / hz) 47179595Sbenno 48179595Sbennostruct pxa_timer_softc { 49179595Sbenno struct resource * pt_res[5]; 50179595Sbenno bus_space_tag_t pt_bst; 51179595Sbenno bus_space_handle_t pt_bsh; 52179595Sbenno}; 53179595Sbenno 54179595Sbennostatic struct resource_spec pxa_timer_spec[] = { 55179595Sbenno { SYS_RES_MEMORY, 0, RF_ACTIVE }, 56179595Sbenno { SYS_RES_IRQ, 0, RF_ACTIVE }, 57179595Sbenno { SYS_RES_IRQ, 1, RF_ACTIVE }, 58179595Sbenno { SYS_RES_IRQ, 2, RF_ACTIVE }, 59179595Sbenno { SYS_RES_IRQ, 3, RF_ACTIVE }, 60179595Sbenno { -1, 0 } 61179595Sbenno}; 62179595Sbenno 63179595Sbennostatic struct pxa_timer_softc *timer_softc = NULL; 64179595Sbenno 65179595Sbennostatic int pxa_timer_probe(device_t); 66179595Sbennostatic int pxa_timer_attach(device_t); 67179595Sbenno 68179595Sbennostatic driver_filter_t pxa_hardclock; 69179595Sbenno 70179595Sbennostatic unsigned pxa_timer_get_timecount(struct timecounter *); 71179595Sbenno 72179595Sbennouint32_t pxa_timer_get_osmr(int); 73179595Sbennovoid pxa_timer_set_osmr(int, uint32_t); 74179595Sbennouint32_t pxa_timer_get_oscr(void); 75179595Sbennovoid pxa_timer_set_oscr(uint32_t); 76179595Sbennouint32_t pxa_timer_get_ossr(void); 77179595Sbennovoid pxa_timer_clear_ossr(uint32_t); 78179595Sbennovoid pxa_timer_watchdog_enable(void); 79179595Sbennovoid pxa_timer_watchdog_disable(void); 80179595Sbennovoid pxa_timer_interrupt_enable(int); 81179595Sbennovoid pxa_timer_interrupt_disable(int); 82179595Sbenno 83179595Sbennostatic struct timecounter pxa_timer_timecounter = { 84179595Sbenno .tc_get_timecount = pxa_timer_get_timecount, 85179595Sbenno .tc_name = "OS Timer", 86179595Sbenno .tc_frequency = PXA_TIMER_FREQUENCY, 87179595Sbenno .tc_counter_mask = ~0u, 88179595Sbenno .tc_quality = 1000, 89179595Sbenno}; 90179595Sbenno 91179595Sbennostatic int 92179595Sbennopxa_timer_probe(device_t dev) 93179595Sbenno{ 94179595Sbenno 95179595Sbenno device_set_desc(dev, "OS Timer"); 96179595Sbenno return (0); 97179595Sbenno} 98179595Sbenno 99179595Sbennostatic int 100179595Sbennopxa_timer_attach(device_t dev) 101179595Sbenno{ 102179595Sbenno int error; 103179595Sbenno void *ihl; 104179595Sbenno struct pxa_timer_softc *sc; 105179595Sbenno 106179595Sbenno sc = (struct pxa_timer_softc *)device_get_softc(dev); 107179595Sbenno 108179595Sbenno if (timer_softc != NULL) 109179595Sbenno return (ENXIO); 110179595Sbenno 111179595Sbenno error = bus_alloc_resources(dev, pxa_timer_spec, sc->pt_res); 112179595Sbenno if (error) { 113179595Sbenno device_printf(dev, "could not allocate resources\n"); 114179595Sbenno return (ENXIO); 115179595Sbenno } 116179595Sbenno 117179595Sbenno sc->pt_bst = rman_get_bustag(sc->pt_res[0]); 118179595Sbenno sc->pt_bsh = rman_get_bushandle(sc->pt_res[0]); 119179595Sbenno 120179595Sbenno timer_softc = sc; 121179595Sbenno 122179595Sbenno pxa_timer_interrupt_disable(-1); 123179595Sbenno pxa_timer_watchdog_disable(); 124179595Sbenno 125179595Sbenno if (bus_setup_intr(dev, sc->pt_res[1], INTR_TYPE_CLK, 126179595Sbenno pxa_hardclock, NULL, NULL, &ihl) != 0) { 127179595Sbenno bus_release_resources(dev, pxa_timer_spec, sc->pt_res); 128179595Sbenno device_printf(dev, "could not setup hardclock interrupt\n"); 129179595Sbenno return (ENXIO); 130179595Sbenno } 131179595Sbenno 132179595Sbenno return (0); 133179595Sbenno} 134179595Sbenno 135179595Sbennostatic int 136179595Sbennopxa_hardclock(void *arg) 137179595Sbenno{ 138179595Sbenno struct trapframe *frame; 139179595Sbenno 140179595Sbenno frame = (struct trapframe *)arg; 141179595Sbenno 142179595Sbenno /* Clear the interrupt */ 143179595Sbenno pxa_timer_clear_ossr(OST_SR_CH0); 144179595Sbenno 145179595Sbenno /* Schedule next tick */ 146179595Sbenno pxa_timer_set_osmr(0, pxa_timer_get_oscr() + PXA_TIMER_TICK); 147179595Sbenno 148179595Sbenno /* Do what we came here for */ 149179595Sbenno hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); 150179595Sbenno 151179595Sbenno return (FILTER_HANDLED); 152179595Sbenno} 153179595Sbenno 154179595Sbennostatic device_method_t pxa_timer_methods[] = { 155179595Sbenno DEVMETHOD(device_probe, pxa_timer_probe), 156179595Sbenno DEVMETHOD(device_attach, pxa_timer_attach), 157179595Sbenno 158179595Sbenno {0, 0} 159179595Sbenno}; 160179595Sbenno 161179595Sbennostatic driver_t pxa_timer_driver = { 162179595Sbenno "timer", 163179595Sbenno pxa_timer_methods, 164179595Sbenno sizeof(struct pxa_timer_softc), 165179595Sbenno}; 166179595Sbenno 167179595Sbennostatic devclass_t pxa_timer_devclass; 168179595Sbenno 169179595SbennoDRIVER_MODULE(pxatimer, pxa, pxa_timer_driver, pxa_timer_devclass, 0, 0); 170179595Sbenno 171179595Sbennostatic unsigned 172179595Sbennopxa_timer_get_timecount(struct timecounter *tc) 173179595Sbenno{ 174179595Sbenno 175179595Sbenno return (pxa_timer_get_oscr()); 176179595Sbenno} 177179595Sbenno 178179595Sbennovoid 179179595Sbennocpu_initclocks(void) 180179595Sbenno{ 181179595Sbenno 182179595Sbenno pxa_timer_set_oscr(0); 183179595Sbenno pxa_timer_set_osmr(0, PXA_TIMER_TICK); 184179595Sbenno pxa_timer_interrupt_enable(0); 185179595Sbenno 186179595Sbenno tc_init(&pxa_timer_timecounter); 187179595Sbenno} 188179595Sbenno 189179595Sbennovoid 190179595Sbennocpu_reset(void) 191179595Sbenno{ 192179595Sbenno uint32_t val; 193179595Sbenno 194278613Sian (void)disable_interrupts(PSR_I|PSR_F); 195179595Sbenno 196179595Sbenno val = pxa_timer_get_oscr(); 197179595Sbenno val += PXA_TIMER_FREQUENCY; 198179595Sbenno pxa_timer_set_osmr(3, val); 199179595Sbenno pxa_timer_watchdog_enable(); 200179595Sbenno 201179595Sbenno for(;;); 202179595Sbenno} 203179595Sbenno 204179595Sbennovoid 205179595SbennoDELAY(int usec) 206179595Sbenno{ 207179595Sbenno uint32_t val; 208179595Sbenno 209179595Sbenno if (timer_softc == NULL) { 210179595Sbenno for (; usec > 0; usec--) 211179595Sbenno for (val = 100; val > 0; val--) 212179595Sbenno ; 213179595Sbenno return; 214179595Sbenno } 215179595Sbenno 216179595Sbenno val = pxa_timer_get_oscr(); 217179595Sbenno val += (PXA_TIMER_FREQUENCY * usec) / 1000000; 218179595Sbenno while (pxa_timer_get_oscr() <= val); 219179595Sbenno} 220179595Sbenno 221179595Sbennouint32_t 222179595Sbennopxa_timer_get_osmr(int which) 223179595Sbenno{ 224179595Sbenno 225179595Sbenno return (bus_space_read_4(timer_softc->pt_bst, 226179595Sbenno timer_softc->pt_bsh, which * 0x4)); 227179595Sbenno} 228179595Sbenno 229179595Sbennovoid 230179595Sbennopxa_timer_set_osmr(int which, uint32_t val) 231179595Sbenno{ 232179595Sbenno 233179595Sbenno bus_space_write_4(timer_softc->pt_bst, 234179595Sbenno timer_softc->pt_bsh, which * 0x4, val); 235179595Sbenno} 236179595Sbenno 237179595Sbennouint32_t 238179595Sbennopxa_timer_get_oscr() 239179595Sbenno{ 240179595Sbenno 241179595Sbenno return (bus_space_read_4(timer_softc->pt_bst, 242179595Sbenno timer_softc->pt_bsh, OST_CR)); 243179595Sbenno} 244179595Sbenno 245179595Sbennovoid 246179595Sbennopxa_timer_set_oscr(uint32_t val) 247179595Sbenno{ 248179595Sbenno 249179595Sbenno bus_space_write_4(timer_softc->pt_bst, 250179595Sbenno timer_softc->pt_bsh, OST_CR, val); 251179595Sbenno} 252179595Sbenno 253179595Sbennouint32_t 254179595Sbennopxa_timer_get_ossr() 255179595Sbenno{ 256179595Sbenno 257179595Sbenno return (bus_space_read_4(timer_softc->pt_bst, 258179595Sbenno timer_softc->pt_bsh, OST_SR)); 259179595Sbenno} 260179595Sbenno 261179595Sbennovoid 262179595Sbennopxa_timer_clear_ossr(uint32_t val) 263179595Sbenno{ 264179595Sbenno 265179595Sbenno bus_space_write_4(timer_softc->pt_bst, 266179595Sbenno timer_softc->pt_bsh, OST_SR, val); 267179595Sbenno} 268179595Sbenno 269179595Sbennovoid 270179595Sbennopxa_timer_watchdog_enable() 271179595Sbenno{ 272179595Sbenno 273179595Sbenno bus_space_write_4(timer_softc->pt_bst, 274179595Sbenno timer_softc->pt_bsh, OST_WR, 0x1); 275179595Sbenno} 276179595Sbenno 277179595Sbennovoid 278179595Sbennopxa_timer_watchdog_disable() 279179595Sbenno{ 280179595Sbenno 281179595Sbenno bus_space_write_4(timer_softc->pt_bst, 282179595Sbenno timer_softc->pt_bsh, OST_WR, 0x0); 283179595Sbenno} 284179595Sbenno 285179595Sbennovoid 286179595Sbennopxa_timer_interrupt_enable(int which) 287179595Sbenno{ 288179595Sbenno uint32_t oier; 289179595Sbenno 290179595Sbenno if (which == -1) { 291179595Sbenno bus_space_write_4(timer_softc->pt_bst, 292179595Sbenno timer_softc->pt_bsh, OST_IR, 0xf); 293179595Sbenno return; 294179595Sbenno } 295179595Sbenno 296179595Sbenno oier = bus_space_read_4(timer_softc->pt_bst, 297179595Sbenno timer_softc->pt_bsh, OST_IR); 298179595Sbenno oier |= 1 << which; 299179595Sbenno bus_space_write_4(timer_softc->pt_bst, 300179595Sbenno timer_softc->pt_bsh, OST_IR, oier); 301179595Sbenno} 302179595Sbenno 303179595Sbennovoid 304179595Sbennopxa_timer_interrupt_disable(int which) 305179595Sbenno{ 306179595Sbenno uint32_t oier; 307179595Sbenno 308179595Sbenno if (which == -1) { 309179595Sbenno bus_space_write_4(timer_softc->pt_bst, 310179595Sbenno timer_softc->pt_bsh, OST_IR, 0); 311179595Sbenno } 312179595Sbenno 313179595Sbenno oier = bus_space_read_4(timer_softc->pt_bst, 314179595Sbenno timer_softc->pt_bsh, OST_IR); 315179595Sbenno oier &= ~(1 << which); 316179595Sbenno bus_space_write_4(timer_softc->pt_bst, 317179595Sbenno timer_softc->pt_bsh, OST_IR, oier); 318179595Sbenno} 319