xref: /linux/drivers/clk/clk-divider_test.c (revision 502d45774af09f1c681c754c4b7cdfb5d7f72fd9)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * KUnit tests for clk_divider_bestdiv()
4  */
5 #include <kunit/test.h>
6 #include <linux/clk.h>
7 #include <linux/clk-provider.h>
8 #include <linux/limits.h>
9 #include <linux/units.h>
10 
11 #define PARENT_RATE_1GHZ	GIGA
12 #define PARENT_RATE_2GHZ	(2 * GIGA)
13 #define PARENT_RATE_4GHZ	(4 * GIGA)
14 
15 KUNIT_DEFINE_ACTION_WRAPPER(clk_hw_unregister_fixed_rate_wrapper,
16 			    clk_hw_unregister_fixed_rate, struct clk_hw *);
17 KUNIT_DEFINE_ACTION_WRAPPER(clk_hw_unregister_divider_wrapper,
18 			    clk_hw_unregister_divider, struct clk_hw *);
19 KUNIT_DEFINE_ACTION_WRAPPER(clk_hw_unregister_mux_wrapper,
20 			    clk_hw_unregister_mux, struct clk_hw *);
21 
22 static const struct clk_div_table bestdiv_table[] = {
23 	{ .val = 0, .div = 2 },
24 	{ .val = 1, .div = 4 },
25 	{ .val = 2, .div = 8 },
26 	{ /* sentinel */ }
27 };
28 
29 /*
30  * Test that clk_round_rate(clk, ULONG_MAX) returns the maximum achievable
31  * rate for a divider clock.
32  */
clk_divider_bestdiv_ulong_max_returns_max_rate(struct kunit * test)33 static void clk_divider_bestdiv_ulong_max_returns_max_rate(struct kunit *test)
34 {
35 	struct clk_hw *parent_hw, *div_hw;
36 	unsigned long rate;
37 	u32 *fake_reg;
38 
39 	fake_reg = kunit_kzalloc(test, sizeof(*fake_reg), GFP_KERNEL);
40 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_reg);
41 
42 	parent_hw = clk_hw_register_fixed_rate(NULL, "bestdiv-parent",
43 					       NULL, 0, PARENT_RATE_1GHZ);
44 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw);
45 	KUNIT_ASSERT_EQ(test, 0,
46 			kunit_add_action_or_reset(test, clk_hw_unregister_fixed_rate_wrapper,
47 						  parent_hw));
48 
49 	div_hw = clk_hw_register_divider_table(NULL, "bestdiv-div",
50 					       "bestdiv-parent",
51 					       CLK_SET_RATE_PARENT,
52 					       (void __iomem __force *)fake_reg,
53 					       0, 2, 0, bestdiv_table, NULL);
54 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, div_hw);
55 	KUNIT_ASSERT_EQ(test, 0,
56 			kunit_add_action_or_reset(test, clk_hw_unregister_divider_wrapper,
57 						  div_hw));
58 
59 	/*
60 	 * ULONG_MAX is the canonical way to probe the maximum rate a clock
61 	 * can produce.
62 	 */
63 	rate = clk_hw_round_rate(div_hw, ULONG_MAX);
64 	KUNIT_EXPECT_EQ(test, rate, PARENT_RATE_1GHZ / 2);
65 }
66 
67 /*
68  * Test that clk_round_rate(clk, ULONG_MAX) returns the correct maximum rate
69  * when a mux clock sits between a divider and its parent candidates.
70  *
71  * Topology:
72  *
73  *   [fixed 4 GHz] --\
74  *                    +--> [mux CLK_SET_RATE_PARENT] --> [div {2,4,8} CLK_SET_RATE_PARENT]
75  *   [fixed 2 GHz] --/
76  *
77  */
clk_divider_bestdiv_mux_ulong_max_returns_max_rate(struct kunit * test)78 static void clk_divider_bestdiv_mux_ulong_max_returns_max_rate(struct kunit *test)
79 {
80 	static const char * const mux_parents[] = {
81 		"bestdiv-mux-parent-a",
82 		"bestdiv-mux-parent-b",
83 	};
84 	struct clk_hw *parent_a_hw, *parent_b_hw, *mux_hw, *div_hw;
85 	u32 *fake_reg_mux, *fake_reg_div;
86 	unsigned long rate;
87 
88 	fake_reg_mux = kunit_kzalloc(test, sizeof(*fake_reg_mux), GFP_KERNEL);
89 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_reg_mux);
90 
91 	fake_reg_div = kunit_kzalloc(test, sizeof(*fake_reg_div), GFP_KERNEL);
92 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_reg_div);
93 
94 	/* Higher-rate parent: the mux should select this for ULONG_MAX. */
95 	parent_a_hw = clk_hw_register_fixed_rate(NULL, "bestdiv-mux-parent-a",
96 						 NULL, 0, PARENT_RATE_4GHZ);
97 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_a_hw);
98 	KUNIT_ASSERT_EQ(test, 0,
99 			kunit_add_action_or_reset(test, clk_hw_unregister_fixed_rate_wrapper,
100 						  parent_a_hw));
101 
102 	/* Lower-rate parent: should not be selected. */
103 	parent_b_hw = clk_hw_register_fixed_rate(NULL, "bestdiv-mux-parent-b",
104 						 NULL, 0, PARENT_RATE_2GHZ);
105 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_b_hw);
106 	KUNIT_ASSERT_EQ(test, 0,
107 			kunit_add_action_or_reset(test, clk_hw_unregister_fixed_rate_wrapper,
108 						  parent_b_hw));
109 
110 	/*
111 	 * 1-bit mux register selects between the two parents.
112 	 * CLK_SET_RATE_PARENT allows the divider's rate request to
113 	 * propagate into clk_mux_determine_rate().
114 	 */
115 	mux_hw = clk_hw_register_mux(NULL, "bestdiv-mux",
116 				     mux_parents, ARRAY_SIZE(mux_parents),
117 				     CLK_SET_RATE_PARENT,
118 				     (void __iomem __force *)fake_reg_mux,
119 				     0, 1, 0, NULL);
120 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mux_hw);
121 	KUNIT_ASSERT_EQ(test, 0,
122 			kunit_add_action_or_reset(test, clk_hw_unregister_mux_wrapper,
123 						  mux_hw));
124 
125 	div_hw = clk_hw_register_divider_table(NULL, "bestdiv-mux-div",
126 					       "bestdiv-mux",
127 					       CLK_SET_RATE_PARENT,
128 					       (void __iomem __force *)fake_reg_div,
129 					       0, 2, 0, bestdiv_table, NULL);
130 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, div_hw);
131 	KUNIT_ASSERT_EQ(test, 0,
132 			kunit_add_action_or_reset(test, clk_hw_unregister_divider_wrapper,
133 						  div_hw));
134 
135 	rate = clk_hw_round_rate(div_hw, ULONG_MAX);
136 	KUNIT_EXPECT_EQ(test, rate, PARENT_RATE_4GHZ / 2);
137 }
138 
139 static struct kunit_case clk_divider_bestdiv_test_cases[] = {
140 	KUNIT_CASE(clk_divider_bestdiv_ulong_max_returns_max_rate),
141 	KUNIT_CASE(clk_divider_bestdiv_mux_ulong_max_returns_max_rate),
142 	{}
143 };
144 
145 static struct kunit_suite clk_divider_bestdiv_test_suite = {
146 	.name = "clk_divider_bestdiv",
147 	.test_cases = clk_divider_bestdiv_test_cases,
148 };
149 
150 kunit_test_suite(clk_divider_bestdiv_test_suite);
151 
152 MODULE_DESCRIPTION("KUnit tests for clk divider");
153 MODULE_LICENSE("GPL");
154