Pankaj Gupta | 68a181e | 2020-12-09 14:02:38 +0530 | [diff] [blame] | 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 | { |
Elyes Haouas | 117a7be | 2023-02-21 14:54:50 +0100 | [diff] [blame] | 62 | ops.get_timer_value = timer_get_value; |
Pankaj Gupta | 68a181e | 2020-12-09 14:02:38 +0530 | [diff] [blame] | 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 |