/* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. * * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in *the the People's Republic of China and other countries. * All Allwinner Technology Co.,Ltd. trademarks are used with permission. * * DISCLAIMER * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY. * * * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __CLK_FACTORS_H__ #define __CLK_FACTORS_H__ #include "clk.h" struct sunxi_clk_factor_freq { u32 factor; u32 freq; }; #define FACTOR_ALL(nv, ns, nw, kv, ks, kw, mv, ms, mw, \ pv, ps, pw, d1v, d1s, d1w, d2v, d2s, d2w) \ ((((nv & ((1 << nw) - 1)) << ns) | \ ((kv & ((1 << kw) - 1)) << ks) | \ ((mv & ((1 << mw) - 1)) << ms) | \ ((pv & ((1 << pw) - 1)) << ps) | \ ((d1v & ((1 << d1w) - 1)) << d1s) | \ ((d2v & ((1 << d2w) - 1)) << d2s))) #define F_N8X8_P16x2(nv, pv) (FACTOR_ALL(nv, 8, 8, 0, 0, 0, 0, 0, 0, pv, 16, 2, 0, 0, 0, 0, 0, 0)) #define F_N8X8_D1V1X1_D2V0X1(nv, d1v, d2v) (FACTOR_ALL(nv, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, d1v, 1, 1, d2v, 0, 1)) #define F_N8X8_D1V1X1(nv, d1v) (FACTOR_ALL(nv, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, d1v, 1, 1, 0, 0, 0)) #define F_N8X8_D1V4X2_D2V0X2(nv, d1v, d2v) (FACTOR_ALL(nv, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, d1v, 4, 2, d2v, 0, 2)) #define F_N8X8_P16X6_D1V1X1_D2V0X1(nv, pv, d1v, d2v) (FACTOR_ALL(nv, 8, 8, 0, 0, 0, 0, 0, 0, pv, 16, 6, d1v, 1, 1, d2v, 0, 1)) #define PLLCPU(n, p, freq) {F_N8X8_P16x2(n, p), freq} #define PLLDDR(n, d1, d2, freq) {F_N8X8_D1V1X1_D2V0X1(n, d1, d2), freq} #define PLLPERIPH0(n, d1, d2, freq) {F_N8X8_D1V1X1_D2V0X1(n, d1, d2), freq} #define PLLPERIPH1(n, d1, d2, freq) {F_N8X8_D1V1X1_D2V0X1(n, d1, d2), freq} #define PLLVIDEO0(n, d1, freq) {F_N8X8_D1V1X1(n, d1), freq} #define PLLAUDIO(n, p, d1, d2, freq) {F_N8X8_P16X6_D1V1X1_D2V0X1(n, p, d1, d2), freq} #define PLLCSI(n, d1, freq) {F_N8X8_D1V1X1(n, d1), freq} #define PLLNPU(n, d1, freq) {F_N8X8_D1V1X1(n, d1), freq} #define SUNXI_CLK_FACTORS_CONFIG(name, _nshift, _nwidth, _kshift, _kwidth, \ _mshift, _mwidth, _pshift, _pwidth, _d1shift, _d1width, \ _d2shift, _d2width, _frac, _outshift, _modeshift, \ _enshift, _sdmshift, _sdmwidth, _sdmpat, _sdmval, \ _mux_inshift, _out_enshift) \ struct sunxi_clk_factors_config sunxi_clk_factor_config_##name = { \ .nshift = _nshift, \ .nwidth = _nwidth, \ .kshift = _kshift, \ .kwidth = _kwidth, \ .mshift = _mshift, \ .mwidth = _mwidth, \ .pshift = _pshift, \ .pwidth = _pwidth, \ .d1shift = _d1shift, \ .d1width = _d1width, \ .d2shift = _d2shift, \ .d2width = _d2width, \ .frac = _frac, \ .outshift = _outshift, \ .modeshift = _modeshift, \ .enshift = _enshift, \ .sdmshift = _sdmshift, \ .sdmwidth = _sdmwidth, \ .sdmpat = _sdmpat, \ .sdmval = _sdmval, \ .updshift = 0, \ .mux_inshift = _mux_inshift, \ .out_enshift = _out_enshift, \ } #define SUNXI_CLK_FACTORS_INIT(_name, _reg, _lock_reg, _lock_bit, _pll_lock_ctrl_reg, _lock_en_bit ) \ struct factor_init_data sunxi_clk_factor_init_##_name = { \ .reg =_reg, \ .lock_reg = _lock_reg, \ .pll_lock_ctrl_reg = _pll_lock_ctrl_reg, \ .lock_bit = _lock_bit, \ .lock_en_bit = _lock_en_bit, \ .lock_mode = PLL_LOCK_NEW_MODE, \ .config = &sunxi_clk_factor_config_##_name, \ .get_factors = &get_factors_##_name, \ .calc_rate = &calc_rate_##_name, \ } #define SUNXI_CLK_FACTOR(_name, _clk, _current_parent, _current_parent_type, _clk_rate, _parent_rate ) \ clk_factor_t sunxi_clk_factor_##_name = { \ .clk_core = { \ .clk = _clk, \ .clk_type = HAL_CLK_FACTOR, \ .current_parent = _current_parent, \ .current_parent_type = _current_parent_type, \ .clk_rate = _clk_rate, \ .parent_rate = _parent_rate, \ .clk_enbale = HAL_CLK_STATUS_DISABLED, \ }, \ .factor_data = &sunxi_clk_factor_init_##_name, \ } /*no-change-from-linux*/ typedef enum pll_lock_mode { PLL_LOCK_NEW_MODE = 0x0, PLL_LOCK_OLD_MODE, PLL_LOCK_NONE_MODE, PLL_LOCK_MODE_MAX, } pll_lock_mode_e; /** * struct clk_factors_value - factor value * * @factorn: factor-n value * @factork: factor-k value * @factorm: factor-m value * @factorp: factor-p value * @factord1: factor-d1 value * @factord2: factor-d2 value * @frac_mode: fraction mode value * @frac_freq: fraction frequnecy value */ /*no-change-from-linux*/ struct clk_factors_value { u16 factorn; u16 factork; u16 factorm; u16 factorp; u16 factord1; u16 factord2; u16 frac_mode; u16 frac_freq; }; /** * struct sunxi_clk_factors_config - factor config * * @nshift: shift to factor-n bit field * @nwidth: width of factor-n bit field * @kshift: shift to factor-k bit field * @kwidth: width of factor-k bit field * @mshift: shift to factor-m bit field * @mwidth: width of factor-m bit field * @pshift: shift to factor-p bit field * @pwidth: width of factor-p bit field * @d1shift: shift to factor-d1 bit field * @d1width: width of factor-d1 bit field * @d2shift: shift to factor-d2 bit field * @d2width: width of factor-d2 bit field * @frac: flag of fraction * @outshift: shift to frequency select bit field * @modeshift: shift to fraction/integer mode select * @enshift: shift to factor enable bit field * @lockshift: shift to factor lock status bit filed * @sdmshift: shift to factor sdm enable bit filed * @sdmwidth shift to factor sdm width bit filed * @sdmpat sdmpat reg address offset * @sdmval sdm default value * @updshift shift to update bit (especial for ddr/ddr0/ddr1) * @delay for flat factors delay. * @mux_inshift shift to multiplexer(multiple 24M source clocks) bit field * @out_enshift shift to enable pll clock output bit field */ /*no-change-from-linux*/ struct sunxi_clk_factors_config { u8 nshift; u8 nwidth; u8 kshift; u8 kwidth; u8 mshift; u8 mwidth; u8 pshift; u8 pwidth; u8 d1shift; u8 d1width; u8 d2shift; u8 d2width; u8 frac; u8 outshift; u8 modeshift; u8 enshift; u8 lockshift; u8 sdmshift; u8 sdmwidth; volatile uint32_t *sdmpat; u32 sdmval; u32 updshift; u32 delay; u32 mux_inshift; u32 out_enshift; }; /** * struct factor_init_data - factor init data * * @name: name of the clock * @parent_name:name of the parent * @num_parents:counter of the parents * @flags: factor optimal configurations * @reg: register address for the factor * @lock_reg: register address for check if the pll has locked * @lock_bit: bit offset of the lock_reg, to check if the the pll has locked * @pll_lock_ctrl_reg: pll lock control register, this function is first used on * the sun50i, to enable the function of pll hardlock * @lock_en_bit:bit offset of the pll_lock_ctrl_reg, to enable the function * @config: configuration of the factor * @get_factors:function for get factors parameter under a given frequency * @calc_rate: function for calculate the factor frequency * @priv_ops: private operations hook for the special factor * @priv_regops:register operation hook for read/write the register * */ struct factor_init_data { //const char *name; //const char **parent_names; //int num_parents; //unsigned long flags; volatile uint32_t *reg; volatile uint32_t *lock_reg; volatile uint32_t *pll_lock_ctrl_reg; u8 lock_bit; u8 lock_en_bit; pll_lock_mode_e lock_mode; struct sunxi_clk_factors_config *config; int (*get_factors)(u32 rate, u32 parent_rate, struct clk_factors_value *factor); int (*calc_rate)(u32 parent_rate, struct clk_factors_value *factor); //struct clk_ops *priv_ops; //struct sunxi_reg_ops *priv_regops; }; hal_clk_status_t sunxi_clk_fators_enable(clk_factor_pt clk); hal_clk_status_t sunxi_clk_fators_disable(clk_factor_pt clk); hal_clk_status_t sunxi_clk_fators_is_enabled(clk_factor_pt clk); hal_clk_status_t sunxi_clk_factors_recalc_rate(clk_factor_pt clk, u32 *rate); hal_clk_status_t sunxi_clk_factors_set_rate(clk_factor_pt clk, u32 rate); u32 sunxi_clk_factors_round_rate(clk_factor_pt clk, u32 rate); int sunxi_clk_com_ftr_sr(struct sunxi_clk_factors_config *f_config, struct clk_factors_value *factor, struct sunxi_clk_factor_freq table[], unsigned long index, unsigned long tbl_count); #endif