| /* SPDX-License-Identifier: GPL-2.0-only */ |
| /* |
| * Copyright (c) 2024 SpacemiT Technology Co. Ltd |
| * Copyright (c) 2024-2025 Haylen Chu <heylenay@4d2.org> |
| */ |
| |
| #ifndef _CCU_PLL_H_ |
| #define _CCU_PLL_H_ |
| |
| #include <linux/clk-provider.h> |
| |
| #include "ccu_common.h" |
| |
| /** |
| * struct ccu_pll_rate_tbl - Structure mapping between PLL rate and register |
| * configuration. |
| * |
| * @rate: PLL rate |
| * @swcr1: Value of register PLLx_SW1_CTRL. |
| * @swcr2: Value of register PLLAx_SW2_CTRL. |
| * @swcr3: value of register PLLx_SW3_CTRL. |
| * |
| * See below tables for the register used in PPL/PPLA clocks |
| * |
| * Regular PLL type |
| * | Enable | swcr3 | PLLx_SW3_CTRL - BIT[31] | |
| * ----------------------------------------------- |
| * | Config | swcr1 | PLLx_SW1_CTRL - BIT[31:0] | |
| * | | swcr2 | Not used | |
| * | | swcr3 | PLLx_SW3_CTRL - BIT[30:0] | |
| * |
| * Special PLL type A |
| * | Enable | swcr2 | PLLAx_SW2_CTRL - BIT[16] | |
| * ----------------------------------------------- |
| * | Config | swcr1 | PLLAx_SW1_CTRL - BIT[31:0] | |
| * | | swcr2 | PLLAx_SW2_CTRL - BIT[15:8] | |
| * | | swcr3 | PLLAx_SW3_CTRL - BIT[31:0] | |
| * |
| */ |
| struct ccu_pll_rate_tbl { |
| unsigned long rate; |
| u32 swcr1; |
| u32 swcr2; |
| u32 swcr3; |
| }; |
| |
| struct ccu_pll_config { |
| const struct ccu_pll_rate_tbl *rate_tbl; |
| u32 tbl_num; |
| u32 reg_lock; |
| u32 mask_lock; |
| }; |
| |
| #define CCU_PLL_RATE(_rate, _swcr1, _swcr3) \ |
| { \ |
| .rate = _rate, \ |
| .swcr1 = _swcr1, \ |
| .swcr3 = _swcr3, \ |
| } |
| |
| #define CCU_PLLA_RATE(_rate, _swcr1, _swcr2, _swcr3) \ |
| { \ |
| .rate = _rate, \ |
| .swcr1 = _swcr1, \ |
| .swcr2 = _swcr2, \ |
| .swcr3 = _swcr3, \ |
| } |
| |
| struct ccu_pll { |
| struct ccu_common common; |
| struct ccu_pll_config config; |
| }; |
| |
| #define CCU_PLL_CONFIG(_table, _reg_lock, _mask_lock) \ |
| { \ |
| .rate_tbl = _table, \ |
| .tbl_num = ARRAY_SIZE(_table), \ |
| .reg_lock = (_reg_lock), \ |
| .mask_lock = (_mask_lock), \ |
| } |
| |
| #define CCU_PLL_COMMON_HWINIT(_name, _ops, _flags) \ |
| (&(struct clk_init_data) { \ |
| .name = #_name, \ |
| .ops = _ops, \ |
| .parent_data = &(struct clk_parent_data) { .index = 0 }, \ |
| .num_parents = 1, \ |
| .flags = _flags, \ |
| }) |
| |
| #define CCU_PLL_X_DEFINE(_name, _table, _reg_swcr1, _reg_swcr2, _reg_swcr3, \ |
| _reg_lock, _mask_lock, _ops, _flags) \ |
| static struct ccu_pll _name = { \ |
| .config = CCU_PLL_CONFIG(_table, _reg_lock, _mask_lock), \ |
| .common = { \ |
| .reg_swcr1 = _reg_swcr1, \ |
| .reg_swcr2 = _reg_swcr2, \ |
| .reg_swcr3 = _reg_swcr3, \ |
| .hw.init = CCU_PLL_COMMON_HWINIT(_name, _ops, _flags) \ |
| } \ |
| } |
| |
| #define CCU_PLL_DEFINE(_name, _table, _reg_swcr1, _reg_swcr3, _reg_lock, \ |
| _mask_lock, _flags) \ |
| CCU_PLL_X_DEFINE(_name, _table, _reg_swcr1, 0, _reg_swcr3, \ |
| _reg_lock, _mask_lock, &spacemit_ccu_pll_ops, _flags) |
| |
| #define CCU_PLLA_DEFINE(_name, _table, _reg_swcr1, _reg_swcr2, _reg_swcr3, \ |
| _reg_lock, _mask_lock, _flags) \ |
| CCU_PLL_X_DEFINE(_name, _table, _reg_swcr1, _reg_swcr2, _reg_swcr3, \ |
| _reg_lock, _mask_lock, &spacemit_ccu_plla_ops, _flags) |
| |
| static inline struct ccu_pll *hw_to_ccu_pll(struct clk_hw *hw) |
| { |
| struct ccu_common *common = hw_to_ccu_common(hw); |
| |
| return container_of(common, struct ccu_pll, common); |
| } |
| |
| extern const struct clk_ops spacemit_ccu_pll_ops; |
| extern const struct clk_ops spacemit_ccu_plla_ops; |
| |
| #endif |