1 /*- 2 * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/bus.h> 33 #include <sys/kernel.h> 34 #include <sys/module.h> 35 #include <sys/malloc.h> 36 #include <sys/rman.h> 37 #include <sys/timeet.h> 38 #include <sys/timetc.h> 39 #include <sys/watchdog.h> 40 #include <machine/bus.h> 41 #include <machine/cpu.h> 42 #include <machine/frame.h> 43 #include <machine/intr.h> 44 45 #include <dev/fdt/fdt_common.h> 46 #include <dev/ofw/openfirm.h> 47 #include <dev/ofw/ofw_bus.h> 48 #include <dev/ofw/ofw_bus_subr.h> 49 50 #include <machine/bus.h> 51 #include <machine/fdt.h> 52 53 #include <arm/ti/ti_prcm.h> 54 55 #define AM335X_NUM_TIMERS 8 56 57 #define DMTIMER_TIDR 0x00 /* Identification Register */ 58 #define DMTIMER_TIOCP_CFG 0x10 /* Timer OCP Configuration Reg */ 59 #define DMTIMER_IQR_EOI 0x20 /* Timer IRQ End-Of-Interrupt Reg */ 60 #define DMTIMER_IRQSTATUS_RAW 0x24 /* Timer IRQSTATUS Raw Reg */ 61 #define DMTIMER_IRQSTATUS 0x28 /* Timer IRQSTATUS Reg */ 62 #define DMTIMER_IRQENABLE_SET 0x2c /* Timer IRQSTATUS Set Reg */ 63 #define DMTIMER_IRQENABLE_CLR 0x30 /* Timer IRQSTATUS Clear Reg */ 64 #define DMTIMER_IRQWAKEEN 0x34 /* Timer IRQ Wakeup Enable Reg */ 65 #define DMTIMER_TCLR 0x38 /* Timer Control Register */ 66 #define DMTIMER_TCRR 0x3C /* Timer Counter Register */ 67 #define DMTIMER_TLDR 0x40 /* Timer Load Reg */ 68 #define DMTIMER_TTGR 0x44 /* Timer Trigger Reg */ 69 #define DMTIMER_TWPS 0x48 /* Timer Write Posted Status Reg */ 70 #define DMTIMER_TMAR 0x4C /* Timer Match Reg */ 71 #define DMTIMER_TCAR1 0x50 /* Timer Capture Reg */ 72 #define DMTIMER_TSICR 0x54 /* Timer Synchr. Interface Control Reg */ 73 #define DMTIMER_TCAR2 0x48 /* Timer Capture Reg */ 74 75 76 struct am335x_dmtimer_softc { 77 struct resource * tmr_mem_res[AM335X_NUM_TIMERS]; 78 struct resource * tmr_irq_res[AM335X_NUM_TIMERS]; 79 uint32_t sysclk_freq; 80 struct am335x_dmtimer { 81 bus_space_tag_t bst; 82 bus_space_handle_t bsh; 83 struct eventtimer et; 84 } t[AM335X_NUM_TIMERS]; 85 }; 86 87 static struct resource_spec am335x_dmtimer_mem_spec[] = { 88 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 89 { SYS_RES_MEMORY, 1, RF_ACTIVE }, 90 { SYS_RES_MEMORY, 2, RF_ACTIVE }, 91 { SYS_RES_MEMORY, 3, RF_ACTIVE }, 92 { SYS_RES_MEMORY, 4, RF_ACTIVE }, 93 { SYS_RES_MEMORY, 5, RF_ACTIVE }, 94 { SYS_RES_MEMORY, 6, RF_ACTIVE }, 95 { SYS_RES_MEMORY, 7, RF_ACTIVE }, 96 { -1, 0, 0 } 97 }; 98 static struct resource_spec am335x_dmtimer_irq_spec[] = { 99 { SYS_RES_IRQ, 0, RF_ACTIVE }, 100 { SYS_RES_IRQ, 1, RF_ACTIVE }, 101 { SYS_RES_IRQ, 2, RF_ACTIVE }, 102 { SYS_RES_IRQ, 3, RF_ACTIVE }, 103 { SYS_RES_IRQ, 4, RF_ACTIVE }, 104 { SYS_RES_IRQ, 5, RF_ACTIVE }, 105 { SYS_RES_IRQ, 6, RF_ACTIVE }, 106 { SYS_RES_IRQ, 7, RF_ACTIVE }, 107 { -1, 0, 0 } 108 }; 109 110 static struct am335x_dmtimer *am335x_dmtimer_tc_tmr = NULL; 111 112 /* Read/Write macros for Timer used as timecounter */ 113 #define am335x_dmtimer_tc_read_4(reg) \ 114 bus_space_read_4(am335x_dmtimer_tc_tmr->bst, \ 115 am335x_dmtimer_tc_tmr->bsh, reg) 116 117 #define am335x_dmtimer_tc_write_4(reg, val) \ 118 bus_space_write_4(am335x_dmtimer_tc_tmr->bst, \ 119 am335x_dmtimer_tc_tmr->bsh, reg, val) 120 121 /* Read/Write macros for Timer used as eventtimer */ 122 #define am335x_dmtimer_et_read_4(reg) \ 123 bus_space_read_4(tmr->bst, tmr->bsh, reg) 124 125 #define am335x_dmtimer_et_write_4(reg, val) \ 126 bus_space_write_4(tmr->bst, tmr->bsh, reg, val) 127 128 static unsigned am335x_dmtimer_tc_get_timecount(struct timecounter *); 129 130 static struct timecounter am335x_dmtimer_tc = { 131 .tc_name = "AM335x Timecounter", 132 .tc_get_timecount = am335x_dmtimer_tc_get_timecount, 133 .tc_poll_pps = NULL, 134 .tc_counter_mask = ~0u, 135 .tc_frequency = 0, 136 .tc_quality = 1000, 137 }; 138 139 static unsigned 140 am335x_dmtimer_tc_get_timecount(struct timecounter *tc) 141 { 142 return am335x_dmtimer_tc_read_4(DMTIMER_TCRR); 143 } 144 145 static int 146 am335x_dmtimer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 147 { 148 struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)et->et_priv; 149 uint32_t load, count; 150 uint32_t tclr = 0; 151 152 if (period != 0) { 153 load = ((uint32_t)et->et_frequency * period) >> 32; 154 tclr |= 2; /* autoreload bit */ 155 panic("periodic timer not implemented\n"); 156 } else { 157 load = 0; 158 } 159 160 if (first != 0) 161 count = ((uint32_t)et->et_frequency * first) >> 32; 162 else 163 count = load; 164 165 /* Reset Timer */ 166 am335x_dmtimer_et_write_4(DMTIMER_TSICR, 2); 167 168 /* Wait for reset to complete */ 169 while (am335x_dmtimer_et_read_4(DMTIMER_TIOCP_CFG) & 1); 170 171 /* set load value */ 172 am335x_dmtimer_et_write_4(DMTIMER_TLDR, 0xFFFFFFFE - load); 173 174 /* set counter value */ 175 am335x_dmtimer_et_write_4(DMTIMER_TCRR, 0xFFFFFFFE - count); 176 177 /* enable overflow interrupt */ 178 am335x_dmtimer_et_write_4(DMTIMER_IRQENABLE_SET, 2); 179 180 /* start timer(ST) */ 181 tclr |= 1; 182 am335x_dmtimer_et_write_4(DMTIMER_TCLR, tclr); 183 184 return (0); 185 } 186 187 static int 188 am335x_dmtimer_stop(struct eventtimer *et) 189 { 190 struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)et->et_priv; 191 192 /* Disable all interrupts */ 193 am335x_dmtimer_et_write_4(DMTIMER_IRQENABLE_CLR, 7); 194 195 /* Stop Timer */ 196 am335x_dmtimer_et_write_4(DMTIMER_TCLR, 0); 197 198 return (0); 199 } 200 201 static int 202 am335x_dmtimer_intr(void *arg) 203 { 204 struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)arg; 205 206 /* Ack interrupt */ 207 am335x_dmtimer_et_write_4(DMTIMER_IRQSTATUS, 7); 208 if (tmr->et.et_active) 209 tmr->et.et_event_cb(&tmr->et, tmr->et.et_arg); 210 211 return (FILTER_HANDLED); 212 } 213 214 static int 215 am335x_dmtimer_probe(device_t dev) 216 { 217 struct am335x_dmtimer_softc *sc; 218 sc = (struct am335x_dmtimer_softc *)device_get_softc(dev); 219 220 if (ofw_bus_is_compatible(dev, "ti,am335x-dmtimer")) { 221 device_set_desc(dev, "AM335x DMTimer"); 222 return(BUS_PROBE_DEFAULT); 223 } 224 225 return (ENXIO); 226 } 227 228 static int 229 am335x_dmtimer_attach(device_t dev) 230 { 231 struct am335x_dmtimer_softc *sc = device_get_softc(dev); 232 void *ihl; 233 int err; 234 int i; 235 236 if (am335x_dmtimer_tc_tmr != NULL) 237 return (EINVAL); 238 239 /* Get the base clock frequency */ 240 err = ti_prcm_clk_get_source_freq(SYS_CLK, &sc->sysclk_freq); 241 if (err) { 242 device_printf(dev, "Error: could not get sysclk frequency\n"); 243 return (ENXIO); 244 } 245 246 /* Request the memory resources */ 247 err = bus_alloc_resources(dev, am335x_dmtimer_mem_spec, 248 sc->tmr_mem_res); 249 if (err) { 250 device_printf(dev, "Error: could not allocate mem resources\n"); 251 return (ENXIO); 252 } 253 254 /* Request the IRQ resources */ 255 err = bus_alloc_resources(dev, am335x_dmtimer_irq_spec, 256 sc->tmr_irq_res); 257 if (err) { 258 device_printf(dev, "Error: could not allocate irq resources\n"); 259 return (ENXIO); 260 } 261 262 for(i=0;i<AM335X_NUM_TIMERS;i++) { 263 sc->t[i].bst = rman_get_bustag(sc->tmr_mem_res[i]); 264 sc->t[i].bsh = rman_get_bushandle(sc->tmr_mem_res[i]); 265 } 266 267 /* Configure DMTimer2 and DMTimer3 source and enable them */ 268 err = ti_prcm_clk_set_source(DMTIMER2_CLK, SYSCLK_CLK); 269 err |= ti_prcm_clk_enable(DMTIMER2_CLK); 270 err |= ti_prcm_clk_set_source(DMTIMER3_CLK, SYSCLK_CLK); 271 err |= ti_prcm_clk_enable(DMTIMER3_CLK); 272 if (err) { 273 device_printf(dev, "Error: could not setup timer clock\n"); 274 return (ENXIO); 275 } 276 277 /* Take DMTimer2 for TC */ 278 am335x_dmtimer_tc_tmr = &sc->t[2]; 279 280 /* Reset Timer */ 281 am335x_dmtimer_tc_write_4(DMTIMER_TSICR, 2); 282 283 /* Wait for reset to complete */ 284 while (am335x_dmtimer_tc_read_4(DMTIMER_TIOCP_CFG) & 1); 285 286 /* set load value */ 287 am335x_dmtimer_tc_write_4(DMTIMER_TLDR, 0); 288 289 /* set counter value */ 290 am335x_dmtimer_tc_write_4(DMTIMER_TCRR, 0); 291 292 /* Set Timer autoreload(AR) and start timer(ST) */ 293 am335x_dmtimer_tc_write_4(DMTIMER_TCLR, 3); 294 295 am335x_dmtimer_tc.tc_frequency = sc->sysclk_freq; 296 tc_init(&am335x_dmtimer_tc); 297 298 /* Register DMTimer3 as ET */ 299 300 /* Setup and enable the timer */ 301 if (bus_setup_intr(dev, sc->tmr_irq_res[3], INTR_TYPE_CLK, 302 am335x_dmtimer_intr, NULL, &sc->t[3], &ihl) != 0) { 303 bus_release_resources(dev, am335x_dmtimer_irq_spec, 304 sc->tmr_irq_res); 305 device_printf(dev, "Unable to setup the clock irq handler.\n"); 306 return (ENXIO); 307 } 308 309 sc->t[3].et.et_name = "AM335x Eventtimer0"; 310 sc->t[3].et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT; 311 sc->t[3].et.et_quality = 1000; 312 sc->t[3].et.et_frequency = sc->sysclk_freq; 313 sc->t[3].et.et_min_period = 314 (0x00000002LLU << 32) / sc->t[3].et.et_frequency; 315 sc->t[3].et.et_max_period = 316 (0xfffffffeLLU << 32) / sc->t[3].et.et_frequency; 317 sc->t[3].et.et_start = am335x_dmtimer_start; 318 sc->t[3].et.et_stop = am335x_dmtimer_stop; 319 sc->t[3].et.et_priv = &sc->t[3]; 320 et_register(&sc->t[3].et); 321 322 return (0); 323 } 324 325 static device_method_t am335x_dmtimer_methods[] = { 326 DEVMETHOD(device_probe, am335x_dmtimer_probe), 327 DEVMETHOD(device_attach, am335x_dmtimer_attach), 328 { 0, 0 } 329 }; 330 331 static driver_t am335x_dmtimer_driver = { 332 "am335x_dmtimer", 333 am335x_dmtimer_methods, 334 sizeof(struct am335x_dmtimer_softc), 335 }; 336 337 static devclass_t am335x_dmtimer_devclass; 338 339 DRIVER_MODULE(am335x_dmtimer, simplebus, am335x_dmtimer_driver, am335x_dmtimer_devclass, 0, 0); 340 MODULE_DEPEND(am335x_dmtimer, am335x_prcm, 1, 1, 1); 341 342 void 343 cpu_initclocks(void) 344 { 345 cpu_initclocks_bsp(); 346 } 347 348 void 349 DELAY(int usec) 350 { 351 int32_t counts; 352 uint32_t first, last; 353 354 if (am335x_dmtimer_tc_tmr == NULL) { 355 for (; usec > 0; usec--) 356 for (counts = 200; counts > 0; counts--) 357 /* Prevent gcc from optimizing out the loop */ 358 cpufunc_nullop(); 359 return; 360 } 361 362 /* Get the number of times to count */ 363 counts = usec * ((am335x_dmtimer_tc.tc_frequency / 1000000) + 1); 364 365 first = am335x_dmtimer_tc_read_4(DMTIMER_TCRR); 366 367 while (counts > 0) { 368 last = am335x_dmtimer_tc_read_4(DMTIMER_TCRR); 369 if (last>first) { 370 counts -= (int32_t)(last - first); 371 } else { 372 counts -= (int32_t)((0xFFFFFFFF - first) + last); 373 } 374 first = last; 375 } 376 } 377 378