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