1/* 2 * Copyright 2019, 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 <stdio.h> 14#include <assert.h> 15#include <errno.h> 16#include <stdlib.h> 17#include <stdint.h> 18 19#include <utils/util.h> 20 21#include <platsupport/timer.h> 22#include <platsupport/plat/timer.h> 23 24/* The GPT status register is w1c (write 1 to clear), and there are 6 status bits in the iMX 25 status register, so writing the value 0b111111 = 0x3F will clear it. */ 26#define GPT_STATUS_REGISTER_CLEAR 0x3F 27 28#define CLEANUP_FAIL_TEXT "Failed to cleanup the GPT after failing to initialise it" 29 30/* GPT CONTROL REGISTER BITS */ 31typedef enum { 32 /* 33 * This bit enables the GPT. 34 */ 35 EN = 0, 36 37 /* 38 * When GPT is disabled (EN=0), then 39 * both Main Counter and Prescaler Counter freeze their count at 40 * current count values. The ENMOD bit determines the value of 41 * the GPT counter when Counter is enabled again (if the EN bit is set). 42 * 43 * If the ENMOD bit is 1, then the Main Counter and Prescaler Counter 44 * values are reset to 0 after GPT is enabled (EN=1). 45 * 46 * If the ENMOD bit is 0, then the Main Counter and Prescaler Counter 47 * restart counting from their frozen values after GPT is enabled (EN=1). 48 * 49 * If GPT is programmed to be disabled in a low power mode (STOP/WAIT), then 50 * the Main Counter and Prescaler Counter freeze at their current count 51 * values when the GPT enters low power mode. 52 * 53 * When GPT exits low power mode, the Main Counter and Prescaler Counter start 54 * counting from their frozen values, regardless of the ENMOD bit value. 55 * 56 * Setting the SWR bit will clear the Main Counter and Prescalar Counter values, 57 * regardless of the value of EN or ENMOD bits. 58 * 59 * A hardware reset resets the ENMOD bit. 60 * A software reset does not affect the ENMOD bit. 61 */ 62 ENMOD = 1, 63 64 /* 65 * This read/write control bit enables the operation of the GPT 66 * during debug mode 67 */ 68 DBGEN = 2, 69 70 /* 71 * This read/write control bit enables the operation of the GPT 72 * during wait mode 73 */ 74 WAITEN = 3, 75 76 /* 77 * This read/write control bit enables the operation of the GPT 78 * during doze mode 79 */ 80 DOZEN = 4, 81 82 /* 83 * This read/write control bit enables the operation of the GPT 84 * during stop mode 85 */ 86 STOPEN = 5, 87 88 /* 89 * bits 6-8 - These bits selects the clock source for the 90 * prescaler and subsequently be used to run the GPT counter. 91 * the following sources are available on i.MX 7 board: 92 * 000: no clock 93 * 001: peripheral clock 94 * 010: high frequency reference clock 95 * 011: external clock (CLKIN) 96 * 100: low frequency reference clock 32 kHZ 97 * 101: crystal oscillator as reference clock 24 MHz 98 * others: reserved 99 * by default the peripheral clock is used. 100 * 101 * For imx6 : 102 * 000: no clock 103 * 001: peripheral clock 104 * 010: high frequency reference clock 105 * 011: external clock (CLKIN) 106 * 100: low frequency reference clock 107 * 101: crystal oscillator divided by 8 as reference clock 108 * 111: crystal osscillator as reference clock 109 */ 110 CLKSRC = 6, 111 112 /* 113 * Freerun or Restart mode. 114 * 115 * 0 Restart mode 116 * 1 Freerun mode 117 */ 118 FRR = 9, 119 120 /* for i.MX7 only 121 * enable the 24 MHz clock input from crystal 122 * a hardware reset resets the EN_24M bit. 123 * a software reset dose not affect the EN_24M bit. 124 * 0: disabled 125 * 1: enabled 126 */ 127 EN_24M = 10, 128 129 /* 130 * Software reset. 131 * 132 * This bit is set when the module is in reset state and is cleared 133 * when the reset procedure is over. Writing a 1 to this bit 134 * produces a single wait state write cycle. Setting this bit 135 * resets all the registers to their default reset values except 136 * for the EN, ENMOD, STOPEN, DOZEN, WAITEN and DBGEN bits in this 137 * control register. 138 */ 139 SWR = 15, 140 141 /* Input capture channel operating modes */ 142 IM1 = 16, IM2 = 18, 143 144 /* Output compare channel operating modes */ 145 OM1 = 20, OM2 = 23, OM3 = 26, 146 147 /* Force output compare channel bits */ 148 FO1 = 29, FO2 = 30, FO3 = 31 149 150} gpt_control_reg; 151 152/* bits in the interrupt/status regiser */ 153enum gpt_interrupt_register_bits { 154 155 /* Output compare interrupt enable bits */ 156 OF1IE = 0, OF2IE = 1, OF3IE = 2, 157 158 /* Input capture interrupt enable bits */ 159 IF1IE = 3, IF2IE = 4, 160 161 /* Rollover interrupt enabled */ 162 ROV = 5, 163}; 164 165/* Memory map for GPT. */ 166struct gpt_map { 167 /* gpt control register */ 168 uint32_t gptcr; 169 /* gpt prescaler register */ 170 uint32_t gptpr; 171 /* gpt status register */ 172 uint32_t gptsr; 173 /* gpt interrupt register */ 174 uint32_t gptir; 175 /* gpt output compare register 1 */ 176 uint32_t gptcr1; 177 /* gpt output compare register 2 */ 178 uint32_t gptcr2; 179 /* gpt output compare register 3 */ 180 uint32_t gptcr3; 181 /* gpt input capture register 1 */ 182 uint32_t gpticr1; 183 /* gpt input capture register 2 */ 184 uint32_t gpticr2; 185 /* gpt counter register */ 186 uint32_t gptcnt; 187}; 188 189int gpt_start(gpt_t *gpt) 190{ 191 gpt->gpt_map->gptcr |= BIT(EN); 192 gpt->high_bits = 0; 193 return 0; 194} 195 196int gpt_stop(gpt_t *gpt) 197{ 198 /* Disable timer. */ 199 gpt->gpt_map->gptcr &= ~(BIT(EN)); 200 gpt->high_bits = 0; 201 return 0; 202} 203 204static void gpt_handle_irq(void *data, ps_irq_acknowledge_fn_t acknowledge_fn, void *ack_data) 205{ 206 assert(data != NULL); 207 gpt_t *gpt = data; 208 /* we've only set the GPT to interrupt on overflow */ 209 if (gpt->gpt_map->gptcr & BIT(FRR)) { 210 /* free-run mode, we should only enable the rollover interrupt */ 211 if (gpt->gpt_map->gptsr & BIT(ROV)) { 212 gpt->high_bits++; 213 } 214 } 215 /* clear the interrupt status register */ 216 gpt->gpt_map->gptsr = GPT_STATUS_REGISTER_CLEAR; 217 /* acknowledge the interrupt and call the user callback if any */ 218 ZF_LOGF_IF(acknowledge_fn(ack_data), "Failed to acknowledge the interrupt from the GPT"); 219 if (gpt->user_callback) { 220 gpt->user_callback(gpt->user_callback_token, LTIMER_OVERFLOW_EVENT); 221 } 222} 223 224uint64_t gpt_get_time(gpt_t *gpt) 225{ 226 uint32_t low_bits = gpt->gpt_map->gptcnt; 227 uint32_t high_bits = gpt->high_bits; 228 if (gpt->gpt_map->gptsr) { 229 /* irq has come in */ 230 high_bits++; 231 } 232 233 uint64_t value = ((uint64_t) high_bits << 32llu) + low_bits; 234 /* convert to ns */ 235 uint64_t ns = (value / (uint64_t)GPT_FREQ) * NS_IN_US * (gpt->prescaler + 1); 236 return ns; 237} 238 239static int allocate_register_callback(pmem_region_t pmem, unsigned curr_num, size_t num_regs, void *token) 240{ 241 assert(token != NULL); 242 /* Should only be called once. I.e. only one register field */ 243 assert(curr_num == 0); 244 gpt_t *gpt = token; 245 gpt->gpt_map = (volatile struct gpt_map *) ps_pmem_map(&gpt->io_ops, pmem, false, PS_MEM_NORMAL); 246 if (!gpt->gpt_map) { 247 ZF_LOGE("Failed to map in registers for the GPT"); 248 return EIO; 249 } 250 gpt->timer_pmem = pmem; 251 return 0; 252} 253 254static int allocate_irq_callback(ps_irq_t irq, unsigned curr_num, size_t num_irqs, void *token) 255{ 256 assert(token != NULL); 257 /* Should only be called once. I.e. only one interrupt field */ 258 assert(curr_num == 0); 259 gpt_t *gpt = token; 260 gpt->irq_id = ps_irq_register(&gpt->io_ops.irq_ops, irq, gpt_handle_irq, gpt); 261 if (gpt->irq_id < 0) { 262 ZF_LOGE("Failed to register the GPT interrupt with the IRQ interface"); 263 return EIO; 264 } 265 return 0; 266} 267 268int gpt_init(gpt_t *gpt, gpt_config_t config) 269{ 270 /* Initialise the structure */ 271 gpt->io_ops = config.io_ops; 272 gpt->user_callback = config.user_callback; 273 gpt->user_callback_token = config.user_callback_token; 274 gpt->irq_id = PS_INVALID_IRQ_ID; 275 gpt->prescaler = config.prescaler; 276 277 /* Read the timer's path in the DTB */ 278 ps_fdt_cookie_t *cookie = NULL; 279 int error = ps_fdt_read_path(&gpt->io_ops.io_fdt, &gpt->io_ops.malloc_ops, config.device_path, &cookie); 280 if (error) { 281 ZF_LOGF_IF(ps_fdt_cleanup_cookie(&gpt->io_ops.malloc_ops, cookie), CLEANUP_FAIL_TEXT); 282 ZF_LOGF_IF(gpt_destroy(gpt), CLEANUP_FAIL_TEXT); 283 return ENODEV; 284 } 285 286 /* Walk the registers and allocate them */ 287 error = ps_fdt_walk_registers(&gpt->io_ops.io_fdt, cookie, allocate_register_callback, gpt); 288 if (error) { 289 ZF_LOGF_IF(ps_fdt_cleanup_cookie(&gpt->io_ops.malloc_ops, cookie), CLEANUP_FAIL_TEXT); 290 ZF_LOGF_IF(gpt_destroy(gpt), CLEANUP_FAIL_TEXT); 291 return ENODEV; 292 } 293 294 /* Walk the interrupts and allocate the first */ 295 error = ps_fdt_walk_irqs(&gpt->io_ops.io_fdt, cookie, allocate_irq_callback, gpt); 296 if (error) { 297 ZF_LOGF_IF(ps_fdt_cleanup_cookie(&gpt->io_ops.malloc_ops, cookie), CLEANUP_FAIL_TEXT); 298 ZF_LOGF_IF(gpt_destroy(gpt), CLEANUP_FAIL_TEXT); 299 return ENODEV; 300 } 301 302 ZF_LOGF_IF(ps_fdt_cleanup_cookie(&gpt->io_ops.malloc_ops, cookie), 303 "Failed to cleanup the FDT cookie after initialising the GPT"); 304 305 uint32_t gptcr = 0; 306 if (gpt == NULL) { 307 return EINVAL; 308 } 309 310 /* Disable GPT. */ 311 gpt->gpt_map->gptcr = 0; 312 gpt->gpt_map->gptsr = GPT_STATUS_REGISTER_CLEAR; 313 314 /* Configure GPT. */ 315 gpt->gpt_map->gptcr = 0 | BIT(SWR); /* Reset the GPT */ 316 /* SWR will be 0 when the reset is done */ 317 while (gpt->gpt_map->gptcr & BIT(SWR)); 318 /* GPT can do more but for this just set it as free running so we can tell the time */ 319 gptcr = BIT(FRR) | BIT(ENMOD); 320 321#ifdef CONFIG_PLAT_IMX7 322 /* eanble the 24MHz source and select the oscillator as CLKSRC */ 323 gptcr |= (BIT(EN_24M) | (5u << CLKSRC)); 324#else 325 gptcr |= BIT(CLKSRC); 326#endif 327 328 gpt->gpt_map->gptcr = gptcr; 329 gpt->gpt_map->gptir = BIT(ROV); /* Interrupt when the timer overflows */ 330 331 /* The prescaler register has two parts when the 24 MHz clocksource is used. 332 * The 24MHz crystal clock is devided by the (the top 15-12 bits + 1) before 333 * it is fed to the CLKSRC field. 334 * The clock selected by the CLKSRC is divided by the (the 11-0 bits + ) again. 335 * For unknown reason, when the prescaler for the 24MHz clock is set to zero, which 336 * is valid according to the manual, the GPTCNT register does not work. So we 337 * set the value at least to 1, using a 12MHz clocksource. 338 */ 339 340#ifdef CONFIG_PLAT_IMX7 341 gpt->gpt_map->gptpr = config.prescaler | (1u << 12); 342#else 343 gpt->gpt_map->gptpr = config.prescaler; /* Set the prescaler */ 344#endif 345 346 gpt->high_bits = 0; 347 348 return 0; 349} 350 351int gpt_destroy(gpt_t *gpt) 352{ 353 if (gpt->gpt_map) { 354 ZF_LOGF_IF(gpt_stop(gpt), "Failed to stop the GPT before de-allocating it"); 355 ps_io_unmap(&gpt->io_ops.io_mapper, (void *) gpt->gpt_map, (size_t) gpt->timer_pmem.length); 356 } 357 358 if (gpt->irq_id != PS_INVALID_IRQ_ID) { 359 ZF_LOGF_IF(ps_irq_unregister(&gpt->io_ops.irq_ops, gpt->irq_id), "Failed to unregister IRQ"); 360 } 361 362 return 0; 363} 364 365int gpt_set_timeout(gpt_t *gpt, uint64_t ns, bool periodic) 366{ 367 uint32_t gptcr = 0; 368 uint64_t counter_value = (uint64_t)(GPT_FREQ / (gpt->prescaler + 1)) * (ns / 1000ULL); 369 if (counter_value >= (1ULL << 32)) { 370 /* Counter too large to be stored in 32 bits. */ 371 ZF_LOGW("ns too high %llu, going to be capping it\n", ns); 372 counter_value = UINT32_MAX; 373 } 374 375 gpt->gpt_map->gptcr = 0; 376 gpt->gpt_map->gptsr = GPT_STATUS_REGISTER_CLEAR; 377 gpt->gpt_map->gptcr = BIT(SWR); 378 while (gpt->gpt_map->gptcr & BIT(SWR)); 379 gptcr = (periodic ? 0 : BIT(FRR)); 380 381#ifdef CONFIG_PLAT_IMX7 382 gptcr |= BIT(EN_24M) | (5u << CLKSRC); 383#else 384 gptcr |= BIT(CLKSRC); 385#endif 386 387 gpt->gpt_map->gptcr = gptcr; 388 gpt->gpt_map->gptcr1 = (uint32_t)counter_value; 389 while (gpt->gpt_map->gptcr1 != counter_value) { 390 gpt->gpt_map->gptcr1 = (uint32_t)counter_value; 391 } 392 393#ifdef CONFIG_PLAT_IMX7 394 gpt->gpt_map->gptpr = gpt->prescaler | BIT(12); 395#else 396 gpt->gpt_map->gptpr = gpt->prescaler; /* Set the prescaler */ 397#endif 398 399 gpt->gpt_map->gptir = 1; 400 gpt->gpt_map->gptcr |= BIT(EN); 401 402 return 0; 403} 404