sbtimer.c revision 1.7
11.7Sthorpej/* $NetBSD: sbtimer.c,v 1.7 2002/10/02 15:52:26 thorpej Exp $ */ 21.1Ssimonb 31.1Ssimonb/* 41.1Ssimonb * Copyright 2000, 2001 51.1Ssimonb * Broadcom Corporation. All rights reserved. 61.1Ssimonb * 71.1Ssimonb * This software is furnished under license and may be used and copied only 81.1Ssimonb * in accordance with the following terms and conditions. Subject to these 91.1Ssimonb * conditions, you may download, copy, install, use, modify and distribute 101.1Ssimonb * modified or unmodified copies of this software in source and/or binary 111.1Ssimonb * form. No title or ownership is transferred hereby. 121.1Ssimonb * 131.1Ssimonb * 1) Any source code used, modified or distributed must reproduce and 141.1Ssimonb * retain this copyright notice and list of conditions as they appear in 151.1Ssimonb * the source file. 161.1Ssimonb * 171.1Ssimonb * 2) No right is granted to use any trade name, trademark, or logo of 181.1Ssimonb * Broadcom Corporation. Neither the "Broadcom Corporation" name nor any 191.1Ssimonb * trademark or logo of Broadcom Corporation may be used to endorse or 201.1Ssimonb * promote products derived from this software without the prior written 211.1Ssimonb * permission of Broadcom Corporation. 221.1Ssimonb * 231.1Ssimonb * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED 241.1Ssimonb * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF 251.1Ssimonb * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 261.1Ssimonb * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE 271.1Ssimonb * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE 281.1Ssimonb * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 291.1Ssimonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 301.1Ssimonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 311.1Ssimonb * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 321.1Ssimonb * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 331.1Ssimonb * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 341.1Ssimonb */ 351.1Ssimonb 361.1Ssimonb#include <sys/param.h> 371.1Ssimonb#include <sys/device.h> 381.1Ssimonb#include <sys/systm.h> 391.1Ssimonb#include <sys/kernel.h> 401.1Ssimonb 411.1Ssimonb#include <mips/locore.h> 421.1Ssimonb 431.1Ssimonb#include <mips/sibyte/include/sb1250_regs.h> 441.1Ssimonb#include <mips/sibyte/include/sb1250_scd.h> 451.1Ssimonb#include <mips/sibyte/dev/sbscdvar.h> 461.1Ssimonb 471.1Ssimonbstruct sbtimer_softc { 481.1Ssimonb struct device sc_dev; 491.1Ssimonb void *sc_intrhand; 501.1Ssimonb int sc_flags; 511.1Ssimonb void *sc_addr_icnt, *sc_addr_cnt, *sc_addr_cfg; 521.1Ssimonb}; 531.1Ssimonb#define SBTIMER_CLOCK 1 541.1Ssimonb#define SBTIMER_STATCLOCK 2 551.1Ssimonb 561.1Ssimonb#define READ_REG(rp) (mips3_ld((uint64_t *)(rp))) 571.1Ssimonb#define WRITE_REG(rp, val) (mips3_sd((uint64_t *)(rp), (val))) 581.1Ssimonb 591.1Ssimonbstatic int sbtimer_match(struct device *, struct cfdata *, void *); 601.1Ssimonbstatic void sbtimer_attach(struct device *, struct device *, void *); 611.1Ssimonb 621.6SthorpejCFATTACH_DECL(sbtimer, sizeof(struct sbtimer_softc), 631.7Sthorpej sbtimer_match, sbtimer_attach, NULL, NULL); 641.1Ssimonb 651.1Ssimonbstatic void sbtimer_clockintr(void *arg, uint32_t status, uint32_t pc); 661.1Ssimonbstatic void sbtimer_statclockintr(void *arg, uint32_t status, 671.1Ssimonb uint32_t pc); 681.1Ssimonbstatic void sbtimer_miscintr(void *arg, uint32_t status, uint32_t pc); 691.1Ssimonb 701.1Ssimonbstatic void sbtimer_clock_init(void *arg); 711.1Ssimonb 721.1Ssimonbstatic int 731.1Ssimonbsbtimer_match(struct device *parent, struct cfdata *match, void *aux) 741.1Ssimonb{ 751.1Ssimonb struct sbscd_attach_args *sap = aux; 761.1Ssimonb 771.1Ssimonb if (sap->sa_locs.sa_type != SBSCD_DEVTYPE_TIMER) 781.1Ssimonb return (0); 791.1Ssimonb 801.1Ssimonb return 1; 811.1Ssimonb} 821.1Ssimonb 831.1Ssimonbstatic void 841.1Ssimonbsbtimer_attach(struct device *parent, struct device *self, void *aux) 851.1Ssimonb{ 861.1Ssimonb struct sbscd_attach_args *sa = aux; 871.1Ssimonb struct sbtimer_softc *sc = (struct sbtimer_softc *)self; 881.1Ssimonb void (*fun)(void *, uint32_t, uint32_t); 891.1Ssimonb int ipl; 901.1Ssimonb const char *comment = ""; 911.1Ssimonb 921.1Ssimonb sc->sc_flags = sc->sc_dev.dv_cfdata->cf_flags; 931.1Ssimonb sc->sc_addr_icnt = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 941.1Ssimonb sa->sa_locs.sa_offset + R_SCD_TIMER_INIT); 951.1Ssimonb sc->sc_addr_cnt = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 961.1Ssimonb sa->sa_locs.sa_offset + R_SCD_TIMER_CNT); 971.1Ssimonb sc->sc_addr_cfg = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 981.1Ssimonb sa->sa_locs.sa_offset + R_SCD_TIMER_CFG); 991.1Ssimonb 1001.1Ssimonb printf(": "); 1011.1Ssimonb if ((sc->sc_flags & SBTIMER_CLOCK) != 0) { 1021.1Ssimonb ipl = IPL_CLOCK; 1031.1Ssimonb fun = sbtimer_clockintr; 1041.1Ssimonb 1051.1Ssimonb if (system_set_clockfns(sc, sbtimer_clock_init)) { 1061.1Ssimonb /* not really the clock */ 1071.1Ssimonb sc->sc_flags &= ~SBTIMER_CLOCK; 1081.1Ssimonb comment = " (not system timer)"; 1091.1Ssimonb goto not_really; 1101.1Ssimonb } 1111.1Ssimonb printf("system timer"); 1121.1Ssimonb } else if ((sc->sc_flags & SBTIMER_STATCLOCK) != 0) { 1131.1Ssimonb ipl = IPL_STATCLOCK; 1141.1Ssimonb fun = sbtimer_statclockintr; 1151.1Ssimonb 1161.1Ssimonb /* XXX make sure it's the statclock */ 1171.1Ssimonb if (1) { 1181.1Ssimonb /* not really the statclock */ 1191.1Ssimonb sc->sc_flags &= ~SBTIMER_STATCLOCK; 1201.1Ssimonb comment = " (not system statistics timer)"; 1211.1Ssimonb goto not_really; 1221.1Ssimonb } 1231.1Ssimonb printf("system statistics timer"); 1241.1Ssimonb } else { 1251.1Ssimonbnot_really: 1261.1Ssimonb ipl = IPL_BIO; /* XXX -- pretty low */ 1271.1Ssimonb fun = sbtimer_miscintr; 1281.1Ssimonb printf("general-purpose timer%s", comment); 1291.1Ssimonb } 1301.1Ssimonb printf("\n"); 1311.1Ssimonb 1321.1Ssimonb /* clear intr & disable timer. */ 1331.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 1341.1Ssimonb 1351.1Ssimonb sc->sc_intrhand = cpu_intr_establish(sa->sa_locs.sa_intr[0], ipl, 1361.1Ssimonb fun, sc); 1371.1Ssimonb} 1381.1Ssimonb 1391.1Ssimonbstatic void 1401.1Ssimonbsbtimer_clock_init(void *arg) 1411.1Ssimonb{ 1421.1Ssimonb struct sbtimer_softc *sc = arg; 1431.1Ssimonb 1441.1Ssimonb printf("%s: ", sc->sc_dev.dv_xname); 1451.1Ssimonb if ((1000000 % hz) == 0) 1461.1Ssimonb printf("%dHz system timer\n", hz); 1471.1Ssimonb else { 1481.1Ssimonb printf("cannot get %dHz clock; using 1000Hz\n", hz); 1491.1Ssimonb hz = 1000; 1501.1Ssimonb tick = 1000000 / hz; 1511.1Ssimonb } 1521.1Ssimonb 1531.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 1541.1Ssimonb if (G_SYS_PLL_DIV(READ_REG(MIPS_PHYS_TO_KSEG1(A_SCD_SYSTEM_CFG))) == 0) { 1551.2Ssimonb printf("%s: PLL_DIV == 0; speeding up clock ticks for simulator\n", 1561.2Ssimonb sc->sc_dev.dv_xname); 1571.1Ssimonb WRITE_REG(sc->sc_addr_icnt, (tick/100) - 1); /* XXX */ 1581.1Ssimonb } else { 1591.1Ssimonb WRITE_REG(sc->sc_addr_icnt, tick - 1); /* XXX */ 1601.1Ssimonb } 1611.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x03); /* XXX */ 1621.1Ssimonb} 1631.1Ssimonb 1641.1Ssimonbstatic void 1651.1Ssimonbsbtimer_clockintr(void *arg, uint32_t status, uint32_t pc) 1661.1Ssimonb{ 1671.1Ssimonb struct sbtimer_softc *sc = arg; 1681.1Ssimonb struct clockframe cf; 1691.1Ssimonb 1701.1Ssimonb /* clear interrupt, but leave timer enabled and in repeating mode */ 1711.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x03); /* XXX */ 1721.1Ssimonb 1731.1Ssimonb cf.pc = pc; 1741.1Ssimonb cf.sr = status; 1751.3Ssimonb 1761.3Ssimonb /* reset the CPU count register (used by microtime) */ 1771.3Ssimonb mips3_cp0_count_write(0); 1781.1Ssimonb 1791.1Ssimonb hardclock(&cf); 1801.1Ssimonb} 1811.1Ssimonb 1821.1Ssimonbstatic void 1831.1Ssimonbsbtimer_statclockintr(void *arg, uint32_t status, uint32_t pc) 1841.1Ssimonb{ 1851.1Ssimonb struct sbtimer_softc *sc = arg; 1861.1Ssimonb struct clockframe cf; 1871.1Ssimonb 1881.1Ssimonb /* clear intr & disable timer, reset initial count, re-enable timer */ 1891.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 1901.1Ssimonb /* XXX more to do */ 1911.1Ssimonb 1921.1Ssimonb cf.pc = pc; 1931.1Ssimonb cf.sr = status; 1941.1Ssimonb 1951.1Ssimonb statclock(&cf); 1961.1Ssimonb} 1971.1Ssimonb 1981.1Ssimonbstatic void 1991.1Ssimonbsbtimer_miscintr(void *arg, uint32_t status, uint32_t pc) 2001.1Ssimonb{ 2011.1Ssimonb struct sbtimer_softc *sc = arg; 2021.1Ssimonb 2031.1Ssimonb /* disable timer */ 2041.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 2051.1Ssimonb 2061.1Ssimonb /* XXX more to do */ 2071.1Ssimonb} 208