1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021, Adrian Chadd <adrian@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /* Driver for Qualcomm IPQ4018 clock and reset device */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
37 #include <sys/sglist.h>
38 #include <sys/random.h>
39 #include <sys/stdatomic.h>
40 #include <sys/mutex.h>
41 
42 #include <machine/bus.h>
43 #include <machine/resource.h>
44 #include <sys/bus.h>
45 
46 #include <dev/fdt/fdt_common.h>
47 #include <dev/ofw/ofw_bus.h>
48 #include <dev/ofw/ofw_bus_subr.h>
49 
50 #include <dev/extres/clk/clk_div.h>
51 #include <dev/extres/clk/clk_fixed.h>
52 #include <dev/extres/clk/clk_mux.h>
53 #include <dev/extres/clk/clk_link.h>
54 
55 #include <dt-bindings/clock/qcom,gcc-ipq4019.h>
56 
57 #include <dev/qcom_clk/qcom_clk_freqtbl.h>
58 #include <dev/qcom_clk/qcom_clk_fepll.h>
59 #include <dev/qcom_clk/qcom_clk_fdiv.h>
60 #include <dev/qcom_clk/qcom_clk_apssdiv.h>
61 #include <dev/qcom_clk/qcom_clk_rcg2.h>
62 #include <dev/qcom_clk/qcom_clk_branch2.h>
63 #include <dev/qcom_clk/qcom_clk_ro_div.h>
64 
65 #include "qcom_gcc_ipq4018_var.h"
66 
67 
68 /* Fixed rate clock. */
69 #define F_RATE(_id, cname, _freq)					\
70 {									\
71 	.clkdef.id = _id,						\
72 	.clkdef.name = cname,						\
73 	.clkdef.parent_names = NULL,					\
74 	.clkdef.parent_cnt = 0,						\
75 	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
76 	.freq = _freq,							\
77 }
78 
79 /* Linked clock. */
80 #define F_LINK(_id, _cname)						\
81 {									\
82 	.clkdef.id = _id,						\
83 	.clkdef.name = _cname,						\
84 	.clkdef.parent_names = NULL,					\
85 	.clkdef.parent_cnt = 0,						\
86 	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
87 }
88 
89 
90 /* FEPLL clock */
91 #define F_FEPLL(_id, _cname, _parent, _reg, _fs, _fw, _rs, _rw)		\
92 {									\
93 	.clkdef.id = _id,						\
94 	.clkdef.name = _cname,						\
95 	.clkdef.parent_names = (const char *[]){_parent},		\
96 	.clkdef.parent_cnt = 1,						\
97 	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
98 	.offset = _reg,							\
99 	.fdbkdiv_shift = _fs,						\
100 	.fdbkdiv_width = _fw,						\
101 	.refclkdiv_shift = _rs,						\
102 	.refclkdiv_width = _rw,						\
103 }
104 
105 /* Fixed divisor clock */
106 #define F_FDIV(_id, _cname, _parent, _divisor)				\
107 {									\
108 	.clkdef.id = _id,						\
109 	.clkdef.name = _cname,						\
110 	.clkdef.parent_names = (const char *[]){_parent},		\
111 	.clkdef.parent_cnt = 1,						\
112 	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
113 	.divisor = _divisor,						\
114 }
115 
116 /* APSS DIV clock */
117 #define F_APSSDIV(_id, _cname, _parent, _doffset, _dshift, _dwidth,	\
118     _eoffset, _eshift, _freqtbl)					\
119 {									\
120 	.clkdef.id = _id,						\
121 	.clkdef.name = _cname,						\
122 	.clkdef.parent_names = (const char *[]){_parent},		\
123 	.clkdef.parent_cnt = 1,						\
124 	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
125 	.div_offset = _doffset,						\
126 	.div_width = _dwidth,						\
127 	.div_shift = _dshift,						\
128 	.enable_offset = _eoffset,					\
129 	.enable_shift = _eshift,					\
130 	.freq_tbl = _freqtbl,						\
131 }
132 
133 /* read-only div table */
134 #define	F_RO_DIV(_id, _cname, _parent, _offset, _shift, _width, _tbl)	\
135 {									\
136 	.clkdef.id = _id,						\
137 	.clkdef.name = _cname,						\
138 	.clkdef.parent_names = (const char *[]){_parent},		\
139 	.clkdef.parent_cnt = 1,						\
140 	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
141 	.offset = _offset,						\
142 	.width = _width,						\
143 	.shift = _shift,						\
144 	.div_tbl = _tbl,						\
145 }
146 
147 /* RCG2 clock */
148 #define F_RCG2(_id, _cname, _parents, _rcgr, _hid_width, _mnd_width,	\
149     _safe_src_idx, _safe_pre_parent_idx, _cfg_offset, _flags,		\
150     _freq_tbl)								\
151 {									\
152 	.clkdef.id = _id,						\
153 	.clkdef.name = _cname,						\
154 	.clkdef.parent_names = _parents,				\
155 	.clkdef.parent_cnt = nitems(_parents),				\
156 	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
157 	.cmd_rcgr = _rcgr,						\
158 	.hid_width = _hid_width,					\
159 	.mnd_width = _mnd_width,					\
160 	.safe_src_idx = _safe_src_idx,					\
161 	.flags= _flags,							\
162 	.safe_pre_parent_idx = _safe_pre_parent_idx,			\
163 	.freq_tbl = _freq_tbl,						\
164 }
165 
166 /* branch2 gate nodes */
167 #define	F_BRANCH2(_id, _cname, _parent, _eo, _es, _hr, _hs, _haltreg,	\
168     _type, _voted, _flags)						\
169 {									\
170 	.clkdef.id = _id,						\
171 	.clkdef.name = _cname,						\
172 	.clkdef.parent_names = (const char *[]){_parent},		\
173 	.clkdef.parent_cnt = 1,						\
174 	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
175 	.enable_offset = _eo,						\
176 	.enable_shift = _es,						\
177 	.hwcg_reg = _hr,						\
178 	.hwcg_bit = _hs,						\
179 	.halt_reg = _haltreg,						\
180 	.halt_check_type = _type,					\
181 	.halt_check_voted = _voted,					\
182 	.flags = _flags,						\
183 }
184 
185 /*
186  * Fixed "gcc_fepll_vco" PLL derived sources:
187  *
188  * P_FEPLL125 - 125MHz
189  * P_FEPLL125DLY - 125MHz
190  * P_FEPLL200 - 200MHz
191  * "fepll500" - 500MHz
192  *
193  * Fixed "gcc_apps_ddrpll_vco" PLL derived sources:
194  *
195  * P_DDRPLL - 192MHz
196  */
197 static struct qcom_clk_fdiv_def fdiv_tbl[] = {
198 	F_FDIV(GCC_FEPLL125_CLK, "fepll125", "gcc_fepll_vco", 32),
199 	F_FDIV(GCC_FEPLL125DLY_CLK, "fepll125dly", "gcc_fepll_vco", 32),
200 	F_FDIV(GCC_FEPLL200_CLK, "fepll200", "gcc_fepll_vco", 20),
201 	F_FDIV(GCC_FEPLL500_CLK, "fepll500", "gcc_fepll_vco", 8),
202 	F_FDIV(GCC_SDCC_PLLDIV_CLK, "ddrpllsdcc", "gcc_apps_ddrpll_vco", 28),
203 };
204 
205 /*
206  * FEPLL - 48MHz (xo) input, 4GHz output
207  * DDRPLL - 48MHz (xo) input, 5.376GHz output
208  */
209 static struct qcom_clk_fepll_def fepll_tbl[] = {
210 	F_FEPLL(GCC_FEPLL_VCO, "gcc_fepll_vco", "xo", 0x2f020, 16, 8, 24, 5),
211 	F_FEPLL(GCC_APSS_DDRPLL_VCO, "gcc_apps_ddrpll_vco", "xo", 0x2e020,
212 	    16, 8, 24, 5),
213 };
214 
215 /*
216  * Frequency table for the APSS PLL/DIV path for the CPU frequency.
217  *
218  * Note - the APSS DIV code only needs the frequency and pre-divisor,
219  * not the other fields.
220  */
221 static struct qcom_clk_freq_tbl apss_freq_tbl[] = {
222 	{ 384000000, "gcc_apps_ddrpll_vco", 0xd, 0, 0 },
223 	{ 413000000, "gcc_apps_ddrpll_vco", 0xc, 0, 0 },
224 	{ 448000000, "gcc_apps_ddrpll_vco", 0xb, 0, 0 },
225 	{ 488000000, "gcc_apps_ddrpll_vco", 0xa, 0, 0 },
226 	{ 512000000, "gcc_apps_ddrpll_vco", 0x9, 0, 0 },
227 	{ 537000000, "gcc_apps_ddrpll_vco", 0x8, 0, 0 },
228 	{ 565000000, "gcc_apps_ddrpll_vco", 0x7, 0, 0 },
229 	{ 597000000, "gcc_apps_ddrpll_vco", 0x6, 0, 0 },
230 	{ 632000000, "gcc_apps_ddrpll_vco", 0x5, 0, 0 },
231 	{ 672000000, "gcc_apps_ddrpll_vco", 0x4, 0, 0 },
232 	{ 716000000, "gcc_apps_ddrpll_vco", 0x3, 0, 0 },
233 	{ 768000000, "gcc_apps_ddrpll_vco", 0x2, 0, 0 },
234 	{ 823000000, "gcc_apps_ddrpll_vco", 0x1, 0, 0 },
235 	{ 896000000, "gcc_apps_ddrpll_vco", 0x0, 0, 0 },
236 	{ 0, }
237 };
238 
239 /*
240  * APSS div/gate
241  */
242 static struct qcom_clk_apssdiv_def apssdiv_tbl[] = {
243 	F_APSSDIV(GCC_APSS_CPU_PLLDIV_CLK, "ddrpllapss",
244 	    "gcc_apps_ddrpll_vco", 0x2e020,
245 	    4, 4, 0x2e000, 0, &apss_freq_tbl[0]),
246 };
247 
248 /*
249  * Parent clocks for the apps_clk_src clock.
250  */
251 static const char * apps_clk_src_parents[] = {
252 	"xo", "ddrpllapss", "fepll500", "fepll200"
253 };
254 
255 /*
256  * Parents lists for a variety of blocks.
257  */
258 static const char * gcc_xo_200_parents[] = {
259 	"xo", "fepll200"
260 };
261 static const char * gcc_xo_200_500_parents[] = {
262 	"xo", "fepll200", "fepll500"
263 };
264 static const char * gcc_xo_200_spi_parents[] = {
265 	"xo", NULL, "fepll200"
266 };
267 static const char * gcc_xo_sdcc1_500_parents[] = {
268 	"xo", "ddrpllsdcc", "fepll500"
269 };
270 
271 static const char * gcc_xo_125_dly_parents[] = {
272 	"xo", "fepll125dly"
273 };
274 
275 static const char * gcc_xo_wcss2g_parents[] = {
276 	"xo", "fepllwcss2g"
277 };
278 
279 static const char * gcc_xo_wcss5g_parents[] = {
280 	"xo", "fepllwcss5g"
281 };
282 
283 static struct qcom_clk_freq_tbl apps_clk_src_freq_tbl[] = {
284 	{ 48000000, "xo", 1, 0, 0 },
285 	{ 200000000, "fepll200", 1, 0, 0 },
286 	{ 384000000, "ddrpllapss", 1, 0, 0 },
287 	{ 413000000, "ddrpllapss", 1, 0, 0 },
288 	{ 448000000, "ddrpllapss", 1, 0, 0 },
289 	{ 488000000, "ddrpllapss", 1, 0, 0 },
290 	{ 500000000, "fepll500", 1, 0, 0 },
291 	{ 512000000, "ddrpllapss", 1, 0, 0 },
292 	{ 537000000, "ddrpllapss", 1, 0, 0 },
293 	{ 565000000, "ddrpllapss", 1, 0, 0 },
294 	{ 597000000, "ddrpllapss", 1, 0, 0 },
295 	{ 632000000, "ddrpllapss", 1, 0, 0 },
296 	{ 672000000, "ddrpllapss", 1, 0, 0 },
297 	{ 716000000, "ddrpllapss", 1, 0, 0 },
298 	{ 0,}
299 
300 };
301 
302 static struct qcom_clk_freq_tbl audio_clk_src_freq_tbl[] = {
303 	{ 48000000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
304 	{ 200000000, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
305 	{ 0,}
306 };
307 
308 static struct qcom_clk_freq_tbl blsp1_qup1_i2c_apps_clk_src_freq_tbl[] = {
309 	{ 19050000, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(10.5), 1, 1 },
310 	{ 0,}
311 };
312 
313 static struct qcom_clk_freq_tbl blsp1_qup1_spi_apps_clk_src_freq_tbl[] = {
314 	{ 960000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(12), 1, 4 },
315 	{ 4800000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1, 10 },
316 	{ 9600000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1, 5 },
317 	{ 15000000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1, 3 },
318 	{ 19200000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 2, 5 },
319 	{ 24000000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1, 2 },
320 	{ 48000000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
321 	{ 0,}
322 };
323 
324 static struct qcom_clk_freq_tbl gcc_pcnoc_ahb_clk_src_freq_tbl[] = {
325 	{ 48000000,  "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
326 	{ 100000000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(2), 0, 0 },
327 	{ 0, }
328 };
329 
330 static struct qcom_clk_freq_tbl blsp1_uart1_apps_clk_src_freq_tbl[] = {
331 	{ 1843200, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 144, 15625 },
332 	{ 3686400, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 288, 15625 },
333 	{ 7372800, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 576, 15625 },
334 	{ 14745600, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1152, 15625 },
335 	{ 16000000, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 2, 25 },
336 	{ 24000000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1, 2 },
337 	{ 32000000, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 4, 25 },
338 	{ 40000000, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1, 5 },
339 	{ 46400000, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 29, 125 },
340 	{ 48000000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
341 	{ 0, }
342 };
343 
344 static struct qcom_clk_freq_tbl gp1_clk_src_freq_tbl[] = {
345 	{ 1250000, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 16, 0 },
346 	{ 2500000, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1),  8, 0 },
347 	{ 5000000, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(1),  4, 0 },
348 	{ 0, }
349 };
350 
351 static struct qcom_clk_freq_tbl sdcc1_apps_clk_src_freq_tbl[] = {
352 	{ 144000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 3, 240 },
353 	{ 400000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1, 0 },
354 	{ 20000000, "fepll500", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1, 25 },
355 	{ 25000000, "fepll500", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1, 20 },
356 	{ 50000000, "fepll500", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1, 10 },
357 	{ 100000000, "fepll500", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 1, 5 },
358 	{ 192000000, "ddrpllsdcc", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
359 	{ 0, }
360 };
361 
362 static struct qcom_clk_freq_tbl apps_ahb_clk_src_freq_tbl[] = {
363 	{ 48000000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
364 	{ 100000000, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(2), 0, 0 },
365 	{ 0, }
366 };
367 
368 static struct qcom_clk_freq_tbl usb30_mock_utmi_clk_src_freq_tbl[] = {
369 	{ 2000000, "fepll200", QCOM_CLK_FREQTBL_PREDIV_RCG2(10), 0, 0 },
370 	{ 0, }
371 };
372 
373 static struct qcom_clk_freq_tbl fephy_125m_dly_clk_src_freq_tbl[] = {
374 	{ 125000000, "fepll125dly", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
375 	{ 0, }
376 };
377 
378 static struct qcom_clk_freq_tbl wcss2g_clk_src_freq_tbl[] = {
379 	{ 48000000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
380 	{ 250000000, "fepllwcss2g", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
381 	{ 0, }
382 };
383 
384 static struct qcom_clk_freq_tbl wcss5g_clk_src_freq_tbl[] = {
385 	{ 48000000, "xo", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
386 	{ 250000000, "fepllwcss5g", QCOM_CLK_FREQTBL_PREDIV_RCG2(1), 0, 0 },
387 	{ 0, }
388 };
389 
390 /*
391  * Divisor table for the 2g/5g wifi clock divisors.
392  */
393 static struct qcom_clk_ro_div_tbl fepllwcss_clk_div_tbl[] = {
394 	{ 0, 15 },
395 	{ 1, 16 },
396 	{ 2, 18 },
397 	{ 3, 20 },
398 	{ 0, 0 }
399 };
400 
401 /*
402  * Read-only divisor table clocks.
403  */
404 static struct qcom_clk_ro_div_def ro_div_tbl[] = {
405 	F_RO_DIV(GCC_FEPLL_WCSS2G_CLK, "fepllwcss2g", "gcc_fepll_vco",
406 	     0x2f020, 8, 2, &fepllwcss_clk_div_tbl[0]),
407 	F_RO_DIV(GCC_FEPLL_WCSS5G_CLK, "fepllwcss5g", "gcc_fepll_vco",
408 	     0x2f020, 12, 2, &fepllwcss_clk_div_tbl[0]),
409 };
410 
411 /*
412  * RCG2 clocks
413  */
414 static struct qcom_clk_rcg2_def rcg2_tbl[] = {
415 	F_RCG2(AUDIO_CLK_SRC, "audio_clk_src", gcc_xo_200_parents,
416 	    0x1b000, 5, 0, -1, -1, 0, 0, &audio_clk_src_freq_tbl[0]),
417 	F_RCG2(BLSP1_QUP1_I2C_APPS_CLK_SRC, "blsp1_qup1_i2c_apps_clk_src",
418 	    gcc_xo_200_parents, 0x200c, 5, 0, -1, -1, 0, 0,
419 	    &blsp1_qup1_i2c_apps_clk_src_freq_tbl[0]),
420 	F_RCG2(BLSP1_QUP2_I2C_APPS_CLK_SRC, "blsp1_qup2_i2c_apps_clk_src",
421 	    gcc_xo_200_parents, 0x3000, 5, 0, -1, -1, 0, 0,
422 	    &blsp1_qup1_i2c_apps_clk_src_freq_tbl[0]),
423 	F_RCG2(BLSP1_QUP1_SPI_APPS_CLK_SRC, "blsp1_qup1_spi_apps_clk_src",
424 	    gcc_xo_200_spi_parents, 0x2024, 5, 8, -1, -1, 0, 0,
425 	    &blsp1_qup1_spi_apps_clk_src_freq_tbl[0]),
426 	F_RCG2(BLSP1_QUP2_SPI_APPS_CLK_SRC, "blsp1_qup2_spi_apps_clk_src",
427 	    gcc_xo_200_spi_parents, 0x3014, 5, 8, -1, -1, 0, 0,
428 	    &blsp1_qup1_spi_apps_clk_src_freq_tbl[0]),
429 	F_RCG2(BLSP1_UART1_APPS_CLK_SRC, "blsp1_uart1_apps_clk_src",
430 	    gcc_xo_200_spi_parents, 0x2044, 5, 16, -1, -1, 0, 0,
431 	    &blsp1_uart1_apps_clk_src_freq_tbl[0]),
432 	F_RCG2(BLSP1_UART2_APPS_CLK_SRC, "blsp1_uart2_apps_clk_src",
433 	    gcc_xo_200_spi_parents, 0x3034, 5, 16, -1, -1, 0, 0,
434 	    &blsp1_uart1_apps_clk_src_freq_tbl[0]),
435 	F_RCG2(GP1_CLK_SRC, "gp1_clk_src", gcc_xo_200_parents, 0x8004,
436 	    5, 8, -1, -1, 0, 0,
437 	    &gp1_clk_src_freq_tbl[0]),
438 	F_RCG2(GP2_CLK_SRC, "gp2_clk_src", gcc_xo_200_parents, 0x9004,
439 	    5, 8, -1, -1, 0, 0,
440 	    &gp1_clk_src_freq_tbl[0]),
441 	F_RCG2(GP3_CLK_SRC, "gp3_clk_src", gcc_xo_200_parents, 0xa004,
442 	    5, 8, -1, -1, 0, 0,
443 	    &gp1_clk_src_freq_tbl[0]),
444 	F_RCG2(SDCC1_APPS_CLK_SRC, "sdcc1_apps_clk_src",
445 	    gcc_xo_sdcc1_500_parents, 0x18004, 5, 0, -1, -1, 0, 0,
446 	    &sdcc1_apps_clk_src_freq_tbl[0]),
447 	F_RCG2(GCC_APPS_CLK_SRC, "apps_clk_src", apps_clk_src_parents,
448 	    0x1900c, 5, 0, -1, 2, 0,
449 	    QCOM_CLK_RCG2_FLAGS_SET_RATE_PARENT,
450 	    &apps_clk_src_freq_tbl[0]),
451 	F_RCG2(GCC_APPS_AHB_CLK_SRC, "apps_ahb_clk_src",
452 	    gcc_xo_200_500_parents, 0x19014, 5, 0, -1, -1, 0,
453 	    0, &apps_ahb_clk_src_freq_tbl[0]),
454 	F_RCG2(GCC_USB3_MOCK_UTMI_CLK_SRC, "usb30_mock_utmi_clk_src",
455 	    gcc_xo_200_parents, 0x1e000, 5, 0, -1, -1, 0, 0,
456 	    &usb30_mock_utmi_clk_src_freq_tbl[0]),
457 	F_RCG2(FEPHY_125M_DLY_CLK_SRC, "fephy_125m_dly_clk_src",
458 	    gcc_xo_125_dly_parents, 0x12000, 5, 0, -1, -1, 0, 0,
459 	    &fephy_125m_dly_clk_src_freq_tbl[0]),
460 	F_RCG2(WCSS2G_CLK_SRC, "wcss2g_clk_src", gcc_xo_wcss2g_parents,
461 	    0x1f000, 5, 0, -1, -1, 0, 0,
462 	    &wcss2g_clk_src_freq_tbl[0]),
463 	F_RCG2(WCSS5G_CLK_SRC, "wcss5g_clk_src", gcc_xo_wcss5g_parents,
464 	    0x20000, 5, 0, -1, -1, 0, 0,
465 	    &wcss5g_clk_src_freq_tbl[0]),
466 	F_RCG2(GCC_PCNOC_AHB_CLK_SRC, "gcc_pcnoc_ahb_clk_src",
467 	    gcc_xo_200_500_parents, 0x21024, 5, 0, -1, -1, 0, 0,
468 	    &gcc_pcnoc_ahb_clk_src_freq_tbl[0]),
469 };
470 
471 /*
472  * branch2 clocks
473  */
474 static struct qcom_clk_branch2_def branch2_tbl[] = {
475 	F_BRANCH2(GCC_AUDIO_AHB_CLK, "gcc_audio_ahb_clk", "pcnoc_clk_src",
476 	    0x1b010, 0, 0, 0, 0x1b010, QCOM_CLK_BRANCH2_BRANCH_HALT,
477 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
478 	F_BRANCH2(GCC_AUDIO_PWM_CLK, "gcc_audio_pwm_clk", "audio_clk_src",
479 	    0x1b00c, 0, 0, 0, 0x1b00c, QCOM_CLK_BRANCH2_BRANCH_HALT,
480 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
481 	F_BRANCH2(GCC_BLSP1_QUP1_I2C_APPS_CLK, "gcc_blsp1_qup1_i2c_apps_clk",
482 	    "blsp1_qup1_i2c_apps_clk_src",
483 	    0x2008, 0, 0, 0, 0x2008, QCOM_CLK_BRANCH2_BRANCH_HALT,
484 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
485 	F_BRANCH2(GCC_BLSP1_QUP2_I2C_APPS_CLK, "gcc_blsp1_qup2_i2c_apps_clk",
486 	    "blsp1_qup2_i2c_apps_clk_src",
487 	    0x3010, 0, 0, 0, 0x3010, QCOM_CLK_BRANCH2_BRANCH_HALT,
488 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
489 	F_BRANCH2(GCC_BLSP1_QUP1_SPI_APPS_CLK, "gcc_blsp1_qup1_spi_apps_clk",
490 	    "blsp1_qup1_spi_apps_clk_src",
491 	    0x2004, 0, 0, 0, 0x2004, QCOM_CLK_BRANCH2_BRANCH_HALT,
492 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
493 	F_BRANCH2(GCC_BLSP1_QUP2_SPI_APPS_CLK, "gcc_blsp1_qup2_spi_apps_clk",
494 	    "blsp1_qup2_spi_apps_clk_src",
495 	    0x300c, 0, 0, 0, 0x300c, QCOM_CLK_BRANCH2_BRANCH_HALT,
496 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
497 	F_BRANCH2(GCC_BLSP1_UART1_APPS_CLK, "gcc_blsp1_uart1_apps_clk",
498 	    "blsp1_uart1_apps_clk_src",
499 	    0x203c, 0, 0, 0, 0x203c, QCOM_CLK_BRANCH2_BRANCH_HALT,
500 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
501 	F_BRANCH2(GCC_BLSP1_UART2_APPS_CLK, "gcc_blsp1_uart2_apps_clk",
502 	    "blsp1_uart2_apps_clk_src",
503 	    0x302c, 0, 0, 0, 0x302c, QCOM_CLK_BRANCH2_BRANCH_HALT,
504 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
505 	F_BRANCH2(GCC_GP1_CLK, "gcc_gp1_clk", "gp1_clk_src",
506 	    0x8000, 0, 0, 0, 0x8000, QCOM_CLK_BRANCH2_BRANCH_HALT,
507 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
508 	F_BRANCH2(GCC_GP2_CLK, "gcc_gp2_clk", "gp2_clk_src",
509 	    0x9000, 0, 0, 0, 0x9000, QCOM_CLK_BRANCH2_BRANCH_HALT,
510 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
511 	F_BRANCH2(GCC_GP3_CLK, "gcc_gp3_clk", "gp3_clk_src",
512 	    0xa000, 0, 0, 0, 0xa000, QCOM_CLK_BRANCH2_BRANCH_HALT,
513 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
514 	/* BRANCH_HALT_VOTED; note the different enable/halt */
515 	F_BRANCH2(GCC_APPS_AHB_CLK_SRC, "gcc_apss_ahb_clk",
516 	    "apps_ahb_clk_src",
517 	    0x6000, 14, 0, 0, 0x19004, QCOM_CLK_BRANCH2_BRANCH_HALT,
518 	    true, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
519 	F_BRANCH2(GCC_BLSP1_AHB_CLK, "gcc_blsp1_ahb_clk",
520 	    "pcnoc_clk_src",
521 	    0x6000, 10, 0, 0, 0x1008, QCOM_CLK_BRANCH2_BRANCH_HALT,
522 	    true, 0), /* BRANCH_HALT_VOTED */
523 	F_BRANCH2(GCC_DCD_XO_CLK, "gcc_dcd_xo_clk", "xo",
524 	    0x2103c, 0, 0, 0, 0x2103c, QCOM_CLK_BRANCH2_BRANCH_HALT,
525 	    false, 0),
526 	F_BRANCH2(GCC_BOOT_ROM_AHB_CLK, "gcc_boot_rom_ahb_clk",
527 	    "pcnoc_clk_src", 0x1300c, 0, 0, 0, 0x1300c,
528 	    QCOM_CLK_BRANCH2_BRANCH_HALT,
529 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
530 	F_BRANCH2(GCC_CRYPTO_AHB_CLK, "gcc_crypto_ahb_clk",
531 	    "pcnoc_clk_src", 0x6000, 0, 0, 0, 0x16024,
532 	    QCOM_CLK_BRANCH2_BRANCH_HALT,
533 	    true, 0), /* BRANCH_HALT_VOTED */
534 	F_BRANCH2(GCC_CRYPTO_AXI_CLK, "gcc_crypto_axi_clk",
535 	    "fepll125", 0x6000, 1, 0, 0, 0x16020,
536 	    QCOM_CLK_BRANCH2_BRANCH_HALT,
537 	    true, 0), /* BRANCH_HALT_VOTED */
538 	F_BRANCH2(GCC_CRYPTO_CLK, "gcc_crypto_clk", "fepll125",
539 	    0x6000, 2, 0, 0, 0x1601c, QCOM_CLK_BRANCH2_BRANCH_HALT,
540 	    true, 0), /* BRANCH_HALT_VOTED */
541 	F_BRANCH2(GCC_ESS_CLK, "gcc_ess_clk", "fephy_125m_dly_clk_src",
542 	    0x12010, 0, 0, 0, 0x12010, QCOM_CLK_BRANCH2_BRANCH_HALT,
543 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
544 	/* BRANCH_HALT_VOTED */
545 	F_BRANCH2(GCC_IMEM_AXI_CLK, "gcc_imem_axi_clk", "fepll200",
546 	    0x6000, 17, 0, 0, 0xe004, QCOM_CLK_BRANCH2_BRANCH_HALT,
547 	    true, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
548 	F_BRANCH2(GCC_IMEM_CFG_AHB_CLK, "gcc_imem_cfg_ahb_clk",
549 	    "pcnoc_clk_src",
550 	    0xe008, 0, 0, 0, 0xe008, QCOM_CLK_BRANCH2_BRANCH_HALT,
551 	    false, 0),
552 	F_BRANCH2(GCC_PCIE_AHB_CLK, "gcc_pcie_ahb_clk", "pcnoc_clk_src",
553 	    0x1d00c, 0, 0, 0, 0x1d00c, QCOM_CLK_BRANCH2_BRANCH_HALT,
554 	    false, 0),
555 	F_BRANCH2(GCC_PCIE_AXI_M_CLK, "gcc_pcie_axi_m_clk", "fepll200",
556 	    0x1d004, 0, 0, 0, 0x1d004, QCOM_CLK_BRANCH2_BRANCH_HALT,
557 	    false, 0),
558 	F_BRANCH2(GCC_PCIE_AXI_S_CLK, "gcc_pcie_axi_s_clk", "fepll200",
559 	    0x1d008, 0, 0, 0, 0x1d008, QCOM_CLK_BRANCH2_BRANCH_HALT,
560 	    false, 0),
561 	F_BRANCH2(GCC_PRNG_AHB_CLK, "gcc_prng_ahb_clk", "pcnoc_clk_src",
562 	    0x6000, 8, 0, 0, 0x13004, QCOM_CLK_BRANCH2_BRANCH_HALT,
563 	    true, 0), /* BRANCH_HALT_VOTED */
564 	F_BRANCH2(GCC_QPIC_AHB_CLK, "gcc_qpic_ahb_clk", "pcnoc_clk_src",
565 	    0x1c008, 0, 0, 0, 0x1c008, QCOM_CLK_BRANCH2_BRANCH_HALT,
566 	    false, 0),
567 	F_BRANCH2(GCC_QPIC_CLK, "gcc_qpic_clk", "pcnoc_clk_src",
568 	    0x1c004, 0, 0, 0, 0x1c004, QCOM_CLK_BRANCH2_BRANCH_HALT,
569 	    false, 0),
570 	F_BRANCH2(GCC_SDCC1_AHB_CLK, "gcc_sdcc1_ahb_clk", "pcnoc_clk_src",
571 	    0x18010, 0, 0, 0, 0x18010, QCOM_CLK_BRANCH2_BRANCH_HALT,
572 	    false, 0),
573 	F_BRANCH2(GCC_SDCC1_APPS_CLK, "gcc_sdcc1_apps_clk",
574 	    "sdcc1_apps_clk_src", 0x1800c, 0, 0, 0, 0x1800c,
575 	    QCOM_CLK_BRANCH2_BRANCH_HALT,
576 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
577 	F_BRANCH2(GCC_TLMM_AHB_CLK, "gcc_tlmm_ahb_clk", "pcnoc_clk_src",
578 	    0x6000, 5, 0, 0, 0x5004, QCOM_CLK_BRANCH2_BRANCH_HALT,
579 	    true, 0), /* BRANCH_HALT_VOTED */
580 	F_BRANCH2(GCC_USB2_MASTER_CLK, "gcc_usb2_master_clk", "pcnoc_clk_src",
581 	    0x1e00c, 0, 0, 0, 0x1e00c, QCOM_CLK_BRANCH2_BRANCH_HALT,
582 	    false, 0),
583 	F_BRANCH2(GCC_USB2_SLEEP_CLK, "gcc_usb2_sleep_clk",
584 	    "gcc_sleep_clk_src", 0x1e010, 0, 0, 0, 0x1e010,
585 	    QCOM_CLK_BRANCH2_BRANCH_HALT,
586 	    false, 0),
587 	F_BRANCH2(GCC_USB2_MOCK_UTMI_CLK, "gcc_usb2_mock_utmi_clk",
588 	    "usb30_mock_utmi_clk_src", 0x1e014, 0, 0, 0, 0x1e014,
589 	    QCOM_CLK_BRANCH2_BRANCH_HALT,
590 	    false, 0),
591 	F_BRANCH2(GCC_USB3_MASTER_CLK, "gcc_usb3_master_clk", "fepll125",
592 	    0x1e028, 0, 0, 0, 0x1e028, QCOM_CLK_BRANCH2_BRANCH_HALT,
593 	    false, 0),
594 	F_BRANCH2(GCC_USB3_SLEEP_CLK, "gcc_usb3_sleep_clk", "gcc_sleep_clk_src",
595 	    0x1e02c, 0, 0, 0, 0x1e02c, QCOM_CLK_BRANCH2_BRANCH_HALT,
596 	    false, 0),
597 	F_BRANCH2(GCC_USB3_MOCK_UTMI_CLK, "gcc_usb3_mock_utmi_clk",
598 	    "usb30_mock_utmi_clk_src",
599 	    0x1e030, 0, 0, 0, 0x1e030, QCOM_CLK_BRANCH2_BRANCH_HALT,
600 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
601 	/* Note - yes, these two have the same registers in linux */
602 	F_BRANCH2(GCC_WCSS2G_CLK, "gcc_wcss2g_clk", "wcss2g_clk_src",
603 	    0x1f00c, 0, 0, 0, 0x1f00c, QCOM_CLK_BRANCH2_BRANCH_HALT,
604 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
605 	F_BRANCH2(GCC_WCSS2G_REF_CLK, "gcc_wcss2g_ref_clk", "xo",
606 	    0x1f00c, 0, 0, 0, 0x1f00c, QCOM_CLK_BRANCH2_BRANCH_HALT,
607 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
608 	F_BRANCH2(GCC_WCSS2G_RTC_CLK, "gcc_wcss2g_rtc_clk", "gcc_sleep_clk_src",
609 	    0x1f010, 0, 0, 0, 0x1f010, QCOM_CLK_BRANCH2_BRANCH_HALT,
610 	    false, 0),
611 
612 	/* Note - yes, these two have the same registers in linux */
613 	F_BRANCH2(GCC_WCSS5G_CLK, "gcc_wcss5g_clk", "wcss5g_clk_src",
614 	    0x1f00c, 0, 0, 0, 0x2000c, QCOM_CLK_BRANCH2_BRANCH_HALT,
615 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
616 	F_BRANCH2(GCC_WCSS5G_REF_CLK, "gcc_wcss5g_ref_clk", "xo",
617 	    0x1f00c, 0, 0, 0, 0x2000c, QCOM_CLK_BRANCH2_BRANCH_HALT,
618 	    false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
619 	F_BRANCH2(GCC_WCSS5G_RTC_CLK, "gcc_wcss5g_rtc_clk", "gcc_sleep_clk_src",
620 	    0x1f010, 0, 0, 0, 0x20010, QCOM_CLK_BRANCH2_BRANCH_HALT,
621 	    false, 0),
622 
623 	F_BRANCH2(GCC_PCNOC_AHB_CLK, "pcnoc_clk_src", "gcc_pcnoc_ahb_clk_src",
624 	    0x21030, 0, 0, 0, 0x21030, QCOM_CLK_BRANCH2_BRANCH_HALT, false,
625 	    QCOM_CLK_BRANCH2_FLAGS_CRITICAL |
626 	    QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT),
627 };
628 
629 static void
630 qcom_gcc_ipq4018_clock_init_fepll(struct qcom_gcc_ipq4018_softc *sc)
631 {
632 	int i, rv;
633 
634 	for (i = 0; i < nitems(fepll_tbl); i++) {
635 		rv = qcom_clk_fepll_register(sc->clkdom, fepll_tbl + i);
636 		if (rv != 0)
637 			panic("qcom_clk_fepll_register failed");
638 	}
639 }
640 
641 static void
642 qcom_gcc_ipq4018_clock_init_fdiv(struct qcom_gcc_ipq4018_softc *sc)
643 {
644 	int i, rv;
645 
646 	for (i = 0; i < nitems(fdiv_tbl); i++) {
647 		rv = qcom_clk_fdiv_register(sc->clkdom, fdiv_tbl + i);
648 		if (rv != 0)
649 			panic("qcom_clk_fdiv_register failed");
650 	}
651 }
652 
653 static void
654 qcom_gcc_ipq4018_clock_init_apssdiv(struct qcom_gcc_ipq4018_softc *sc)
655 {
656 	int i, rv;
657 
658 	for (i = 0; i < nitems(apssdiv_tbl); i++) {
659 		rv = qcom_clk_apssdiv_register(sc->clkdom, apssdiv_tbl + i);
660 		if (rv != 0)
661 			panic("qcom_clk_apssdiv_register failed");
662 	}
663 }
664 
665 static void
666 qcom_gcc_ipq4018_clock_init_rcg2(struct qcom_gcc_ipq4018_softc *sc)
667 {
668 	int i, rv;
669 
670 	for (i = 0; i < nitems(rcg2_tbl); i++) {
671 		rv = qcom_clk_rcg2_register(sc->clkdom, rcg2_tbl + i);
672 		if (rv != 0)
673 			panic("qcom_clk_rcg2_register failed");
674 	}
675 }
676 
677 static void
678 qcom_gcc_ipq4018_clock_init_branch2(struct qcom_gcc_ipq4018_softc *sc)
679 {
680 	int i, rv;
681 
682 	for (i = 0; i < nitems(branch2_tbl); i++) {
683 		rv = qcom_clk_branch2_register(sc->clkdom, branch2_tbl + i);
684 		if (rv != 0)
685 			panic("qcom_clk_branch2_register failed");
686 	}
687 }
688 
689 static void
690 qcom_gcc_ipq4018_clock_init_ro_div(struct qcom_gcc_ipq4018_softc *sc)
691 {
692 	int i, rv;
693 
694 	for (i = 0; i < nitems(ro_div_tbl); i++) {
695 		rv = qcom_clk_ro_div_register(sc->clkdom, ro_div_tbl + i);
696 		if (rv != 0)
697 			panic("qcom_clk_ro_div_register failed");
698 	}
699 }
700 
701 int
702 qcom_gcc_ipq4018_clock_read(device_t dev, bus_addr_t addr, uint32_t *val)
703 {
704 	struct qcom_gcc_ipq4018_softc *sc;
705 
706 	sc = device_get_softc(dev);
707 	*val = bus_read_4(sc->reg, addr);
708 	return (0);
709 }
710 
711 int
712 qcom_gcc_ipq4018_clock_write(device_t dev, bus_addr_t addr, uint32_t val)
713 {
714 	struct qcom_gcc_ipq4018_softc *sc;
715 
716 	sc = device_get_softc(dev);
717 	bus_write_4(sc->reg, addr, val);
718 	return (0);
719 }
720 
721 int
722 qcom_gcc_ipq4018_clock_modify(device_t dev, bus_addr_t addr,
723      uint32_t clear_mask, uint32_t set_mask)
724 {
725 	struct qcom_gcc_ipq4018_softc *sc;
726 	uint32_t reg;
727 
728 	sc = device_get_softc(dev);
729 	reg = bus_read_4(sc->reg, addr);
730 	reg &= clear_mask;
731 	reg |= set_mask;
732 	bus_write_4(sc->reg, addr, reg);
733 	return (0);
734 }
735 
736 void
737 qcom_gcc_ipq4018_clock_setup(struct qcom_gcc_ipq4018_softc *sc)
738 {
739 
740 	sc->clkdom = clkdom_create(sc->dev);
741 
742 	/* Setup stuff */
743 	qcom_gcc_ipq4018_clock_init_fepll(sc);
744 	qcom_gcc_ipq4018_clock_init_fdiv(sc);
745 	qcom_gcc_ipq4018_clock_init_apssdiv(sc);
746 	qcom_gcc_ipq4018_clock_init_rcg2(sc);
747 	qcom_gcc_ipq4018_clock_init_branch2(sc);
748 	qcom_gcc_ipq4018_clock_init_ro_div(sc);
749 
750 	/* Finalise clock tree */
751 	clkdom_finit(sc->clkdom);
752 }
753 
754 void
755 qcom_gcc_ipq4018_clock_lock(device_t dev)
756 {
757 	struct qcom_gcc_ipq4018_softc *sc;
758 
759 	sc = device_get_softc(dev);
760 	mtx_lock(&sc->mtx);
761 }
762 
763 void
764 qcom_gcc_ipq4018_clock_unlock(device_t dev)
765 {
766 	struct qcom_gcc_ipq4018_softc *sc;
767 
768 	sc = device_get_softc(dev);
769 	mtx_unlock(&sc->mtx);
770 }
771