blob: 5ce33d618468228520edbad32b352c94411562b7 [file] [log] [blame]
Green Wanecefa5f2021-05-27 06:52:08 -07001/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (C) 2020-2021 SiFive, Inc.
4 * Wesley Terpstra
5 * Paul Walmsley
6 * Zong Li
7 * Pragnesh Patel
8 */
9
10#ifndef __SIFIVE_CLK_SIFIVE_PRCI_H
11#define __SIFIVE_CLK_SIFIVE_PRCI_H
12
13#include <clk.h>
14#include <linux/clk/analogbits-wrpll-cln28hpc.h>
15
16/*
17 * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
18 * hfclk and rtcclk
19 */
20#define EXPECTED_CLK_PARENT_COUNT 2
21
22/*
23 * Register offsets and bitmasks
24 */
25
26/* COREPLLCFG0 */
27#define PRCI_COREPLLCFG0_OFFSET 0x4
28#define PRCI_COREPLLCFG0_DIVR_SHIFT 0
29#define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
30#define PRCI_COREPLLCFG0_DIVF_SHIFT 6
31#define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
32#define PRCI_COREPLLCFG0_DIVQ_SHIFT 15
33#define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
34#define PRCI_COREPLLCFG0_RANGE_SHIFT 18
35#define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
36#define PRCI_COREPLLCFG0_BYPASS_SHIFT 24
37#define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
38#define PRCI_COREPLLCFG0_FSE_SHIFT 25
39#define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
40#define PRCI_COREPLLCFG0_LOCK_SHIFT 31
41#define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
42
43/* COREPLLCFG1 */
44#define PRCI_COREPLLCFG1_OFFSET 0x8
45#define PRCI_COREPLLCFG1_CKE_SHIFT 31
46#define PRCI_COREPLLCFG1_CKE_MASK (0x1 << PRCI_COREPLLCFG1_CKE_SHIFT)
47
48/* DDRPLLCFG0 */
49#define PRCI_DDRPLLCFG0_OFFSET 0xc
50#define PRCI_DDRPLLCFG0_DIVR_SHIFT 0
51#define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
52#define PRCI_DDRPLLCFG0_DIVF_SHIFT 6
53#define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
54#define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15
55#define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
56#define PRCI_DDRPLLCFG0_RANGE_SHIFT 18
57#define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
58#define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24
59#define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
60#define PRCI_DDRPLLCFG0_FSE_SHIFT 25
61#define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
62#define PRCI_DDRPLLCFG0_LOCK_SHIFT 31
63#define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
64
65/* DDRPLLCFG1 */
66#define PRCI_DDRPLLCFG1_OFFSET 0x10
67#define PRCI_DDRPLLCFG1_CKE_SHIFT 31
68#define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
69
70/* PCIEAUXCFG1 */
71#define PRCI_PCIEAUXCFG1_OFFSET 0x14
72#define PRCI_PCIEAUXCFG1_SHIFT 0
73#define PRCI_PCIEAUXCFG1_MASK (0x1 << PRCI_PCIEAUXCFG1_SHIFT)
74
75/* GEMGXLPLLCFG0 */
76#define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c
77#define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0
78#define PRCI_GEMGXLPLLCFG0_DIVR_MASK \
79 (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
80#define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6
81#define PRCI_GEMGXLPLLCFG0_DIVF_MASK \
82 (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
83#define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15
84#define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
85#define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18
86#define PRCI_GEMGXLPLLCFG0_RANGE_MASK \
87 (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
88#define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24
89#define PRCI_GEMGXLPLLCFG0_BYPASS_MASK \
90 (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
91#define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25
92#define PRCI_GEMGXLPLLCFG0_FSE_MASK \
93 (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
94#define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31
95#define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
96
97/* GEMGXLPLLCFG1 */
98#define PRCI_GEMGXLPLLCFG1_OFFSET 0x20
99#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 31
100#define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
101
102/* CORECLKSEL */
103#define PRCI_CORECLKSEL_OFFSET 0x24
104#define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0
105#define PRCI_CORECLKSEL_CORECLKSEL_MASK \
106 (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
107
108/* DEVICESRESETREG */
109#define PRCI_DEVICESRESETREG_OFFSET 0x28
110#define PRCI_DEVICERESETCNT 6
111
112/* CLKMUXSTATUSREG */
113#define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c
114#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1
115#define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \
116 (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
117
118/* CLTXPLLCFG0 */
119#define PRCI_CLTXPLLCFG0_OFFSET 0x30
120#define PRCI_CLTXPLLCFG0_DIVR_SHIFT 0
121#define PRCI_CLTXPLLCFG0_DIVR_MASK (0x3f << PRCI_CLTXPLLCFG0_DIVR_SHIFT)
122#define PRCI_CLTXPLLCFG0_DIVF_SHIFT 6
123#define PRCI_CLTXPLLCFG0_DIVF_MASK (0x1ff << PRCI_CLTXPLLCFG0_DIVF_SHIFT)
124#define PRCI_CLTXPLLCFG0_DIVQ_SHIFT 15
125#define PRCI_CLTXPLLCFG0_DIVQ_MASK (0x7 << PRCI_CLTXPLLCFG0_DIVQ_SHIFT)
126#define PRCI_CLTXPLLCFG0_RANGE_SHIFT 18
127#define PRCI_CLTXPLLCFG0_RANGE_MASK (0x7 << PRCI_CLTXPLLCFG0_RANGE_SHIFT)
128#define PRCI_CLTXPLLCFG0_BYPASS_SHIFT 24
129#define PRCI_CLTXPLLCFG0_BYPASS_MASK (0x1 << PRCI_CLTXPLLCFG0_BYPASS_SHIFT)
130#define PRCI_CLTXPLLCFG0_FSE_SHIFT 25
131#define PRCI_CLTXPLLCFG0_FSE_MASK (0x1 << PRCI_CLTXPLLCFG0_FSE_SHIFT)
132#define PRCI_CLTXPLLCFG0_LOCK_SHIFT 31
133#define PRCI_CLTXPLLCFG0_LOCK_MASK (0x1 << PRCI_CLTXPLLCFG0_LOCK_SHIFT)
134
135/* CLTXPLLCFG1 */
136#define PRCI_CLTXPLLCFG1_OFFSET 0x34
137#define PRCI_CLTXPLLCFG1_CKE_SHIFT 24
138#define PRCI_CLTXPLLCFG1_CKE_MASK (0x1 << PRCI_CLTXPLLCFG1_CKE_SHIFT)
139
140/* DVFSCOREPLLCFG0 */
141#define PRCI_DVFSCOREPLLCFG0_OFFSET 0x38
142
143/* DVFSCOREPLLCFG1 */
144#define PRCI_DVFSCOREPLLCFG1_OFFSET 0x3c
145#define PRCI_DVFSCOREPLLCFG1_CKE_SHIFT 24
146#define PRCI_DVFSCOREPLLCFG1_CKE_MASK (0x1 << PRCI_DVFSCOREPLLCFG1_CKE_SHIFT)
147
148/* COREPLLSEL */
149#define PRCI_COREPLLSEL_OFFSET 0x40
150#define PRCI_COREPLLSEL_COREPLLSEL_SHIFT 0
151#define PRCI_COREPLLSEL_COREPLLSEL_MASK \
152 (0x1 << PRCI_COREPLLSEL_COREPLLSEL_SHIFT)
153
154/* HFPCLKPLLCFG0 */
155#define PRCI_HFPCLKPLLCFG0_OFFSET 0x50
156#define PRCI_HFPCLKPLL_CFG0_DIVR_SHIFT 0
157#define PRCI_HFPCLKPLL_CFG0_DIVR_MASK \
158 (0x3f << PRCI_HFPCLKPLLCFG0_DIVR_SHIFT)
159#define PRCI_HFPCLKPLL_CFG0_DIVF_SHIFT 6
160#define PRCI_HFPCLKPLL_CFG0_DIVF_MASK \
161 (0x1ff << PRCI_HFPCLKPLLCFG0_DIVF_SHIFT)
162#define PRCI_HFPCLKPLL_CFG0_DIVQ_SHIFT 15
163#define PRCI_HFPCLKPLL_CFG0_DIVQ_MASK \
164 (0x7 << PRCI_HFPCLKPLLCFG0_DIVQ_SHIFT)
165#define PRCI_HFPCLKPLL_CFG0_RANGE_SHIFT 18
166#define PRCI_HFPCLKPLL_CFG0_RANGE_MASK \
167 (0x7 << PRCI_HFPCLKPLLCFG0_RANGE_SHIFT)
168#define PRCI_HFPCLKPLL_CFG0_BYPASS_SHIFT 24
169#define PRCI_HFPCLKPLL_CFG0_BYPASS_MASK \
170 (0x1 << PRCI_HFPCLKPLLCFG0_BYPASS_SHIFT)
171#define PRCI_HFPCLKPLL_CFG0_FSE_SHIFT 25
172#define PRCI_HFPCLKPLL_CFG0_FSE_MASK \
173 (0x1 << PRCI_HFPCLKPLLCFG0_FSE_SHIFT)
174#define PRCI_HFPCLKPLL_CFG0_LOCK_SHIFT 31
175#define PRCI_HFPCLKPLL_CFG0_LOCK_MASK \
176 (0x1 << PRCI_HFPCLKPLLCFG0_LOCK_SHIFT)
177
178/* HFPCLKPLLCFG1 */
179#define PRCI_HFPCLKPLLCFG1_OFFSET 0x54
180#define PRCI_HFPCLKPLLCFG1_CKE_SHIFT 24
181#define PRCI_HFPCLKPLLCFG1_CKE_MASK \
182 (0x1 << PRCI_HFPCLKPLLCFG1_CKE_SHIFT)
183
184/* HFPCLKPLLSEL */
185#define PRCI_HFPCLKPLLSEL_OFFSET 0x58
186#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT 0
187#define PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK \
188 (0x1 << PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_SHIFT)
189
190/* HFPCLKPLLDIV */
191#define PRCI_HFPCLKPLLDIV_OFFSET 0x5c
192
193/* PRCIPLL */
194#define PRCI_PRCIPLL_OFFSET 0xe0
195
196#define PRCI_PRCIPLL_CLTXPLL (0x1 << 0)
197#define PRCI_PRCIPLL_GEMGXLPLL (0x1 << 1)
198#define PRCI_PRCIPLL_DDRPLL (0x1 << 2)
199#define PRCI_PRCIPLL_HFPCLKPLL (0x1 << 3)
200#define PRCI_PRCIPLL_DVFSCOREPLL (0x1 << 4)
201#define PRCI_PRCIPLL_COREPLL (0x1 << 5)
202
203/* PROCMONCFG */
204#define PRCI_PROCMONCFG_OFFSET 0xF0
205#define PRCI_PROCMONCFG_CORE_CLOCK_SHIFT 24
206#define PRCI_PROCMONCFG_CORE_CLOCK_MASK \
207 (0x1 << PRCI_PROCMONCFG_CORE_CLOCK_SHIFT)
208
209/*
210 * Private structures
211 */
212
213/**
214 * struct __prci_data - per-device-instance data
215 * @va: base virtual address of the PRCI IP block
216 * @parent: parent clk instance
217 *
218 * PRCI per-device instance data
219 */
220struct __prci_data {
221 void *va;
222 struct clk parent_hfclk;
223 struct clk parent_rtcclk;
224};
225
226/**
227 * struct __prci_wrpll_data - WRPLL configuration and integration data
228 * @c: WRPLL current configuration record
229 * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
230 * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
231 * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
232 * @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address
233 * @release_reset: fn ptr to code to release clock reset
234 *
235 * @enable_bypass and @disable_bypass are used for WRPLL instances
236 * that contain a separate external glitchless clock mux downstream
237 * from the PLL. The WRPLL internal bypass mux is not glitchless.
238 */
239struct __prci_wrpll_data {
240 struct wrpll_cfg c;
241 void (*enable_bypass)(struct __prci_data *pd);
242 void (*disable_bypass)(struct __prci_data *pd);
243 u8 cfg0_offs;
244 u8 cfg1_offs;
245 void (*release_reset)(struct __prci_data *pd);
246};
247
248/**
249 * struct __prci_clock - describes a clock device managed by PRCI
250 * @name: user-readable clock name string - should match the manual
251 * @parent_name: parent name for this clock
252 * @ops: struct __prci_clock_ops for control
253 * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
254 * @pd: PRCI-specific data associated with this clock (if not NULL)
255 *
256 * PRCI clock data. Used by the PRCI driver to register PRCI-provided
257 * clocks to the Linux clock infrastructure.
258 */
259struct __prci_clock {
260 const char *name;
261 const char *parent_name;
262 const struct __prci_clock_ops *ops;
263 struct __prci_wrpll_data *pwd;
264 struct __prci_data *pd;
265};
266
267/* struct __prci_clock_ops - clock operations */
268struct __prci_clock_ops {
269 int (*set_rate)(struct __prci_clock *pc,
270 unsigned long rate,
271 unsigned long parent_rate);
272 unsigned long (*round_rate)(struct __prci_clock *pc,
273 unsigned long rate,
274 unsigned long *parent_rate);
275 unsigned long (*recalc_rate)(struct __prci_clock *pc,
276 unsigned long parent_rate);
277 int (*enable_clk)(struct __prci_clock *pc, bool enable);
278};
279
280/*
281 * struct prci_clk_desc - describes the information of clocks of each SoCs
282 * @clks: point to a array of __prci_clock
283 * @num_clks: the number of element of clks
284 */
285struct prci_clk_desc {
286 struct __prci_clock *clks;
287 size_t num_clks;
288};
289
290void sifive_prci_ethernet_release_reset(struct __prci_data *pd);
291void sifive_prci_ddr_release_reset(struct __prci_data *pd);
292void sifive_prci_cltx_release_reset(struct __prci_data *pd);
293
294/* Core clock mux control */
295void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd);
296void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd);
297void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd);
298void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd);
299void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd);
300void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd);
301void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd);
302
303unsigned long sifive_prci_wrpll_round_rate(struct __prci_clock *pc,
304 unsigned long rate,
305 unsigned long *parent_rate);
306
307/* Linux clock framework integration */
308int sifive_prci_wrpll_set_rate(struct __prci_clock *pc,
309 unsigned long rate,
310 unsigned long parent_rate);
311
312unsigned long sifive_prci_wrpll_recalc_rate(struct __prci_clock *pc,
313 unsigned long parent_rate);
314
315unsigned long sifive_prci_tlclksel_recalc_rate(struct __prci_clock *pc,
316 unsigned long parent_rate);
317
318unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct __prci_clock *pc,
319 unsigned long parent_rate);
320
321int sifive_prci_clock_enable(struct __prci_clock *pc, bool enable);
322
323#endif /* __SIFIVE_CLK_SIFIVE_PRCI_H */