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 */ 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 */ 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