1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Kunit test for clk gate basic type |
4 | */ |
5 | #include <linux/clk.h> |
6 | #include <linux/clk-provider.h> |
7 | #include <linux/platform_device.h> |
8 | |
9 | #include <kunit/test.h> |
10 | |
11 | static void clk_gate_register_test_dev(struct kunit *test) |
12 | { |
13 | struct clk_hw *ret; |
14 | struct platform_device *pdev; |
15 | |
16 | pdev = platform_device_register_simple(name: "test_gate_device" , id: -1, NULL, num: 0); |
17 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); |
18 | |
19 | ret = clk_hw_register_gate(&pdev->dev, "test_gate" , NULL, 0, NULL, |
20 | 0, 0, NULL); |
21 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret); |
22 | KUNIT_EXPECT_STREQ(test, "test_gate" , clk_hw_get_name(ret)); |
23 | KUNIT_EXPECT_EQ(test, 0UL, clk_hw_get_flags(ret)); |
24 | |
25 | clk_hw_unregister_gate(hw: ret); |
26 | platform_device_put(pdev); |
27 | } |
28 | |
29 | static void clk_gate_register_test_parent_names(struct kunit *test) |
30 | { |
31 | struct clk_hw *parent; |
32 | struct clk_hw *ret; |
33 | |
34 | parent = clk_hw_register_fixed_rate(NULL, "test_parent" , NULL, 0, |
35 | 1000000); |
36 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); |
37 | |
38 | ret = clk_hw_register_gate(NULL, "test_gate" , "test_parent" , 0, NULL, |
39 | 0, 0, NULL); |
40 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret); |
41 | KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret)); |
42 | |
43 | clk_hw_unregister_gate(hw: ret); |
44 | clk_hw_unregister_fixed_rate(hw: parent); |
45 | } |
46 | |
47 | static void clk_gate_register_test_parent_data(struct kunit *test) |
48 | { |
49 | struct clk_hw *parent; |
50 | struct clk_hw *ret; |
51 | struct clk_parent_data pdata = { }; |
52 | |
53 | parent = clk_hw_register_fixed_rate(NULL, "test_parent" , NULL, 0, |
54 | 1000000); |
55 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); |
56 | pdata.hw = parent; |
57 | |
58 | ret = clk_hw_register_gate_parent_data(NULL, "test_gate" , &pdata, 0, |
59 | NULL, 0, 0, NULL); |
60 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret); |
61 | KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret)); |
62 | |
63 | clk_hw_unregister_gate(hw: ret); |
64 | clk_hw_unregister_fixed_rate(hw: parent); |
65 | } |
66 | |
67 | static void clk_gate_register_test_parent_data_legacy(struct kunit *test) |
68 | { |
69 | struct clk_hw *parent; |
70 | struct clk_hw *ret; |
71 | struct clk_parent_data pdata = { }; |
72 | |
73 | parent = clk_hw_register_fixed_rate(NULL, "test_parent" , NULL, 0, |
74 | 1000000); |
75 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); |
76 | pdata.name = "test_parent" ; |
77 | |
78 | ret = clk_hw_register_gate_parent_data(NULL, "test_gate" , &pdata, 0, |
79 | NULL, 0, 0, NULL); |
80 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret); |
81 | KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret)); |
82 | |
83 | clk_hw_unregister_gate(hw: ret); |
84 | clk_hw_unregister_fixed_rate(hw: parent); |
85 | } |
86 | |
87 | static void clk_gate_register_test_parent_hw(struct kunit *test) |
88 | { |
89 | struct clk_hw *parent; |
90 | struct clk_hw *ret; |
91 | |
92 | parent = clk_hw_register_fixed_rate(NULL, "test_parent" , NULL, 0, |
93 | 1000000); |
94 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); |
95 | |
96 | ret = clk_hw_register_gate_parent_hw(NULL, "test_gate" , parent, 0, NULL, |
97 | 0, 0, NULL); |
98 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret); |
99 | KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret)); |
100 | |
101 | clk_hw_unregister_gate(hw: ret); |
102 | clk_hw_unregister_fixed_rate(hw: parent); |
103 | } |
104 | |
105 | static void clk_gate_register_test_hiword_invalid(struct kunit *test) |
106 | { |
107 | struct clk_hw *ret; |
108 | |
109 | ret = clk_hw_register_gate(NULL, "test_gate" , NULL, 0, NULL, |
110 | 20, CLK_GATE_HIWORD_MASK, NULL); |
111 | |
112 | KUNIT_EXPECT_TRUE(test, IS_ERR(ret)); |
113 | } |
114 | |
115 | static struct kunit_case clk_gate_register_test_cases[] = { |
116 | KUNIT_CASE(clk_gate_register_test_dev), |
117 | KUNIT_CASE(clk_gate_register_test_parent_names), |
118 | KUNIT_CASE(clk_gate_register_test_parent_data), |
119 | KUNIT_CASE(clk_gate_register_test_parent_data_legacy), |
120 | KUNIT_CASE(clk_gate_register_test_parent_hw), |
121 | KUNIT_CASE(clk_gate_register_test_hiword_invalid), |
122 | {} |
123 | }; |
124 | |
125 | static struct kunit_suite clk_gate_register_test_suite = { |
126 | .name = "clk-gate-register-test" , |
127 | .test_cases = clk_gate_register_test_cases, |
128 | }; |
129 | |
130 | struct clk_gate_test_context { |
131 | void __iomem *fake_mem; |
132 | struct clk_hw *hw; |
133 | struct clk_hw *parent; |
134 | __le32 fake_reg; /* Keep at end, KASAN can detect out of bounds */ |
135 | }; |
136 | |
137 | static struct clk_gate_test_context *clk_gate_test_alloc_ctx(struct kunit *test) |
138 | { |
139 | struct clk_gate_test_context *ctx; |
140 | |
141 | test->priv = ctx = kunit_kzalloc(test, size: sizeof(*ctx), GFP_KERNEL); |
142 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); |
143 | ctx->fake_mem = (void __force __iomem *)&ctx->fake_reg; |
144 | |
145 | return ctx; |
146 | } |
147 | |
148 | static void clk_gate_test_parent_rate(struct kunit *test) |
149 | { |
150 | struct clk_gate_test_context *ctx = test->priv; |
151 | struct clk_hw *parent = ctx->parent; |
152 | struct clk_hw *hw = ctx->hw; |
153 | unsigned long prate = clk_hw_get_rate(hw: parent); |
154 | unsigned long rate = clk_hw_get_rate(hw); |
155 | |
156 | KUNIT_EXPECT_EQ(test, prate, rate); |
157 | } |
158 | |
159 | static void clk_gate_test_enable(struct kunit *test) |
160 | { |
161 | struct clk_gate_test_context *ctx = test->priv; |
162 | struct clk_hw *parent = ctx->parent; |
163 | struct clk_hw *hw = ctx->hw; |
164 | struct clk *clk = hw->clk; |
165 | u32 enable_val = BIT(5); |
166 | |
167 | KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); |
168 | |
169 | KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); |
170 | KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw)); |
171 | KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw)); |
172 | KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent)); |
173 | KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent)); |
174 | } |
175 | |
176 | static void clk_gate_test_disable(struct kunit *test) |
177 | { |
178 | struct clk_gate_test_context *ctx = test->priv; |
179 | struct clk_hw *parent = ctx->parent; |
180 | struct clk_hw *hw = ctx->hw; |
181 | struct clk *clk = hw->clk; |
182 | u32 enable_val = BIT(5); |
183 | u32 disable_val = 0; |
184 | |
185 | KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); |
186 | KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); |
187 | |
188 | clk_disable_unprepare(clk); |
189 | KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg)); |
190 | KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw)); |
191 | KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw)); |
192 | KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent)); |
193 | KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent)); |
194 | } |
195 | |
196 | static struct kunit_case clk_gate_test_cases[] = { |
197 | KUNIT_CASE(clk_gate_test_parent_rate), |
198 | KUNIT_CASE(clk_gate_test_enable), |
199 | KUNIT_CASE(clk_gate_test_disable), |
200 | {} |
201 | }; |
202 | |
203 | static int clk_gate_test_init(struct kunit *test) |
204 | { |
205 | struct clk_hw *parent; |
206 | struct clk_hw *hw; |
207 | struct clk_gate_test_context *ctx; |
208 | |
209 | ctx = clk_gate_test_alloc_ctx(test); |
210 | parent = clk_hw_register_fixed_rate(NULL, "test_parent" , NULL, 0, |
211 | 2000000); |
212 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); |
213 | |
214 | hw = clk_hw_register_gate_parent_hw(NULL, "test_gate" , parent, 0, |
215 | ctx->fake_mem, 5, 0, NULL); |
216 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); |
217 | |
218 | ctx->hw = hw; |
219 | ctx->parent = parent; |
220 | |
221 | return 0; |
222 | } |
223 | |
224 | static void clk_gate_test_exit(struct kunit *test) |
225 | { |
226 | struct clk_gate_test_context *ctx = test->priv; |
227 | |
228 | clk_hw_unregister_gate(hw: ctx->hw); |
229 | clk_hw_unregister_fixed_rate(hw: ctx->parent); |
230 | } |
231 | |
232 | static struct kunit_suite clk_gate_test_suite = { |
233 | .name = "clk-gate-test" , |
234 | .init = clk_gate_test_init, |
235 | .exit = clk_gate_test_exit, |
236 | .test_cases = clk_gate_test_cases, |
237 | }; |
238 | |
239 | static void clk_gate_test_invert_enable(struct kunit *test) |
240 | { |
241 | struct clk_gate_test_context *ctx = test->priv; |
242 | struct clk_hw *parent = ctx->parent; |
243 | struct clk_hw *hw = ctx->hw; |
244 | struct clk *clk = hw->clk; |
245 | u32 enable_val = 0; |
246 | |
247 | KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); |
248 | |
249 | KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); |
250 | KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw)); |
251 | KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw)); |
252 | KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent)); |
253 | KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent)); |
254 | } |
255 | |
256 | static void clk_gate_test_invert_disable(struct kunit *test) |
257 | { |
258 | struct clk_gate_test_context *ctx = test->priv; |
259 | struct clk_hw *parent = ctx->parent; |
260 | struct clk_hw *hw = ctx->hw; |
261 | struct clk *clk = hw->clk; |
262 | u32 enable_val = 0; |
263 | u32 disable_val = BIT(15); |
264 | |
265 | KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); |
266 | KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); |
267 | |
268 | clk_disable_unprepare(clk); |
269 | KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg)); |
270 | KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw)); |
271 | KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw)); |
272 | KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent)); |
273 | KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent)); |
274 | } |
275 | |
276 | static struct kunit_case clk_gate_test_invert_cases[] = { |
277 | KUNIT_CASE(clk_gate_test_invert_enable), |
278 | KUNIT_CASE(clk_gate_test_invert_disable), |
279 | {} |
280 | }; |
281 | |
282 | static int clk_gate_test_invert_init(struct kunit *test) |
283 | { |
284 | struct clk_hw *parent; |
285 | struct clk_hw *hw; |
286 | struct clk_gate_test_context *ctx; |
287 | |
288 | ctx = clk_gate_test_alloc_ctx(test); |
289 | parent = clk_hw_register_fixed_rate(NULL, "test_parent" , NULL, 0, |
290 | 2000000); |
291 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); |
292 | |
293 | ctx->fake_reg = cpu_to_le32(BIT(15)); /* Default to off */ |
294 | hw = clk_hw_register_gate_parent_hw(NULL, "test_gate" , parent, 0, |
295 | ctx->fake_mem, 15, |
296 | CLK_GATE_SET_TO_DISABLE, NULL); |
297 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); |
298 | |
299 | ctx->hw = hw; |
300 | ctx->parent = parent; |
301 | |
302 | return 0; |
303 | } |
304 | |
305 | static struct kunit_suite clk_gate_test_invert_suite = { |
306 | .name = "clk-gate-invert-test" , |
307 | .init = clk_gate_test_invert_init, |
308 | .exit = clk_gate_test_exit, |
309 | .test_cases = clk_gate_test_invert_cases, |
310 | }; |
311 | |
312 | static void clk_gate_test_hiword_enable(struct kunit *test) |
313 | { |
314 | struct clk_gate_test_context *ctx = test->priv; |
315 | struct clk_hw *parent = ctx->parent; |
316 | struct clk_hw *hw = ctx->hw; |
317 | struct clk *clk = hw->clk; |
318 | u32 enable_val = BIT(9) | BIT(9 + 16); |
319 | |
320 | KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); |
321 | |
322 | KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); |
323 | KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw)); |
324 | KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw)); |
325 | KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent)); |
326 | KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent)); |
327 | } |
328 | |
329 | static void clk_gate_test_hiword_disable(struct kunit *test) |
330 | { |
331 | struct clk_gate_test_context *ctx = test->priv; |
332 | struct clk_hw *parent = ctx->parent; |
333 | struct clk_hw *hw = ctx->hw; |
334 | struct clk *clk = hw->clk; |
335 | u32 enable_val = BIT(9) | BIT(9 + 16); |
336 | u32 disable_val = BIT(9 + 16); |
337 | |
338 | KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); |
339 | KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); |
340 | |
341 | clk_disable_unprepare(clk); |
342 | KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg)); |
343 | KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw)); |
344 | KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw)); |
345 | KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent)); |
346 | KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent)); |
347 | } |
348 | |
349 | static struct kunit_case clk_gate_test_hiword_cases[] = { |
350 | KUNIT_CASE(clk_gate_test_hiword_enable), |
351 | KUNIT_CASE(clk_gate_test_hiword_disable), |
352 | {} |
353 | }; |
354 | |
355 | static int clk_gate_test_hiword_init(struct kunit *test) |
356 | { |
357 | struct clk_hw *parent; |
358 | struct clk_hw *hw; |
359 | struct clk_gate_test_context *ctx; |
360 | |
361 | ctx = clk_gate_test_alloc_ctx(test); |
362 | parent = clk_hw_register_fixed_rate(NULL, "test_parent" , NULL, 0, |
363 | 2000000); |
364 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); |
365 | |
366 | hw = clk_hw_register_gate_parent_hw(NULL, "test_gate" , parent, 0, |
367 | ctx->fake_mem, 9, |
368 | CLK_GATE_HIWORD_MASK, NULL); |
369 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); |
370 | |
371 | ctx->hw = hw; |
372 | ctx->parent = parent; |
373 | |
374 | return 0; |
375 | } |
376 | |
377 | static struct kunit_suite clk_gate_test_hiword_suite = { |
378 | .name = "clk-gate-hiword-test" , |
379 | .init = clk_gate_test_hiword_init, |
380 | .exit = clk_gate_test_exit, |
381 | .test_cases = clk_gate_test_hiword_cases, |
382 | }; |
383 | |
384 | static void clk_gate_test_is_enabled(struct kunit *test) |
385 | { |
386 | struct clk_hw *hw; |
387 | struct clk_gate_test_context *ctx; |
388 | |
389 | ctx = clk_gate_test_alloc_ctx(test); |
390 | ctx->fake_reg = cpu_to_le32(BIT(7)); |
391 | hw = clk_hw_register_gate(NULL, "test_gate" , NULL, 0, ctx->fake_mem, 7, |
392 | 0, NULL); |
393 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); |
394 | KUNIT_ASSERT_TRUE(test, clk_hw_is_enabled(hw)); |
395 | |
396 | clk_hw_unregister_gate(hw); |
397 | } |
398 | |
399 | static void clk_gate_test_is_disabled(struct kunit *test) |
400 | { |
401 | struct clk_hw *hw; |
402 | struct clk_gate_test_context *ctx; |
403 | |
404 | ctx = clk_gate_test_alloc_ctx(test); |
405 | ctx->fake_reg = cpu_to_le32(BIT(4)); |
406 | hw = clk_hw_register_gate(NULL, "test_gate" , NULL, 0, ctx->fake_mem, 7, |
407 | 0, NULL); |
408 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); |
409 | KUNIT_ASSERT_FALSE(test, clk_hw_is_enabled(hw)); |
410 | |
411 | clk_hw_unregister_gate(hw); |
412 | } |
413 | |
414 | static void clk_gate_test_is_enabled_inverted(struct kunit *test) |
415 | { |
416 | struct clk_hw *hw; |
417 | struct clk_gate_test_context *ctx; |
418 | |
419 | ctx = clk_gate_test_alloc_ctx(test); |
420 | ctx->fake_reg = cpu_to_le32(BIT(31)); |
421 | hw = clk_hw_register_gate(NULL, "test_gate" , NULL, 0, ctx->fake_mem, 2, |
422 | CLK_GATE_SET_TO_DISABLE, NULL); |
423 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); |
424 | KUNIT_ASSERT_TRUE(test, clk_hw_is_enabled(hw)); |
425 | |
426 | clk_hw_unregister_gate(hw); |
427 | } |
428 | |
429 | static void clk_gate_test_is_disabled_inverted(struct kunit *test) |
430 | { |
431 | struct clk_hw *hw; |
432 | struct clk_gate_test_context *ctx; |
433 | |
434 | ctx = clk_gate_test_alloc_ctx(test); |
435 | ctx->fake_reg = cpu_to_le32(BIT(29)); |
436 | hw = clk_hw_register_gate(NULL, "test_gate" , NULL, 0, ctx->fake_mem, 29, |
437 | CLK_GATE_SET_TO_DISABLE, NULL); |
438 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); |
439 | KUNIT_ASSERT_FALSE(test, clk_hw_is_enabled(hw)); |
440 | |
441 | clk_hw_unregister_gate(hw); |
442 | } |
443 | |
444 | static struct kunit_case clk_gate_test_enabled_cases[] = { |
445 | KUNIT_CASE(clk_gate_test_is_enabled), |
446 | KUNIT_CASE(clk_gate_test_is_disabled), |
447 | KUNIT_CASE(clk_gate_test_is_enabled_inverted), |
448 | KUNIT_CASE(clk_gate_test_is_disabled_inverted), |
449 | {} |
450 | }; |
451 | |
452 | static struct kunit_suite clk_gate_test_enabled_suite = { |
453 | .name = "clk-gate-is_enabled-test" , |
454 | .test_cases = clk_gate_test_enabled_cases, |
455 | }; |
456 | |
457 | kunit_test_suites( |
458 | &clk_gate_register_test_suite, |
459 | &clk_gate_test_suite, |
460 | &clk_gate_test_invert_suite, |
461 | &clk_gate_test_hiword_suite, |
462 | &clk_gate_test_enabled_suite |
463 | ); |
464 | MODULE_LICENSE("GPL v2" ); |
465 | |