mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
299 lines
11 KiB
299 lines
11 KiB
/* 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/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) |
|
|
|
/* 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) |
|
|
|
/* 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 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 */ |
|
long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate, |
|
unsigned long *parent_rate); |
|
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); |
|
|
|
#endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */
|
|
|