File Index
Files and directories
Sign in
FILE

dispcc-qcm2290.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/qcom/dispcc-qcm2290.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
  4 * Copyright (c) 2021, Linaro Ltd.
  5 */
  6
  7#include <linux/clk-provider.h>
  8#include <linux/err.h>
  9#include <linux/kernel.h>
 10#include <linux/mod_devicetable.h>
 11#include <linux/module.h>
 12#include <linux/platform_device.h>
 13#include <linux/regmap.h>
 14
 15#include <dt-bindings/clock/qcom,dispcc-qcm2290.h>
 16
 17#include "clk-alpha-pll.h"
 18#include "clk-branch.h"
 19#include "clk-rcg.h"
 20#include "clk-regmap.h"
 21#include "clk-regmap-divider.h"
 22#include "common.h"
 23#include "gdsc.h"
 24#include "reset.h"
 25
 26enum {
 27	P_BI_TCXO,
 28	P_BI_TCXO_AO,
 29	P_DISP_CC_PLL0_OUT_MAIN,
 30	P_DSI0_PHY_PLL_OUT_BYTECLK,
 31	P_DSI0_PHY_PLL_OUT_DSICLK,
 32	P_GPLL0_OUT_DIV,
 33	P_GPLL0_OUT_MAIN,
 34	P_SLEEP_CLK,
 35};
 36
 37static const struct pll_vco spark_vco[] = {
 38	{ 500000000, 1000000000, 2 },
 39};
 40
 41/* 768MHz configuration */
 42static const struct alpha_pll_config disp_cc_pll0_config = {
 43	.l = 0x28,
 44	.vco_val = 0x2 << 20,
 45	.vco_mask = GENMASK(21, 20),
 46	.main_output_mask = BIT(0),
 47	.config_ctl_val = 0x4001055B,
 48};
 49
 50static struct clk_alpha_pll disp_cc_pll0 = {
 51	.offset = 0x0,
 52	.vco_table = spark_vco,
 53	.num_vco = ARRAY_SIZE(spark_vco),
 54	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
 55	.clkr = {
 56		.hw.init = &(struct clk_init_data){
 57			.name = "disp_cc_pll0",
 58			.parent_data = &(const struct clk_parent_data){
 59				.fw_name = "bi_tcxo",
 60			},
 61			.num_parents = 1,
 62			.ops = &clk_alpha_pll_ops,
 63		},
 64	},
 65};
 66
 67static const struct parent_map disp_cc_parent_map_0[] = {
 68	{ P_BI_TCXO, 0 },
 69	{ P_DSI0_PHY_PLL_OUT_BYTECLK, 1 },
 70};
 71
 72static const struct clk_parent_data disp_cc_parent_data_0[] = {
 73	{ .fw_name = "bi_tcxo" },
 74	{ .fw_name = "dsi0_phy_pll_out_byteclk" },
 75};
 76
 77static const struct parent_map disp_cc_parent_map_1[] = {
 78	{ P_BI_TCXO, 0 },
 79};
 80
 81static const struct clk_parent_data disp_cc_parent_data_1[] = {
 82	{ .fw_name = "bi_tcxo" },
 83};
 84
 85static const struct parent_map disp_cc_parent_map_2[] = {
 86	{ P_BI_TCXO_AO, 0 },
 87	{ P_GPLL0_OUT_DIV, 4 },
 88};
 89
 90static const struct clk_parent_data disp_cc_parent_data_2[] = {
 91	{ .fw_name = "bi_tcxo_ao" },
 92	{ .fw_name = "gcc_disp_gpll0_div_clk_src" },
 93};
 94
 95static const struct parent_map disp_cc_parent_map_3[] = {
 96	{ P_BI_TCXO, 0 },
 97	{ P_DISP_CC_PLL0_OUT_MAIN, 1 },
 98	{ P_GPLL0_OUT_MAIN, 4 },
 99};
100
101static const struct clk_parent_data disp_cc_parent_data_3[] = {
102	{ .fw_name = "bi_tcxo" },
103	{ .hw = &disp_cc_pll0.clkr.hw },
104	{ .fw_name = "gcc_disp_gpll0_clk_src" },
105};
106
107static const struct parent_map disp_cc_parent_map_4[] = {
108	{ P_BI_TCXO, 0 },
109	{ P_DSI0_PHY_PLL_OUT_DSICLK, 1 },
110};
111
112static const struct clk_parent_data disp_cc_parent_data_4[] = {
113	{ .fw_name = "bi_tcxo" },
114	{ .fw_name = "dsi0_phy_pll_out_dsiclk" },
115};
116
117static const struct parent_map disp_cc_parent_map_5[] = {
118	{ P_SLEEP_CLK, 0 },
119};
120
121static const struct clk_parent_data disp_cc_parent_data_5[] = {
122	{ .fw_name = "sleep_clk" },
123};
124
125static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = {
126	.cmd_rcgr = 0x20a4,
127	.mnd_width = 0,
128	.hid_width = 5,
129	.parent_map = disp_cc_parent_map_0,
130	.clkr.hw.init = &(struct clk_init_data){
131		.name = "disp_cc_mdss_byte0_clk_src",
132		.parent_data = disp_cc_parent_data_0,
133		.num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
134		/* For set_rate and set_parent to succeed, parent(s) must be enabled */
135		.flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
136		.ops = &clk_byte2_ops,
137	},
138};
139
140static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
141	.reg = 0x20bc,
142	.shift = 0,
143	.width = 2,
144	.clkr.hw.init = &(struct clk_init_data) {
145		.name = "disp_cc_mdss_byte0_div_clk_src",
146		.parent_hws = (const struct clk_hw*[]){
147			&disp_cc_mdss_byte0_clk_src.clkr.hw,
148		},
149		.num_parents = 1,
150		.ops = &clk_regmap_div_ops,
151	},
152};
153
154static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = {
155	F(19200000, P_BI_TCXO_AO, 1, 0, 0),
156	F(37500000, P_GPLL0_OUT_DIV, 8, 0, 0),
157	F(75000000, P_GPLL0_OUT_DIV, 4, 0, 0),
158	{ }
159};
160
161static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = {
162	.cmd_rcgr = 0x2154,
163	.mnd_width = 0,
164	.hid_width = 5,
165	.parent_map = disp_cc_parent_map_2,
166	.freq_tbl = ftbl_disp_cc_mdss_ahb_clk_src,
167	.clkr.hw.init = &(struct clk_init_data){
168		.name = "disp_cc_mdss_ahb_clk_src",
169		.parent_data = disp_cc_parent_data_2,
170		.num_parents = ARRAY_SIZE(disp_cc_parent_data_2),
171		.ops = &clk_rcg2_shared_ops,
172	},
173};
174
175static const struct freq_tbl ftbl_disp_cc_mdss_esc0_clk_src[] = {
176	F(19200000, P_BI_TCXO, 1, 0, 0),
177	{ }
178};
179
180static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = {
181	.cmd_rcgr = 0x20c0,
182	.mnd_width = 0,
183	.hid_width = 5,
184	.parent_map = disp_cc_parent_map_0,
185	.freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src,
186	.clkr.hw.init = &(struct clk_init_data){
187		.name = "disp_cc_mdss_esc0_clk_src",
188		.parent_data = disp_cc_parent_data_0,
189		.num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
190		.ops = &clk_rcg2_ops,
191	},
192};
193
194static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = {
195	F(19200000, P_BI_TCXO, 1, 0, 0),
196	F(192000000, P_DISP_CC_PLL0_OUT_MAIN, 4, 0, 0),
197	F(256000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
198	F(307200000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
199	F(384000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0),
200	{ }
201};
202
203static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
204	.cmd_rcgr = 0x2074,
205	.mnd_width = 0,
206	.hid_width = 5,
207	.parent_map = disp_cc_parent_map_3,
208	.freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src,
209	.clkr.hw.init = &(struct clk_init_data){
210		.name = "disp_cc_mdss_mdp_clk_src",
211		.parent_data = disp_cc_parent_data_3,
212		.num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
213		.flags = CLK_SET_RATE_PARENT,
214		.ops = &clk_rcg2_shared_ops,
215	},
216};
217
218static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = {
219	.cmd_rcgr = 0x205c,
220	.mnd_width = 8,
221	.hid_width = 5,
222	.parent_map = disp_cc_parent_map_4,
223	.clkr.hw.init = &(struct clk_init_data){
224		.name = "disp_cc_mdss_pclk0_clk_src",
225		.parent_data = disp_cc_parent_data_4,
226		.num_parents = ARRAY_SIZE(disp_cc_parent_data_4),
227		/* For set_rate and set_parent to succeed, parent(s) must be enabled */
228		.flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
229		.ops = &clk_pixel_ops,
230	},
231};
232
233static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = {
234	.cmd_rcgr = 0x208c,
235	.mnd_width = 0,
236	.hid_width = 5,
237	.parent_map = disp_cc_parent_map_1,
238	.freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src,
239	.clkr.hw.init = &(struct clk_init_data){
240		.name = "disp_cc_mdss_vsync_clk_src",
241		.parent_data = disp_cc_parent_data_1,
242		.num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
243		.flags = CLK_SET_RATE_PARENT,
244		.ops = &clk_rcg2_shared_ops,
245	},
246};
247
248static const struct freq_tbl ftbl_disp_cc_sleep_clk_src[] = {
249	F(32764, P_SLEEP_CLK, 1, 0, 0),
250	{ }
251};
252
253static struct clk_rcg2 disp_cc_sleep_clk_src = {
254	.cmd_rcgr = 0x6050,
255	.mnd_width = 0,
256	.hid_width = 5,
257	.parent_map = disp_cc_parent_map_5,
258	.freq_tbl = ftbl_disp_cc_sleep_clk_src,
259	.clkr.hw.init = &(struct clk_init_data){
260		.name = "disp_cc_sleep_clk_src",
261		.parent_data = disp_cc_parent_data_5,
262		.num_parents = ARRAY_SIZE(disp_cc_parent_data_5),
263		.ops = &clk_rcg2_ops,
264	},
265};
266
267static struct clk_branch disp_cc_mdss_ahb_clk = {
268	.halt_reg = 0x2044,
269	.halt_check = BRANCH_HALT,
270	.clkr = {
271		.enable_reg = 0x2044,
272		.enable_mask = BIT(0),
273		.hw.init = &(struct clk_init_data){
274			.name = "disp_cc_mdss_ahb_clk",
275			.parent_hws = (const struct clk_hw*[]){
276				&disp_cc_mdss_ahb_clk_src.clkr.hw,
277			},
278			.num_parents = 1,
279			.flags = CLK_SET_RATE_PARENT,
280			.ops = &clk_branch2_ops,
281		},
282	},
283};
284
285static struct clk_branch disp_cc_mdss_byte0_clk = {
286	.halt_reg = 0x201c,
287	.halt_check = BRANCH_HALT,
288	.clkr = {
289		.enable_reg = 0x201c,
290		.enable_mask = BIT(0),
291		.hw.init = &(struct clk_init_data){
292			.name = "disp_cc_mdss_byte0_clk",
293			.parent_hws = (const struct clk_hw*[]){
294				&disp_cc_mdss_byte0_clk_src.clkr.hw,
295			},
296			.num_parents = 1,
297			.flags = CLK_SET_RATE_PARENT,
298			.ops = &clk_branch2_ops,
299		},
300	},
301};
302
303static struct clk_branch disp_cc_mdss_byte0_intf_clk = {
304	.halt_reg = 0x2020,
305	.halt_check = BRANCH_HALT,
306	.clkr = {
307		.enable_reg = 0x2020,
308		.enable_mask = BIT(0),
309		.hw.init = &(struct clk_init_data){
310			.name = "disp_cc_mdss_byte0_intf_clk",
311			.parent_hws = (const struct clk_hw*[]){
312				&disp_cc_mdss_byte0_div_clk_src.clkr.hw,
313			},
314			.num_parents = 1,
315			.flags = CLK_SET_RATE_PARENT,
316			.ops = &clk_branch2_ops,
317		},
318	},
319};
320
321static struct clk_branch disp_cc_mdss_esc0_clk = {
322	.halt_reg = 0x2024,
323	.halt_check = BRANCH_HALT,
324	.clkr = {
325		.enable_reg = 0x2024,
326		.enable_mask = BIT(0),
327		.hw.init = &(struct clk_init_data){
328			.name = "disp_cc_mdss_esc0_clk",
329			.parent_hws = (const struct clk_hw*[]){
330				&disp_cc_mdss_esc0_clk_src.clkr.hw,
331			},
332			.num_parents = 1,
333			.flags = CLK_SET_RATE_PARENT,
334			.ops = &clk_branch2_ops,
335		},
336	},
337};
338
339static struct clk_branch disp_cc_mdss_mdp_clk = {
340	.halt_reg = 0x2008,
341	.halt_check = BRANCH_HALT,
342	.clkr = {
343		.enable_reg = 0x2008,
344		.enable_mask = BIT(0),
345		.hw.init = &(struct clk_init_data){
346			.name = "disp_cc_mdss_mdp_clk",
347			.parent_hws = (const struct clk_hw*[]){
348				&disp_cc_mdss_mdp_clk_src.clkr.hw,
349			},
350			.num_parents = 1,
351			.flags = CLK_SET_RATE_PARENT,
352			.ops = &clk_branch2_ops,
353		},
354	},
355};
356
357static struct clk_branch disp_cc_mdss_mdp_lut_clk = {
358	.halt_reg = 0x2010,
359	.halt_check = BRANCH_HALT_VOTED,
360	.clkr = {
361		.enable_reg = 0x2010,
362		.enable_mask = BIT(0),
363		.hw.init = &(struct clk_init_data){
364			.name = "disp_cc_mdss_mdp_lut_clk",
365			.parent_hws = (const struct clk_hw*[]){
366				&disp_cc_mdss_mdp_clk_src.clkr.hw,
367			},
368			.num_parents = 1,
369			.flags = CLK_SET_RATE_PARENT,
370			.ops = &clk_branch2_ops,
371		},
372	},
373};
374
375static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk = {
376	.halt_reg = 0x4004,
377	.halt_check = BRANCH_HALT_VOTED,
378	.clkr = {
379		.enable_reg = 0x4004,
380		.enable_mask = BIT(0),
381		.hw.init = &(struct clk_init_data){
382			.name = "disp_cc_mdss_non_gdsc_ahb_clk",
383			.parent_hws = (const struct clk_hw*[]){
384				&disp_cc_mdss_ahb_clk_src.clkr.hw,
385			},
386			.num_parents = 1,
387			.flags = CLK_SET_RATE_PARENT,
388			.ops = &clk_branch2_ops,
389		},
390	},
391};
392
393static struct clk_branch disp_cc_mdss_pclk0_clk = {
394	.halt_reg = 0x2004,
395	.halt_check = BRANCH_HALT,
396	.clkr = {
397		.enable_reg = 0x2004,
398		.enable_mask = BIT(0),
399		.hw.init = &(struct clk_init_data){
400			.name = "disp_cc_mdss_pclk0_clk",
401			.parent_hws = (const struct clk_hw*[]){
402				&disp_cc_mdss_pclk0_clk_src.clkr.hw,
403			},
404			.num_parents = 1,
405			.flags = CLK_SET_RATE_PARENT,
406			.ops = &clk_branch2_ops,
407		},
408	},
409};
410
411static struct clk_branch disp_cc_mdss_vsync_clk = {
412	.halt_reg = 0x2018,
413	.halt_check = BRANCH_HALT,
414	.clkr = {
415		.enable_reg = 0x2018,
416		.enable_mask = BIT(0),
417		.hw.init = &(struct clk_init_data){
418			.name = "disp_cc_mdss_vsync_clk",
419			.parent_hws = (const struct clk_hw*[]){
420				&disp_cc_mdss_vsync_clk_src.clkr.hw,
421			},
422			.num_parents = 1,
423			.flags = CLK_SET_RATE_PARENT,
424			.ops = &clk_branch2_ops,
425		},
426	},
427};
428
429static struct clk_branch disp_cc_sleep_clk = {
430	.halt_reg = 0x6068,
431	.halt_check = BRANCH_HALT,
432	.clkr = {
433		.enable_reg = 0x6068,
434		.enable_mask = BIT(0),
435		.hw.init = &(struct clk_init_data){
436			.name = "disp_cc_sleep_clk",
437			.parent_hws = (const struct clk_hw*[]){
438				&disp_cc_sleep_clk_src.clkr.hw,
439			},
440			.num_parents = 1,
441			.flags = CLK_SET_RATE_PARENT,
442			.ops = &clk_branch2_ops,
443		},
444	},
445};
446
447static const struct qcom_reset_map disp_cc_qcm2290_resets[] = {
448	[DISP_CC_MDSS_CORE_BCR] = { 0x2000 },
449};
450
451static struct gdsc mdss_gdsc = {
452	.gdscr = 0x3000,
453	.pd = {
454		.name = "mdss_gdsc",
455	},
456	.pwrsts = PWRSTS_OFF_ON,
457	.flags = HW_CTRL,
458};
459
460static struct gdsc *disp_cc_qcm2290_gdscs[] = {
461	[MDSS_GDSC] = &mdss_gdsc,
462};
463
464static struct clk_regmap *disp_cc_qcm2290_clocks[] = {
465	[DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr,
466	[DISP_CC_MDSS_AHB_CLK_SRC] = &disp_cc_mdss_ahb_clk_src.clkr,
467	[DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr,
468	[DISP_CC_MDSS_BYTE0_CLK_SRC] = &disp_cc_mdss_byte0_clk_src.clkr,
469	[DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = &disp_cc_mdss_byte0_div_clk_src.clkr,
470	[DISP_CC_MDSS_BYTE0_INTF_CLK] = &disp_cc_mdss_byte0_intf_clk.clkr,
471	[DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr,
472	[DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr,
473	[DISP_CC_MDSS_MDP_CLK] = &disp_cc_mdss_mdp_clk.clkr,
474	[DISP_CC_MDSS_MDP_CLK_SRC] = &disp_cc_mdss_mdp_clk_src.clkr,
475	[DISP_CC_MDSS_MDP_LUT_CLK] = &disp_cc_mdss_mdp_lut_clk.clkr,
476	[DISP_CC_MDSS_NON_GDSC_AHB_CLK] = &disp_cc_mdss_non_gdsc_ahb_clk.clkr,
477	[DISP_CC_MDSS_PCLK0_CLK] = &disp_cc_mdss_pclk0_clk.clkr,
478	[DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr,
479	[DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr,
480	[DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr,
481	[DISP_CC_PLL0] = &disp_cc_pll0.clkr,
482	[DISP_CC_SLEEP_CLK] = &disp_cc_sleep_clk.clkr,
483	[DISP_CC_SLEEP_CLK_SRC] = &disp_cc_sleep_clk_src.clkr,
484};
485
486static const struct regmap_config disp_cc_qcm2290_regmap_config = {
487	.reg_bits = 32,
488	.reg_stride = 4,
489	.val_bits = 32,
490	.max_register = 0x10000,
491	.fast_io = true,
492};
493
494static const struct qcom_cc_desc disp_cc_qcm2290_desc = {
495	.config = &disp_cc_qcm2290_regmap_config,
496	.clks = disp_cc_qcm2290_clocks,
497	.num_clks = ARRAY_SIZE(disp_cc_qcm2290_clocks),
498	.gdscs = disp_cc_qcm2290_gdscs,
499	.num_gdscs = ARRAY_SIZE(disp_cc_qcm2290_gdscs),
500	.resets = disp_cc_qcm2290_resets,
501	.num_resets = ARRAY_SIZE(disp_cc_qcm2290_resets),
502};
503
504static const struct of_device_id disp_cc_qcm2290_match_table[] = {
505	{ .compatible = "qcom,qcm2290-dispcc" },
506	{ }
507};
508MODULE_DEVICE_TABLE(of, disp_cc_qcm2290_match_table);
509
510static int disp_cc_qcm2290_probe(struct platform_device *pdev)
511{
512	struct regmap *regmap;
513	int ret;
514
515	regmap = qcom_cc_map(pdev, &disp_cc_qcm2290_desc);
516	if (IS_ERR(regmap))
517		return PTR_ERR(regmap);
518
519	clk_alpha_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
520
521	/* Keep some clocks always-on */
522	qcom_branch_set_clk_en(regmap, 0x604c); /* DISP_CC_XO_CLK */
523
524	ret = qcom_cc_really_probe(&pdev->dev, &disp_cc_qcm2290_desc, regmap);
525	if (ret) {
526		dev_err(&pdev->dev, "Failed to register DISP CC clocks\n");
527		return ret;
528	}
529
530	return ret;
531}
532
533static struct platform_driver disp_cc_qcm2290_driver = {
534	.probe = disp_cc_qcm2290_probe,
535	.driver = {
536		.name = "dispcc-qcm2290",
537		.of_match_table = disp_cc_qcm2290_match_table,
538	},
539};
540
541module_platform_driver(disp_cc_qcm2290_driver);
542
543MODULE_DESCRIPTION("QTI DISP_CC qcm2290 Driver");
544MODULE_LICENSE("GPL v2");
~/ Read-only file preview.