1 /* 2 * Copyright (c) 2026 Bojan Novković <bnovkov@FreeBSD.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 8 /* 9 * Common helper macros for the Spacemit K1 SoC clocks. 10 */ 11 12 #ifndef _K1_CLK_H_ 13 #define _K1_CLK_H_ 14 15 #include <dev/clk/clk.h> 16 17 /* 18 * Helper macro to count the number of parent clocks passed 19 * to the K1_CLK_COMMON macro. The maximum number of parents 20 * for the K1 clocks is 8. 21 */ 22 #define _K1_CLK_PARENT_CNT_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, N, ...) N 23 #define K1_CLK_PARENT_CNT(...) _K1_CLK_PARENT_CNT_IMPL(_, ## __VA_ARGS__, 8, \ 24 7, 6, 5, 4, 3, 2, 1, 0) 25 26 #define K1_CLK_COMMON(_clkname, _id, ...) \ 27 .clkdef = { \ 28 .id = _id, \ 29 .name = #_clkname, \ 30 .parent_names = (const char*[]) { __VA_ARGS__ }, \ 31 .parent_cnt = K1_CLK_PARENT_CNT(__VA_ARGS__), \ 32 } 33 34 #define K1_CLK_GATE(_clkname, _id, _reg, _gate_bit, ...) \ 35 { \ 36 K1_CLK_COMMON(_clkname, _id, __VA_ARGS__), \ 37 .reg = _reg, \ 38 .gate_mask = 1 << _gate_bit, \ 39 } 40 41 #define K1_CLK_DIV(_clkname, _id, _reg, _div_bits, _div_shift, \ 42 _fc_bit, ...) \ 43 { \ 44 K1_CLK_COMMON(_clkname, _id, __VA_ARGS__), \ 45 .reg = _reg, \ 46 .div_nbits = _div_bits, \ 47 .div_shift = _div_shift, \ 48 .fc_mask = 1 << _fc_bit, \ 49 } 50 51 #define K1_CLK_DIV_MUX(_clkname, _id, _reg, _div_bits, \ 52 _div_shift, _mux_nbits, _mux_shift, _fc_bit, ...) \ 53 { \ 54 K1_CLK_COMMON(_clkname, _id, __VA_ARGS__), \ 55 .reg = _reg, \ 56 .div_nbits = _div_bits, \ 57 .div_shift = _div_shift, \ 58 .mux_nbits = _mux_nbits, \ 59 .mux_shift = _mux_shift, \ 60 .fc_mask = 1 <<_fc_bit, \ 61 } 62 63 #define K1_CLK_DIV_GATE(_clkname, _id, _reg, _div_bits, _div_shift, \ 64 _gate_bit, ...) \ 65 { \ 66 K1_CLK_COMMON(_clkname, _id, __VA_ARGS__), \ 67 .reg = _reg, \ 68 .gate_mask = (1 << _gate_bit), \ 69 .div_nbits = _div_bits, \ 70 .div_shift = _div_shift, \ 71 } 72 73 #define K1_CLK_MUX_GATE(_clkname, _id, _reg, _mux_nbits, _mux_shift, \ 74 _gate_bit, ...) \ 75 { \ 76 K1_CLK_COMMON(_clkname, _id, __VA_ARGS__), \ 77 .reg = _reg, \ 78 .gate_mask = (1 << _gate_bit), \ 79 .mux_nbits = _mux_nbits, \ 80 .mux_shift = _mux_shift, \ 81 } 82 83 #define K1_CLK_DIV_MUX_GATE(_clkname, _id, _reg, _div_bits, \ 84 _div_shift, _mux_nbits, _mux_shift, \ 85 _gate_bit, _fc_bit, ...) \ 86 { \ 87 K1_CLK_COMMON(_clkname, _id, __VA_ARGS__), \ 88 .reg = _reg, \ 89 .gate_mask = (1 << _gate_bit), \ 90 .div_nbits = _div_bits, \ 91 .div_shift = _div_shift, \ 92 .mux_nbits = _mux_nbits, \ 93 .mux_shift = _mux_shift, \ 94 .fc_mask = 1 <<_fc_bit, \ 95 } 96 97 #define K1_RESET(_id, _reg, _assert_bit, _deassert_bit) \ 98 [_id] = { \ 99 .reg = _reg, \ 100 .assert_mask = (1 << _assert_bit), \ 101 .deassert_mask = (1 << _deassert_bit), \ 102 } 103 104 struct k1_clk_def { 105 struct clknode_init_def clkdef; 106 107 uint64_t rate; /* Fixed clock frequency. */ 108 uint32_t fixed_div; /* Fixed clock divisor. */ 109 uint32_t reg; /* Control register offset.*/ 110 uint32_t div_nbits; /* Frequency divisor. */ 111 uint32_t div_shift; 112 uint32_t gate_mask; /* Gate bit. */ 113 uint32_t mux_nbits; /* Multiplexer offset. */ 114 uint32_t mux_shift; 115 uint32_t fc_mask; /* Frequency change request bit. */ 116 }; 117 118 struct k1_reset_def { 119 uint32_t reg; 120 uint32_t assert_mask; 121 uint32_t deassert_mask; 122 }; 123 124 struct k1_clkdev_softc { 125 struct mtx mtx; 126 struct clkdom *clkdom; 127 struct resource *res; 128 129 const struct k1_clk_def *clks; 130 const struct k1_reset_def *resets; 131 int nclks; 132 int nresets; 133 134 /* 135 * Allow derived clknode implementations to 136 * override the generic K1 clock routines. 137 */ 138 clknode_class_t clknode_class; 139 }; 140 141 DECLARE_CLASS(k1_clkdev_driver); 142 DECLARE_CLASS(k1_clknode_class); 143 144 int k1_clk_attach(device_t dev); 145 146 #endif 147