blob: 448c0ba93ea637a9ba396c39d4ebae4ef811311c [file] [log] [blame]
Pankaj Gupta68a181e2020-12-09 14:02:38 +05301/*
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
16static uintptr_t g_nxp_timer_addr;
17static timer_ops_t ops;
18
19uint64_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
28static 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
60static void delay_timer_init_args(uint32_t mult, uint32_t div)
61{
Elyes Haouas117a7be2023-02-21 14:54:50 +010062 ops.get_timer_value = timer_get_value;
Pankaj Gupta68a181e2020-12-09 14:02:38 +053063 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 */
76void 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 ******************************************************************************/
118void 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
137void 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