xref: /linux/drivers/clk/sifive/sifive-prci.h (revision c816e1ddf2b60b31d121118488c5a854d9a2fad9)
1*c816e1ddSZong Li /* SPDX-License-Identifier: GPL-2.0 */
2*c816e1ddSZong Li /*
3*c816e1ddSZong Li  * Copyright (C) 2018-2019 SiFive, Inc.
4*c816e1ddSZong Li  * Wesley Terpstra
5*c816e1ddSZong Li  * Paul Walmsley
6*c816e1ddSZong Li  * Zong Li
7*c816e1ddSZong Li  */
8*c816e1ddSZong Li 
9*c816e1ddSZong Li #ifndef __SIFIVE_CLK_SIFIVE_PRCI_H
10*c816e1ddSZong Li #define __SIFIVE_CLK_SIFIVE_PRCI_H
11*c816e1ddSZong Li 
12*c816e1ddSZong Li #include <linux/clk/analogbits-wrpll-cln28hpc.h>
13*c816e1ddSZong Li #include <linux/clk-provider.h>
14*c816e1ddSZong Li #include <linux/platform_device.h>
15*c816e1ddSZong Li 
16*c816e1ddSZong Li /*
17*c816e1ddSZong Li  * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
18*c816e1ddSZong Li  *     hfclk and rtcclk
19*c816e1ddSZong Li  */
20*c816e1ddSZong Li #define EXPECTED_CLK_PARENT_COUNT 2
21*c816e1ddSZong Li 
22*c816e1ddSZong Li /*
23*c816e1ddSZong Li  * Register offsets and bitmasks
24*c816e1ddSZong Li  */
25*c816e1ddSZong Li 
26*c816e1ddSZong Li /* COREPLLCFG0 */
27*c816e1ddSZong Li #define PRCI_COREPLLCFG0_OFFSET		0x4
28*c816e1ddSZong Li #define PRCI_COREPLLCFG0_DIVR_SHIFT	0
29*c816e1ddSZong Li #define PRCI_COREPLLCFG0_DIVR_MASK	(0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
30*c816e1ddSZong Li #define PRCI_COREPLLCFG0_DIVF_SHIFT	6
31*c816e1ddSZong Li #define PRCI_COREPLLCFG0_DIVF_MASK	(0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
32*c816e1ddSZong Li #define PRCI_COREPLLCFG0_DIVQ_SHIFT	15
33*c816e1ddSZong Li #define PRCI_COREPLLCFG0_DIVQ_MASK	(0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
34*c816e1ddSZong Li #define PRCI_COREPLLCFG0_RANGE_SHIFT	18
35*c816e1ddSZong Li #define PRCI_COREPLLCFG0_RANGE_MASK	(0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
36*c816e1ddSZong Li #define PRCI_COREPLLCFG0_BYPASS_SHIFT	24
37*c816e1ddSZong Li #define PRCI_COREPLLCFG0_BYPASS_MASK	(0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
38*c816e1ddSZong Li #define PRCI_COREPLLCFG0_FSE_SHIFT	25
39*c816e1ddSZong Li #define PRCI_COREPLLCFG0_FSE_MASK	(0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
40*c816e1ddSZong Li #define PRCI_COREPLLCFG0_LOCK_SHIFT	31
41*c816e1ddSZong Li #define PRCI_COREPLLCFG0_LOCK_MASK	(0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
42*c816e1ddSZong Li 
43*c816e1ddSZong Li /* DDRPLLCFG0 */
44*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_OFFSET		0xc
45*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_DIVR_SHIFT	0
46*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_DIVR_MASK	(0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
47*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_DIVF_SHIFT	6
48*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_DIVF_MASK	(0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
49*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_DIVQ_SHIFT	15
50*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_DIVQ_MASK	(0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
51*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_RANGE_SHIFT	18
52*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_RANGE_MASK	(0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
53*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_BYPASS_SHIFT	24
54*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_BYPASS_MASK	(0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
55*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_FSE_SHIFT	25
56*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_FSE_MASK	(0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
57*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_LOCK_SHIFT	31
58*c816e1ddSZong Li #define PRCI_DDRPLLCFG0_LOCK_MASK	(0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
59*c816e1ddSZong Li 
60*c816e1ddSZong Li /* DDRPLLCFG1 */
61*c816e1ddSZong Li #define PRCI_DDRPLLCFG1_OFFSET		0x10
62*c816e1ddSZong Li #define PRCI_DDRPLLCFG1_CKE_SHIFT	24
63*c816e1ddSZong Li #define PRCI_DDRPLLCFG1_CKE_MASK	(0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
64*c816e1ddSZong Li 
65*c816e1ddSZong Li /* GEMGXLPLLCFG0 */
66*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_OFFSET	0x1c
67*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT	0
68*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_DIVR_MASK	(0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
69*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT	6
70*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_DIVF_MASK	(0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
71*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT	15
72*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_DIVQ_MASK	(0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
73*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT	18
74*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_RANGE_MASK	(0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
75*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT	24
76*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_BYPASS_MASK	(0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
77*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_FSE_SHIFT	25
78*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_FSE_MASK	(0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
79*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT	31
80*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG0_LOCK_MASK	(0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
81*c816e1ddSZong Li 
82*c816e1ddSZong Li /* GEMGXLPLLCFG1 */
83*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG1_OFFSET	0x20
84*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG1_CKE_SHIFT	24
85*c816e1ddSZong Li #define PRCI_GEMGXLPLLCFG1_CKE_MASK	(0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
86*c816e1ddSZong Li 
87*c816e1ddSZong Li /* CORECLKSEL */
88*c816e1ddSZong Li #define PRCI_CORECLKSEL_OFFSET			0x24
89*c816e1ddSZong Li #define PRCI_CORECLKSEL_CORECLKSEL_SHIFT	0
90*c816e1ddSZong Li #define PRCI_CORECLKSEL_CORECLKSEL_MASK					\
91*c816e1ddSZong Li 		(0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
92*c816e1ddSZong Li 
93*c816e1ddSZong Li /* DEVICESRESETREG */
94*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_OFFSET				0x28
95*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT		0
96*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK			\
97*c816e1ddSZong Li 		(0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
98*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT		1
99*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK				\
100*c816e1ddSZong Li 		(0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
101*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT		2
102*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK				\
103*c816e1ddSZong Li 		(0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
104*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT		3
105*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK				\
106*c816e1ddSZong Li 		(0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
107*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT			5
108*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK				\
109*c816e1ddSZong Li 		(0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
110*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT		6
111*c816e1ddSZong Li #define PRCI_DEVICESRESETREG_CHIPLINK_RST_N_MASK			\
112*c816e1ddSZong Li 		(0x1 << PRCI_DEVICESRESETREG_CHIPLINK_RST_N_SHIFT)
113*c816e1ddSZong Li 
114*c816e1ddSZong Li /* CLKMUXSTATUSREG */
115*c816e1ddSZong Li #define PRCI_CLKMUXSTATUSREG_OFFSET				0x2c
116*c816e1ddSZong Li #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT		1
117*c816e1ddSZong Li #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK			\
118*c816e1ddSZong Li 		(0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
119*c816e1ddSZong Li 
120*c816e1ddSZong Li /*
121*c816e1ddSZong Li  * Private structures
122*c816e1ddSZong Li  */
123*c816e1ddSZong Li 
124*c816e1ddSZong Li /**
125*c816e1ddSZong Li  * struct __prci_data - per-device-instance data
126*c816e1ddSZong Li  * @va: base virtual address of the PRCI IP block
127*c816e1ddSZong Li  * @hw_clks: encapsulates struct clk_hw records
128*c816e1ddSZong Li  *
129*c816e1ddSZong Li  * PRCI per-device instance data
130*c816e1ddSZong Li  */
131*c816e1ddSZong Li struct __prci_data {
132*c816e1ddSZong Li 	void __iomem *va;
133*c816e1ddSZong Li 	struct clk_hw_onecell_data hw_clks;
134*c816e1ddSZong Li };
135*c816e1ddSZong Li 
136*c816e1ddSZong Li /**
137*c816e1ddSZong Li  * struct __prci_wrpll_data - WRPLL configuration and integration data
138*c816e1ddSZong Li  * @c: WRPLL current configuration record
139*c816e1ddSZong Li  * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
140*c816e1ddSZong Li  * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
141*c816e1ddSZong Li  * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
142*c816e1ddSZong Li  *
143*c816e1ddSZong Li  * @enable_bypass and @disable_bypass are used for WRPLL instances
144*c816e1ddSZong Li  * that contain a separate external glitchless clock mux downstream
145*c816e1ddSZong Li  * from the PLL.  The WRPLL internal bypass mux is not glitchless.
146*c816e1ddSZong Li  */
147*c816e1ddSZong Li struct __prci_wrpll_data {
148*c816e1ddSZong Li 	struct wrpll_cfg c;
149*c816e1ddSZong Li 	void (*enable_bypass)(struct __prci_data *pd);
150*c816e1ddSZong Li 	void (*disable_bypass)(struct __prci_data *pd);
151*c816e1ddSZong Li 	u8 cfg0_offs;
152*c816e1ddSZong Li };
153*c816e1ddSZong Li 
154*c816e1ddSZong Li /**
155*c816e1ddSZong Li  * struct __prci_clock - describes a clock device managed by PRCI
156*c816e1ddSZong Li  * @name: user-readable clock name string - should match the manual
157*c816e1ddSZong Li  * @parent_name: parent name for this clock
158*c816e1ddSZong Li  * @ops: struct clk_ops for the Linux clock framework to use for control
159*c816e1ddSZong Li  * @hw: Linux-private clock data
160*c816e1ddSZong Li  * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
161*c816e1ddSZong Li  * @pd: PRCI-specific data associated with this clock (if not NULL)
162*c816e1ddSZong Li  *
163*c816e1ddSZong Li  * PRCI clock data.  Used by the PRCI driver to register PRCI-provided
164*c816e1ddSZong Li  * clocks to the Linux clock infrastructure.
165*c816e1ddSZong Li  */
166*c816e1ddSZong Li struct __prci_clock {
167*c816e1ddSZong Li 	const char *name;
168*c816e1ddSZong Li 	const char *parent_name;
169*c816e1ddSZong Li 	const struct clk_ops *ops;
170*c816e1ddSZong Li 	struct clk_hw hw;
171*c816e1ddSZong Li 	struct __prci_wrpll_data *pwd;
172*c816e1ddSZong Li 	struct __prci_data *pd;
173*c816e1ddSZong Li };
174*c816e1ddSZong Li 
175*c816e1ddSZong Li #define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)
176*c816e1ddSZong Li 
177*c816e1ddSZong Li /*
178*c816e1ddSZong Li  * struct prci_clk_desc - describes the information of clocks of each SoCs
179*c816e1ddSZong Li  * @clks: point to a array of __prci_clock
180*c816e1ddSZong Li  * @num_clks: the number of element of clks
181*c816e1ddSZong Li  */
182*c816e1ddSZong Li struct prci_clk_desc {
183*c816e1ddSZong Li 	struct __prci_clock *clks;
184*c816e1ddSZong Li 	size_t num_clks;
185*c816e1ddSZong Li };
186*c816e1ddSZong Li 
187*c816e1ddSZong Li /* Core clock mux control */
188*c816e1ddSZong Li void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd);
189*c816e1ddSZong Li void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd);
190*c816e1ddSZong Li 
191*c816e1ddSZong Li /* Linux clock framework integration */
192*c816e1ddSZong Li long sifive_prci_wrpll_round_rate(struct clk_hw *hw, unsigned long rate,
193*c816e1ddSZong Li 				  unsigned long *parent_rate);
194*c816e1ddSZong Li int sifive_prci_wrpll_set_rate(struct clk_hw *hw, unsigned long rate,
195*c816e1ddSZong Li 			       unsigned long parent_rate);
196*c816e1ddSZong Li unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
197*c816e1ddSZong Li 					    unsigned long parent_rate);
198*c816e1ddSZong Li unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
199*c816e1ddSZong Li 					       unsigned long parent_rate);
200*c816e1ddSZong Li 
201*c816e1ddSZong Li #endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */
202