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
get_timer_val(uint64_t start)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
timer_get_value(void)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
delay_timer_init_args(uint32_t mult,uint32_t div)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 */
delay_timer_init(uintptr_t nxp_timer_addr)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 ******************************************************************************/
ls_configure_sys_timer(uintptr_t ls_sys_timctl_base,uint8_t ls_config_cntacr,uint8_t plat_ls_ns_timer_frame_id)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
enable_init_timer(void)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