| /* SPDX-License-Identifier: GPL-2.0 */ | |
| /* | |
| * Copyright (C) 2018-2019 SiFive, Inc. | |
| * Wesley Terpstra | |
| * Paul Walmsley | |
| * Zong Li | |
| */ | |
| #ifndef __SIFIVE_CLK_SIFIVE_PRCI_H | |
| #define __SIFIVE_CLK_SIFIVE_PRCI_H | |
| #include <linux/clk/analogbits-wrpll-cln28hpc.h> | |
| #include <linux/clk-provider.h> | |
| #include <linux/reset/reset-simple.h> | |
| #include <linux/platform_device.h> | |
| /* | |
| * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects: | |
| * hfclk and rtcclk | |
| */ | |
| #define EXPECTED_CLK_PARENT_COUNT 2 | |
| /* | |
| * Register offsets and bitmasks | |
| */ | |
| /* COREPLLCFG0 */ | |
| #define PRCI_COREPLLCFG0_OFFSET 0x4 | |
| #define PRCI_COREPLLCFG0_DIVR_SHIFT 0 | |
| #define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT) | |
| #define PRCI_COREPLLCFG0_DIVF_SHIFT 6 | |
| #define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT) | |
| #define PRCI_COREPLLCFG0_DIVQ_SHIFT 15 | |
| #define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT) | |
| #define PRCI_COREPLLCFG0_RANGE_SHIFT 18 | |
| #define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT) | |
| #define PRCI_COREPLLCFG0_BYPASS_SHIFT 24 | |
| #define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT) | |
| #define PRCI_COREPLLCFG0_FSE_SHIFT 25 | |
| #define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT) | |
| #define PRCI_COREPLLCFG0_LOCK_SHIFT 31 | |
| #define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT) | |
| /* COREPLLCFG1 */ | |
| #define PRCI_COREPLLCFG1_OFFSET 0x8 | |
| #define PRCI_COREPLLCFG1_CKE_SHIFT 31 | |
| #define PRCI_COREPLLCFG1_CKE_MASK (0x1 << PRCI_COREPLLCFG1_CKE_SHIFT) | |
| /* DDRPLLCFG0 */ | |
| #define PRCI_DDRPLLCFG0_OFFSET 0xc | |
| #define PRCI_DDRPLLCFG0_DIVR_SHIFT 0 | |
| #define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT) | |
| #define PRCI_DDRPLLCFG0_DIVF_SHIFT 6 | |
| #define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT) | |
| #define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15 | |
| #define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT) | |
| #define PRCI_DDRPLLCFG0_RANGE_SHIFT 18 | |
| #define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT) | |
| #define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24 | |
| #define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT) | |
| #define PRCI_DDRPLLCFG0_FSE_SHIFT 25 | |
| #define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT) | |
| #define PRCI_DDRPLLCFG0_LOCK_SHIFT 31 | |
| #define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT) | |
| /* DDRPLLCFG1 */ | |
| #define PRCI_DDRPLLCFG1_OFFSET 0x10 | |
| #define PRCI_DDRPLLCFG1_CKE_SHIFT 31 | |
| #define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT) | |
| /* PCIEAUX */ | |
| #define PRCI_PCIE_AUX_OFFSET 0x14 | |
| #define PRCI_PCIE_AUX_EN_SHIFT 0 | |
| #define PRCI_PCIE_AUX_EN_MASK (0x1 << PRCI_PCIE_AUX_EN_SHIFT) | |
| /* GEMGXLPLLCFG0 */ | |
| #define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c | |
| #define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0 | |
| #define PRCI_GEMGXLPLLCFG0_DIVR_MASK (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT) | |
| #define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6 | |
| #define PRCI_GEMGXLPLLCFG0_DIVF_MASK (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT) | |
| #define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15 | |
| #define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT) | |
| #define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18 | |
| #define PRCI_GEMGXLPLLCFG0_RANGE_MASK (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT) | |
| #define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24 | |
| #define PRCI_GEMGXLPLLCFG0_BYPASS_MASK (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT) | |
| #define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25 | |
| #define PRCI_GEMGXLPLLCFG0_FSE_MASK (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT) | |
| #define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31 | |
| #define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT) | |
| /* GEMGXLPLLCFG1 */ | |
| #define PRCI_GEMGXLPLLCFG1_OFFSET 0x20 | |
| #define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 31 | |
| #define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT) | |
| /* CORECLKSEL */ | |
| #define PRCI_CORECLKSEL_OFFSET 0x24 | |
| #define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0 | |
| #define PRCI_CORECLKSEL_CORECLKSEL_MASK \ | |
| (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT) | |
| /* DEVICESRESETREG */ | |
| #define PRCI_DEVICESRESETREG_OFFSET 0x28 | |
| #define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0 | |
| #define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK \ | |
| (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT) | |
| #define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1 | |
| #define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK \ | |
| (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT) | |
| #define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2 | |
| #define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK \ | |
| (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT) | |
| #define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3 | |
| #define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK \ | |
| (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT) | |
| #define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5 | |
| #define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK \ | |
| (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT) | |
| #define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT 6 | |
| #define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_MASK \ | |
| (0x1 << PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT) | |
| #define PRCI_RST_NR 7 | |
| /* CLKMUXSTATUSREG */ | |
| #define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c | |
| #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1 | |
| #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \ | |
| (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT) | |
| /* CLTXPLLCFG0 */ | |
| #define PRCI_CLTXPLLCFG0_OFFSET 0x30 | |
| #define PRCI_CLTXPLLCFG0_DIVR_SHIFT 0 | |
| #define PRCI_CLTXPLLCFG0_DIVR_MASK (0x3f << PRCI_CLTXPLLCFG0_DIVR_SHIFT) | |
| #define PRCI_CLTXPLLCFG0_DIVF_SHIFT 6 | |
| #define PRCI_CLTXPLLCFG0_DIVF_MASK (0x1ff << PRCI_CLTXPLLCFG0_DIVF_SHIFT) | |
| #define PRCI_CLTXPLLCFG0_DIVQ_SHIFT 15 | |
| #define PRCI_CLTXPLLCFG0_DIVQ_MASK (0x7 << PRCI_CLTXPLLCFG0_DIVQ_SHIFT) | |
| #define PRCI_CLTXPLLCFG0_RANGE_SHIFT 18 | |
| #define PRCI_CLTXPLLCFG0_RANGE_MASK (0x7 << PRCI_CLTXPLLCFG0_RANGE_SHIFT) | |
| #define PRCI_CLTXPLLCFG0_BYPASS_SHIFT 24 | |
| #define PRCI_CLTXPLLCFG0_BYPASS_MASK (0x1 << PRCI_CLTXPLLCFG0_BYPASS_SHIFT) | |
| #define PRCI_CLTXPLLCFG0_FSE_SHIFT 25 | |
| #define PRCI_CLTXPLLCFG0_FSE_MASK (0x1 << PRCI_CLTXPLLCFG0_FSE_SHIFT) | |
| #define PRCI_CLTXPLLCFG0_LOCK_SHIFT 31 | |
| #define PRCI_CLTXPLLCFG0_LOCK_MASK (0x1 << PRCI_CLTXPLLCFG0_LOCK_SHIFT) | |
| /* CLTXPLLCFG1 */ | |
| #define PRCI_CLTXPLLCFG1_OFFSET 0x34 | |
| #define PRCI_CLTXPLLCFG1_CKE_SHIFT 31 | |
| #define PRCI_CLTXPLLCFG1_CKE_MASK (0x1 << PRCI_CLTXPLLCFG1_CKE_SHIFT) | |
| /* DVFSCOREPLLCFG0 */ | |
| #define PRCI_DVFSCOREPLLCFG0_OFFSET 0x38 | |
| /* DVFSCOREPLLCFG1 */ | |
| #define PRCI_DVFSCOREPLLCFG1_OFFSET 0x3c | |
| #define PRCI_DVFSCOREPLLCFG1_CKE_SHIFT 31 | |
| #define PRCI_DVFSCOREPLLCFG1_CKE_MASK (0x1 << PRCI_DVFSCOREPLLCFG1_CKE_SHIFT) | |
| /* COREPLLSEL */ | |
| #define PRCI_COREPLLSEL_OFFSET 0x40 | |
| #define PRCI_COREPLLSEL_COREPLLSEL_SHIFT 0 | |
| #define PRCI_COREPLLSEL_COREPLLSEL_MASK \ | |
| (0x1 << PRCI_COREPLLSEL_COREPLLSEL_SHIFT) | |
| /* HFPCLKPLLCFG0 */ | |
| #define PRCI_HFPCLKPLLCFG0_OFFSET 0x50 | |
| #define PRCI_HFPCLKPLL_CFG0_DIVR_SHIFT 0 | |
| #define PRCI_HFPCLKPLL_CFG0_DIVR_MASK \ | |
| (0x3f << PRCI_HFPCLKPLLCFG0_DIVR_SHIFT) | |
| #define PRCI_HFPCLKPLL_CFG0_DIVF_SHIFT 6 | |
| #define PRCI_HFPCLKPLL_CFG0_DIVF_MASK \ | |
| (0x1ff << PRCI_HFPCLKPLLCFG0_DIVF_SHIFT) | |
| #define PRCI_HFPCLKPLL_CFG0_DIVQ_SHIFT 15 | |
| #define PRCI_HFPCLKPLL_CFG0_DIVQ_MASK \ | |
| (0x7 << PRCI_HFPCLKPLLCFG0_DIVQ_SHIFT) | |
| #define PRCI_HFPCLKPLL_CFG0_RANGE_SHIFT 18 | |
| #define PRCI_HFPCLKPLL_CFG0_RANGE_MASK \ | |
| (0x7 << PRCI_HFPCLKPLLCFG0_RANGE_SHIFT) | |
| #define PRCI_HFPCLKPLL_CFG0_BYPASS_SHIFT 24 | |
| #define PRCI_HFPCLKPLL_CFG0_BYPASS_MASK \ | |
| (0x1 << PRCI_HFPCLKPLLCFG0_BYPASS_SHIFT) | |
| #define PRCI_HFPCLKPLL_CFG0_FSE_SHIFT 25 | |
| #define PRCI_HFPCLKPLL_CFG0_FSE_MASK \ | |
| (0x1 << PRCI_HFPCLKPLLCFG0_FSE_SHIFT) | |
| #define PRCI_HFPCLKPLL_CFG0_LOCK_SHIFT 31 | |
| #define PRCI_HFPCLKPLL_CFG0_LOCK_MASK \ | |
| (0x1 << PRCI_HFPCLKPLLCFG0_LOCK_SHIFT) | |
| /* HFPCLKPLLCFG1 */ | |
| #define PRCI_HFPCLKPLLCFG1_OFFSET 0x54 | |
| #define PRCI_HFPCLKPLLCFG1_CKE_SHIFT 31 | |
| #define PRCI_HFPCLKPLLCFG1_CKE_MASK \ | |
| (0x1 << PRCI_HFPCLKPLLCFG1_CKE_SHIFT) | |
| /* HFPCLKPLLSEL */ | |
| #define PRCI_HFPCLKPLLSEL_OFFSET 0x58 | |
| #define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT 0 | |
| #define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK \ | |
| (0x1 << PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT) | |
| /* HFPCLKPLLDIV */ | |
| #define PRCI_HFPCLKPLLDIV_OFFSET 0x5c | |
| /* PRCIPLL */ | |
| #define PRCI_PRCIPLL_OFFSET 0xe0 | |
| /* PROCMONCFG */ | |
| #define PRCI_PROCMONCFG_OFFSET 0xf0 | |
| /* | |
| * Private structures | |
| */ | |
| /** | |
| * struct __prci_data - per-device-instance data | |
| * @va: base virtual address of the PRCI IP block | |
| * @hw_clks: encapsulates struct clk_hw records | |
| * | |
| * PRCI per-device instance data | |
| */ | |
| struct __prci_data { | |
| void __iomem *va; | |
| struct reset_simple_data reset; | |
| struct clk_hw_onecell_data hw_clks; | |
| }; | |
| /** | |
| * struct __prci_wrpll_data - WRPLL configuration and integration data | |
| * @c: WRPLL current configuration record | |
| * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL) | |
| * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL) | |
| * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address | |
| * @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address | |
| * | |
| * @enable_bypass and @disable_bypass are used for WRPLL instances | |
| * that contain a separate external glitchless clock mux downstream | |
| * from the PLL. The WRPLL internal bypass mux is not glitchless. | |
| */ | |
| struct __prci_wrpll_data { | |
| struct wrpll_cfg c; | |
| void (*enable_bypass)(struct __prci_data *pd); | |
| void (*disable_bypass)(struct __prci_data *pd); | |
| u8 cfg0_offs; | |
| u8 cfg1_offs; | |
| }; | |
| /** | |
| * struct __prci_clock - describes a clock device managed by PRCI | |
| * @name: user-readable clock name string - should match the manual | |
| * @parent_name: parent name for this clock | |
| * @ops: struct clk_ops for the Linux clock framework to use for control | |
| * @hw: Linux-private clock data | |
| * @pwd: WRPLL-specific data, associated with this clock (if not NULL) | |
| * @pd: PRCI-specific data associated with this clock (if not NULL) | |
| * | |
| * PRCI clock data. Used by the PRCI driver to register PRCI-provided | |
| * clocks to the Linux clock infrastructure. | |
| */ | |
| struct __prci_clock { | |
| const char *name; | |
| const char *parent_name; | |
| const struct clk_ops *ops; | |
| struct clk_hw hw; | |
| struct __prci_wrpll_data *pwd; | |
| struct __prci_data *pd; | |
| }; | |
| #define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw) | |
| /* | |
| * struct prci_clk_desc - describes the information of clocks of each SoCs | |
| * @clks: point to a array of __prci_clock | |
| * @num_clks: the number of element of clks | |
| */ | |
| struct prci_clk_desc { | |
| struct __prci_clock *clks; | |
| size_t num_clks; | |
| }; | |
| /* Core clock mux control */ | |
| void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd); | |
| void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd); | |
| void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd); | |
| void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd); | |
| void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd); | |
| void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd); | |
| void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd); | |
| /* Linux clock framework integration */ | |
| int sifive_prci_wrpll_determine_rate(struct clk_hw *hw, | |
| struct clk_rate_request *req); | |
| int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate, | |
| unsigned long parent_rate); | |
| int sifive_clk_is_enabled(struct clk_hw *hw); | |
| int sifive_prci_clock_enable(struct clk_hw *hw); | |
| void sifive_prci_clock_disable(struct clk_hw *hw); | |
| unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw, | |
| unsigned long parent_rate); | |
| unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw, | |
| unsigned long parent_rate); | |
| unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw, | |
| unsigned long parent_rate); | |
| int sifive_prci_pcie_aux_clock_is_enabled(struct clk_hw *hw); | |
| int sifive_prci_pcie_aux_clock_enable(struct clk_hw *hw); | |
| void sifive_prci_pcie_aux_clock_disable(struct clk_hw *hw); | |
| #endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */ |