1 /* $NetBSD: sbtimer.c,v 1.21 2017/07/24 09:56:46 mrg 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. The "Broadcom Corporation" name may not be 19 * used to endorse or promote products derived from this software 20 * without the prior written permission of Broadcom Corporation. 21 * 22 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED 23 * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF 24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 25 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE 26 * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE 27 * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 32 * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: sbtimer.c,v 1.21 2017/07/24 09:56:46 mrg Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/device.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/cpu.h> 43 44 #include <mips/locore.h> 45 46 #include <mips/sibyte/include/sb1250_regs.h> 47 #include <mips/sibyte/include/sb1250_scd.h> 48 #include <mips/sibyte/dev/sbscdvar.h> 49 50 #include <evbmips/sbmips/systemsw.h> 51 52 struct sbtimer_softc { 53 device_t sc_dev; 54 void *sc_intrhand; 55 int sc_flags; 56 void *sc_addr_icnt, *sc_addr_cnt, *sc_addr_cfg; 57 }; 58 #define SBTIMER_CLOCK 1 59 #define SBTIMER_STATCLOCK 2 60 61 #define READ_REG(rp) mips3_ld((register_t)(rp)) 62 #define WRITE_REG(rp, val) mips3_sd((register_t)(rp), (val)) 63 64 static int sbtimer_match(device_t, cfdata_t, void *); 65 static void sbtimer_attach(device_t, device_t, void *); 66 67 CFATTACH_DECL_NEW(sbtimer, sizeof(struct sbtimer_softc), 68 sbtimer_match, sbtimer_attach, NULL, NULL); 69 70 static void sbtimer_clockintr(void *arg, uint32_t status, vaddr_t pc); 71 static void sbtimer_statclockintr(void *arg, uint32_t status, vaddr_t pc); 72 static void sbtimer_miscintr(void *arg, uint32_t status, vaddr_t pc); 73 74 static void sbtimer_clock_init(void *arg); 75 76 static int 77 sbtimer_match(device_t parent, cfdata_t match, void *aux) 78 { 79 struct sbscd_attach_args *sap = aux; 80 81 if (sap->sa_locs.sa_type != SBSCD_DEVTYPE_TIMER) 82 return (0); 83 84 return 1; 85 } 86 87 static void 88 sbtimer_attach(device_t parent, device_t self, void *aux) 89 { 90 struct sbscd_attach_args *sa = aux; 91 struct sbtimer_softc *sc = device_private(self); 92 void (*fun)(void *, uint32_t, vaddr_t); 93 int ipl; 94 const char *comment = ""; 95 96 sc->sc_dev = self; 97 98 sc->sc_flags = device_cfdata(sc->sc_dev)->cf_flags; 99 sc->sc_addr_icnt = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 100 sa->sa_locs.sa_offset + R_SCD_TIMER_INIT); 101 sc->sc_addr_cnt = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 102 sa->sa_locs.sa_offset + R_SCD_TIMER_CNT); 103 sc->sc_addr_cfg = (uint64_t *)MIPS_PHYS_TO_KSEG1(sa->sa_base + 104 sa->sa_locs.sa_offset + R_SCD_TIMER_CFG); 105 106 aprint_normal(": "); 107 if ((sc->sc_flags & SBTIMER_CLOCK) != 0) { 108 ipl = IPL_CLOCK; 109 fun = sbtimer_clockintr; 110 111 if (system_set_clockfns(sc, sbtimer_clock_init)) { 112 /* not really the clock */ 113 sc->sc_flags &= ~SBTIMER_CLOCK; 114 comment = " (not system timer)"; 115 goto not_really; 116 } 117 aprint_normal("system timer"); 118 } else if ((sc->sc_flags & SBTIMER_STATCLOCK) != 0) { 119 ipl = IPL_HIGH; 120 fun = sbtimer_statclockintr; 121 122 /* XXX make sure it's the statclock */ 123 if (1) { 124 /* not really the statclock */ 125 sc->sc_flags &= ~SBTIMER_STATCLOCK; 126 comment = " (not system statistics timer)"; 127 goto not_really; 128 } 129 aprint_normal("system statistics timer"); 130 } else { 131 not_really: 132 ipl = IPL_BIO; /* XXX -- pretty low */ 133 fun = sbtimer_miscintr; 134 aprint_normal("general-purpose timer%s", comment); 135 } 136 aprint_normal("\n"); 137 138 /* clear intr & disable timer. */ 139 WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 140 141 sc->sc_intrhand = cpu_intr_establish(sa->sa_locs.sa_intr[0], ipl, 142 fun, sc); 143 } 144 145 static void 146 sbtimer_clock_init(void *arg) 147 { 148 struct sbtimer_softc *sc = arg; 149 150 if ((1000000 % hz) == 0) { 151 aprint_normal_dev(sc->sc_dev, "%dHz system timer\n", hz); 152 } else { 153 aprint_error_dev(sc->sc_dev, 154 "cannot get %dHz clock; using 1000Hz\n", hz); 155 hz = 1000; 156 tick = 1000000 / hz; 157 } 158 159 WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 160 if (G_SYS_PLL_DIV(READ_REG(MIPS_PHYS_TO_KSEG1(A_SCD_SYSTEM_CFG))) == 0) { 161 aprint_debug_dev(sc->sc_dev, 162 "PLL_DIV == 0; speeding up clock ticks for simulator\n"); 163 WRITE_REG(sc->sc_addr_icnt, (tick/100) - 1); /* XXX */ 164 } else { 165 WRITE_REG(sc->sc_addr_icnt, tick - 1); /* XXX */ 166 } 167 WRITE_REG(sc->sc_addr_cfg, 0x03); /* XXX */ 168 } 169 170 static void 171 sbtimer_clockintr(void *arg, uint32_t status, vaddr_t pc) 172 { 173 struct sbtimer_softc *sc = arg; 174 struct clockframe cf; 175 176 /* clear interrupt, but leave timer enabled and in repeating mode */ 177 WRITE_REG(sc->sc_addr_cfg, 0x03); /* XXX */ 178 179 cf.pc = pc; 180 cf.sr = status; 181 cf.intr = (curcpu()->ci_idepth > 1); 182 183 hardclock(&cf); 184 185 /* 186 * We never want a CPU core clock interrupt, so adjust the CP0 187 * compare register to just before the CP0 clock register's value 188 * each time. 189 */ 190 mips3_cp0_compare_write(mips3_cp0_count_read() - 1); 191 } 192 193 static void 194 sbtimer_statclockintr(void *arg, uint32_t status, vaddr_t pc) 195 { 196 struct sbtimer_softc *sc = arg; 197 struct clockframe cf; 198 199 /* clear intr & disable timer, reset initial count, re-enable timer */ 200 WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 201 /* XXX more to do */ 202 203 cf.pc = pc; 204 cf.sr = status; 205 206 statclock(&cf); 207 } 208 209 static void 210 sbtimer_miscintr(void *arg, uint32_t status, vaddr_t pc) 211 { 212 struct sbtimer_softc *sc = arg; 213 214 /* disable timer */ 215 WRITE_REG(sc->sc_addr_cfg, 0x00); /* XXX */ 216 217 /* XXX more to do */ 218 } 219