xref: /linux/drivers/clk/clk-divider_test.c (revision 502d45774af09f1c681c754c4b7cdfb5d7f72fd9)
150ca555dSLad Prabhakar // SPDX-License-Identifier: GPL-2.0
250ca555dSLad Prabhakar /*
350ca555dSLad Prabhakar  * KUnit tests for clk_divider_bestdiv()
450ca555dSLad Prabhakar  */
550ca555dSLad Prabhakar #include <kunit/test.h>
650ca555dSLad Prabhakar #include <linux/clk.h>
750ca555dSLad Prabhakar #include <linux/clk-provider.h>
850ca555dSLad Prabhakar #include <linux/limits.h>
950ca555dSLad Prabhakar #include <linux/units.h>
1050ca555dSLad Prabhakar 
1150ca555dSLad Prabhakar #define PARENT_RATE_1GHZ	GIGA
1250ca555dSLad Prabhakar #define PARENT_RATE_2GHZ	(2 * GIGA)
1350ca555dSLad Prabhakar #define PARENT_RATE_4GHZ	(4 * GIGA)
1450ca555dSLad Prabhakar 
1550ca555dSLad Prabhakar KUNIT_DEFINE_ACTION_WRAPPER(clk_hw_unregister_fixed_rate_wrapper,
1650ca555dSLad Prabhakar 			    clk_hw_unregister_fixed_rate, struct clk_hw *);
1750ca555dSLad Prabhakar KUNIT_DEFINE_ACTION_WRAPPER(clk_hw_unregister_divider_wrapper,
1850ca555dSLad Prabhakar 			    clk_hw_unregister_divider, struct clk_hw *);
1950ca555dSLad Prabhakar KUNIT_DEFINE_ACTION_WRAPPER(clk_hw_unregister_mux_wrapper,
2050ca555dSLad Prabhakar 			    clk_hw_unregister_mux, struct clk_hw *);
2150ca555dSLad Prabhakar 
2250ca555dSLad Prabhakar static const struct clk_div_table bestdiv_table[] = {
2350ca555dSLad Prabhakar 	{ .val = 0, .div = 2 },
2450ca555dSLad Prabhakar 	{ .val = 1, .div = 4 },
2550ca555dSLad Prabhakar 	{ .val = 2, .div = 8 },
2650ca555dSLad Prabhakar 	{ /* sentinel */ }
2750ca555dSLad Prabhakar };
2850ca555dSLad Prabhakar 
2950ca555dSLad Prabhakar /*
3050ca555dSLad Prabhakar  * Test that clk_round_rate(clk, ULONG_MAX) returns the maximum achievable
3150ca555dSLad Prabhakar  * rate for a divider clock.
3250ca555dSLad Prabhakar  */
clk_divider_bestdiv_ulong_max_returns_max_rate(struct kunit * test)3350ca555dSLad Prabhakar static void clk_divider_bestdiv_ulong_max_returns_max_rate(struct kunit *test)
3450ca555dSLad Prabhakar {
3550ca555dSLad Prabhakar 	struct clk_hw *parent_hw, *div_hw;
3650ca555dSLad Prabhakar 	unsigned long rate;
3750ca555dSLad Prabhakar 	u32 *fake_reg;
3850ca555dSLad Prabhakar 
3950ca555dSLad Prabhakar 	fake_reg = kunit_kzalloc(test, sizeof(*fake_reg), GFP_KERNEL);
4050ca555dSLad Prabhakar 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_reg);
4150ca555dSLad Prabhakar 
4250ca555dSLad Prabhakar 	parent_hw = clk_hw_register_fixed_rate(NULL, "bestdiv-parent",
4350ca555dSLad Prabhakar 					       NULL, 0, PARENT_RATE_1GHZ);
4450ca555dSLad Prabhakar 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw);
4550ca555dSLad Prabhakar 	KUNIT_ASSERT_EQ(test, 0,
4650ca555dSLad Prabhakar 			kunit_add_action_or_reset(test, clk_hw_unregister_fixed_rate_wrapper,
4750ca555dSLad Prabhakar 						  parent_hw));
4850ca555dSLad Prabhakar 
4950ca555dSLad Prabhakar 	div_hw = clk_hw_register_divider_table(NULL, "bestdiv-div",
5050ca555dSLad Prabhakar 					       "bestdiv-parent",
5150ca555dSLad Prabhakar 					       CLK_SET_RATE_PARENT,
5250ca555dSLad Prabhakar 					       (void __iomem __force *)fake_reg,
5350ca555dSLad Prabhakar 					       0, 2, 0, bestdiv_table, NULL);
5450ca555dSLad Prabhakar 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, div_hw);
5550ca555dSLad Prabhakar 	KUNIT_ASSERT_EQ(test, 0,
5650ca555dSLad Prabhakar 			kunit_add_action_or_reset(test, clk_hw_unregister_divider_wrapper,
5750ca555dSLad Prabhakar 						  div_hw));
5850ca555dSLad Prabhakar 
5950ca555dSLad Prabhakar 	/*
6050ca555dSLad Prabhakar 	 * ULONG_MAX is the canonical way to probe the maximum rate a clock
6150ca555dSLad Prabhakar 	 * can produce.
6250ca555dSLad Prabhakar 	 */
6350ca555dSLad Prabhakar 	rate = clk_hw_round_rate(div_hw, ULONG_MAX);
64*e129a400SLad Prabhakar 	KUNIT_EXPECT_EQ(test, rate, PARENT_RATE_1GHZ / 2);
6550ca555dSLad Prabhakar }
6650ca555dSLad Prabhakar 
6750ca555dSLad Prabhakar /*
6850ca555dSLad Prabhakar  * Test that clk_round_rate(clk, ULONG_MAX) returns the correct maximum rate
6950ca555dSLad Prabhakar  * when a mux clock sits between a divider and its parent candidates.
7050ca555dSLad Prabhakar  *
7150ca555dSLad Prabhakar  * Topology:
7250ca555dSLad Prabhakar  *
7350ca555dSLad Prabhakar  *   [fixed 4 GHz] --\
7450ca555dSLad Prabhakar  *                    +--> [mux CLK_SET_RATE_PARENT] --> [div {2,4,8} CLK_SET_RATE_PARENT]
7550ca555dSLad Prabhakar  *   [fixed 2 GHz] --/
7650ca555dSLad Prabhakar  *
7750ca555dSLad Prabhakar  */
clk_divider_bestdiv_mux_ulong_max_returns_max_rate(struct kunit * test)7850ca555dSLad Prabhakar static void clk_divider_bestdiv_mux_ulong_max_returns_max_rate(struct kunit *test)
7950ca555dSLad Prabhakar {
8050ca555dSLad Prabhakar 	static const char * const mux_parents[] = {
8150ca555dSLad Prabhakar 		"bestdiv-mux-parent-a",
8250ca555dSLad Prabhakar 		"bestdiv-mux-parent-b",
8350ca555dSLad Prabhakar 	};
8450ca555dSLad Prabhakar 	struct clk_hw *parent_a_hw, *parent_b_hw, *mux_hw, *div_hw;
8550ca555dSLad Prabhakar 	u32 *fake_reg_mux, *fake_reg_div;
8650ca555dSLad Prabhakar 	unsigned long rate;
8750ca555dSLad Prabhakar 
8850ca555dSLad Prabhakar 	fake_reg_mux = kunit_kzalloc(test, sizeof(*fake_reg_mux), GFP_KERNEL);
8950ca555dSLad Prabhakar 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_reg_mux);
9050ca555dSLad Prabhakar 
9150ca555dSLad Prabhakar 	fake_reg_div = kunit_kzalloc(test, sizeof(*fake_reg_div), GFP_KERNEL);
9250ca555dSLad Prabhakar 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_reg_div);
9350ca555dSLad Prabhakar 
9450ca555dSLad Prabhakar 	/* Higher-rate parent: the mux should select this for ULONG_MAX. */
9550ca555dSLad Prabhakar 	parent_a_hw = clk_hw_register_fixed_rate(NULL, "bestdiv-mux-parent-a",
9650ca555dSLad Prabhakar 						 NULL, 0, PARENT_RATE_4GHZ);
9750ca555dSLad Prabhakar 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_a_hw);
9850ca555dSLad Prabhakar 	KUNIT_ASSERT_EQ(test, 0,
9950ca555dSLad Prabhakar 			kunit_add_action_or_reset(test, clk_hw_unregister_fixed_rate_wrapper,
10050ca555dSLad Prabhakar 						  parent_a_hw));
10150ca555dSLad Prabhakar 
10250ca555dSLad Prabhakar 	/* Lower-rate parent: should not be selected. */
10350ca555dSLad Prabhakar 	parent_b_hw = clk_hw_register_fixed_rate(NULL, "bestdiv-mux-parent-b",
10450ca555dSLad Prabhakar 						 NULL, 0, PARENT_RATE_2GHZ);
10550ca555dSLad Prabhakar 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_b_hw);
10650ca555dSLad Prabhakar 	KUNIT_ASSERT_EQ(test, 0,
10750ca555dSLad Prabhakar 			kunit_add_action_or_reset(test, clk_hw_unregister_fixed_rate_wrapper,
10850ca555dSLad Prabhakar 						  parent_b_hw));
10950ca555dSLad Prabhakar 
11050ca555dSLad Prabhakar 	/*
11150ca555dSLad Prabhakar 	 * 1-bit mux register selects between the two parents.
11250ca555dSLad Prabhakar 	 * CLK_SET_RATE_PARENT allows the divider's rate request to
11350ca555dSLad Prabhakar 	 * propagate into clk_mux_determine_rate().
11450ca555dSLad Prabhakar 	 */
11550ca555dSLad Prabhakar 	mux_hw = clk_hw_register_mux(NULL, "bestdiv-mux",
11650ca555dSLad Prabhakar 				     mux_parents, ARRAY_SIZE(mux_parents),
11750ca555dSLad Prabhakar 				     CLK_SET_RATE_PARENT,
11850ca555dSLad Prabhakar 				     (void __iomem __force *)fake_reg_mux,
11950ca555dSLad Prabhakar 				     0, 1, 0, NULL);
12050ca555dSLad Prabhakar 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mux_hw);
12150ca555dSLad Prabhakar 	KUNIT_ASSERT_EQ(test, 0,
12250ca555dSLad Prabhakar 			kunit_add_action_or_reset(test, clk_hw_unregister_mux_wrapper,
12350ca555dSLad Prabhakar 						  mux_hw));
12450ca555dSLad Prabhakar 
12550ca555dSLad Prabhakar 	div_hw = clk_hw_register_divider_table(NULL, "bestdiv-mux-div",
12650ca555dSLad Prabhakar 					       "bestdiv-mux",
12750ca555dSLad Prabhakar 					       CLK_SET_RATE_PARENT,
12850ca555dSLad Prabhakar 					       (void __iomem __force *)fake_reg_div,
12950ca555dSLad Prabhakar 					       0, 2, 0, bestdiv_table, NULL);
13050ca555dSLad Prabhakar 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, div_hw);
13150ca555dSLad Prabhakar 	KUNIT_ASSERT_EQ(test, 0,
13250ca555dSLad Prabhakar 			kunit_add_action_or_reset(test, clk_hw_unregister_divider_wrapper,
13350ca555dSLad Prabhakar 						  div_hw));
13450ca555dSLad Prabhakar 
13550ca555dSLad Prabhakar 	rate = clk_hw_round_rate(div_hw, ULONG_MAX);
136*e129a400SLad Prabhakar 	KUNIT_EXPECT_EQ(test, rate, PARENT_RATE_4GHZ / 2);
13750ca555dSLad Prabhakar }
13850ca555dSLad Prabhakar 
13950ca555dSLad Prabhakar static struct kunit_case clk_divider_bestdiv_test_cases[] = {
14050ca555dSLad Prabhakar 	KUNIT_CASE(clk_divider_bestdiv_ulong_max_returns_max_rate),
14150ca555dSLad Prabhakar 	KUNIT_CASE(clk_divider_bestdiv_mux_ulong_max_returns_max_rate),
14250ca555dSLad Prabhakar 	{}
14350ca555dSLad Prabhakar };
14450ca555dSLad Prabhakar 
14550ca555dSLad Prabhakar static struct kunit_suite clk_divider_bestdiv_test_suite = {
14650ca555dSLad Prabhakar 	.name = "clk_divider_bestdiv",
14750ca555dSLad Prabhakar 	.test_cases = clk_divider_bestdiv_test_cases,
14850ca555dSLad Prabhakar };
14950ca555dSLad Prabhakar 
15050ca555dSLad Prabhakar kunit_test_suite(clk_divider_bestdiv_test_suite);
15150ca555dSLad Prabhakar 
15250ca555dSLad Prabhakar MODULE_DESCRIPTION("KUnit tests for clk divider");
15350ca555dSLad Prabhakar MODULE_LICENSE("GPL");
154