xref: /rk3399_ARM-atf/lib/pmf/pmf_main.c (revision e0c7d8f56c4a9dc92f89d2999d600986ed99acb3)
1a31d8983SYatharth Kochar /*
24c700c15SGovindraj Raja  * Copyright (c) 2016-2018, Arm Limited and Contributors. All rights reserved.
3a31d8983SYatharth Kochar  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
5a31d8983SYatharth Kochar  */
609d40e0eSAntonio Nino Diaz 
709d40e0eSAntonio Nino Diaz #include <assert.h>
809d40e0eSAntonio Nino Diaz #include <errno.h>
909d40e0eSAntonio Nino Diaz #include <string.h>
1009d40e0eSAntonio Nino Diaz 
11a31d8983SYatharth Kochar #include <arch.h>
12a31d8983SYatharth Kochar #include <arch_helpers.h>
1309d40e0eSAntonio Nino Diaz #include <common/debug.h>
1409d40e0eSAntonio Nino Diaz #include <lib/pmf/pmf.h>
1509d40e0eSAntonio Nino Diaz #include <lib/utils_def.h>
1609d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
17a31d8983SYatharth Kochar 
18a31d8983SYatharth Kochar /*******************************************************************************
19a31d8983SYatharth Kochar  * The 'pmf_svc_descs' array holds the PMF service descriptors exported by
20da04341eSChris Kay  * services by placing them in the '.pmf_svc_descs' linker section.
21a31d8983SYatharth Kochar  * The 'pmf_svc_descs_indices' array holds the index of a descriptor in the
22a31d8983SYatharth Kochar  * 'pmf_svc_descs' array. The TIF[15:10] bits in the time-stamp id are used
23a31d8983SYatharth Kochar  * to get an index into the 'pmf_svc_descs_indices' array. This gives the
24a31d8983SYatharth Kochar  * index of the descriptor in the 'pmf_svc_descs' array  which contains the
25a31d8983SYatharth Kochar  * service function pointers.
26a31d8983SYatharth Kochar  ******************************************************************************/
279f85f9e3SJoel Hutton 
289f85f9e3SJoel Hutton IMPORT_SYM(uintptr_t, __PMF_SVC_DESCS_START__,		PMF_SVC_DESCS_START);
299f85f9e3SJoel Hutton IMPORT_SYM(uintptr_t, __PMF_SVC_DESCS_END__,		PMF_SVC_DESCS_END);
30931f7c61SSoby Mathew IMPORT_SYM(uintptr_t, __PMF_PERCPU_TIMESTAMP_END__,	PMF_PERCPU_TIMESTAMP_END);
31195e363fSAntonio Nino Diaz IMPORT_SYM(uintptr_t,  __PMF_TIMESTAMP_START__,		PMF_TIMESTAMP_ARRAY_START);
32931f7c61SSoby Mathew 
33931f7c61SSoby Mathew #define PMF_PERCPU_TIMESTAMP_SIZE	(PMF_PERCPU_TIMESTAMP_END - PMF_TIMESTAMP_ARRAY_START)
34a31d8983SYatharth Kochar 
35a31d8983SYatharth Kochar #define PMF_SVC_DESCS_MAX		10
36a31d8983SYatharth Kochar 
37a31d8983SYatharth Kochar /*
38a31d8983SYatharth Kochar  * This is used to traverse through registered PMF services.
39a31d8983SYatharth Kochar  */
40a31d8983SYatharth Kochar static pmf_svc_desc_t *pmf_svc_descs;
41a31d8983SYatharth Kochar 
42a31d8983SYatharth Kochar /*
43a31d8983SYatharth Kochar  * This array is used to store registered PMF services in sorted order.
44a31d8983SYatharth Kochar  */
45a31d8983SYatharth Kochar static int pmf_svc_descs_indices[PMF_SVC_DESCS_MAX];
46a31d8983SYatharth Kochar 
47a31d8983SYatharth Kochar /*
48a31d8983SYatharth Kochar  * This is used to track total number of successfully registered PMF services.
49a31d8983SYatharth Kochar  */
50a31d8983SYatharth Kochar static int pmf_num_services;
51a31d8983SYatharth Kochar 
52a31d8983SYatharth Kochar /*
53a31d8983SYatharth Kochar  * This is the main PMF function that initialize registered
54a31d8983SYatharth Kochar  * PMF services and also sort them in ascending order.
55a31d8983SYatharth Kochar  */
pmf_setup(void)56a31d8983SYatharth Kochar int pmf_setup(void)
57a31d8983SYatharth Kochar {
58a31d8983SYatharth Kochar 	int rc, ii, jj = 0;
59a31d8983SYatharth Kochar 	int pmf_svc_descs_num, temp_val;
60a31d8983SYatharth Kochar 
61a31d8983SYatharth Kochar 	/* If no PMF services are registered then simply bail out */
62a31d8983SYatharth Kochar 	pmf_svc_descs_num = (PMF_SVC_DESCS_END - PMF_SVC_DESCS_START)/
63a31d8983SYatharth Kochar 				 sizeof(pmf_svc_desc_t);
64a31d8983SYatharth Kochar 	if (pmf_svc_descs_num == 0)
65a31d8983SYatharth Kochar 		return 0;
66a31d8983SYatharth Kochar 
67a31d8983SYatharth Kochar 	assert(pmf_svc_descs_num < PMF_SVC_DESCS_MAX);
68a31d8983SYatharth Kochar 
69a31d8983SYatharth Kochar 	pmf_svc_descs = (pmf_svc_desc_t *) PMF_SVC_DESCS_START;
70a31d8983SYatharth Kochar 	for (ii = 0; ii < pmf_svc_descs_num; ii++) {
71a31d8983SYatharth Kochar 
72195e363fSAntonio Nino Diaz 		assert(pmf_svc_descs[ii].get_ts != NULL);
73a31d8983SYatharth Kochar 
74a31d8983SYatharth Kochar 		/*
75a31d8983SYatharth Kochar 		 * Call the initialization routine for this
76a31d8983SYatharth Kochar 		 * PMF service, if it is defined.
77a31d8983SYatharth Kochar 		 */
78195e363fSAntonio Nino Diaz 		if (pmf_svc_descs[ii].init != NULL) {
79a31d8983SYatharth Kochar 			rc = pmf_svc_descs[ii].init();
80195e363fSAntonio Nino Diaz 			if (rc != 0) {
81a31d8983SYatharth Kochar 				WARN("Could not initialize PMF"
82a31d8983SYatharth Kochar 					"service %s - skipping \n",
83a31d8983SYatharth Kochar 					pmf_svc_descs[ii].name);
84a31d8983SYatharth Kochar 				continue;
85a31d8983SYatharth Kochar 			}
86a31d8983SYatharth Kochar 		}
87a31d8983SYatharth Kochar 
88a31d8983SYatharth Kochar 		/* Update the pmf_svc_descs_indices array */
89a31d8983SYatharth Kochar 		pmf_svc_descs_indices[jj++] = ii;
90a31d8983SYatharth Kochar 	}
91a31d8983SYatharth Kochar 
92a31d8983SYatharth Kochar 	pmf_num_services = jj;
93a31d8983SYatharth Kochar 
94a31d8983SYatharth Kochar 	/*
95a31d8983SYatharth Kochar 	 * Sort the successfully registered PMF services
96a31d8983SYatharth Kochar 	 * according to service ID
97a31d8983SYatharth Kochar 	 */
98a31d8983SYatharth Kochar 	for (ii = 1; ii < pmf_num_services; ii++) {
99a31d8983SYatharth Kochar 		for (jj = 0; jj < (pmf_num_services - ii); jj++) {
100a31d8983SYatharth Kochar 			if ((pmf_svc_descs[jj].svc_config & PMF_SVC_ID_MASK) >
101a31d8983SYatharth Kochar 				(pmf_svc_descs[jj + 1].svc_config &
102a31d8983SYatharth Kochar 						PMF_SVC_ID_MASK)) {
103a31d8983SYatharth Kochar 				temp_val = pmf_svc_descs_indices[jj];
104a31d8983SYatharth Kochar 				pmf_svc_descs_indices[jj] =
105a31d8983SYatharth Kochar 						pmf_svc_descs_indices[jj+1];
106a31d8983SYatharth Kochar 				pmf_svc_descs_indices[jj+1] = temp_val;
107a31d8983SYatharth Kochar 			}
108a31d8983SYatharth Kochar 		}
109a31d8983SYatharth Kochar 	}
110a31d8983SYatharth Kochar 
111a31d8983SYatharth Kochar 	return 0;
112a31d8983SYatharth Kochar }
113a31d8983SYatharth Kochar 
114a31d8983SYatharth Kochar /*
115a31d8983SYatharth Kochar  * This function implements binary search to find registered
116a31d8983SYatharth Kochar  * PMF service based on Service ID provided in `tid` argument.
117a31d8983SYatharth Kochar  */
get_service(unsigned int tid)118a31d8983SYatharth Kochar static pmf_svc_desc_t *get_service(unsigned int tid)
119a31d8983SYatharth Kochar {
120a31d8983SYatharth Kochar 	int low = 0;
121a31d8983SYatharth Kochar 	int mid;
122a31d8983SYatharth Kochar 	int high = pmf_num_services;
123a31d8983SYatharth Kochar 	unsigned int svc_id = tid & PMF_SVC_ID_MASK;
124a31d8983SYatharth Kochar 	int index;
125a31d8983SYatharth Kochar 	unsigned int desc_svc_id;
126a31d8983SYatharth Kochar 
127a31d8983SYatharth Kochar 	if (pmf_num_services == 0)
128a31d8983SYatharth Kochar 		return NULL;
129a31d8983SYatharth Kochar 
130195e363fSAntonio Nino Diaz 	assert(pmf_svc_descs != NULL);
131a31d8983SYatharth Kochar 
132a31d8983SYatharth Kochar 	do {
133a31d8983SYatharth Kochar 		mid = (low + high) / 2;
134a31d8983SYatharth Kochar 		index = pmf_svc_descs_indices[mid];
135a31d8983SYatharth Kochar 
136a31d8983SYatharth Kochar 		desc_svc_id = pmf_svc_descs[index].svc_config & PMF_SVC_ID_MASK;
137a31d8983SYatharth Kochar 		if (svc_id < desc_svc_id)
138a31d8983SYatharth Kochar 			high = mid - 1;
139a31d8983SYatharth Kochar 		if (svc_id > desc_svc_id)
140a31d8983SYatharth Kochar 			low = mid + 1;
141a31d8983SYatharth Kochar 	} while ((svc_id != desc_svc_id) && (low <= high));
142a31d8983SYatharth Kochar 
143a31d8983SYatharth Kochar 	/*
144a31d8983SYatharth Kochar 	 * Make sure the Service found supports the tid range.
145a31d8983SYatharth Kochar 	 */
146a31d8983SYatharth Kochar 	if ((svc_id == desc_svc_id) && ((tid & PMF_TID_MASK) <
147a31d8983SYatharth Kochar 		(pmf_svc_descs[index].svc_config & PMF_TID_MASK)))
148a31d8983SYatharth Kochar 		return (pmf_svc_desc_t *)&pmf_svc_descs[index];
149a31d8983SYatharth Kochar 
150a31d8983SYatharth Kochar 	return NULL;
151a31d8983SYatharth Kochar }
152a31d8983SYatharth Kochar 
153a31d8983SYatharth Kochar /*
154a31d8983SYatharth Kochar  * This function gets the time-stamp value for the PMF services
155a31d8983SYatharth Kochar  * registered for SMC interface based on `tid` and `mpidr`.
156a31d8983SYatharth Kochar  */
pmf_get_timestamp_smc(unsigned int tid,u_register_t mpidr,unsigned int flags,unsigned long long * ts_value)157a31d8983SYatharth Kochar int pmf_get_timestamp_smc(unsigned int tid,
158a31d8983SYatharth Kochar 		u_register_t mpidr,
159a31d8983SYatharth Kochar 		unsigned int flags,
160a31d8983SYatharth Kochar 		unsigned long long *ts_value)
161a31d8983SYatharth Kochar {
162a31d8983SYatharth Kochar 	pmf_svc_desc_t *svc_desc;
163195e363fSAntonio Nino Diaz 	assert(ts_value != NULL);
164a31d8983SYatharth Kochar 
165a31d8983SYatharth Kochar 	/* Search for registered service. */
166a31d8983SYatharth Kochar 	svc_desc = get_service(tid);
167a31d8983SYatharth Kochar 
168*e60c1847SManish Pandey 	if (svc_desc == NULL) {
169a31d8983SYatharth Kochar 		*ts_value = 0;
170a31d8983SYatharth Kochar 		return -EINVAL;
171a31d8983SYatharth Kochar 	} else {
172a31d8983SYatharth Kochar 		/* Call the service time-stamp handler. */
173a31d8983SYatharth Kochar 		*ts_value = svc_desc->get_ts(tid, mpidr, flags);
174a31d8983SYatharth Kochar 		return 0;
175a31d8983SYatharth Kochar 	}
176a31d8983SYatharth Kochar }
177a31d8983SYatharth Kochar 
178a31d8983SYatharth Kochar /*
179a31d8983SYatharth Kochar  * This function can be used to dump `ts` value for given `tid`.
180a31d8983SYatharth Kochar  * Assumption is that the console is already initialized.
181a31d8983SYatharth Kochar  */
__pmf_dump_timestamp(unsigned int tid,unsigned long long ts)182a31d8983SYatharth Kochar void __pmf_dump_timestamp(unsigned int tid, unsigned long long ts)
183a31d8983SYatharth Kochar {
18439b6cc66SAntonio Nino Diaz 	printf("PMF:cpu %u	tid %u	ts %llu\n",
185a31d8983SYatharth Kochar 		plat_my_core_pos(), tid, ts);
186a31d8983SYatharth Kochar }
187a31d8983SYatharth Kochar 
188a31d8983SYatharth Kochar /*
189a31d8983SYatharth Kochar  * This function calculate the address identified by
190a31d8983SYatharth Kochar  * `base_addr`, `tid` and `cpuid`.
191a31d8983SYatharth Kochar  */
calc_ts_addr(uintptr_t base_addr,unsigned int tid,unsigned int cpuid)192a31d8983SYatharth Kochar static inline uintptr_t calc_ts_addr(uintptr_t base_addr,
193a31d8983SYatharth Kochar 		unsigned int tid,
194a31d8983SYatharth Kochar 		unsigned int cpuid)
195a31d8983SYatharth Kochar {
196a31d8983SYatharth Kochar 	assert(cpuid < PLATFORM_CORE_COUNT);
197a31d8983SYatharth Kochar 	assert(base_addr >= PMF_TIMESTAMP_ARRAY_START);
198a31d8983SYatharth Kochar 	assert(base_addr < ((PMF_TIMESTAMP_ARRAY_START +
199a31d8983SYatharth Kochar 		PMF_PERCPU_TIMESTAMP_SIZE) - ((tid & PMF_TID_MASK) *
200a31d8983SYatharth Kochar 		sizeof(unsigned long long))));
201a31d8983SYatharth Kochar 
202a31d8983SYatharth Kochar 	base_addr += ((cpuid * PMF_PERCPU_TIMESTAMP_SIZE) +
203a31d8983SYatharth Kochar 		((tid & PMF_TID_MASK) * sizeof(unsigned long long)));
204a31d8983SYatharth Kochar 
205a31d8983SYatharth Kochar 	return base_addr;
206a31d8983SYatharth Kochar }
207a31d8983SYatharth Kochar 
208a31d8983SYatharth Kochar /*
209a31d8983SYatharth Kochar  * This function stores the `ts` value to the storage identified by
210a31d8983SYatharth Kochar  * `base_addr`, `tid` and current cpu id.
211a31d8983SYatharth Kochar  * Note: The timestamp addresses are cache line aligned per cpu
212a31d8983SYatharth Kochar  * and only the owning CPU would ever write into it.
213a31d8983SYatharth Kochar  */
__pmf_store_timestamp(uintptr_t base_addr,unsigned int tid,unsigned long long ts)214a31d8983SYatharth Kochar void __pmf_store_timestamp(uintptr_t base_addr,
215a31d8983SYatharth Kochar 			unsigned int tid,
216a31d8983SYatharth Kochar 			unsigned long long ts)
217a31d8983SYatharth Kochar {
218a31d8983SYatharth Kochar 	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
219a31d8983SYatharth Kochar 				 tid, plat_my_core_pos());
220a31d8983SYatharth Kochar 	*ts_addr = ts;
221a31d8983SYatharth Kochar }
222a31d8983SYatharth Kochar 
223a31d8983SYatharth Kochar /*
224a31d8983SYatharth Kochar  * This is the cached version of `pmf_store_my_timestamp`
225a31d8983SYatharth Kochar  * Note: The timestamp addresses are cache line aligned per cpu
226a31d8983SYatharth Kochar  * and only the owning CPU would ever write into it.
227a31d8983SYatharth Kochar  */
__pmf_store_timestamp_with_cache_maint(uintptr_t base_addr,unsigned int tid,unsigned long long ts)228a31d8983SYatharth Kochar void __pmf_store_timestamp_with_cache_maint(uintptr_t base_addr,
229a31d8983SYatharth Kochar 			unsigned int tid,
230a31d8983SYatharth Kochar 			unsigned long long ts)
231a31d8983SYatharth Kochar {
232a31d8983SYatharth Kochar 	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
233a31d8983SYatharth Kochar 				 tid, plat_my_core_pos());
234a31d8983SYatharth Kochar 	*ts_addr = ts;
235a31d8983SYatharth Kochar 	flush_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long));
236a31d8983SYatharth Kochar }
237a31d8983SYatharth Kochar 
238a31d8983SYatharth Kochar /*
239a31d8983SYatharth Kochar  * This function retrieves the `ts` value from the storage identified by
240a31d8983SYatharth Kochar  * `base_addr`, `tid` and `cpuid`.
241a31d8983SYatharth Kochar  * Note: The timestamp addresses are cache line aligned per cpu.
242a31d8983SYatharth Kochar  */
__pmf_get_timestamp(uintptr_t base_addr,unsigned int tid,unsigned int cpuid,unsigned int flags)243a31d8983SYatharth Kochar unsigned long long __pmf_get_timestamp(uintptr_t base_addr,
244a31d8983SYatharth Kochar 			unsigned int tid,
245a31d8983SYatharth Kochar 			unsigned int cpuid,
246a31d8983SYatharth Kochar 			unsigned int flags)
247a31d8983SYatharth Kochar {
248a31d8983SYatharth Kochar 	assert(cpuid < PLATFORM_CORE_COUNT);
249a31d8983SYatharth Kochar 	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
250a31d8983SYatharth Kochar 				tid, cpuid);
251a31d8983SYatharth Kochar 
252195e363fSAntonio Nino Diaz 	if ((flags & PMF_CACHE_MAINT) != 0U)
253a31d8983SYatharth Kochar 		inv_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long));
254a31d8983SYatharth Kochar 
255a31d8983SYatharth Kochar 	return *ts_addr;
256a31d8983SYatharth Kochar }
257