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