timer.c revision 264219
1/*- 2 * Copyright (c) 2009 Yohanes Nugroho <yohanes@gmail.com>. 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 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 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#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: head/sys/arm/cavium/cns11xx/timer.c 257200 2013-10-27 01:34:10Z ian $"); 28 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/bus.h> 32#include <sys/kernel.h> 33#include <sys/module.h> 34#include <sys/malloc.h> 35#include <sys/rman.h> 36#include <sys/timetc.h> 37#include <sys/watchdog.h> 38#include <machine/bus.h> 39#include <machine/cpu.h> 40#include <machine/intr.h> 41 42#include "econa_reg.h" 43#include "econa_var.h" 44 45#define INITIAL_TIMECOUNTER (0xffffffff) 46 47static int timers_initialized = 0; 48 49#define HZ 100 50 51extern unsigned int CPU_clock; 52extern unsigned int AHB_clock; 53extern unsigned int APB_clock; 54 55static unsigned long timer_counter = 0; 56 57struct ec_timer_softc { 58 struct resource * timer_res[3]; 59 bus_space_tag_t timer_bst; 60 bus_space_handle_t timer_bsh; 61 struct mtx timer_mtx; 62}; 63 64static struct resource_spec ec_timer_spec[] = { 65 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 66 { SYS_RES_IRQ, 0, RF_ACTIVE }, 67 { SYS_RES_IRQ, 1, RF_ACTIVE }, 68 { -1, 0 } 69}; 70 71static unsigned ec_timer_get_timecount(struct timecounter *); 72 73static struct timecounter ec_timecounter = { 74 .tc_get_timecount = ec_timer_get_timecount, 75 .tc_name = "CPU Timer", 76 /* This is assigned on the fly in the init sequence */ 77 .tc_frequency = 0, 78 .tc_counter_mask = ~0u, 79 .tc_quality = 1000, 80}; 81 82static struct ec_timer_softc *timer_softc = NULL; 83 84static inline 85void write_4(unsigned int val, unsigned int addr) 86{ 87 bus_space_write_4(timer_softc->timer_bst, 88 timer_softc->timer_bsh, addr, val); 89 90} 91 92static inline 93unsigned int read_4(unsigned int addr) 94{ 95 96 return bus_space_read_4(timer_softc->timer_bst, 97 timer_softc->timer_bsh, addr); 98} 99 100#define uSECS_PER_TICK (1000000 / APB_clock) 101#define TICKS2USECS(x) ((x) * uSECS_PER_TICK) 102 103static unsigned 104read_timer_counter_noint(void) 105{ 106 107 arm_mask_irq(0); 108 unsigned int v = read_4(TIMER_TM1_COUNTER_REG); 109 arm_unmask_irq(0); 110 return v; 111} 112 113void 114DELAY(int usec) 115{ 116 uint32_t val, val_temp; 117 int nticks; 118 119 if (!timers_initialized) { 120 for (; usec > 0; usec--) 121 for (val = 100; val > 0; val--) 122 ; 123 return; 124 } 125 126 val = read_timer_counter_noint(); 127 nticks = (((APB_clock / 1000) * usec) / 1000) + 100; 128 129 while (nticks > 0) { 130 val_temp = read_timer_counter_noint(); 131 if (val > val_temp) 132 nticks -= (val - val_temp); 133 else 134 nticks -= (val + (timer_counter - val_temp)); 135 136 val = val_temp; 137 } 138 139} 140 141/* 142 * Setup timer 143 */ 144static inline void 145setup_timer(unsigned int counter_value) 146{ 147 unsigned int control_value; 148 unsigned int mask_value; 149 150 control_value = read_4(TIMER_TM_CR_REG); 151 152 mask_value = read_4(TIMER_TM_INTR_MASK_REG); 153 write_4(counter_value, TIMER_TM1_COUNTER_REG); 154 write_4(counter_value, TIMER_TM1_LOAD_REG); 155 write_4(0, TIMER_TM1_MATCH1_REG); 156 write_4(0,TIMER_TM1_MATCH2_REG); 157 158 control_value &= ~(TIMER1_CLOCK_SOURCE); 159 control_value |= TIMER1_UP_DOWN_COUNT; 160 161 write_4(0, TIMER_TM2_COUNTER_REG); 162 write_4(0, TIMER_TM2_LOAD_REG); 163 write_4(~0u, TIMER_TM2_MATCH1_REG); 164 write_4(~0u,TIMER_TM2_MATCH2_REG); 165 166 control_value &= ~(TIMER2_CLOCK_SOURCE); 167 control_value &= ~(TIMER2_UP_DOWN_COUNT); 168 169 mask_value &= ~(63); 170 171 write_4(control_value, TIMER_TM_CR_REG); 172 write_4(mask_value, TIMER_TM_INTR_MASK_REG); 173} 174 175/* 176 * Enable timer 177 */ 178static inline void 179timer_enable(void) 180{ 181 unsigned int control_value; 182 183 control_value = read_4(TIMER_TM_CR_REG); 184 185 control_value |= TIMER1_OVERFLOW_ENABLE; 186 control_value |= TIMER1_ENABLE; 187 control_value |= TIMER2_OVERFLOW_ENABLE; 188 control_value |= TIMER2_ENABLE; 189 190 write_4(control_value, TIMER_TM_CR_REG); 191} 192 193static inline unsigned int 194read_second_timer_counter(void) 195{ 196 197 return read_4(TIMER_TM2_COUNTER_REG); 198} 199 200/* 201 * Get timer interrupt status 202 */ 203static inline unsigned int 204read_timer_interrupt_status(void) 205{ 206 207 return read_4(TIMER_TM_INTR_STATUS_REG); 208} 209 210/* 211 * Clear timer interrupt status 212 */ 213static inline void 214clear_timer_interrupt_status(unsigned int irq) 215{ 216 unsigned int interrupt_status; 217 218 interrupt_status = read_4(TIMER_TM_INTR_STATUS_REG); 219 if (irq == 0) { 220 if (interrupt_status & (TIMER1_MATCH1_INTR)) 221 interrupt_status &= ~(TIMER1_MATCH1_INTR); 222 if (interrupt_status & (TIMER1_MATCH2_INTR)) 223 interrupt_status &= ~(TIMER1_MATCH2_INTR); 224 if (interrupt_status & (TIMER1_OVERFLOW_INTR)) 225 interrupt_status &= ~(TIMER1_OVERFLOW_INTR); 226 } 227 if (irq == 1) { 228 if (interrupt_status & (TIMER2_MATCH1_INTR)) 229 interrupt_status &= ~(TIMER2_MATCH1_INTR); 230 if (interrupt_status & (TIMER2_MATCH2_INTR)) 231 interrupt_status &= ~(TIMER2_MATCH2_INTR); 232 if (interrupt_status & (TIMER2_OVERFLOW_INTR)) 233 interrupt_status &= ~(TIMER2_OVERFLOW_INTR); 234 } 235 236 write_4(interrupt_status, TIMER_TM_INTR_STATUS_REG); 237} 238 239static unsigned 240ec_timer_get_timecount(struct timecounter *a) 241{ 242 unsigned int ticks1; 243 arm_mask_irq(1); 244 ticks1 = read_second_timer_counter(); 245 arm_unmask_irq(1); 246 return ticks1; 247} 248 249/* 250 * Setup timer 251 */ 252static inline void 253do_setup_timer(void) 254{ 255 256 timer_counter = APB_clock/HZ; 257 /* 258 * setup timer-related values 259 */ 260 setup_timer(timer_counter); 261} 262 263void 264cpu_initclocks(void) 265{ 266 267 ec_timecounter.tc_frequency = APB_clock; 268 tc_init(&ec_timecounter); 269 timer_enable(); 270 timers_initialized = 1; 271} 272 273void 274cpu_startprofclock(void) 275{ 276 277} 278 279void 280cpu_stopprofclock(void) 281{ 282 283} 284 285static int 286ec_timer_probe(device_t dev) 287{ 288 289 device_set_desc(dev, "Econa CPU Timer"); 290 return (0); 291} 292 293static int 294ec_reset(void *arg) 295{ 296 297 arm_mask_irq(1); 298 clear_timer_interrupt_status(1); 299 arm_unmask_irq(1); 300 return (FILTER_HANDLED); 301} 302 303static int 304ec_hardclock(void *arg) 305{ 306 struct trapframe *frame; 307 unsigned int val; 308 /*clear timer interrupt status*/ 309 310 arm_mask_irq(0); 311 312 val = read_4(TIMER_INTERRUPT_STATUS_REG); 313 val &= ~(TIMER1_OVERFLOW_INTERRUPT); 314 write_4(val, TIMER_INTERRUPT_STATUS_REG); 315 316 frame = (struct trapframe *)arg; 317 hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); 318 319 arm_unmask_irq(0); 320 321 return (FILTER_HANDLED); 322} 323 324static int 325ec_timer_attach(device_t dev) 326{ 327 struct ec_timer_softc *sc; 328 int error; 329 void *ihl; 330 331 332 if (timer_softc != NULL) 333 return (ENXIO); 334 335 sc = (struct ec_timer_softc *)device_get_softc(dev); 336 337 timer_softc = sc; 338 339 error = bus_alloc_resources(dev, ec_timer_spec, sc->timer_res); 340 if (error) { 341 device_printf(dev, "could not allocate resources\n"); 342 return (ENXIO); 343 } 344 345 sc->timer_bst = rman_get_bustag(sc->timer_res[0]); 346 sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]); 347 348 do_setup_timer(); 349 350 if (bus_setup_intr(dev, sc->timer_res[1], INTR_TYPE_CLK, 351 ec_hardclock, NULL, NULL, &ihl) != 0) { 352 bus_release_resources(dev, ec_timer_spec, sc->timer_res); 353 device_printf(dev, "could not setup hardclock interrupt\n"); 354 return (ENXIO); 355 } 356 357 if (bus_setup_intr(dev, sc->timer_res[2], INTR_TYPE_CLK, 358 ec_reset, NULL, NULL, &ihl) != 0) { 359 bus_release_resources(dev, ec_timer_spec, sc->timer_res); 360 device_printf(dev, "could not setup timer interrupt\n"); 361 return (ENXIO); 362 } 363 364 return (0); 365} 366 367static device_method_t ec_timer_methods[] = { 368 DEVMETHOD(device_probe, ec_timer_probe), 369 DEVMETHOD(device_attach, ec_timer_attach), 370 { 0, 0 } 371}; 372 373static driver_t ec_timer_driver = { 374 "timer", 375 ec_timer_methods, 376 sizeof(struct ec_timer_softc), 377}; 378 379static devclass_t ec_timer_devclass; 380 381DRIVER_MODULE(timer, econaarm, ec_timer_driver, ec_timer_devclass, 0, 0); 382