| /* SPDX-License-Identifier: GPL-2.0 */ |
| /* |
| * Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd.. |
| * All rights reserved. |
| * |
| * Authors: |
| * Yifeng Huang <huangyifeng@eswincomputing.com> |
| * Xuyang Dong <dongxuyang@eswincomputing.com> |
| */ |
| |
| #ifndef __ESWIN_COMMON_H__ |
| #define __ESWIN_COMMON_H__ |
| |
| #define APLL_HIGH_FREQ 983040000 |
| #define APLL_LOW_FREQ 225792000 |
| #define PLL_HIGH_FREQ 1800000000 |
| #define PLL_LOW_FREQ 24000000 |
| |
| /* |
| * ESWIN_PRIV_DIV_MIN_2: If ESWIN_PRIV_DIV_MIN_2 is set, the minimum value of |
| * the register is 2, i.e. the minimum division ratio is 2. |
| */ |
| #define ESWIN_PRIV_DIV_MIN_2 BIT(0) |
| |
| enum eswin_clk_type { |
| CLK_FIXED_FACTOR, |
| CLK_MUX, |
| CLK_DIVIDER, |
| CLK_GATE, |
| }; |
| |
| struct eswin_clock_data { |
| void __iomem *base; |
| struct clk_hw *original_clk; |
| struct notifier_block pll_nb; |
| spinlock_t lock; /* protect register read-modify-write cycle */ |
| struct clk_hw_onecell_data clk_data; |
| }; |
| |
| struct eswin_divider_clock { |
| struct clk_hw hw; |
| unsigned int id; |
| const char *name; |
| const struct clk_parent_data *parent_data; |
| void __iomem *ctrl_reg; /* register address of the divider clock */ |
| unsigned long flags; |
| unsigned long reg; /* register offset */ |
| u8 shift; |
| u8 width; |
| unsigned long div_flags; |
| unsigned long priv_flag; |
| spinlock_t *lock; /* protect register read-modify-write cycle */ |
| }; |
| |
| struct eswin_fixed_rate_clock { |
| struct clk_hw hw; |
| unsigned int id; |
| const char *name; |
| unsigned long flags; |
| unsigned long rate; |
| }; |
| |
| struct eswin_fixed_factor_clock { |
| struct clk_hw hw; |
| unsigned int id; |
| const char *name; |
| const struct clk_parent_data *parent_data; |
| unsigned long mult; |
| unsigned long div; |
| unsigned long flags; |
| }; |
| |
| struct eswin_gate_clock { |
| struct clk_hw hw; |
| unsigned int id; |
| const char *name; |
| const struct clk_parent_data *parent_data; |
| unsigned long flags; |
| unsigned long reg; |
| u8 bit_idx; |
| u8 gate_flags; |
| }; |
| |
| struct eswin_mux_clock { |
| struct clk_hw hw; |
| unsigned int id; |
| const char *name; |
| const struct clk_parent_data *parent_data; |
| u8 num_parents; |
| unsigned long flags; |
| unsigned long reg; |
| u8 shift; |
| u8 width; |
| u8 mux_flags; |
| u32 *table; |
| }; |
| |
| struct eswin_pll_clock { |
| struct clk_hw hw; |
| u32 id; |
| const char *name; |
| const struct clk_parent_data *parent_data; |
| const u32 ctrl_reg0; |
| const u8 fbdiv_shift; |
| |
| const u32 ctrl_reg1; |
| const u8 frac_shift; |
| |
| const u32 ctrl_reg2; |
| |
| const u32 status_reg; |
| const u8 lock_shift; |
| const u8 lock_width; |
| |
| const u64 max_rate; |
| const u64 min_rate; |
| }; |
| |
| struct eswin_clk_pll { |
| struct clk_hw hw; |
| u32 id; |
| void __iomem *ctrl_reg0; |
| u8 fbdiv_shift; |
| |
| void __iomem *ctrl_reg1; |
| u8 frac_shift; |
| |
| void __iomem *ctrl_reg2; |
| |
| void __iomem *status_reg; |
| u8 lock_shift; |
| u8 lock_width; |
| |
| u64 max_rate; |
| u64 min_rate; |
| }; |
| |
| struct eswin_clk_info { |
| unsigned int type; |
| unsigned int pid; |
| unsigned int id; |
| struct clk_hw hw; |
| union { |
| struct eswin_divider_clock div; |
| struct eswin_fixed_factor_clock factor; |
| struct eswin_gate_clock gate; |
| struct eswin_mux_clock mux; |
| } data; |
| }; |
| |
| struct eswin_clock_data *eswin_clk_init(struct platform_device *pdev, |
| size_t nr_clks); |
| int eswin_clk_register_fixed_rate(struct device *dev, |
| struct eswin_fixed_rate_clock *clks, |
| int nums, struct eswin_clock_data *data); |
| int eswin_clk_register_pll(struct device *dev, struct eswin_pll_clock *clks, |
| int nums, struct eswin_clock_data *data); |
| int eswin_clk_register_fixed_factor(struct device *dev, |
| struct eswin_fixed_factor_clock *clks, |
| int nums, struct eswin_clock_data *data); |
| int eswin_clk_register_mux(struct device *dev, struct eswin_mux_clock *clks, |
| int nums, struct eswin_clock_data *data); |
| int eswin_clk_register_divider(struct device *dev, |
| struct eswin_divider_clock *clks, |
| int nums, struct eswin_clock_data *data); |
| int eswin_clk_register_gate(struct device *dev, struct eswin_gate_clock *clks, |
| int nums, struct eswin_clock_data *data); |
| int eswin_clk_register_clks(struct device *dev, struct eswin_clk_info *clks, |
| int nums, struct eswin_clock_data *data); |
| struct clk_hw *eswin_register_clkdiv(struct device *dev, unsigned int id, |
| const char *name, |
| const struct clk_hw *parent_hw, |
| unsigned long flags, void __iomem *reg, |
| u8 shift, u8 width, |
| unsigned long clk_divider_flags, |
| unsigned long priv_flag, spinlock_t *lock); |
| |
| #define ESWIN_DIV(_id, _name, _pdata, _flags, _reg, _shift, _width, \ |
| _dflags, _pflag) \ |
| { \ |
| .id = _id, \ |
| .name = _name, \ |
| .parent_data = _pdata, \ |
| .flags = _flags, \ |
| .reg = _reg, \ |
| .shift = _shift, \ |
| .width = _width, \ |
| .div_flags = _dflags, \ |
| .priv_flag = _pflag, \ |
| } |
| |
| #define ESWIN_DIV_TYPE(_id, _name, _pid, _flags, _reg, _shift, _width, \ |
| _dflags, _pflag) \ |
| { \ |
| .type = CLK_DIVIDER, \ |
| .pid = _pid, \ |
| .id = _id, \ |
| .data = { \ |
| .div = { \ |
| .name = _name, \ |
| .flags = _flags, \ |
| .reg = _reg, \ |
| .shift = _shift, \ |
| .width = _width, \ |
| .div_flags = _dflags, \ |
| .priv_flag = _pflag, \ |
| }, \ |
| }, \ |
| } |
| |
| #define ESWIN_FACTOR(_id, _name, _pdata, _mult, _div, _flags) \ |
| { \ |
| .id = _id, \ |
| .name = _name, \ |
| .parent_data = _pdata, \ |
| .mult = _mult, \ |
| .div = _div, \ |
| .flags = _flags, \ |
| } |
| |
| #define ESWIN_FACTOR_TYPE(_id, _name, _pid, _mult, _div, _flags) \ |
| { \ |
| .type = CLK_FIXED_FACTOR, \ |
| .pid = _pid, \ |
| .id = _id, \ |
| .data = { \ |
| .factor = { \ |
| .name = _name, \ |
| .mult = _mult, \ |
| .div = _div, \ |
| .flags = _flags, \ |
| }, \ |
| }, \ |
| } |
| |
| #define ESWIN_FIXED(_id, _name, _flags, _rate) \ |
| { \ |
| .id = _id, \ |
| .name = _name, \ |
| .flags = _flags, \ |
| .rate = _rate, \ |
| } |
| |
| #define ESWIN_GATE(_id, _name, _pdata, _flags, _reg, _idx, _gflags) \ |
| { \ |
| .id = _id, \ |
| .name = _name, \ |
| .parent_data = _pdata, \ |
| .flags = _flags, \ |
| .reg = _reg, \ |
| .bit_idx = _idx, \ |
| .gate_flags = _gflags, \ |
| } |
| |
| #define ESWIN_GATE_TYPE(_id, _name, _pid, _flags, _reg, _idx, _gflags) \ |
| { \ |
| .type = CLK_GATE, \ |
| .pid = _pid, \ |
| .id = _id, \ |
| .data = { \ |
| .gate = { \ |
| .name = _name, \ |
| .flags = _flags, \ |
| .reg = _reg, \ |
| .bit_idx = _idx, \ |
| .gate_flags = _gflags, \ |
| }, \ |
| }, \ |
| } |
| |
| #define ESWIN_MUX(_id, _name, _pdata, _num_parents, _flags, _reg, \ |
| _shift, _width, _mflags) \ |
| { \ |
| .id = _id, \ |
| .name = _name, \ |
| .parent_data = _pdata, \ |
| .num_parents = _num_parents, \ |
| .flags = _flags, \ |
| .reg = _reg, \ |
| .shift = _shift, \ |
| .width = _width, \ |
| .mux_flags = _mflags, \ |
| .table = NULL, \ |
| } |
| |
| #define ESWIN_MUX_TBL(_id, _name, _pdata, _num_parents, _flags, _reg, \ |
| _shift, _width, _mflags, _table) \ |
| { \ |
| .id = _id, \ |
| .name = _name, \ |
| .parent_data = _pdata, \ |
| .num_parents = _num_parents, \ |
| .flags = _flags, \ |
| .reg = _reg, \ |
| .shift = _shift, \ |
| .width = _width, \ |
| .mux_flags = _mflags, \ |
| .table = _table, \ |
| } |
| |
| #define ESWIN_MUX_TYPE(_id, _name, _pdata, _num_parents, _flags, _reg, \ |
| _shift, _width, _mflags, _table) \ |
| { \ |
| .type = CLK_MUX, \ |
| .id = _id, \ |
| .data = { \ |
| .mux = { \ |
| .name = _name, \ |
| .parent_data = _pdata, \ |
| .num_parents = _num_parents, \ |
| .flags = _flags, \ |
| .reg = _reg, \ |
| .shift = _shift, \ |
| .width = _width, \ |
| .mux_flags = _mflags, \ |
| .table = _table, \ |
| }, \ |
| }, \ |
| } |
| |
| #define ESWIN_PLL(_id, _name, _pdata, _reg0, _fb_shift, _reg1, \ |
| _frac_shift, _reg2, _reg, _lock_shift, _lock_width, \ |
| _max_rate, _min_rate) \ |
| { \ |
| .id = _id, \ |
| .name = _name, \ |
| .parent_data = _pdata, \ |
| .ctrl_reg0 = _reg0, \ |
| .fbdiv_shift = _fb_shift, \ |
| .ctrl_reg1 = _reg1, \ |
| .frac_shift = _frac_shift, \ |
| .ctrl_reg2 = _reg2, \ |
| .status_reg = _reg, \ |
| .lock_shift = _lock_shift, \ |
| .lock_width = _lock_width, \ |
| .max_rate = _max_rate, \ |
| .min_rate = _min_rate, \ |
| } |
| |
| #endif /* __ESWIN_COMMON_H__ */ |