11.21Smrg/* $NetBSD: sbtimer.c,v 1.21 2017/07/24 09:56:46 mrg 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.8Scgd * Broadcom Corporation. The "Broadcom Corporation" name may not be 191.8Scgd * used to endorse or promote products derived from this software 201.8Scgd * without the prior written permission of Broadcom Corporation. 211.1Ssimonb * 221.1Ssimonb * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED 231.1Ssimonb * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF 241.1Ssimonb * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 251.1Ssimonb * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE 261.1Ssimonb * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE 271.1Ssimonb * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 281.1Ssimonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 291.1Ssimonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 301.1Ssimonb * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 311.1Ssimonb * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 321.1Ssimonb * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 331.1Ssimonb */ 341.9Slukem 351.9Slukem#include <sys/cdefs.h> 361.21Smrg__KERNEL_RCSID(0, "$NetBSD: sbtimer.c,v 1.21 2017/07/24 09:56:46 mrg Exp $"); 371.1Ssimonb 381.1Ssimonb#include <sys/param.h> 391.1Ssimonb#include <sys/device.h> 401.1Ssimonb#include <sys/systm.h> 411.1Ssimonb#include <sys/kernel.h> 421.19Stsutsui#include <sys/cpu.h> 431.1Ssimonb 441.1Ssimonb#include <mips/locore.h> 451.1Ssimonb 461.1Ssimonb#include <mips/sibyte/include/sb1250_regs.h> 471.1Ssimonb#include <mips/sibyte/include/sb1250_scd.h> 481.1Ssimonb#include <mips/sibyte/dev/sbscdvar.h> 491.1Ssimonb 501.21Smrg#include <evbmips/sbmips/systemsw.h> 511.21Smrg 521.1Ssimonbstruct sbtimer_softc { 531.16Smatt device_t sc_dev; 541.1Ssimonb void *sc_intrhand; 551.1Ssimonb int sc_flags; 561.1Ssimonb void *sc_addr_icnt, *sc_addr_cnt, *sc_addr_cfg; 571.1Ssimonb}; 581.1Ssimonb#define SBTIMER_CLOCK 1 591.1Ssimonb#define SBTIMER_STATCLOCK 2 601.1Ssimonb 611.20Schristos#define READ_REG(rp) mips3_ld((register_t)(rp)) 621.20Schristos#define WRITE_REG(rp, val) mips3_sd((register_t)(rp), (val)) 631.1Ssimonb 641.16Smattstatic int sbtimer_match(device_t, cfdata_t, void *); 651.16Smattstatic void sbtimer_attach(device_t, device_t, void *); 661.1Ssimonb 671.16SmattCFATTACH_DECL_NEW(sbtimer, sizeof(struct sbtimer_softc), 681.7Sthorpej sbtimer_match, sbtimer_attach, NULL, NULL); 691.1Ssimonb 701.15Smattstatic void sbtimer_clockintr(void *arg, uint32_t status, vaddr_t pc); 711.15Smattstatic void sbtimer_statclockintr(void *arg, uint32_t status, vaddr_t pc); 721.15Smattstatic void sbtimer_miscintr(void *arg, uint32_t status, vaddr_t pc); 731.1Ssimonb 741.1Ssimonbstatic void sbtimer_clock_init(void *arg); 751.1Ssimonb 761.1Ssimonbstatic int 771.16Smattsbtimer_match(device_t parent, cfdata_t match, void *aux) 781.1Ssimonb{ 791.1Ssimonb struct sbscd_attach_args *sap = aux; 801.1Ssimonb 811.1Ssimonb if (sap->sa_locs.sa_type != SBSCD_DEVTYPE_TIMER) 821.1Ssimonb return (0); 831.1Ssimonb 841.1Ssimonb return 1; 851.1Ssimonb} 861.1Ssimonb 871.1Ssimonbstatic void 881.16Smattsbtimer_attach(device_t parent, device_t self, void *aux) 891.1Ssimonb{ 901.1Ssimonb struct sbscd_attach_args *sa = aux; 911.16Smatt struct sbtimer_softc *sc = device_private(self); 921.15Smatt void (*fun)(void *, uint32_t, vaddr_t); 931.1Ssimonb int ipl; 941.1Ssimonb const char *comment = ""; 951.1Ssimonb 961.16Smatt sc->sc_dev = self; 971.16Smatt 981.16Smatt sc->sc_flags = device_cfdata(sc->sc_dev)->cf_flags; 991.18Smatt sc->sc_addr_icnt = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 1001.18Smatt sa->sa_locs.sa_offset + R_SCD_TIMER_INIT); 1011.18Smatt sc->sc_addr_cnt = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 1021.18Smatt sa->sa_locs.sa_offset + R_SCD_TIMER_CNT); 1031.18Smatt sc->sc_addr_cfg = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 1041.18Smatt sa->sa_locs.sa_offset + R_SCD_TIMER_CFG); 1051.1Ssimonb 1061.17Smatt aprint_normal(": "); 1071.1Ssimonb if ((sc->sc_flags & SBTIMER_CLOCK) != 0) { 1081.1Ssimonb ipl = IPL_CLOCK; 1091.1Ssimonb fun = sbtimer_clockintr; 1101.1Ssimonb 1111.1Ssimonb if (system_set_clockfns(sc, sbtimer_clock_init)) { 1121.1Ssimonb /* not really the clock */ 1131.1Ssimonb sc->sc_flags &= ~SBTIMER_CLOCK; 1141.1Ssimonb comment = " (not system timer)"; 1151.1Ssimonb goto not_really; 1161.1Ssimonb } 1171.17Smatt aprint_normal("system timer"); 1181.1Ssimonb } else if ((sc->sc_flags & SBTIMER_STATCLOCK) != 0) { 1191.12Sad ipl = IPL_HIGH; 1201.1Ssimonb fun = sbtimer_statclockintr; 1211.1Ssimonb 1221.1Ssimonb /* XXX make sure it's the statclock */ 1231.1Ssimonb if (1) { 1241.1Ssimonb /* not really the statclock */ 1251.1Ssimonb sc->sc_flags &= ~SBTIMER_STATCLOCK; 1261.1Ssimonb comment = " (not system statistics timer)"; 1271.1Ssimonb goto not_really; 1281.1Ssimonb } 1291.17Smatt aprint_normal("system statistics timer"); 1301.1Ssimonb } else { 1311.1Ssimonbnot_really: 1321.1Ssimonb ipl = IPL_BIO; /* XXX -- pretty low */ 1331.1Ssimonb fun = sbtimer_miscintr; 1341.17Smatt aprint_normal("general-purpose timer%s", comment); 1351.1Ssimonb } 1361.17Smatt aprint_normal("\n"); 1371.1Ssimonb 1381.1Ssimonb /* clear intr & disable timer. */ 1391.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 1401.1Ssimonb 1411.1Ssimonb sc->sc_intrhand = cpu_intr_establish(sa->sa_locs.sa_intr[0], ipl, 1421.1Ssimonb fun, sc); 1431.1Ssimonb} 1441.1Ssimonb 1451.1Ssimonbstatic void 1461.1Ssimonbsbtimer_clock_init(void *arg) 1471.1Ssimonb{ 1481.1Ssimonb struct sbtimer_softc *sc = arg; 1491.1Ssimonb 1501.17Smatt if ((1000000 % hz) == 0) { 1511.17Smatt aprint_normal_dev(sc->sc_dev, "%dHz system timer\n", hz); 1521.17Smatt } else { 1531.17Smatt aprint_error_dev(sc->sc_dev, 1541.17Smatt "cannot get %dHz clock; using 1000Hz\n", hz); 1551.1Ssimonb hz = 1000; 1561.1Ssimonb tick = 1000000 / hz; 1571.1Ssimonb } 1581.1Ssimonb 1591.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 1601.1Ssimonb if (G_SYS_PLL_DIV(READ_REG(MIPS_PHYS_TO_KSEG1(A_SCD_SYSTEM_CFG))) == 0) { 1611.17Smatt aprint_debug_dev(sc->sc_dev, 1621.17Smatt "PLL_DIV == 0; speeding up clock ticks for simulator\n"); 1631.1Ssimonb WRITE_REG(sc->sc_addr_icnt, (tick/100) - 1); /* XXX */ 1641.1Ssimonb } else { 1651.1Ssimonb WRITE_REG(sc->sc_addr_icnt, tick - 1); /* XXX */ 1661.1Ssimonb } 1671.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x03); /* XXX */ 1681.1Ssimonb} 1691.1Ssimonb 1701.1Ssimonbstatic void 1711.15Smattsbtimer_clockintr(void *arg, uint32_t status, vaddr_t pc) 1721.1Ssimonb{ 1731.1Ssimonb struct sbtimer_softc *sc = arg; 1741.1Ssimonb struct clockframe cf; 1751.1Ssimonb 1761.1Ssimonb /* clear interrupt, but leave timer enabled and in repeating mode */ 1771.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x03); /* XXX */ 1781.1Ssimonb 1791.1Ssimonb cf.pc = pc; 1801.1Ssimonb cf.sr = status; 1811.19Stsutsui cf.intr = (curcpu()->ci_idepth > 1); 1821.3Ssimonb 1831.13Ssimonb hardclock(&cf); 1841.1Ssimonb 1851.13Ssimonb /* 1861.13Ssimonb * We never want a CPU core clock interrupt, so adjust the CP0 1871.13Ssimonb * compare register to just before the CP0 clock register's value 1881.13Ssimonb * each time. 1891.13Ssimonb */ 1901.13Ssimonb mips3_cp0_compare_write(mips3_cp0_count_read() - 1); 1911.1Ssimonb} 1921.1Ssimonb 1931.1Ssimonbstatic void 1941.15Smattsbtimer_statclockintr(void *arg, uint32_t status, vaddr_t pc) 1951.1Ssimonb{ 1961.1Ssimonb struct sbtimer_softc *sc = arg; 1971.1Ssimonb struct clockframe cf; 1981.1Ssimonb 1991.1Ssimonb /* clear intr & disable timer, reset initial count, re-enable timer */ 2001.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 2011.1Ssimonb /* XXX more to do */ 2021.1Ssimonb 2031.1Ssimonb cf.pc = pc; 2041.1Ssimonb cf.sr = status; 2051.1Ssimonb 2061.1Ssimonb statclock(&cf); 2071.1Ssimonb} 2081.1Ssimonb 2091.1Ssimonbstatic void 2101.15Smattsbtimer_miscintr(void *arg, uint32_t status, vaddr_t pc) 2111.1Ssimonb{ 2121.1Ssimonb struct sbtimer_softc *sc = arg; 2131.1Ssimonb 2141.1Ssimonb /* disable timer */ 2151.1Ssimonb WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 2161.1Ssimonb 2171.1Ssimonb /* XXX more to do */ 2181.1Ssimonb} 219