1/* 2 * Copyright 2020, 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 <string.h> 18#include <utils/util.h> 19#include <inttypes.h> 20#include <utils/fence.h> 21#include <utils/arch/io.h> 22 23#include <platsupport/timer.h> 24#include <platsupport/plat/timer.h> 25 26#define CLEANUP_FAIL_TEXT "Failed to cleanup the TTC after failing to initialise it" 27 28#define CLKCTRL_EXT_NEDGE BIT(6) 29#define CLKCTRL_EXT_SRC_EN BIT(5) 30#define CLKCTRL_PRESCALE_VAL(N) (((N) & 0xf) << 1) /* rate = clk_src/[2^(N+1)] */ 31#define CLKCTRL_GET_PRESCALE_VAL(v) (((v) >> 1) & 0xf) 32#define CLKCTRL_PRESCALE_EN BIT(0) 33#define CLKCTRL_PRESCALE_MASK (CLKCTRL_PRESCALE_VAL(0xf) | CLKCTRL_PRESCALE_EN) 34 35/* Waveform polarity: When this bit is high, the 36 * waveform output goes from high to low on 37 * Match_1 interrupt and returns high on overflow 38 * or interval interrupt; when low, the waveform 39 * goes from low to high on Match_1 interrupt and 40 * returns low on overflow or interval interrupt */ 41#define CNTCTRL_WAVE_POL BIT(6) 42/* Output waveform enable, active low. */ 43#define CNTCTRL_WAVE_EN BIT(5) 44/* Setting this bit high resets the counter value and 45 * restarts counting; the RST bit is automatically 46 * cleared on restart. */ 47#define CNTCTRL_RST BIT(4) 48/* Register Match mode: when Match is set, an 49 * interrupt is generated when the count value 50 * matches one of the three match registers and the 51 * corresponding bit is set in the Interrupt Enable 52 * register. 53 */ 54#define CNTCTRL_MATCH BIT(3) 55/* Register Match mode: when Match is set, an 56 * interrupt is generated when the count value 57 * matches one of the three match registers and the 58 * corresponding bit is set in the Interrupt Enable 59 * register. */ 60#define CNTCTRL_DECR BIT(2) 61/* When this bit is high, the timer is in Interval 62 * Mode, and the counter generates interrupts at 63 * regular intervals; when low, the timer is in 64 * overflow mode. */ 65#define CNTCTRL_INT BIT(1) 66/* Disable counter: when this bit is high, the counter 67 * is stopped, holding its last value until reset, 68 * restarted or enabled again. */ 69#define CNTCTRL_STOP BIT(0) 70 71/* Event timer overflow interrupt */ 72#define INT_EVENT_OVR BIT(5) 73/* Counter overflow */ 74#define INT_CNT_OVR BIT(4) 75/* Match 3 interrupt */ 76#define INT_MATCH2 BIT(3) 77/* Match 2 interrupt */ 78#define INT_MATCH1 BIT(2) 79/* Match 1 interrupt */ 80#define INT_MATCH0 BIT(1) 81/* Interval interrupt */ 82#define INT_INTERVAL BIT(0) 83 84/* Event Control Timer register: controls the behavior of the internal counter */ 85 86/* Specifies how to handle overflow at the internal counter (during the counting phase 87 * of the external pulse) 88 * 89 * - When 0: Overflow causes E_En to be 0 (see E_En bit description) 90 * - When 1: Overflow causes the internal counter to wrap around and continues incrementing 91 */ 92#define EVCTRL_OVR BIT(2) 93/* Specifies the counting phase of the external pulse */ 94#define EVCTRL_LO BIT(1) 95/* When 0, immediately resets the internal counter to 0, and stops incrementing*/ 96#define EVCTRL_EN BIT(0) 97 98#define PRESCALE_MAX 0xf 99#define PCLK_FREQ 111110000U 100 101#ifdef CONFIG_PLAT_ZYNQMP 102#define CNT_WIDTH 32 103#define CNT_MAX ((1ULL << CNT_WIDTH) - 1) 104#else 105#define CNT_WIDTH 16 106#define CNT_MAX (BIT(CNT_WIDTH) - 1) 107#endif 108 109 110/* Byte offsets into a field of ttc_tmr_regs_t for each ttc */ 111#define TTCX_TIMER1_OFFSET 0x0 112#define TTCX_TIMER2_OFFSET 0x4 113#define TTCX_TIMER3_OFFSET 0x8 114 115#define TTCX_TIMER1_IRQ_POS 0 116#define TTCX_TIMER2_IRQ_POS 1 117#define TTCX_TIMER3_IRQ_POS 2 118 119struct ttc_tmr_regs { 120 /* Controls prescaler, selects clock input, edge */ 121 uint32_t clk_ctrl[3]; /* +0x00 */ 122 /* Enables counter, sets mode of operation, sets up/down 123 * counting, enables matching, enables waveform output */ 124 uint32_t cnt_ctrl[3]; /* +0x0C */ 125 /* Returns current counter value */ 126 uint32_t cnt_val[3]; /* +0x18 */ 127 /* Sets interval value - If interval is enabled, this is the maximum value 128 * that the counter will count up to or down from */ 129 uint32_t interval[3]; /* +0x24 */ 130 /* Sets match values, total 3 */ 131 uint32_t match[3][3]; /* +0x30 */ 132 /* Shows current interrupt status */ 133 uint32_t int_sts[3]; /* +0x54 */ 134 /* Enable interrupts */ 135 uint32_t int_en[3]; /* +0x60 */ 136 /* Enable event timer, stop timer, sets phrase */ 137 uint32_t event_ctrl[3]; /* +0x6C */ 138 /* Shows width of external pulse */ 139 uint32_t event[3]; /* +0x78 */ 140}; 141typedef volatile struct ttc_tmr_regs ttc_tmr_regs_t; 142 143static freq_t _ttc_clk_get_freq(clk_t *clk); 144static freq_t _ttc_clk_set_freq(clk_t *clk, freq_t hz); 145static void _ttc_clk_recal(clk_t *clk); 146static clk_t *_ttc_clk_init(clk_t *clk); 147 148static inline ttc_tmr_regs_t *ttc_get_regs(ttc_t *ttc) 149{ 150 return ttc->regs; 151} 152 153static inline size_t ttc_get_timer_shift(ttc_id_t id) 154{ 155 switch (id) { 156 case TTC0_TIMER1: 157 case TTC1_TIMER1: 158#ifdef CONFIG_PLAT_ZYNQMP 159 case TTC2_TIMER1: 160 case TTC3_TIMER1: 161#endif 162 return TTCX_TIMER1_OFFSET; 163 case TTC0_TIMER2: 164 case TTC1_TIMER2: 165#ifdef CONFIG_PLAT_ZYNQMP 166 case TTC2_TIMER2: 167 case TTC3_TIMER2: 168#endif 169 return TTCX_TIMER2_OFFSET; 170 case TTC0_TIMER3: 171 case TTC1_TIMER3: 172#ifdef CONFIG_PLAT_ZYNQMP 173 case TTC2_TIMER3: 174 case TTC3_TIMER3: 175#endif 176 return TTCX_TIMER3_OFFSET; 177 default: 178 ZF_LOGF("Invalid ttc_id_t!"); 179 return 0; 180 } 181} 182 183static inline unsigned ttc_get_irq_pos(ttc_id_t id) 184{ 185 switch (id) { 186 case TTC0_TIMER1: 187 case TTC1_TIMER1: 188#ifdef CONFIG_PLAT_ZYNQMP 189 case TTC2_TIMER1: 190 case TTC3_TIMER1: 191#endif 192 return TTCX_TIMER1_IRQ_POS; 193 case TTC0_TIMER2: 194 case TTC1_TIMER2: 195#ifdef CONFIG_PLAT_ZYNQMP 196 case TTC2_TIMER2: 197 case TTC3_TIMER2: 198#endif 199 return TTCX_TIMER2_IRQ_POS; 200 case TTC0_TIMER3: 201 case TTC1_TIMER3: 202#ifdef CONFIG_PLAT_ZYNQMP 203 case TTC2_TIMER3: 204 case TTC3_TIMER3: 205#endif 206 return TTCX_TIMER3_IRQ_POS; 207 default: 208 ZF_LOGF("Invalid ttc_id_t!"); 209 return 0; 210 } 211} 212 213static inline char *ttc_get_device_path(ttc_id_t id) 214{ 215 switch (id) { 216 case TTC0_TIMER1: 217 case TTC0_TIMER2: 218 case TTC0_TIMER3: 219 return TTC0_PATH; 220 case TTC1_TIMER1: 221 case TTC1_TIMER2: 222 case TTC1_TIMER3: 223 return TTC1_PATH; 224#ifdef CONFIG_PLAT_ZYNQMP 225 case TTC2_TIMER1: 226 case TTC2_TIMER2: 227 case TTC2_TIMER3: 228 return TTC2_PATH; 229 case TTC3_TIMER1: 230 case TTC3_TIMER2: 231 case TTC3_TIMER3: 232 return TTC3_PATH; 233#endif /* CONFIG_PLAT_ZYNQMP */ 234 default: 235 ZF_LOGF("Invalid ttc_id_t!"); 236 return NULL; 237 } 238} 239 240/****************** Clocks ******************/ 241 242static ttc_t *ttc_clk_get_priv(clk_t *clk) 243{ 244 return (ttc_t *)clk->priv; 245} 246 247/* FPGA PL Clocks */ 248static freq_t _ttc_clk_get_freq(clk_t *clk) 249{ 250 ttc_t *ttc = ttc_clk_get_priv(clk); 251 ttc_tmr_regs_t *regs = ttc_get_regs(ttc); 252 uint32_t clk_ctrl; 253 freq_t fin, fout; 254 /* Get the parent frequency */ 255 if (clk->parent) { 256 fin = clk_get_freq(clk->parent); 257 } else { 258 fin = PCLK_FREQ; 259 } 260 /* Calculate fout */ 261 clk_ctrl = *regs->clk_ctrl; 262 if (clk_ctrl & CLKCTRL_PRESCALE_EN) { 263 fout = fin >> (CLKCTRL_GET_PRESCALE_VAL(clk_ctrl) + 1); 264 } else { 265 fout = fin; 266 } 267 /* Return */ 268 return fout; 269} 270 271static freq_t _ttc_clk_set_freq(clk_t *clk, freq_t hz) 272{ 273 ttc_t *ttc = ttc_clk_get_priv(clk); 274 ttc_tmr_regs_t *regs = ttc_get_regs(ttc); 275 uint32_t v; 276 freq_t fin; 277 int ps; 278 /* Determine input clock frequency */ 279 if (clk->parent) { 280 fin = clk_get_freq(clk->parent); 281 } else { 282 fin = PCLK_FREQ; 283 } 284 /* Find a prescale value */ 285 for (ps = 0; fin > hz; ps++, fin >>= 1); 286 if (ps > PRESCALE_MAX) { 287 return 0; 288 } 289 /* Configure the timer */ 290 v = regs->clk_ctrl[0] & ~CLKCTRL_PRESCALE_MASK; 291 if (ps > 0) { 292 v |= CLKCTRL_PRESCALE_EN | CLKCTRL_PRESCALE_VAL(ps - 1); 293 } else { 294 v &= ~CLKCTRL_PRESCALE_EN; 295 } 296 *regs->clk_ctrl = v; 297 return clk_get_freq(clk); 298} 299 300static void _ttc_clk_recal(clk_t *clk UNUSED) 301{ 302 assert(0); 303} 304 305static clk_t *_ttc_clk_init(clk_t *clk) 306{ 307 return clk; 308} 309 310static inline freq_t _ttc_get_freq(ttc_t *ttc) 311{ 312 return ttc->freq; 313} 314 315static inline freq_t _ttc_set_freq(ttc_t *ttc, freq_t hz) 316{ 317 ttc->freq = clk_set_freq(&ttc->clk, hz); 318 return ttc->freq; 319} 320 321static inline bool _ttc_check_interrupt(ttc_t *ttc) 322{ 323 ttc_tmr_regs_t *regs = ttc_get_regs(ttc); 324 /* The int_sts register is being accessed through typedef ttc_tmr_regs_t 325 * which is marked volatile, so the compiler will not elide this read. 326 */ 327 uint32_t res = *regs->int_sts; 328 /* There are no data dependencies within this function that imply that the 329 * CPU cannot reorder this read in the pipeline. Use a CPU read barrier to 330 * inform the CPU that it should stall reads until this read has completed. 331 */ 332 THREAD_MEMORY_RELEASE(); 333 334 return !!res; 335} 336 337/********************************************/ 338 339/* Computes the optimal clock frequency for interrupting after 340 * a given period of time. This will be the highest frequency 341 * such that starting from 0, the timer counter will reach its 342 * maximum value in AT MOST the specified time. 343 * 344 * If no such frequency is supported by the clock (ie. the 345 * requested time is too high) this returns ETIME. Returns 0 346 * on success. 347 * 348 * If a frequency is found, the clock is reprogrammed to run 349 * at that frequency. The number of ticks it will take for the 350 * requested time to pass (ie. the interval) is computed and 351 * returned via an argument (interval). */ 352static inline int _ttc_set_freq_for_ns(ttc_t *ttc, uint64_t ns, uint64_t *interval) 353{ 354 freq_t fin, f; 355 uint64_t interval_value; 356 357 /* Set the clock source frequency 358 * 1 / (fin / max_cnt) > interval 359 * fin < max_cnt / interval */ 360 f = freq_cycles_and_ns_to_hz(CNT_MAX, ns); 361 fin = _ttc_set_freq(ttc, f); 362 if (fin > f) { 363 /* This happens when the requested time is so long that the clock can't 364 * run slow enough. In this case, the clock driver reported the minimum 365 * rate it can run at, and we can use that to calculate a maximum time. 366 */ 367 ZF_LOGE("Timeout too big for timer, max %"PRIu64", got %"PRIu64"\n", 368 freq_cycles_and_hz_to_ns(CNT_MAX, fin), ns); 369 370 return ETIME; 371 } 372 373 interval_value = freq_ns_and_hz_to_cycles(ns, fin); 374 375 assert(interval_value <= CNT_MAX); 376 377 if (interval) { 378 *interval = interval_value; 379 } 380 381 return 0; 382} 383 384int ttc_start(ttc_t *ttc) 385{ 386 ttc_tmr_regs_t *regs = ttc_get_regs(ttc); 387 *regs->cnt_ctrl &= ~CNTCTRL_STOP; 388 return 0; 389} 390 391int ttc_stop(ttc_t *ttc) 392{ 393 ttc_tmr_regs_t *regs = ttc_get_regs(ttc); 394 *regs->cnt_ctrl |= CNTCTRL_STOP; 395 return 0; 396} 397 398void ttc_freerun(ttc_t *ttc) 399{ 400 ttc_tmr_regs_t *regs = ttc_get_regs(ttc); 401 *regs->cnt_ctrl = CNTCTRL_RST; 402 *regs->int_en = INT_EVENT_OVR | INT_CNT_OVR; 403} 404 405/* Set up the ttc to fire an interrupt every ns nanoseconds. 406 * The first such interrupt may arrive before ns nanoseconds 407 * have passed since calling. */ 408static int _ttc_periodic(ttc_tmr_regs_t *regs, uint64_t interval) 409{ 410 *regs->interval = interval; 411 412 /* Interval mode: Continuously count from 0 to value in interval register, 413 * triggering an interval interrupt and resetting the counter to 0 414 * whenever the counter passes through 0. */ 415 *regs->cnt_ctrl |= CNTCTRL_INT; 416 417 /* The INTERVAL interrupt is used in periodic mode. The only source of 418 * interrupts will be when the counter passes through 0 after reaching 419 * the value in the interval register. */ 420 *regs->int_en = INT_INTERVAL; 421 422 return 0; 423} 424 425static void ttc_handle_irq(void *data, ps_irq_acknowledge_fn_t acknowledge_fn, void *ack_data) 426{ 427 assert(data != NULL); 428 ttc_t *ttc = data; 429 ttc_tmr_regs_t *regs = ttc_get_regs(ttc); 430 431 bool interrupt_pending = _ttc_check_interrupt(ttc); 432 433 if (ttc->is_timestamp) { 434 /* Check if we already updated the timestamp when reading the time, 435 * the interrupt status register should be empty if we did */ 436 if (interrupt_pending) { 437 ttc->hi_time += ttc_ticks_to_ns(ttc, CNT_MAX); 438 } 439 } else { 440 /* The MATCH0 interrupt is used in oneshot mode. It is enabled when a 441 * oneshot function is called, and disabled here so only one interrupt 442 * is triggered per call. */ 443 *regs->int_en &= ~INT_MATCH0; 444 } 445 446 /* Acknowledge the interrupt and call the user callback if any */ 447 ZF_LOGF_IF(acknowledge_fn(ack_data), "Failed to acknowledge the interrupt from the TTC"); 448 if (ttc->user_callback) { 449 if (ttc->is_timestamp) { 450 ttc->user_callback(ttc->user_callback_token, LTIMER_OVERFLOW_EVENT); 451 } else { 452 ttc->user_callback(ttc->user_callback_token, LTIMER_TIMEOUT_EVENT); 453 } 454 } 455} 456 457uint64_t ttc_ticks_to_ns(ttc_t *ttc, uint32_t ticks) 458{ 459 if (!ttc) { 460 return 0; 461 } 462 uint32_t fin = _ttc_get_freq(ttc); 463 return freq_cycles_and_hz_to_ns(ticks, fin); 464} 465 466uint64_t ttc_get_time(ttc_t *ttc) 467{ 468 ttc_tmr_regs_t *regs = ttc_get_regs(ttc); 469 uint32_t cnt = *regs->cnt_val; 470 bool interrupt_pending = _ttc_check_interrupt(ttc); 471 /* Check if there is an interrupt pending, i.e. counter overflowed */ 472 if (interrupt_pending) { 473 /* Re-read the counter again */ 474 cnt = *regs->cnt_val; 475 /* Bump the hi_time counter now, as there may be latency in serving the interrupt */ 476 ttc->hi_time += ttc_ticks_to_ns(ttc, CNT_MAX); 477 } 478 uint32_t fin = _ttc_get_freq(ttc); 479 return ttc->hi_time + freq_cycles_and_hz_to_ns(cnt, fin); 480} 481 482/* Set up the ttc to fire an interrupt ns nanoseconds after this 483 * function is called. */ 484static int _ttc_oneshot_relative(ttc_tmr_regs_t *regs, uint64_t interval) 485{ 486 487 /* In overflow mode the ttc will continuously count up to 0xffff and reset to 0. 488 * The ttc will be programmed to interrupt when the counter reaches 489 * current_time + interval, allowing the addition to wrap around (16 bits). 490 */ 491 492#ifdef CONFIG_PLAT_ZYNQMP 493 *regs->match[0] = (interval + *regs->cnt_val); 494#else 495 *regs->match[0] = (interval + *regs->cnt_val) % BIT(CNT_WIDTH); 496#endif 497 498 /* Overflow mode: Continuously count from 0 to 0xffff (this is a 16 bit ttc). 499 * In this mode no interrval interrupts. A match interrupt (MATCH0) will be used 500 * in this mode. */ 501 *regs->cnt_ctrl &= ~CNTCTRL_INT; 502 503 /* The MATCH0 interrupt is used in oneshot mode. The only source of interrupts 504 * will be when the counter passes through the value in the match[0] register. 505 * This interrupt is disabled in the irq handler so it is only triggered once. 506 */ 507 *regs->int_en = INT_MATCH0; 508 509 return 0; 510} 511 512int ttc_set_timeout(ttc_t *ttc, uint64_t ns, bool periodic) 513{ 514 if (ttc == NULL) { 515 return EINVAL; 516 } 517 518 /* Program the clock and compute the interval value */ 519 uint64_t interval; 520 int error = _ttc_set_freq_for_ns(ttc, ns, &interval); 521 if (error) { 522 return error; 523 } 524 525 ttc_tmr_regs_t *regs = ttc_get_regs(ttc); 526 if (periodic) { 527 return _ttc_periodic(regs, interval); 528 } else { 529 return _ttc_oneshot_relative(regs, interval); 530 } 531} 532 533static int allocate_register_callback(pmem_region_t pmem, unsigned curr_num, size_t num_regs, void *token) 534{ 535 assert(token != NULL); 536 ttc_t *ttc = token; 537 ttc->regs = ps_pmem_map(&ttc->io_ops, pmem, false, PS_MEM_NORMAL); 538 if (ttc->regs == NULL) { 539 ZF_LOGE("Failed to map in registers for the TTC"); 540 return EIO; 541 } 542 /* This sets the base of the ttc_tmr_regs_t pointer to 543 * an offset into the ttc's mmio region such that 544 * ((ttc_tmr_regs_t*)vaddr)->clk_ctrl 545 * (and all other registers) refers to the address of the 546 * register relevant for the specified ttc device. */ 547 ttc->regs += ttc_get_timer_shift(ttc->id); 548 ttc->timer_pmem = pmem; 549 return 0; 550} 551 552static int allocate_irq_callback(ps_irq_t irq, unsigned curr_num, size_t num_irqs, void *token) 553{ 554 assert(token != NULL); 555 ttc_t *ttc = token; 556 assert(num_irqs == IRQS_PER_TTC); 557 /* Get the corresponding IRQ position and register the IRQ if it matches */ 558 unsigned irq_pos = ttc_get_irq_pos(ttc->id); 559 if (irq_pos == curr_num) { 560 ttc->irq_id = ps_irq_register(&ttc->io_ops.irq_ops, irq, ttc_handle_irq, ttc); 561 if (ttc->irq_id < 0) { 562 ZF_LOGE("Failed to register the IRQ for TTC timer %d", ttc->id); 563 return EIO; 564 } 565 } 566 return 0; 567} 568 569int ttc_init(ttc_t *ttc, ttc_config_t config) 570{ 571 if (ttc == NULL) { 572 ZF_LOGE("ttc is NULL"); 573 return EINVAL; 574 } 575 576 /* Initialise all the struct members */ 577 ttc->io_ops = config.io_ops; 578 ttc->user_callback = config.user_callback; 579 ttc->user_callback_token = config.user_callback_token; 580 ttc->irq_id = PS_INVALID_IRQ_ID; 581 ttc->is_timestamp = config.is_timestamp; 582 ttc->id = config.id; 583 584 char *device_path = ttc_get_device_path(config.id); 585 586 /* Read the timer's path in the DTB */ 587 ps_fdt_cookie_t *cookie = NULL; 588 int error = ps_fdt_read_path(&ttc->io_ops.io_fdt, &ttc->io_ops.malloc_ops, device_path, &cookie); 589 if (error) { 590 ZF_LOGF_IF(ps_fdt_cleanup_cookie(&ttc->io_ops.malloc_ops, cookie), CLEANUP_FAIL_TEXT); 591 ZF_LOGF_IF(ttc_destroy(ttc), CLEANUP_FAIL_TEXT); 592 return ENODEV; 593 } 594 595 /* Walk the registers and allocate them */ 596 error = ps_fdt_walk_registers(&ttc->io_ops.io_fdt, cookie, allocate_register_callback, ttc); 597 if (error) { 598 ZF_LOGF_IF(ps_fdt_cleanup_cookie(&ttc->io_ops.malloc_ops, cookie), CLEANUP_FAIL_TEXT); 599 ZF_LOGF_IF(ttc_destroy(ttc), CLEANUP_FAIL_TEXT); 600 return ENODEV; 601 } 602 603 /* Walk the interrupts and allocate the corresponding interrupt for this timer */ 604 error = ps_fdt_walk_irqs(&ttc->io_ops.io_fdt, cookie, allocate_irq_callback, ttc); 605 if (error) { 606 ZF_LOGF_IF(ps_fdt_cleanup_cookie(&ttc->io_ops.malloc_ops, cookie), CLEANUP_FAIL_TEXT); 607 ZF_LOGF_IF(ttc_destroy(ttc), CLEANUP_FAIL_TEXT); 608 return ENODEV; 609 } 610 611 /* Configure clock source */ 612 memset(&ttc->clk, 0, sizeof(ttc->clk)); 613 ttc->clk.name = STRINGIFY(config.id); 614 ttc->clk.get_freq = _ttc_clk_get_freq; 615 ttc->clk.set_freq = _ttc_clk_set_freq; 616 ttc->clk.recal = _ttc_clk_recal; 617 ttc->clk.init = _ttc_clk_init; 618 ttc->clk.priv = ttc; 619 620 if (config.clk_src) { 621 clk_register_child(config.clk_src, &ttc->clk); 622 } 623 ttc->freq = clk_get_freq(&ttc->clk); 624 625 ttc_tmr_regs_t *regs = ttc_get_regs(ttc); 626 *regs->int_en = 0; 627 FORCE_READ(regs->int_sts); /* Clear on read */ 628 *regs->cnt_ctrl = CNTCTRL_RST | CNTCTRL_STOP | CNTCTRL_INT | CNTCTRL_MATCH; 629 *regs->clk_ctrl = 0; 630 *regs->int_en = INT_INTERVAL; 631 *regs->interval = CNT_MAX; 632 633 return 0; 634} 635 636int ttc_destroy(ttc_t *ttc) 637{ 638 assert(ttc != NULL); 639 640 if (ttc->regs) { 641 ZF_LOGF_IF(ttc_stop(ttc), "Failed to stop the TTC before de-allocating it"); 642 ps_io_unmap(&ttc->io_ops.io_mapper, ttc->regs, (size_t) ttc->timer_pmem.length); 643 } 644 645 if (ttc->irq_id != PS_INVALID_IRQ_ID) { 646 ZF_LOGF_IF(ps_irq_unregister(&ttc->io_ops.irq_ops, ttc->irq_id), "Failed to unregister IRQ"); 647 } 648 649 return 0; 650} 651