xref: /rk3399_ARM-atf/drivers/nxp/timer/nxp_timer.c (revision 50b8ea115f117e17646d73fe7606bee14bd02630)
1447a42e7SPankaj Gupta /*
2447a42e7SPankaj Gupta  * Copyright 2021 NXP
3447a42e7SPankaj Gupta  *
4447a42e7SPankaj Gupta  * SPDX-License-Identifier: BSD-3-Clause
5447a42e7SPankaj Gupta  *
6447a42e7SPankaj Gupta  */
7447a42e7SPankaj Gupta 
8447a42e7SPankaj Gupta #include <arch_helpers.h>
9447a42e7SPankaj Gupta #include <common/debug.h>
10447a42e7SPankaj Gupta #include <drivers/delay_timer.h>
11447a42e7SPankaj Gupta #include <lib/mmio.h>
12447a42e7SPankaj Gupta #include <lib/utils_def.h>
13447a42e7SPankaj Gupta #include <nxp_timer.h>
14447a42e7SPankaj Gupta #include <plat/common/platform.h>
15447a42e7SPankaj Gupta 
16447a42e7SPankaj Gupta static uintptr_t g_nxp_timer_addr;
17447a42e7SPankaj Gupta static timer_ops_t ops;
18447a42e7SPankaj Gupta 
19447a42e7SPankaj Gupta uint64_t get_timer_val(uint64_t start)
20447a42e7SPankaj Gupta {
21447a42e7SPankaj Gupta 	uint64_t cntpct;
22447a42e7SPankaj Gupta 
23447a42e7SPankaj Gupta 	isb();
24447a42e7SPankaj Gupta 	cntpct = read_cntpct_el0();
25447a42e7SPankaj Gupta 	return (cntpct * 1000ULL / read_cntfrq_el0() - start);
26447a42e7SPankaj Gupta }
27447a42e7SPankaj Gupta 
28447a42e7SPankaj Gupta static uint32_t timer_get_value(void)
29447a42e7SPankaj Gupta {
30447a42e7SPankaj Gupta 	uint64_t cntpct;
31447a42e7SPankaj Gupta 
32447a42e7SPankaj Gupta 	isb();
33447a42e7SPankaj Gupta 	cntpct = read_cntpct_el0();
34447a42e7SPankaj Gupta #ifdef ERRATA_SOC_A008585
35447a42e7SPankaj Gupta 	uint8_t	max_fetch_count = 10U;
36447a42e7SPankaj Gupta 	/* This erratum number needs to be confirmed to match ARM document */
37447a42e7SPankaj Gupta 	uint64_t temp;
38447a42e7SPankaj Gupta 
39447a42e7SPankaj Gupta 	isb();
40447a42e7SPankaj Gupta 	temp = read_cntpct_el0();
41447a42e7SPankaj Gupta 
42447a42e7SPankaj Gupta 	while (temp != cntpct && max_fetch_count) {
43447a42e7SPankaj Gupta 		isb();
44447a42e7SPankaj Gupta 		cntpct = read_cntpct_el0();
45447a42e7SPankaj Gupta 		isb();
46447a42e7SPankaj Gupta 		temp = read_cntpct_el0();
47447a42e7SPankaj Gupta 		max_fetch_count--;
48447a42e7SPankaj Gupta 	}
49447a42e7SPankaj Gupta #endif
50447a42e7SPankaj Gupta 
51447a42e7SPankaj Gupta 	/*
52447a42e7SPankaj Gupta 	 * Generic delay timer implementation expects the timer to be a down
53447a42e7SPankaj Gupta 	 * counter. We apply bitwise NOT operator to the tick values returned
54447a42e7SPankaj Gupta 	 * by read_cntpct_el0() to simulate the down counter. The value is
55447a42e7SPankaj Gupta 	 * clipped from 64 to 32 bits.
56447a42e7SPankaj Gupta 	 */
57447a42e7SPankaj Gupta 	return (uint32_t)(~cntpct);
58447a42e7SPankaj Gupta }
59447a42e7SPankaj Gupta 
60447a42e7SPankaj Gupta static void delay_timer_init_args(uint32_t mult, uint32_t div)
61447a42e7SPankaj Gupta {
62*50b8ea11SElyes Haouas 	ops.get_timer_value	= timer_get_value;
63447a42e7SPankaj Gupta 	ops.clk_mult		= mult;
64447a42e7SPankaj Gupta 	ops.clk_div		= div;
65447a42e7SPankaj Gupta 
66447a42e7SPankaj Gupta 	timer_init(&ops);
67447a42e7SPankaj Gupta 
68447a42e7SPankaj Gupta 	VERBOSE("Generic delay timer configured with mult=%u and div=%u\n",
69447a42e7SPankaj Gupta 		mult, div);
70447a42e7SPankaj Gupta }
71447a42e7SPankaj Gupta 
72447a42e7SPankaj Gupta /*
73447a42e7SPankaj Gupta  * Initialise the nxp on-chip free rolling usec counter as the delay
74447a42e7SPankaj Gupta  * timer.
75447a42e7SPankaj Gupta  */
76447a42e7SPankaj Gupta void delay_timer_init(uintptr_t nxp_timer_addr)
77447a42e7SPankaj Gupta {
78447a42e7SPankaj Gupta 	/* Value in ticks */
79447a42e7SPankaj Gupta 	unsigned int mult = MHZ_TICKS_PER_SEC;
80447a42e7SPankaj Gupta 
81447a42e7SPankaj Gupta 	unsigned int div;
82447a42e7SPankaj Gupta 
83447a42e7SPankaj Gupta 	unsigned int counter_base_frequency = plat_get_syscnt_freq2();
84447a42e7SPankaj Gupta 
85447a42e7SPankaj Gupta 	g_nxp_timer_addr = nxp_timer_addr;
86447a42e7SPankaj Gupta 	/* Rounding off the Counter Frequency to MHZ_TICKS_PER_SEC */
87447a42e7SPankaj Gupta 	if (counter_base_frequency > MHZ_TICKS_PER_SEC) {
88447a42e7SPankaj Gupta 		counter_base_frequency = (counter_base_frequency
89447a42e7SPankaj Gupta 					/ MHZ_TICKS_PER_SEC)
90447a42e7SPankaj Gupta 					* MHZ_TICKS_PER_SEC;
91447a42e7SPankaj Gupta 	} else {
92447a42e7SPankaj Gupta 		counter_base_frequency = (counter_base_frequency
93447a42e7SPankaj Gupta 					/ KHZ_TICKS_PER_SEC)
94447a42e7SPankaj Gupta 					* KHZ_TICKS_PER_SEC;
95447a42e7SPankaj Gupta 	}
96447a42e7SPankaj Gupta 
97447a42e7SPankaj Gupta 	/* Value in ticks per second (Hz) */
98447a42e7SPankaj Gupta 	div = counter_base_frequency;
99447a42e7SPankaj Gupta 
100447a42e7SPankaj Gupta 	/* Reduce multiplier and divider by dividing them repeatedly by 10 */
101447a42e7SPankaj Gupta 	while ((mult % 10U == 0U) && (div % 10U == 0U)) {
102447a42e7SPankaj Gupta 		mult /= 10U;
103447a42e7SPankaj Gupta 		div /= 10U;
104447a42e7SPankaj Gupta 	}
105447a42e7SPankaj Gupta 
106447a42e7SPankaj Gupta 	/* Enable and initialize the System level generic timer */
107447a42e7SPankaj Gupta 	mmio_write_32(g_nxp_timer_addr + CNTCR_OFF,
108447a42e7SPankaj Gupta 			CNTCR_FCREQ(0) | CNTCR_EN);
109447a42e7SPankaj Gupta 
110447a42e7SPankaj Gupta 	delay_timer_init_args(mult, div);
111447a42e7SPankaj Gupta }
112447a42e7SPankaj Gupta 
113447a42e7SPankaj Gupta 
114447a42e7SPankaj Gupta #ifdef IMAGE_BL31
115447a42e7SPankaj Gupta /*******************************************************************************
116447a42e7SPankaj Gupta  * TBD: Configures access to the system counter timer module.
117447a42e7SPankaj Gupta  ******************************************************************************/
118447a42e7SPankaj Gupta void ls_configure_sys_timer(uintptr_t ls_sys_timctl_base,
119447a42e7SPankaj Gupta 			    uint8_t ls_config_cntacr,
120447a42e7SPankaj Gupta 			    uint8_t plat_ls_ns_timer_frame_id)
121447a42e7SPankaj Gupta {
122447a42e7SPankaj Gupta 	unsigned int reg_val;
123447a42e7SPankaj Gupta 
124447a42e7SPankaj Gupta 	if (ls_config_cntacr == 1U) {
125447a42e7SPankaj Gupta 		reg_val = (1U << CNTACR_RPCT_SHIFT) | (1U << CNTACR_RVCT_SHIFT);
126447a42e7SPankaj Gupta 		reg_val |= (1U << CNTACR_RFRQ_SHIFT) | (1U << CNTACR_RVOFF_SHIFT);
127447a42e7SPankaj Gupta 		reg_val |= (1U << CNTACR_RWVT_SHIFT) | (1U << CNTACR_RWPT_SHIFT);
128447a42e7SPankaj Gupta 		mmio_write_32(ls_sys_timctl_base +
129447a42e7SPankaj Gupta 		      CNTACR_BASE(plat_ls_ns_timer_frame_id), reg_val);
130447a42e7SPankaj Gupta 		mmio_write_32(ls_sys_timctl_base, plat_get_syscnt_freq2());
131447a42e7SPankaj Gupta 	}
132447a42e7SPankaj Gupta 
133447a42e7SPankaj Gupta 	reg_val = (1U << CNTNSAR_NS_SHIFT(plat_ls_ns_timer_frame_id));
134447a42e7SPankaj Gupta 	mmio_write_32(ls_sys_timctl_base + CNTNSAR, reg_val);
135447a42e7SPankaj Gupta }
136447a42e7SPankaj Gupta 
137447a42e7SPankaj Gupta void enable_init_timer(void)
138447a42e7SPankaj Gupta {
139447a42e7SPankaj Gupta 	/* Enable and initialize the System level generic timer */
140447a42e7SPankaj Gupta 	mmio_write_32(g_nxp_timer_addr + CNTCR_OFF,
141447a42e7SPankaj Gupta 			CNTCR_FCREQ(0) | CNTCR_EN);
142447a42e7SPankaj Gupta }
143447a42e7SPankaj Gupta #endif
144