1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <stdbool.h> 14#include <stdio.h> 15#include <assert.h> 16#include <errno.h> 17#include <stdlib.h> 18 19#include <utils/util.h> 20 21#include <platsupport/timer.h> 22#include <platsupport/mach/gpt.h> 23#include <platsupport/io.h> 24#include <platsupport/ltimer.h> 25#include <platsupport/fdt.h> 26 27typedef enum { 28 29 /* Start or stop the timer */ 30 ST = 0, 31 32 /* Autoreload mode */ 33 AR = 1, 34 35 /* Prescale value 36 * Timer is prescaled 2^(PTV+1). 37 * EG: PTV = 3. Timer increases every 16 clock periods. 38 */ 39 PTV = 2, 40 41 /* Enable prescaler */ 42 PRE = 5, 43 44 /* Compare enabled */ 45 CE = 6, 46 47 /* Pulse-width-modulation output pin default setting when 48 * counter is stopped or trigger output mode is set to no trigger 49 * 0x0: Default value of PWM_out output: 0 50 * 0x1: Default value of PWM_out output: 1 51 */ 52 SCPWM = 7, 53 54 /* Transition capture mode 55 * 0x0: No capture 56 * 0x1: Capture on rising edges of EVENT_CAPTURE pin. 57 * 0x2: Capture on falling edges of EVENT_CAPTURE pin. 58 * 0x3: Capture on both edges of EVENT_CAPTURE pin. 59 */ 60 TCM = 8, 61 62 /* Trigger output mode 63 * 0x0: No trigger 64 * 0x1: Overflow trigger 65 * 0x2: Overflow and match trigger 66 * 0x3: Reserved 67 */ 68 TRG = 10, 69 70 /* Pulse or toggle select bit. Pulse 0. Toggle 1. */ 71 PT = 12, 72 73 /* Capture mode select bit (first/second) 74 * 0x0: Capture the first enabled capture event in TCAR1. 75 * 0x1: Capture the second enabled capture event in TCAR2. 76 */ 77 CAPT_MODE = 13, 78 79 /* PWM output/event detection input pin direction control: 80 * 0x0: Configures the pin as an output (needed when PWM mode is required) 81 * 0x1: Configures the pin as an input (needed when capture mode is required) 82 */ 83 GPO_CFG = 14 84} gpt_control_reg; 85 86typedef enum { 87 88 /* Enable match interrupt */ 89 MAT_IT_ENA = 0, 90 91 /* Enable overflow interrupt */ 92 OVF_IT_ENA = 1, 93 94 /* Enable capture interrupt */ 95 TCAR_IT_ENA = 2 96 97} gpt_int_en_reg; 98 99typedef enum { 100 /* General guide for all three flags: 101 * Read 1: Interrupt pending 102 * Read 0: No Interrupt pending 103 * Write 1: Clear flag 104 * Write 0: No change 105 */ 106 107 /* match interrupt */ 108 MAT_IT_FLAG = 0, 109 110 /* overflow interrupt */ 111 OVF_IT_FLAG = 1, 112 113 /* capture interrupt */ 114 TCAR_IT_FLAG = 2 115 116} gpt_int_stat_reg; 117 118typedef enum { 119 120 /* PWM output/event detection input pin direction control: 121 * 0x0: Configures the pin as an output (needed when PWMmode is required) 122 * 0x1: Configures the pin as an input (needed when capture mode is required) 123 */ 124 AUTOIDLE = 0, 125 126 /* Software reset. This bit is automatically reset by the hardware. 127 * During reads, it always returns 0. 128 * 0x0: Normal mode 129 * 0x1: The module is reset. 130 */ 131 SOFTRESET = 1, 132 133 /* Software reset. This bit is automatically reset by the RW 0 134 * hardware. During reads, it always returns 0. 135 * 0x0: Normal mode 136 * 0x1: The module is reset. 137 */ 138 ENAWAKEUP = 3 139 140} gpt_cfg_reg; 141 142/* Memory map for GPT */ 143struct gpt_map { 144 uint32_t tidr; // GPTIMER_TIDR 0x00 145 uint32_t padding1[3]; 146 uint32_t cfg; // GPTIMER_CFG 0x10 147 uint32_t tistat; // GPTIMER_TISTAT 0x14 148 uint32_t tisr; // GPTIMER_TISR 0x18 149 uint32_t tier; // GPTIMER_TIER 0x1C 150 uint32_t twer; // GPTIMER_TWER 0x20 151 uint32_t tclr; // GPTIMER_TCLR 0x24 152 uint32_t tcrr; // GPTIMER_TCRR 0x28 153 uint32_t tldr; // GPTIMER_TLDR 0x2C 154 uint32_t ttgr; // GPTIMER_TTGR 0x30 155 uint32_t twps; // GPTIMER_TWPS 0x34 156 uint32_t tmar; // GPTIMER_TMAR 0x38 157 uint32_t tcar1; // GPTIMER_TCAR1 0x3C 158 uint32_t tsicr; // GPTIMER_TSICR 0x40 159 uint32_t tcar2; // GPTIMER_TCAR2 0x44 160 uint32_t tpir; // GPTIMER_TPIR 0x48 161 uint32_t tnir; // GPTIMER_TNIR 0x4C 162 uint32_t tcvr; // GPTIMER_TCVR 0x50 163 uint32_t tocr; // GPTIMER_TOCR 0x54 164 uint32_t towr; // GPTIMER_TOWR 0x58 165}; 166 167void gpt_start(gpt_t *gpt) 168{ 169 assert(gpt != NULL && gpt->gpt_map != NULL); 170 gpt->gpt_map->tclr |= BIT(ST); 171} 172 173void gpt_stop(gpt_t *gpt) 174{ 175 assert(gpt != NULL && gpt->gpt_map != NULL); 176 /* Disable timer. */ 177 gpt->gpt_map->tclr &= ~BIT(ST); 178} 179 180static void gpt_handle_irq(void *data, ps_irq_acknowledge_fn_t acknowledge_fn, void *ack_data) 181{ 182 gpt_t *gpt = data; 183 uint32_t tisr = gpt->gpt_map->tisr; 184 185 /* track timekeeping overflow */ 186 if (tisr & BIT(OVF_IT_FLAG)) { 187 gpt->high_bits++; 188 } 189 190 /* ack any possible irqs */ 191 gpt->gpt_map->tisr = (BIT(OVF_IT_FLAG) | BIT(MAT_IT_FLAG) | BIT(TCAR_IT_FLAG)); 192 193 if (acknowledge_fn(ack_data)) { 194 ZF_LOGE("Failed to acknowledge ps_irq"); 195 } 196 197 if (gpt->user_callback) { 198 if (tisr & BIT(OVF_IT_FLAG)) { 199 gpt->user_callback(gpt->user_callback_token, LTIMER_OVERFLOW_EVENT); 200 } else if (tisr & BIT(MAT_IT_FLAG)) { 201 gpt->user_callback(gpt->user_callback_token, LTIMER_TIMEOUT_EVENT); 202 } else { 203 ZF_LOGE("Unknown interrupt neither overflow or match"); 204 } 205 } 206} 207 208static bool gpt_ok_prescaler(uint32_t prescaler) 209{ 210 if (prescaler > 7) { 211 ZF_LOGE("Prescaler value set too large for device, value: %d, max 7", prescaler); 212 return false; 213 } 214 215 return true; 216} 217 218static uint64_t gpt_ticks_to_ns(uint64_t ticks) 219{ 220 return (ticks / CLK_MHZ) * NS_IN_US; 221} 222 223static uint64_t gpt_ns_to_ticks(uint64_t ns) 224{ 225 return ns / NS_IN_US * CLK_MHZ; 226} 227 228uint64_t gpt_get_max(void) 229{ 230 return gpt_ticks_to_ns(UINT32_MAX - 1); 231} 232 233static void gpt_init(gpt_t *gpt) 234{ 235 /* Disable GPT. */ 236 gpt->gpt_map->tclr = 0; 237 238 /* Perform a soft reset */ 239 gpt->gpt_map->cfg = BIT(SOFTRESET); 240 241 while (!gpt->gpt_map->tistat); /* Wait for timer to reset */ 242 243 /* set prescaler */ 244 if (gpt->prescaler > 0) { 245 gpt->gpt_map->tclr = (gpt->prescaler << PTV); /* Set the prescaler */ 246 gpt->gpt_map->tclr |= BIT(PRE); /* Enable the prescaler */ 247 } 248} 249 250/* Relative timeout driver for the gpt. 251 * 252 * This driver sets up the gpt for relative timeouts (oneshot or periodic) only. 253 * 254 * It works by setting the timer to interrupt on overflow and reloading the timer 255 * with (0xFFFFFFFF - relative timeout). 256 */ 257 258int rel_gpt_set_timeout(gpt_t *gpt, uint64_t ns, bool periodic) 259{ 260 uint32_t reload = periodic ? BIT(AR) : 0; 261 uint64_t ticks = gpt_ns_to_ticks(ns) / BIT(gpt->prescaler + 1); 262 263 if (ticks >= UINT32_MAX) { 264 /* too big for this timer implementation */ 265 ZF_LOGE("Timeout too big for timer, max %u, got %llu\n", UINT32_MAX - 1, ticks); 266 return ETIME; 267 } 268 269 /* invert ticks - it's an upcounter and will interrupt on overflow */ 270 ticks = UINT32_MAX - ticks; 271 272 gpt_init(gpt); 273 274 /* Clear pending overflows. */ 275 gpt->gpt_map->tisr |= BIT(OVF_IT_FLAG); 276 277 /* Set the reload value. */ 278 gpt->gpt_map->tldr = (uint32_t) ticks; 279 280 /* Reset the read register. */ 281 gpt->gpt_map->tcrr = (uint32_t) ticks; 282 283 /* Enable interrupt on overflow. */ 284 gpt->gpt_map->tier |= BIT(OVF_IT_ENA); 285 286 assert(!(gpt->gpt_map->tisr & BIT(OVF_IT_FLAG))); 287 /* Set autoreload and start the timer. */ 288 gpt->gpt_map->tclr |= (reload | BIT(ST)); 289 290 /* success */ 291 return 0; 292} 293 294int rel_gpt_init(gpt_t *gpt, gpt_config_t config) 295{ 296 if (!gpt_ok_prescaler(config.prescaler)) { 297 return EINVAL; 298 } 299 300 gpt->prescaler = config.prescaler; 301 302 gpt_init(gpt); 303 304 return 0; 305} 306 307uint64_t abs_gpt_get_time(gpt_t *gpt) 308{ 309 bool overflow; 310 uint64_t ticks; 311 312 overflow = !!(gpt->gpt_map->tisr & OVF_IT_FLAG); 313 /* high bits */ 314 ticks = ((uint64_t)(gpt->high_bits + overflow)) << 32llu; 315 /* low bits */ 316 ticks += gpt->gpt_map->tcrr; 317 ticks = ticks * BIT(gpt->prescaler + 1); 318 319 return gpt_ticks_to_ns(ticks); 320} 321 322int abs_gpt_init(gpt_t *gpt, gpt_config_t config) 323{ 324 if (!gpt_ok_prescaler(config.prescaler)) { 325 return EINVAL; 326 } 327 328 gpt->prescaler = config.prescaler; 329 330 /* enable interrupt on overflow. */ 331 gpt->gpt_map->tier |= BIT(OVF_IT_ENA); 332 333 /* set the reload value. */ 334 gpt->gpt_map->tldr = 0u; 335 336 /* reset the read register. */ 337 gpt->gpt_map->tcrr = 0u; 338 339 /* clear pending irqs. */ 340 gpt->gpt_map->tisr |= BIT(OVF_IT_FLAG | MAT_IT_FLAG | TCAR_IT_FLAG); 341 342 gpt->gpt_map->tclr |= (BIT(CE) | BIT(AR)); 343 344 gpt_init(gpt); 345 346 return 0; 347} 348 349static int allocate_register_callback(pmem_region_t pmem, unsigned curr_num, size_t num_regs, void *token) 350{ 351 gpt_t *gpt = token; 352 assert(num_regs == 1 && curr_num == 0); 353 void *vaddr = ps_pmem_map(&gpt->ops, pmem, false, PS_MEM_NORMAL); 354 if (vaddr == NULL) { 355 return EIO; 356 } 357 gpt->gpt_map = vaddr; 358 gpt->timer_pmem = pmem; 359 return 0; 360} 361 362static int allocate_irq_callback(ps_irq_t irq, unsigned curr_num, size_t num_irqs, void *token) 363{ 364 gpt_t *gpt = token; 365 /* Device should only have one interrupt */ 366 if (num_irqs != 1) { 367 return ENODEV; 368 } 369 assert(curr_num == 0); 370 irq_id_t irq_id = ps_irq_register(&gpt->ops.irq_ops, irq, gpt_handle_irq, gpt); 371 if (irq_id < 0) { 372 return EIO; 373 } 374 gpt->irq_id = irq_id; 375 return 0; 376} 377 378void gpt_destroy(gpt_t *gpt) 379{ 380 int error; 381 382 /* pre-set INVALID_IRQ_ID before init and do not run if not initialised */ 383 if (gpt->irq_id != PS_INVALID_IRQ_ID) { 384 error = ps_irq_unregister(&gpt->ops.irq_ops, gpt->irq_id); 385 ZF_LOGE_IF(error, "Unable to un-register timer gpt irq") 386 } 387 388 /* check if pwm_map is NULL and do not run if not initialised */ 389 if (gpt->gpt_map != NULL) { 390 gpt_stop(gpt); 391 ps_pmem_unmap(&gpt->ops, gpt->timer_pmem, (void *) gpt->gpt_map); 392 } 393} 394 395int gpt_create(gpt_t *gpt, ps_io_ops_t ops, char *fdt_path, ltimer_callback_fn_t user_cb_fn, void *user_cb_token) 396{ 397 int error; 398 399 if (gpt == NULL || fdt_path == NULL) { 400 return EINVAL; 401 } 402 403 /* Set up gpt */ 404 gpt->ops = ops; 405 gpt->user_callback = user_cb_fn; 406 gpt->user_callback_token = user_cb_token; 407 408 /* Set up variables that will be set by callback */ 409 gpt->gpt_map = NULL; 410 gpt->irq_id = PS_INVALID_IRQ_ID; 411 412 /* Gather FDT info */ 413 ps_fdt_cookie_t *cookie = NULL; 414 error = ps_fdt_read_path(&ops.io_fdt, &ops.malloc_ops, fdt_path, &cookie); 415 if (error) { 416 gpt_destroy(gpt); 417 return error; 418 } 419 420 /* walk the registers and allocate them */ 421 error = ps_fdt_walk_registers(&ops.io_fdt, cookie, allocate_register_callback, gpt); 422 if (error) { 423 gpt_destroy(gpt); 424 return error; 425 } 426 427 /* walk the interrupts and allocate the first */ 428 error = ps_fdt_walk_irqs(&ops.io_fdt, cookie, allocate_irq_callback, gpt); 429 if (error) { 430 gpt_destroy(gpt); 431 return error; 432 } 433 434 error = ps_fdt_cleanup_cookie(&ops.malloc_ops, cookie); 435 if (error) { 436 gpt_destroy(gpt); 437 return error; 438 } 439 440 return 0; 441} 442