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