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