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