1 /* 2 * Copyright 2021 NXP 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 */ 7 8 #include <arch_helpers.h> 9 #include <common/debug.h> 10 #include <drivers/delay_timer.h> 11 #include <lib/mmio.h> 12 #include <lib/utils_def.h> 13 #include <nxp_timer.h> 14 #include <plat/common/platform.h> 15 16 static uintptr_t g_nxp_timer_addr; 17 static timer_ops_t ops; 18 19 uint64_t get_timer_val(uint64_t start) 20 { 21 uint64_t cntpct; 22 23 isb(); 24 cntpct = read_cntpct_el0(); 25 return (cntpct * 1000ULL / read_cntfrq_el0() - start); 26 } 27 28 static uint32_t timer_get_value(void) 29 { 30 uint64_t cntpct; 31 32 isb(); 33 cntpct = read_cntpct_el0(); 34 #ifdef ERRATA_SOC_A008585 35 uint8_t max_fetch_count = 10U; 36 /* This erratum number needs to be confirmed to match ARM document */ 37 uint64_t temp; 38 39 isb(); 40 temp = read_cntpct_el0(); 41 42 while (temp != cntpct && max_fetch_count) { 43 isb(); 44 cntpct = read_cntpct_el0(); 45 isb(); 46 temp = read_cntpct_el0(); 47 max_fetch_count--; 48 } 49 #endif 50 51 /* 52 * Generic delay timer implementation expects the timer to be a down 53 * counter. We apply bitwise NOT operator to the tick values returned 54 * by read_cntpct_el0() to simulate the down counter. The value is 55 * clipped from 64 to 32 bits. 56 */ 57 return (uint32_t)(~cntpct); 58 } 59 60 static void delay_timer_init_args(uint32_t mult, uint32_t div) 61 { 62 ops.get_timer_value = timer_get_value, 63 ops.clk_mult = mult; 64 ops.clk_div = div; 65 66 timer_init(&ops); 67 68 VERBOSE("Generic delay timer configured with mult=%u and div=%u\n", 69 mult, div); 70 } 71 72 /* 73 * Initialise the nxp on-chip free rolling usec counter as the delay 74 * timer. 75 */ 76 void delay_timer_init(uintptr_t nxp_timer_addr) 77 { 78 /* Value in ticks */ 79 unsigned int mult = MHZ_TICKS_PER_SEC; 80 81 unsigned int div; 82 83 unsigned int counter_base_frequency = plat_get_syscnt_freq2(); 84 85 g_nxp_timer_addr = nxp_timer_addr; 86 /* Rounding off the Counter Frequency to MHZ_TICKS_PER_SEC */ 87 if (counter_base_frequency > MHZ_TICKS_PER_SEC) { 88 counter_base_frequency = (counter_base_frequency 89 / MHZ_TICKS_PER_SEC) 90 * MHZ_TICKS_PER_SEC; 91 } else { 92 counter_base_frequency = (counter_base_frequency 93 / KHZ_TICKS_PER_SEC) 94 * KHZ_TICKS_PER_SEC; 95 } 96 97 /* Value in ticks per second (Hz) */ 98 div = counter_base_frequency; 99 100 /* Reduce multiplier and divider by dividing them repeatedly by 10 */ 101 while ((mult % 10U == 0U) && (div % 10U == 0U)) { 102 mult /= 10U; 103 div /= 10U; 104 } 105 106 /* Enable and initialize the System level generic timer */ 107 mmio_write_32(g_nxp_timer_addr + CNTCR_OFF, 108 CNTCR_FCREQ(0) | CNTCR_EN); 109 110 delay_timer_init_args(mult, div); 111 } 112 113 114 #ifdef IMAGE_BL31 115 /******************************************************************************* 116 * TBD: Configures access to the system counter timer module. 117 ******************************************************************************/ 118 void ls_configure_sys_timer(uintptr_t ls_sys_timctl_base, 119 uint8_t ls_config_cntacr, 120 uint8_t plat_ls_ns_timer_frame_id) 121 { 122 unsigned int reg_val; 123 124 if (ls_config_cntacr == 1U) { 125 reg_val = (1U << CNTACR_RPCT_SHIFT) | (1U << CNTACR_RVCT_SHIFT); 126 reg_val |= (1U << CNTACR_RFRQ_SHIFT) | (1U << CNTACR_RVOFF_SHIFT); 127 reg_val |= (1U << CNTACR_RWVT_SHIFT) | (1U << CNTACR_RWPT_SHIFT); 128 mmio_write_32(ls_sys_timctl_base + 129 CNTACR_BASE(plat_ls_ns_timer_frame_id), reg_val); 130 mmio_write_32(ls_sys_timctl_base, plat_get_syscnt_freq2()); 131 } 132 133 reg_val = (1U << CNTNSAR_NS_SHIFT(plat_ls_ns_timer_frame_id)); 134 mmio_write_32(ls_sys_timctl_base + CNTNSAR, reg_val); 135 } 136 137 void enable_init_timer(void) 138 { 139 /* Enable and initialize the System level generic timer */ 140 mmio_write_32(g_nxp_timer_addr + CNTCR_OFF, 141 CNTCR_FCREQ(0) | CNTCR_EN); 142 } 143 #endif 144