sbtimer.c revision 1.1
1/* $NetBSD: sbtimer.c,v 1.1 2002/03/05 23:46:43 simonb Exp $ */ 2 3/* XXX wasabi copyright */ 4 5/* 6 * Copyright 2000, 2001 7 * Broadcom Corporation. All rights reserved. 8 * 9 * This software is furnished under license and may be used and copied only 10 * in accordance with the following terms and conditions. Subject to these 11 * conditions, you may download, copy, install, use, modify and distribute 12 * modified or unmodified copies of this software in source and/or binary 13 * form. No title or ownership is transferred hereby. 14 * 15 * 1) Any source code used, modified or distributed must reproduce and 16 * retain this copyright notice and list of conditions as they appear in 17 * the source file. 18 * 19 * 2) No right is granted to use any trade name, trademark, or logo of 20 * Broadcom Corporation. Neither the "Broadcom Corporation" name nor any 21 * trademark or logo of Broadcom Corporation may be used to endorse or 22 * promote products derived from this software without the prior written 23 * permission of Broadcom Corporation. 24 * 25 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED 26 * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 28 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE 29 * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE 30 * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 33 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 34 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 35 * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38#include <sys/param.h> 39#include <sys/device.h> 40#include <sys/systm.h> 41#include <sys/kernel.h> 42 43#include <mips/locore.h> 44 45#include <mips/sibyte/include/sb1250_regs.h> 46#include <mips/sibyte/include/sb1250_scd.h> 47#include <mips/sibyte/dev/sbscdvar.h> 48 49struct sbtimer_softc { 50 struct device sc_dev; 51 void *sc_intrhand; 52 int sc_flags; 53 void *sc_addr_icnt, *sc_addr_cnt, *sc_addr_cfg; 54}; 55#define SBTIMER_CLOCK 1 56#define SBTIMER_STATCLOCK 2 57 58#define READ_REG(rp) (mips3_ld((uint64_t *)(rp))) 59#define WRITE_REG(rp, val) (mips3_sd((uint64_t *)(rp), (val))) 60 61static int sbtimer_match(struct device *, struct cfdata *, void *); 62static void sbtimer_attach(struct device *, struct device *, void *); 63 64struct cfattach sbtimer_ca = { 65 sizeof(struct sbtimer_softc), sbtimer_match, sbtimer_attach 66}; 67 68static void sbtimer_clockintr(void *arg, uint32_t status, uint32_t pc); 69static void sbtimer_statclockintr(void *arg, uint32_t status, 70 uint32_t pc); 71static void sbtimer_miscintr(void *arg, uint32_t status, uint32_t pc); 72 73static void sbtimer_clock_init(void *arg); 74 75int printticks = 0; 76 77static int 78sbtimer_match(struct device *parent, struct cfdata *match, void *aux) 79{ 80 struct sbscd_attach_args *sap = aux; 81 82 if (sap->sa_locs.sa_type != SBSCD_DEVTYPE_TIMER) 83 return (0); 84 85 return 1; 86} 87 88static void 89sbtimer_attach(struct device *parent, struct device *self, void *aux) 90{ 91 struct sbscd_attach_args *sa = aux; 92 struct sbtimer_softc *sc = (struct sbtimer_softc *)self; 93 void (*fun)(void *, uint32_t, uint32_t); 94 int ipl; 95 const char *comment = ""; 96 97 sc->sc_flags = sc->sc_dev.dv_cfdata->cf_flags; 98 sc->sc_addr_icnt = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 99 sa->sa_locs.sa_offset + R_SCD_TIMER_INIT); 100 sc->sc_addr_cnt = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 101 sa->sa_locs.sa_offset + R_SCD_TIMER_CNT); 102 sc->sc_addr_cfg = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 103 sa->sa_locs.sa_offset + R_SCD_TIMER_CFG); 104 105 printf(": "); 106 if ((sc->sc_flags & SBTIMER_CLOCK) != 0) { 107 ipl = IPL_CLOCK; 108 fun = sbtimer_clockintr; 109 110 if (system_set_clockfns(sc, sbtimer_clock_init)) { 111 /* not really the clock */ 112 sc->sc_flags &= ~SBTIMER_CLOCK; 113 comment = " (not system timer)"; 114 goto not_really; 115 } 116 printf("system timer"); 117 } else if ((sc->sc_flags & SBTIMER_STATCLOCK) != 0) { 118 ipl = IPL_STATCLOCK; 119 fun = sbtimer_statclockintr; 120 121 /* XXX make sure it's the statclock */ 122 if (1) { 123 /* not really the statclock */ 124 sc->sc_flags &= ~SBTIMER_STATCLOCK; 125 comment = " (not system statistics timer)"; 126 goto not_really; 127 } 128 printf("system statistics timer"); 129 } else { 130not_really: 131 ipl = IPL_BIO; /* XXX -- pretty low */ 132 fun = sbtimer_miscintr; 133 printf("general-purpose timer%s", comment); 134 } 135 printf("\n"); 136 137 /* clear intr & disable timer. */ 138 WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 139 140 sc->sc_intrhand = cpu_intr_establish(sa->sa_locs.sa_intr[0], ipl, 141 fun, sc); 142} 143 144static void 145sbtimer_clock_init(void *arg) 146{ 147 struct sbtimer_softc *sc = arg; 148 149 printf("%s: ", sc->sc_dev.dv_xname); 150 if ((1000000 % hz) == 0) 151 printf("%dHz system timer\n", hz); 152 else { 153 printf("cannot get %dHz clock; using 1000Hz\n", hz); 154 hz = 1000; 155 tick = 1000000 / hz; 156 } 157 158 WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 159 if (G_SYS_PLL_DIV(READ_REG(MIPS_PHYS_TO_KSEG1(A_SCD_SYSTEM_CFG))) == 0) { 160 printf("%s: PLL_DIV == 0; speeding up clock ticks for simulator\n", sc->sc_dev.dv_xname); 161 WRITE_REG(sc->sc_addr_icnt, (tick/100) - 1); /* XXX */ 162 } else { 163 WRITE_REG(sc->sc_addr_icnt, tick - 1); /* XXX */ 164 } 165 WRITE_REG(sc->sc_addr_cfg, 0x03); /* XXX */ 166} 167 168static void 169sbtimer_clockintr(void *arg, uint32_t status, uint32_t pc) 170{ 171 struct sbtimer_softc *sc = arg; 172 struct clockframe cf; 173 174 /* clear interrupt, but leave timer enabled and in repeating mode */ 175 WRITE_REG(sc->sc_addr_cfg, 0x03); /* XXX */ 176 177 if (printticks) 178 printf("+"); 179 cf.pc = pc; 180 cf.sr = status; 181 182 hardclock(&cf); 183} 184 185static void 186sbtimer_statclockintr(void *arg, uint32_t status, uint32_t pc) 187{ 188 struct sbtimer_softc *sc = arg; 189 struct clockframe cf; 190 191 /* clear intr & disable timer, reset initial count, re-enable timer */ 192 WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 193 /* XXX more to do */ 194 195 cf.pc = pc; 196 cf.sr = status; 197 198 statclock(&cf); 199} 200 201static void 202sbtimer_miscintr(void *arg, uint32_t status, uint32_t pc) 203{ 204 struct sbtimer_softc *sc = arg; 205 206 /* disable timer */ 207 WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 208 209 /* XXX more to do */ 210} 211