| /* SPDX-License-Identifier: GPL-2.0 */ |
| #ifndef __MACH_MMP_CLK_H |
| #define __MACH_MMP_CLK_H |
| |
| #include <linux/clk-provider.h> |
| #include <linux/pm_domain.h> |
| #include <linux/clkdev.h> |
| |
| #define APBC_NO_BUS_CTRL BIT(0) |
| #define APBC_POWER_CTRL BIT(1) |
| |
| |
| /* Clock type "factor" */ |
| struct mmp_clk_factor_masks { |
| unsigned int factor; |
| unsigned int num_mask; |
| unsigned int den_mask; |
| unsigned int num_shift; |
| unsigned int den_shift; |
| unsigned int enable_mask; |
| }; |
| |
| struct mmp_clk_factor_tbl { |
| unsigned int num; |
| unsigned int den; |
| }; |
| |
| struct mmp_clk_factor { |
| struct clk_hw hw; |
| void __iomem *base; |
| struct mmp_clk_factor_masks *masks; |
| struct mmp_clk_factor_tbl *ftbl; |
| unsigned int ftbl_cnt; |
| spinlock_t *lock; |
| }; |
| |
| extern struct clk *mmp_clk_register_factor(const char *name, |
| const char *parent_name, unsigned long flags, |
| void __iomem *base, struct mmp_clk_factor_masks *masks, |
| struct mmp_clk_factor_tbl *ftbl, unsigned int ftbl_cnt, |
| spinlock_t *lock); |
| |
| /* Clock type "mix" */ |
| #define MMP_CLK_BITS_MASK(width, shift) \ |
| (((1 << (width)) - 1) << (shift)) |
| #define MMP_CLK_BITS_GET_VAL(data, width, shift) \ |
| ((data & MMP_CLK_BITS_MASK(width, shift)) >> (shift)) |
| #define MMP_CLK_BITS_SET_VAL(val, width, shift) \ |
| (((val) << (shift)) & MMP_CLK_BITS_MASK(width, shift)) |
| |
| enum { |
| MMP_CLK_MIX_TYPE_V1, |
| MMP_CLK_MIX_TYPE_V2, |
| MMP_CLK_MIX_TYPE_V3, |
| }; |
| |
| /* The register layout */ |
| struct mmp_clk_mix_reg_info { |
| void __iomem *reg_clk_ctrl; |
| void __iomem *reg_clk_sel; |
| u8 width_div; |
| u8 shift_div; |
| u8 width_mux; |
| u8 shift_mux; |
| u8 bit_fc; |
| }; |
| |
| /* The suggested clock table from user. */ |
| struct mmp_clk_mix_clk_table { |
| unsigned long rate; |
| u8 parent_index; |
| unsigned int divisor; |
| unsigned int valid; |
| }; |
| |
| struct mmp_clk_mix_config { |
| struct mmp_clk_mix_reg_info reg_info; |
| struct mmp_clk_mix_clk_table *table; |
| unsigned int table_size; |
| u32 *mux_table; |
| struct clk_div_table *div_table; |
| u8 div_flags; |
| u8 mux_flags; |
| }; |
| |
| struct mmp_clk_mix { |
| struct clk_hw hw; |
| struct mmp_clk_mix_reg_info reg_info; |
| struct mmp_clk_mix_clk_table *table; |
| u32 *mux_table; |
| struct clk_div_table *div_table; |
| unsigned int table_size; |
| u8 div_flags; |
| u8 mux_flags; |
| unsigned int type; |
| spinlock_t *lock; |
| }; |
| |
| extern const struct clk_ops mmp_clk_mix_ops; |
| extern struct clk *mmp_clk_register_mix(struct device *dev, |
| const char *name, |
| const char * const *parent_names, |
| u8 num_parents, |
| unsigned long flags, |
| struct mmp_clk_mix_config *config, |
| spinlock_t *lock); |
| |
| |
| /* Clock type "gate". MMP private gate */ |
| #define MMP_CLK_GATE_NEED_DELAY BIT(0) |
| |
| struct mmp_clk_gate { |
| struct clk_hw hw; |
| void __iomem *reg; |
| u32 mask; |
| u32 val_enable; |
| u32 val_disable; |
| unsigned int flags; |
| spinlock_t *lock; |
| }; |
| |
| extern const struct clk_ops mmp_clk_gate_ops; |
| extern struct clk *mmp_clk_register_gate(struct device *dev, const char *name, |
| const char *parent_name, unsigned long flags, |
| void __iomem *reg, u32 mask, u32 val_enable, |
| u32 val_disable, unsigned int gate_flags, |
| spinlock_t *lock); |
| |
| extern struct clk *mmp_clk_register_apbc(const char *name, |
| const char *parent_name, void __iomem *base, |
| unsigned int delay, unsigned int apbc_flags, spinlock_t *lock); |
| extern struct clk *mmp_clk_register_apmu(const char *name, |
| const char *parent_name, void __iomem *base, u32 enable_mask, |
| spinlock_t *lock); |
| |
| struct mmp_clk_unit { |
| unsigned int nr_clks; |
| struct clk **clk_table; |
| struct clk_onecell_data clk_data; |
| }; |
| |
| struct mmp_param_fixed_rate_clk { |
| unsigned int id; |
| char *name; |
| const char *parent_name; |
| unsigned long flags; |
| unsigned long fixed_rate; |
| }; |
| void mmp_register_fixed_rate_clks(struct mmp_clk_unit *unit, |
| struct mmp_param_fixed_rate_clk *clks, |
| int size); |
| |
| struct mmp_param_fixed_factor_clk { |
| unsigned int id; |
| char *name; |
| const char *parent_name; |
| unsigned long mult; |
| unsigned long div; |
| unsigned long flags; |
| }; |
| void mmp_register_fixed_factor_clks(struct mmp_clk_unit *unit, |
| struct mmp_param_fixed_factor_clk *clks, |
| int size); |
| |
| struct mmp_param_general_gate_clk { |
| unsigned int id; |
| const char *name; |
| const char *parent_name; |
| unsigned long flags; |
| unsigned long offset; |
| u8 bit_idx; |
| u8 gate_flags; |
| spinlock_t *lock; |
| }; |
| void mmp_register_general_gate_clks(struct mmp_clk_unit *unit, |
| struct mmp_param_general_gate_clk *clks, |
| void __iomem *base, int size); |
| |
| struct mmp_param_gate_clk { |
| unsigned int id; |
| char *name; |
| const char *parent_name; |
| unsigned long flags; |
| unsigned long offset; |
| u32 mask; |
| u32 val_enable; |
| u32 val_disable; |
| unsigned int gate_flags; |
| spinlock_t *lock; |
| }; |
| void mmp_register_gate_clks(struct mmp_clk_unit *unit, |
| struct mmp_param_gate_clk *clks, |
| void __iomem *base, int size); |
| |
| struct mmp_param_mux_clk { |
| unsigned int id; |
| char *name; |
| const char * const *parent_name; |
| u8 num_parents; |
| unsigned long flags; |
| unsigned long offset; |
| u8 shift; |
| u8 width; |
| u8 mux_flags; |
| spinlock_t *lock; |
| }; |
| void mmp_register_mux_clks(struct mmp_clk_unit *unit, |
| struct mmp_param_mux_clk *clks, |
| void __iomem *base, int size); |
| |
| struct mmp_param_div_clk { |
| unsigned int id; |
| char *name; |
| const char *parent_name; |
| unsigned long flags; |
| unsigned long offset; |
| u8 shift; |
| u8 width; |
| u8 div_flags; |
| spinlock_t *lock; |
| }; |
| void mmp_register_div_clks(struct mmp_clk_unit *unit, |
| struct mmp_param_div_clk *clks, |
| void __iomem *base, int size); |
| |
| struct mmp_param_pll_clk { |
| unsigned int id; |
| char *name; |
| unsigned long default_rate; |
| unsigned long enable_offset; |
| u32 enable; |
| unsigned long offset; |
| u8 shift; |
| /* MMP3 specific: */ |
| unsigned long input_rate; |
| unsigned long postdiv_offset; |
| unsigned long postdiv_shift; |
| }; |
| void mmp_register_pll_clks(struct mmp_clk_unit *unit, |
| struct mmp_param_pll_clk *clks, |
| void __iomem *base, int size); |
| |
| #define DEFINE_MIX_REG_INFO(w_d, s_d, w_m, s_m, fc) \ |
| { \ |
| .width_div = (w_d), \ |
| .shift_div = (s_d), \ |
| .width_mux = (w_m), \ |
| .shift_mux = (s_m), \ |
| .bit_fc = (fc), \ |
| } |
| |
| void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit, |
| int nr_clks); |
| void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id, |
| struct clk *clk); |
| |
| /* Power islands */ |
| #define MMP_PM_DOMAIN_NO_DISABLE BIT(0) |
| |
| struct generic_pm_domain *mmp_pm_domain_register(const char *name, |
| void __iomem *reg, |
| u32 power_on, u32 reset, u32 clock_enable, |
| unsigned int flags, spinlock_t *lock); |
| |
| #endif |