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