xref: /linux/drivers/clk/hisilicon/crg-hi3798cv200.c (revision 8dd765a5d769c521d73931850d1c8708fbc490cb)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Hi3798CV200 Clock and Reset Generator Driver
4  *
5  * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
6  */
7 
8 #include <dt-bindings/clock/histb-clock.h>
9 #include <linux/clk-provider.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/platform_device.h>
13 #include "clk.h"
14 #include "crg.h"
15 #include "reset.h"
16 
17 /* hi3798CV200 core CRG */
18 #define HI3798CV200_INNER_CLK_OFFSET		64
19 #define HI3798CV200_FIXED_24M			65
20 #define HI3798CV200_FIXED_25M			66
21 #define HI3798CV200_FIXED_50M			67
22 #define HI3798CV200_FIXED_75M			68
23 #define HI3798CV200_FIXED_100M			69
24 #define HI3798CV200_FIXED_150M			70
25 #define HI3798CV200_FIXED_200M			71
26 #define HI3798CV200_FIXED_250M			72
27 #define HI3798CV200_FIXED_300M			73
28 #define HI3798CV200_FIXED_400M			74
29 #define HI3798CV200_MMC_MUX			75
30 #define HI3798CV200_ETH_PUB_CLK			76
31 #define HI3798CV200_ETH_BUS_CLK			77
32 #define HI3798CV200_ETH_BUS0_CLK		78
33 #define HI3798CV200_ETH_BUS1_CLK		79
34 #define HI3798CV200_COMBPHY1_MUX		80
35 #define HI3798CV200_FIXED_12M			81
36 #define HI3798CV200_FIXED_48M			82
37 #define HI3798CV200_FIXED_60M			83
38 #define HI3798CV200_FIXED_166P5M		84
39 #define HI3798CV200_SDIO0_MUX			85
40 #define HI3798CV200_COMBPHY0_MUX		86
41 
42 #define HI3798CV200_CRG_NR_CLKS			128
43 
44 static const struct hisi_fixed_rate_clock hi3798cv200_fixed_rate_clks[] = {
45 	{ HISTB_OSC_CLK, "clk_osc", NULL, 0, 24000000, },
46 	{ HISTB_APB_CLK, "clk_apb", NULL, 0, 100000000, },
47 	{ HISTB_AHB_CLK, "clk_ahb", NULL, 0, 200000000, },
48 	{ HI3798CV200_FIXED_12M, "12m", NULL, 0, 12000000, },
49 	{ HI3798CV200_FIXED_24M, "24m", NULL, 0, 24000000, },
50 	{ HI3798CV200_FIXED_25M, "25m", NULL, 0, 25000000, },
51 	{ HI3798CV200_FIXED_48M, "48m", NULL, 0, 48000000, },
52 	{ HI3798CV200_FIXED_50M, "50m", NULL, 0, 50000000, },
53 	{ HI3798CV200_FIXED_60M, "60m", NULL, 0, 60000000, },
54 	{ HI3798CV200_FIXED_75M, "75m", NULL, 0, 75000000, },
55 	{ HI3798CV200_FIXED_100M, "100m", NULL, 0, 100000000, },
56 	{ HI3798CV200_FIXED_150M, "150m", NULL, 0, 150000000, },
57 	{ HI3798CV200_FIXED_166P5M, "166p5m", NULL, 0, 165000000, },
58 	{ HI3798CV200_FIXED_200M, "200m", NULL, 0, 200000000, },
59 	{ HI3798CV200_FIXED_250M, "250m", NULL, 0, 250000000, },
60 };
61 
62 static const char *const mmc_mux_p[] = {
63 		"100m", "50m", "25m", "200m", "150m" };
64 static u32 mmc_mux_table[] = {0, 1, 2, 3, 6};
65 
66 static const char *const comphy_mux_p[] = {
67 		"100m", "25m"};
68 static u32 comphy_mux_table[] = {2, 3};
69 
70 static const char *const sdio_mux_p[] = {
71 		"100m", "50m", "150m", "166p5m" };
72 static u32 sdio_mux_table[] = {0, 1, 2, 3};
73 
74 static struct hisi_mux_clock hi3798cv200_mux_clks[] = {
75 	{ HI3798CV200_MMC_MUX, "mmc_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p),
76 		CLK_SET_RATE_PARENT, 0xa0, 8, 3, 0, mmc_mux_table, },
77 	{ HI3798CV200_COMBPHY0_MUX, "combphy0_mux",
78 		comphy_mux_p, ARRAY_SIZE(comphy_mux_p),
79 		CLK_SET_RATE_PARENT, 0x188, 2, 2, 0, comphy_mux_table, },
80 	{ HI3798CV200_COMBPHY1_MUX, "combphy1_mux",
81 		comphy_mux_p, ARRAY_SIZE(comphy_mux_p),
82 		CLK_SET_RATE_PARENT, 0x188, 10, 2, 0, comphy_mux_table, },
83 	{ HI3798CV200_SDIO0_MUX, "sdio0_mux", sdio_mux_p,
84 		ARRAY_SIZE(sdio_mux_p), CLK_SET_RATE_PARENT,
85 		0x9c, 8, 2, 0, sdio_mux_table, },
86 };
87 
88 static u32 mmc_phase_regvals[] = {0, 1, 2, 3, 4, 5, 6, 7};
89 static u32 mmc_phase_degrees[] = {0, 45, 90, 135, 180, 225, 270, 315};
90 
91 static struct hisi_phase_clock hi3798cv200_phase_clks[] = {
92 	{ HISTB_MMC_SAMPLE_CLK, "mmc_sample", "clk_mmc_ciu",
93 		CLK_SET_RATE_PARENT, 0xa0, 12, 3, mmc_phase_degrees,
94 		mmc_phase_regvals, ARRAY_SIZE(mmc_phase_regvals) },
95 	{ HISTB_MMC_DRV_CLK, "mmc_drive", "clk_mmc_ciu",
96 		CLK_SET_RATE_PARENT, 0xa0, 16, 3, mmc_phase_degrees,
97 		mmc_phase_regvals, ARRAY_SIZE(mmc_phase_regvals) },
98 };
99 
100 static const struct hisi_gate_clock hi3798cv200_gate_clks[] = {
101 	/* UART */
102 	{ HISTB_UART2_CLK, "clk_uart2", "75m",
103 		CLK_SET_RATE_PARENT, 0x68, 4, 0, },
104 	/* I2C */
105 	{ HISTB_I2C0_CLK, "clk_i2c0", "clk_apb",
106 		CLK_SET_RATE_PARENT, 0x6C, 4, 0, },
107 	{ HISTB_I2C1_CLK, "clk_i2c1", "clk_apb",
108 		CLK_SET_RATE_PARENT, 0x6C, 8, 0, },
109 	{ HISTB_I2C2_CLK, "clk_i2c2", "clk_apb",
110 		CLK_SET_RATE_PARENT, 0x6C, 12, 0, },
111 	{ HISTB_I2C3_CLK, "clk_i2c3", "clk_apb",
112 		CLK_SET_RATE_PARENT, 0x6C, 16, 0, },
113 	{ HISTB_I2C4_CLK, "clk_i2c4", "clk_apb",
114 		CLK_SET_RATE_PARENT, 0x6C, 20, 0, },
115 	/* SPI */
116 	{ HISTB_SPI0_CLK, "clk_spi0", "clk_apb",
117 		CLK_SET_RATE_PARENT, 0x70, 0, 0, },
118 	/* SDIO */
119 	{ HISTB_SDIO0_BIU_CLK, "clk_sdio0_biu", "200m",
120 			CLK_SET_RATE_PARENT, 0x9c, 0, 0, },
121 	{ HISTB_SDIO0_CIU_CLK, "clk_sdio0_ciu", "sdio0_mux",
122 		CLK_SET_RATE_PARENT, 0x9c, 1, 0, },
123 	/* EMMC */
124 	{ HISTB_MMC_BIU_CLK, "clk_mmc_biu", "200m",
125 		CLK_SET_RATE_PARENT, 0xa0, 0, 0, },
126 	{ HISTB_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux",
127 		CLK_SET_RATE_PARENT, 0xa0, 1, 0, },
128 	/* PCIE*/
129 	{ HISTB_PCIE_BUS_CLK, "clk_pcie_bus", "200m",
130 		CLK_SET_RATE_PARENT, 0x18c, 0, 0, },
131 	{ HISTB_PCIE_SYS_CLK, "clk_pcie_sys", "100m",
132 		CLK_SET_RATE_PARENT, 0x18c, 1, 0, },
133 	{ HISTB_PCIE_PIPE_CLK, "clk_pcie_pipe", "250m",
134 		CLK_SET_RATE_PARENT, 0x18c, 2, 0, },
135 	{ HISTB_PCIE_AUX_CLK, "clk_pcie_aux", "24m",
136 		CLK_SET_RATE_PARENT, 0x18c, 3, 0, },
137 	/* Ethernet */
138 	{ HI3798CV200_ETH_PUB_CLK, "clk_pub", NULL,
139 		CLK_SET_RATE_PARENT, 0xcc, 5, 0, },
140 	{ HI3798CV200_ETH_BUS_CLK, "clk_bus", "clk_pub",
141 		CLK_SET_RATE_PARENT, 0xcc, 0, 0, },
142 	{ HI3798CV200_ETH_BUS0_CLK, "clk_bus_m0", "clk_bus",
143 		CLK_SET_RATE_PARENT, 0xcc, 1, 0, },
144 	{ HI3798CV200_ETH_BUS1_CLK, "clk_bus_m1", "clk_bus",
145 		CLK_SET_RATE_PARENT, 0xcc, 2, 0, },
146 	{ HISTB_ETH0_MAC_CLK, "clk_mac0", "clk_bus_m0",
147 		CLK_SET_RATE_PARENT, 0xcc, 3, 0, },
148 	{ HISTB_ETH0_MACIF_CLK, "clk_macif0", "clk_bus_m0",
149 		CLK_SET_RATE_PARENT, 0xcc, 24, 0, },
150 	{ HISTB_ETH1_MAC_CLK, "clk_mac1", "clk_bus_m1",
151 		CLK_SET_RATE_PARENT, 0xcc, 4, 0, },
152 	{ HISTB_ETH1_MACIF_CLK, "clk_macif1", "clk_bus_m1",
153 		CLK_SET_RATE_PARENT, 0xcc, 25, 0, },
154 	/* COMBPHY0 */
155 	{ HISTB_COMBPHY0_CLK, "clk_combphy0", "combphy0_mux",
156 		CLK_SET_RATE_PARENT, 0x188, 0, 0, },
157 	/* COMBPHY1 */
158 	{ HISTB_COMBPHY1_CLK, "clk_combphy1", "combphy1_mux",
159 		CLK_SET_RATE_PARENT, 0x188, 8, 0, },
160 	/* USB2 */
161 	{ HISTB_USB2_BUS_CLK, "clk_u2_bus", "clk_ahb",
162 		CLK_SET_RATE_PARENT, 0xb8, 0, 0, },
163 	{ HISTB_USB2_PHY_CLK, "clk_u2_phy", "60m",
164 		CLK_SET_RATE_PARENT, 0xb8, 4, 0, },
165 	{ HISTB_USB2_12M_CLK, "clk_u2_12m", "12m",
166 		CLK_SET_RATE_PARENT, 0xb8, 2, 0 },
167 	{ HISTB_USB2_48M_CLK, "clk_u2_48m", "48m",
168 		CLK_SET_RATE_PARENT, 0xb8, 1, 0 },
169 	{ HISTB_USB2_UTMI_CLK, "clk_u2_utmi", "60m",
170 		CLK_SET_RATE_PARENT, 0xb8, 5, 0 },
171 	{ HISTB_USB2_OTG_UTMI_CLK, "clk_u2_otg_utmi", "60m",
172 		CLK_SET_RATE_PARENT, 0xb8, 3, 0 },
173 	{ HISTB_USB2_PHY1_REF_CLK, "clk_u2_phy1_ref", "24m",
174 		CLK_SET_RATE_PARENT, 0xbc, 0, 0 },
175 	{ HISTB_USB2_PHY2_REF_CLK, "clk_u2_phy2_ref", "24m",
176 		CLK_SET_RATE_PARENT, 0xbc, 2, 0 },
177 	/* USB3 */
178 	{ HISTB_USB3_BUS_CLK, "clk_u3_bus", NULL,
179 		CLK_SET_RATE_PARENT, 0xb0, 0, 0 },
180 	{ HISTB_USB3_UTMI_CLK, "clk_u3_utmi", NULL,
181 		CLK_SET_RATE_PARENT, 0xb0, 4, 0 },
182 	{ HISTB_USB3_PIPE_CLK, "clk_u3_pipe", NULL,
183 		CLK_SET_RATE_PARENT, 0xb0, 3, 0 },
184 	{ HISTB_USB3_SUSPEND_CLK, "clk_u3_suspend", NULL,
185 		CLK_SET_RATE_PARENT, 0xb0, 2, 0 },
186 	{ HISTB_USB3_BUS_CLK1, "clk_u3_bus1", NULL,
187 		CLK_SET_RATE_PARENT, 0xb0, 16, 0 },
188 	{ HISTB_USB3_UTMI_CLK1, "clk_u3_utmi1", NULL,
189 		CLK_SET_RATE_PARENT, 0xb0, 20, 0 },
190 	{ HISTB_USB3_PIPE_CLK1, "clk_u3_pipe1", NULL,
191 		CLK_SET_RATE_PARENT, 0xb0, 19, 0 },
192 	{ HISTB_USB3_SUSPEND_CLK1, "clk_u3_suspend1", NULL,
193 		CLK_SET_RATE_PARENT, 0xb0, 18, 0 },
194 };
195 
196 static struct hisi_clock_data *hi3798cv200_clk_register(
197 				struct platform_device *pdev)
198 {
199 	struct hisi_clock_data *clk_data;
200 	int ret;
201 
202 	clk_data = hisi_clk_alloc(pdev, HI3798CV200_CRG_NR_CLKS);
203 	if (!clk_data)
204 		return ERR_PTR(-ENOMEM);
205 
206 	/* hisi_phase_clock is resource managed */
207 	ret = hisi_clk_register_phase(&pdev->dev,
208 				hi3798cv200_phase_clks,
209 				ARRAY_SIZE(hi3798cv200_phase_clks),
210 				clk_data);
211 	if (ret)
212 		return ERR_PTR(ret);
213 
214 	ret = hisi_clk_register_fixed_rate(hi3798cv200_fixed_rate_clks,
215 				     ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
216 				     clk_data);
217 	if (ret)
218 		return ERR_PTR(ret);
219 
220 	ret = hisi_clk_register_mux(hi3798cv200_mux_clks,
221 				ARRAY_SIZE(hi3798cv200_mux_clks),
222 				clk_data);
223 	if (ret)
224 		goto unregister_fixed_rate;
225 
226 	ret = hisi_clk_register_gate(hi3798cv200_gate_clks,
227 				ARRAY_SIZE(hi3798cv200_gate_clks),
228 				clk_data);
229 	if (ret)
230 		goto unregister_mux;
231 
232 	ret = of_clk_add_provider(pdev->dev.of_node,
233 			of_clk_src_onecell_get, &clk_data->clk_data);
234 	if (ret)
235 		goto unregister_gate;
236 
237 	return clk_data;
238 
239 unregister_gate:
240 	hisi_clk_unregister_gate(hi3798cv200_gate_clks,
241 				ARRAY_SIZE(hi3798cv200_gate_clks),
242 				clk_data);
243 unregister_mux:
244 	hisi_clk_unregister_mux(hi3798cv200_mux_clks,
245 				ARRAY_SIZE(hi3798cv200_mux_clks),
246 				clk_data);
247 unregister_fixed_rate:
248 	hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks,
249 				ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
250 				clk_data);
251 	return ERR_PTR(ret);
252 }
253 
254 static void hi3798cv200_clk_unregister(struct platform_device *pdev)
255 {
256 	struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
257 
258 	of_clk_del_provider(pdev->dev.of_node);
259 
260 	hisi_clk_unregister_gate(hi3798cv200_gate_clks,
261 				ARRAY_SIZE(hi3798cv200_gate_clks),
262 				crg->clk_data);
263 	hisi_clk_unregister_mux(hi3798cv200_mux_clks,
264 				ARRAY_SIZE(hi3798cv200_mux_clks),
265 				crg->clk_data);
266 	hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks,
267 				ARRAY_SIZE(hi3798cv200_fixed_rate_clks),
268 				crg->clk_data);
269 }
270 
271 static const struct hisi_crg_funcs hi3798cv200_crg_funcs = {
272 	.register_clks = hi3798cv200_clk_register,
273 	.unregister_clks = hi3798cv200_clk_unregister,
274 };
275 
276 /* hi3798CV200 sysctrl CRG */
277 
278 #define HI3798CV200_SYSCTRL_NR_CLKS 16
279 
280 static const struct hisi_gate_clock hi3798cv200_sysctrl_gate_clks[] = {
281 	{ HISTB_IR_CLK, "clk_ir", "24m",
282 		CLK_SET_RATE_PARENT, 0x48, 4, 0, },
283 	{ HISTB_TIMER01_CLK, "clk_timer01", "24m",
284 		CLK_SET_RATE_PARENT, 0x48, 6, 0, },
285 	{ HISTB_UART0_CLK, "clk_uart0", "75m",
286 		CLK_SET_RATE_PARENT, 0x48, 10, 0, },
287 };
288 
289 static struct hisi_clock_data *hi3798cv200_sysctrl_clk_register(
290 					struct platform_device *pdev)
291 {
292 	struct hisi_clock_data *clk_data;
293 	int ret;
294 
295 	clk_data = hisi_clk_alloc(pdev, HI3798CV200_SYSCTRL_NR_CLKS);
296 	if (!clk_data)
297 		return ERR_PTR(-ENOMEM);
298 
299 	ret = hisi_clk_register_gate(hi3798cv200_sysctrl_gate_clks,
300 				ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
301 				clk_data);
302 	if (ret)
303 		return ERR_PTR(ret);
304 
305 	ret = of_clk_add_provider(pdev->dev.of_node,
306 			of_clk_src_onecell_get, &clk_data->clk_data);
307 	if (ret)
308 		goto unregister_gate;
309 
310 	return clk_data;
311 
312 unregister_gate:
313 	hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks,
314 				ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
315 				clk_data);
316 	return ERR_PTR(ret);
317 }
318 
319 static void hi3798cv200_sysctrl_clk_unregister(struct platform_device *pdev)
320 {
321 	struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
322 
323 	of_clk_del_provider(pdev->dev.of_node);
324 
325 	hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks,
326 				ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks),
327 				crg->clk_data);
328 }
329 
330 static const struct hisi_crg_funcs hi3798cv200_sysctrl_funcs = {
331 	.register_clks = hi3798cv200_sysctrl_clk_register,
332 	.unregister_clks = hi3798cv200_sysctrl_clk_unregister,
333 };
334 
335 static const struct of_device_id hi3798cv200_crg_match_table[] = {
336 	{ .compatible = "hisilicon,hi3798cv200-crg",
337 		.data = &hi3798cv200_crg_funcs },
338 	{ .compatible = "hisilicon,hi3798cv200-sysctrl",
339 		.data = &hi3798cv200_sysctrl_funcs },
340 	{ }
341 };
342 MODULE_DEVICE_TABLE(of, hi3798cv200_crg_match_table);
343 
344 static int hi3798cv200_crg_probe(struct platform_device *pdev)
345 {
346 	struct hisi_crg_dev *crg;
347 
348 	crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
349 	if (!crg)
350 		return -ENOMEM;
351 
352 	crg->funcs = of_device_get_match_data(&pdev->dev);
353 	if (!crg->funcs)
354 		return -ENOENT;
355 
356 	crg->rstc = hisi_reset_init(pdev);
357 	if (!crg->rstc)
358 		return -ENOMEM;
359 
360 	crg->clk_data = crg->funcs->register_clks(pdev);
361 	if (IS_ERR(crg->clk_data)) {
362 		hisi_reset_exit(crg->rstc);
363 		return PTR_ERR(crg->clk_data);
364 	}
365 
366 	platform_set_drvdata(pdev, crg);
367 	return 0;
368 }
369 
370 static void hi3798cv200_crg_remove(struct platform_device *pdev)
371 {
372 	struct hisi_crg_dev *crg = platform_get_drvdata(pdev);
373 
374 	hisi_reset_exit(crg->rstc);
375 	crg->funcs->unregister_clks(pdev);
376 }
377 
378 static struct platform_driver hi3798cv200_crg_driver = {
379 	.probe          = hi3798cv200_crg_probe,
380 	.remove_new	= hi3798cv200_crg_remove,
381 	.driver         = {
382 		.name   = "hi3798cv200-crg",
383 		.of_match_table = hi3798cv200_crg_match_table,
384 	},
385 };
386 
387 static int __init hi3798cv200_crg_init(void)
388 {
389 	return platform_driver_register(&hi3798cv200_crg_driver);
390 }
391 core_initcall(hi3798cv200_crg_init);
392 
393 static void __exit hi3798cv200_crg_exit(void)
394 {
395 	platform_driver_unregister(&hi3798cv200_crg_driver);
396 }
397 module_exit(hi3798cv200_crg_exit);
398 
399 MODULE_LICENSE("GPL v2");
400 MODULE_DESCRIPTION("HiSilicon Hi3798CV200 CRG Driver");
401