1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/devicetree.h>
8 #include <zephyr/devicetree/clocks.h>
9 #include <zephyr/drivers/clock_control/nrf_clock_control.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/ztest.h>
12 
13 struct test_clk_context {
14 	const struct device *clk_dev;
15 	const struct nrf_clock_spec *clk_specs;
16 	size_t clk_specs_size;
17 };
18 
19 const struct nrf_clock_spec test_clk_specs_hsfll[] = {
20 	{
21 		.frequency = MHZ(128),
22 		.accuracy = 0,
23 		.precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT,
24 	},
25 	{
26 		.frequency = MHZ(320),
27 		.accuracy = 0,
28 		.precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT,
29 	},
30 	{
31 		.frequency = MHZ(64),
32 		.accuracy = 0,
33 		.precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT,
34 	},
35 };
36 
37 #if CONFIG_BOARD_NRF54H20DK_NRF54H20_CPUAPP
38 const struct nrf_clock_spec test_clk_specs_fll16m[] = {
39 	{
40 		.frequency = MHZ(16),
41 		.accuracy = 20000,
42 		.precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT,
43 	},
44 	{
45 		.frequency = MHZ(16),
46 		.accuracy = 5020,
47 		.precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT,
48 	},
49 	{
50 		.frequency = MHZ(16),
51 		.accuracy = 30,
52 		.precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT,
53 	},
54 };
55 
56 static const struct test_clk_context fll16m_test_clk_contexts[] = {
57 	{
58 		.clk_dev = DEVICE_DT_GET(DT_NODELABEL(fll16m)),
59 		.clk_specs = test_clk_specs_fll16m,
60 		.clk_specs_size = ARRAY_SIZE(test_clk_specs_fll16m),
61 	},
62 };
63 
64 const struct nrf_clock_spec invalid_test_clk_specs_fll16m[] = {
65 	{
66 		.frequency = MHZ(16),
67 		.accuracy = 20,
68 		.precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT,
69 	},
70 	{
71 		.frequency = MHZ(19),
72 		.accuracy = 0,
73 		.precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT,
74 	},
75 	{
76 		.frequency = MHZ(16),
77 		.accuracy = 0,
78 		.precision = NRF_CLOCK_CONTROL_PRECISION_HIGH,
79 	},
80 };
81 
82 static const struct test_clk_context invalid_fll16m_test_clk_contexts[] = {
83 	{
84 		.clk_dev = DEVICE_DT_GET(DT_NODELABEL(fll16m)),
85 		.clk_specs = invalid_test_clk_specs_fll16m,
86 		.clk_specs_size = ARRAY_SIZE(invalid_test_clk_specs_fll16m),
87 	},
88 };
89 
90 static const struct test_clk_context cpuapp_hsfll_test_clk_contexts[] = {
91 	{
92 		.clk_dev = DEVICE_DT_GET(DT_NODELABEL(cpuapp_hsfll)),
93 		.clk_specs = test_clk_specs_hsfll,
94 		.clk_specs_size = ARRAY_SIZE(test_clk_specs_hsfll),
95 	},
96 };
97 #elif defined(CONFIG_BOARD_NRF54H20DK_NRF54H20_CPURAD)
98 static const struct test_clk_context cpurad_hsfll_test_clk_contexts[] = {
99 	{
100 		.clk_dev = DEVICE_DT_GET(DT_NODELABEL(cpurad_hsfll)),
101 		.clk_specs = test_clk_specs_hsfll,
102 		.clk_specs_size = ARRAY_SIZE(test_clk_specs_hsfll),
103 	},
104 };
105 #endif
106 
107 const struct nrf_clock_spec test_clk_specs_global_hsfll[] = {
108 	{
109 		.frequency = MHZ(320),
110 	},
111 	{
112 		.frequency = MHZ(256),
113 	},
114 	{
115 		.frequency = MHZ(128),
116 	},
117 	{
118 		.frequency = MHZ(64),
119 	},
120 };
121 
122 static const struct test_clk_context global_hsfll_test_clk_contexts[] = {
123 	{
124 		.clk_dev = DEVICE_DT_GET(DT_NODELABEL(hsfll120)),
125 		.clk_specs = test_clk_specs_global_hsfll,
126 		.clk_specs_size = ARRAY_SIZE(test_clk_specs_global_hsfll),
127 	},
128 };
129 
130 const struct nrf_clock_spec test_clk_specs_lfclk[] = {
131 	{
132 		.frequency = 32768,
133 		.accuracy = 0,
134 		.precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT,
135 	},
136 	{
137 		.frequency = 32768,
138 		.accuracy = 20,
139 		.precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT,
140 	},
141 	{
142 		.frequency = 32768,
143 		.accuracy = 20,
144 		.precision = NRF_CLOCK_CONTROL_PRECISION_HIGH,
145 	},
146 };
147 
148 static const struct test_clk_context lfclk_test_clk_contexts[] = {
149 	{
150 		.clk_dev = DEVICE_DT_GET(DT_NODELABEL(lfclk)),
151 		.clk_specs = test_clk_specs_lfclk,
152 		.clk_specs_size = ARRAY_SIZE(test_clk_specs_lfclk),
153 	},
154 };
155 
test_request_release_clock_spec(const struct device * clk_dev,const struct nrf_clock_spec * clk_spec)156 static void test_request_release_clock_spec(const struct device *clk_dev,
157 					    const struct nrf_clock_spec *clk_spec)
158 {
159 	int ret = 0;
160 	int res = 0;
161 	struct onoff_client cli;
162 	uint32_t rate;
163 
164 	TC_PRINT("Clock under test: %s\n", clk_dev->name);
165 	sys_notify_init_spinwait(&cli.notify);
166 	ret = nrf_clock_control_request(clk_dev, clk_spec, &cli);
167 	zassert_between_inclusive(ret, 0, 2);
168 	do {
169 		ret = sys_notify_fetch_result(&cli.notify, &res);
170 		k_yield();
171 	} while (ret == -EAGAIN);
172 	TC_PRINT("Clock control request return value: %d\n", ret);
173 	TC_PRINT("Clock control request response code: %d\n", res);
174 	zassert_ok(ret);
175 	zassert_ok(res);
176 	ret = clock_control_get_rate(clk_dev, NULL, &rate);
177 	if (ret != -ENOSYS) {
178 		zassert_ok(ret);
179 		zassert_equal(rate, clk_spec->frequency);
180 	}
181 	k_msleep(1000);
182 	ret = nrf_clock_control_release(clk_dev, clk_spec);
183 	zassert_equal(ret, ONOFF_STATE_ON);
184 }
185 
test_clock_control_request(const struct test_clk_context * clk_contexts,size_t contexts_size)186 static void test_clock_control_request(const struct test_clk_context *clk_contexts,
187 				       size_t contexts_size)
188 {
189 	const struct test_clk_context *clk_context;
190 	size_t clk_specs_size;
191 	const struct device *clk_dev;
192 	const struct nrf_clock_spec *clk_spec;
193 
194 	for (size_t i = 0; i < contexts_size; i++) {
195 		clk_context = &clk_contexts[i];
196 		clk_specs_size = clk_context->clk_specs_size;
197 
198 		for (size_t u = 0; u < clk_specs_size; u++) {
199 			clk_dev = clk_context->clk_dev;
200 			clk_spec = &clk_context->clk_specs[u];
201 
202 			TC_PRINT("Applying clock (%s) spec: frequency %d, accuracy %d, precision "
203 				 "%d\n",
204 				 clk_dev->name, clk_spec->frequency, clk_spec->accuracy,
205 				 clk_spec->precision);
206 			test_request_release_clock_spec(clk_dev, clk_spec);
207 		}
208 	}
209 }
210 
211 #if CONFIG_BOARD_NRF54H20DK_NRF54H20_CPUAPP
ZTEST(nrf2_clock_control,test_cpuapp_hsfll_control)212 ZTEST(nrf2_clock_control, test_cpuapp_hsfll_control)
213 {
214 
215 	TC_PRINT("APPLICATION DOMAIN HSFLL test\n");
216 	/* Wait for the DVFS init to complete */
217 	k_msleep(3000);
218 	test_clock_control_request(cpuapp_hsfll_test_clk_contexts,
219 				   ARRAY_SIZE(cpuapp_hsfll_test_clk_contexts));
220 }
221 
ZTEST(nrf2_clock_control,test_fll16m_control)222 ZTEST(nrf2_clock_control, test_fll16m_control)
223 {
224 	TC_PRINT("FLL16M test\n");
225 	test_clock_control_request(fll16m_test_clk_contexts, ARRAY_SIZE(fll16m_test_clk_contexts));
226 }
227 
ZTEST(nrf2_clock_control,test_invalid_fll16m_clock_spec_response)228 ZTEST(nrf2_clock_control, test_invalid_fll16m_clock_spec_response)
229 {
230 	int ret = 0;
231 	int res = 0;
232 	struct onoff_client cli;
233 	const struct test_clk_context *clk_context;
234 	size_t clk_specs_size;
235 	const struct device *clk_dev;
236 	const struct nrf_clock_spec *clk_spec;
237 
238 	TC_PRINT("FLL16M invalid clock specification test\n");
239 
240 	for (size_t i = 0; i < ARRAY_SIZE(invalid_fll16m_test_clk_contexts); i++) {
241 		clk_context = &invalid_fll16m_test_clk_contexts[i];
242 		clk_specs_size = clk_context->clk_specs_size;
243 
244 		for (size_t u = 0; u < clk_specs_size; u++) {
245 			clk_dev = clk_context->clk_dev;
246 			clk_spec = &clk_context->clk_specs[u];
247 
248 			TC_PRINT("Applying clock (%s) spec: frequency %d, accuracy %d, precision "
249 				 "%d\n",
250 				 clk_dev->name, clk_spec->frequency, clk_spec->accuracy,
251 				 clk_spec->precision);
252 
253 			sys_notify_init_spinwait(&cli.notify);
254 			ret = nrf_clock_control_request(clk_dev, clk_spec, &cli);
255 			TC_PRINT("Clock control request return value: %d\n", ret);
256 			TC_PRINT("Clock control request response code: %d\n", res);
257 			zassert_equal(ret, -EINVAL);
258 			zassert_ok(res);
259 		}
260 	}
261 }
262 #elif defined(CONFIG_BOARD_NRF54H20DK_NRF54H20_CPURAD)
ZTEST(nrf2_clock_control,test_cpurad_hsfll_control)263 ZTEST(nrf2_clock_control, test_cpurad_hsfll_control)
264 {
265 	TC_PRINT("RADIO DOMAIN HSFLL test\n");
266 	test_clock_control_request(cpurad_hsfll_test_clk_contexts,
267 				   ARRAY_SIZE(cpurad_hsfll_test_clk_contexts));
268 }
269 #endif
270 
ZTEST(nrf2_clock_control,test_lfclk_control)271 ZTEST(nrf2_clock_control, test_lfclk_control)
272 {
273 	TC_PRINT("LFCLK test\n");
274 	test_clock_control_request(lfclk_test_clk_contexts, ARRAY_SIZE(lfclk_test_clk_contexts));
275 }
276 
ZTEST(nrf2_clock_control,test_global_hsfll_control)277 ZTEST(nrf2_clock_control, test_global_hsfll_control)
278 {
279 	TC_PRINT("Global HSFLL test\n");
280 	test_clock_control_request(global_hsfll_test_clk_contexts,
281 				   ARRAY_SIZE(global_hsfll_test_clk_contexts));
282 }
283 
ZTEST(nrf2_clock_control,test_safe_request_cancellation)284 ZTEST(nrf2_clock_control, test_safe_request_cancellation)
285 {
286 	int ret = 0;
287 	int res = 0;
288 	struct onoff_client cli;
289 	const struct test_clk_context *clk_context = &lfclk_test_clk_contexts[0];
290 	const struct device *clk_dev = clk_context->clk_dev;
291 	const struct nrf_clock_spec *clk_spec = &test_clk_specs_lfclk[0];
292 
293 	TC_PRINT("Safe clock request cancellation\n");
294 	TC_PRINT("Clock under test: %s\n", clk_dev->name);
295 	sys_notify_init_spinwait(&cli.notify);
296 	ret = nrf_clock_control_request(clk_dev, clk_spec, &cli);
297 	zassert_between_inclusive(ret, 0, 2);
298 	TC_PRINT("Clock control request return value: %d\n", ret);
299 	TC_PRINT("Clock control request response code: %d\n", res);
300 	zassert_ok(res);
301 	ret = nrf_clock_control_cancel_or_release(clk_dev, clk_spec, &cli);
302 	TC_PRINT("Clock control safe cancellation return value: %d\n", ret);
303 	zassert_between_inclusive(ret, ONOFF_STATE_ON, ONOFF_STATE_TO_ON);
304 }
305 
306 ZTEST_SUITE(nrf2_clock_control, NULL, NULL, NULL, NULL, NULL);
307