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