b73fe79a7a3a82de47a00f34a5ca8d7f63b0c15b
[platform/kernel/linux-starfive.git] / drivers / clk / starfive / clk-starfive-jh7110-vout.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * StarFive JH7110 vout Clock Driver
4  *
5  * Copyright (C) 2022 Xingyu Wu <xingyu.wu@starfivetech.com>
6  */
7
8 #include <linux/bits.h>
9 #include <linux/clk.h>
10 #include <linux/clk-provider.h>
11 #include <linux/debugfs.h>
12 #include <linux/device.h>
13 #include <linux/init.h>
14 #include <linux/io.h>
15 #include <linux/kernel.h>
16 #include <linux/mod_devicetable.h>
17 #include <linux/module.h>
18 #include <linux/platform_device.h>
19 #include <linux/of_device.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/reset.h>
22
23 #include <dt-bindings/clock/starfive-jh7110-vout.h>
24 #include "clk-starfive-jh7110.h"
25
26 /* external clocks */
27 #define JH7110_HDMITX0_PIXELCLK                 (JH7110_CLK_VOUT_END + 0)
28 #define JH7110_MIPITX_DPHY_RXESC                (JH7110_CLK_VOUT_END + 1)
29 #define JH7110_MIPITX_DPHY_TXBYTEHS             (JH7110_CLK_VOUT_END + 2)
30
31 struct vout_init_crg {
32         int num_clks;
33         struct clk_bulk_data *clks;
34         struct reset_control *rsts;
35 };
36
37 static const struct jh7110_clk_data jh7110_clk_vout_data[] __initconst = {
38         //divider
39         JH7110__DIV(JH7110_APB, "apb", 8, JH7110_DISP_AHB),
40         JH7110__DIV(JH7110_DC8200_PIX0, "dc8200_pix0", 63, JH7110_DISP_ROOT),
41         JH7110__DIV(JH7110_DSI_SYS, "dsi_sys", 31, JH7110_DISP_ROOT),
42         JH7110__DIV(JH7110_TX_ESC, "tx_esc", 31, JH7110_DISP_AHB),
43         //dc8200
44         JH7110_GATE(JH7110_U0_DC8200_CLK_AXI, "u0_dc8200_clk_axi",
45                         GATE_FLAG_NORMAL, JH7110_DISP_AXI),
46         JH7110_GATE(JH7110_U0_DC8200_CLK_CORE, "u0_dc8200_clk_core",
47                         GATE_FLAG_NORMAL, JH7110_DISP_AXI),
48         JH7110_GATE(JH7110_U0_DC8200_CLK_AHB, "u0_dc8200_clk_ahb",
49                         GATE_FLAG_NORMAL, JH7110_DISP_AHB),
50         JH7110_GMUX(JH7110_U0_DC8200_CLK_PIX0, "u0_dc8200_clk_pix0",
51                         GATE_FLAG_NORMAL, PARENT_NUMS_2,
52                         JH7110_DC8200_PIX0,
53                         JH7110_HDMITX0_PIXELCLK),
54         JH7110_GMUX(JH7110_U0_DC8200_CLK_PIX1, "u0_dc8200_clk_pix1",
55                         GATE_FLAG_NORMAL, PARENT_NUMS_2,
56                         JH7110_DC8200_PIX0,
57                         JH7110_HDMITX0_PIXELCLK),
58
59         JH7110_GMUX(JH7110_DOM_VOUT_TOP_LCD_CLK, "dom_vout_top_lcd_clk",
60                         GATE_FLAG_NORMAL, PARENT_NUMS_2,
61                         JH7110_U0_DC8200_CLK_PIX0_OUT,
62                         JH7110_U0_DC8200_CLK_PIX1_OUT),
63         //dsiTx
64         JH7110_GATE(JH7110_U0_CDNS_DSITX_CLK_APB, "u0_cdns_dsiTx_clk_apb",
65                         GATE_FLAG_NORMAL, JH7110_DSI_SYS),
66         JH7110_GATE(JH7110_U0_CDNS_DSITX_CLK_SYS, "u0_cdns_dsiTx_clk_sys",
67                         GATE_FLAG_NORMAL, JH7110_DSI_SYS),
68         JH7110_GMUX(JH7110_U0_CDNS_DSITX_CLK_DPI, "u0_cdns_dsiTx_clk_api",
69                         GATE_FLAG_NORMAL, PARENT_NUMS_2,
70                         JH7110_DC8200_PIX0,
71                         JH7110_HDMITX0_PIXELCLK),
72         JH7110_GATE(JH7110_U0_CDNS_DSITX_CLK_TXESC, "u0_cdns_dsiTx_clk_txesc",
73                         GATE_FLAG_NORMAL, JH7110_TX_ESC),
74         //mipitx DPHY
75         JH7110_GATE(JH7110_U0_MIPITX_DPHY_CLK_TXESC, "u0_mipitx_dphy_clk_txesc",
76                         GATE_FLAG_NORMAL, JH7110_TX_ESC),
77         //hdmi
78         JH7110_GATE(JH7110_U0_HDMI_TX_CLK_MCLK, "u0_hdmi_tx_clk_mclk",
79                         GATE_FLAG_NORMAL, JH7110_HDMITX0_MCLK),
80         JH7110_GATE(JH7110_U0_HDMI_TX_CLK_BCLK, "u0_hdmi_tx_clk_bclk",
81                         GATE_FLAG_NORMAL, JH7110_HDMITX0_SCK),
82         JH7110_GATE(JH7110_U0_HDMI_TX_CLK_SYS, "u0_hdmi_tx_clk_sys",
83                         GATE_FLAG_NORMAL, JH7110_DISP_APB),
84 };
85
86 static struct clk_bulk_data vout_top_clks[] = {
87         { .id = "vout_src" },
88         { .id = "vout_top_ahb" },
89 };
90
91 static int jh7110_vout_crg_get(struct device *dev, struct vout_init_crg *crg)
92 {
93         int ret;
94
95         crg->rsts = devm_reset_control_array_get_shared(dev);
96         if (IS_ERR(crg->rsts)) {
97                 dev_err(dev, "rst get failed\n");
98                 return PTR_ERR(crg->rsts);
99         }
100
101         crg->clks = vout_top_clks;
102         crg->num_clks = ARRAY_SIZE(vout_top_clks);
103         ret = clk_bulk_get(dev, crg->num_clks, crg->clks);
104         if (ret) {
105                 dev_err(dev, "clks get failed: %d\n", ret);
106                 goto clks_get_failed;
107         }
108
109         return 0;
110
111 clks_get_failed:
112         reset_control_assert(crg->rsts);
113         reset_control_put(crg->rsts);
114
115         return ret;
116 }
117
118 static int jh7110_vout_crg_enable(struct device *dev, struct vout_init_crg *crg, bool enable)
119 {
120         int ret;
121
122         dev_dbg(dev, "jh7110_vout_crg_%sable\n", enable ? "en":"dis");
123
124         if (enable) {
125                 ret = reset_control_deassert(crg->rsts);
126                 if (ret) {
127                         dev_err(dev, "rst deassert failed: %d\n", ret);
128                         goto crg_failed;
129                 }
130
131                 ret = clk_bulk_prepare_enable(crg->num_clks, crg->clks);
132                 if (ret) {
133                         dev_err(dev, "clks enable failed: %d\n", ret);
134                         goto crg_failed;
135                 }
136         } else {
137                 clk_bulk_disable_unprepare(crg->num_clks, crg->clks);
138         }
139
140         return 0;
141 crg_failed:
142         return ret;
143 }
144
145 #ifdef CONFIG_PM_SLEEP
146 static int clk_vout_system_pm_suspend(struct device *dev)
147 {
148         return pm_runtime_force_suspend(dev);
149 }
150
151 static int clk_vout_system_pm_resume(struct device *dev)
152 {
153         return pm_runtime_force_resume(dev);
154 }
155 #endif
156
157 #ifdef CONFIG_PM
158 static int clk_vout_runtime_suspend(struct device *dev)
159 {
160         struct vout_init_crg *crg = dev_get_drvdata(dev);
161
162         return jh7110_vout_crg_enable(dev, crg, false);
163 }
164
165 static int clk_vout_runtime_resume(struct device *dev)
166 {
167         struct vout_init_crg *crg = dev_get_drvdata(dev);
168
169         return jh7110_vout_crg_enable(dev, crg, true);
170 }
171 #endif
172
173 static const struct dev_pm_ops clk_vout_pm_ops = {
174         SET_RUNTIME_PM_OPS(clk_vout_runtime_suspend, clk_vout_runtime_resume, NULL)
175         SET_LATE_SYSTEM_SLEEP_PM_OPS(clk_vout_system_pm_suspend, clk_vout_system_pm_resume)
176 };
177
178 static struct clk_hw *jh7110_vout_clk_get(struct of_phandle_args *clkspec,
179                                         void *data)
180 {
181         struct jh7110_clk_priv *priv = data;
182         unsigned int idx = clkspec->args[0];
183
184         if (idx < JH7110_CLK_VOUT_REG_END)
185                 return &priv->reg[idx].hw;
186
187         if (idx < JH7110_CLK_VOUT_END)
188                 return priv->pll[PLL_OFV(idx)];
189
190         return ERR_PTR(-EINVAL);
191 }
192
193 static int __init clk_starfive_jh7110_vout_probe(struct platform_device *pdev)
194 {
195         struct jh7110_clk_priv *priv;
196         struct vout_init_crg *crg;
197         unsigned int idx;
198         int ret = 0;
199
200         priv = devm_kzalloc(&pdev->dev, struct_size(priv,
201                                 reg, JH7110_DISP_ROOT), GFP_KERNEL);
202         if (!priv)
203                 return -ENOMEM;
204
205         spin_lock_init(&priv->rmw_lock);
206         priv->dev = &pdev->dev;
207         priv->vout_base = devm_platform_ioremap_resource(pdev, 0);
208         if (IS_ERR(priv->vout_base))
209                 return PTR_ERR(priv->vout_base);
210
211         crg = devm_kzalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
212         if (!crg)
213                 return -ENOMEM;
214         dev_set_drvdata(&pdev->dev, crg);
215
216         ret = jh7110_vout_crg_get(&pdev->dev, crg);
217         if (ret)
218                 goto init_failed;
219
220         pm_runtime_use_autosuspend(&pdev->dev);
221         pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
222         pm_runtime_enable(&pdev->dev);
223         ret = pm_runtime_get_sync(&pdev->dev);
224         if (ret < 0) {
225                 dev_err(&pdev->dev, "failed to get pm runtime: %d\n", ret);
226                 goto init_failed;
227         }
228
229         //source
230         priv->pll[PLL_OFV(JH7110_DISP_ROOT)] =
231                         devm_clk_hw_register_fixed_factor(
232                         priv->dev, "disp_root",
233                         "u0_dom_vout_top_clk_dom_vout_top_clk_vout_src",
234                         0, 1, 1);
235         priv->pll[PLL_OFV(JH7110_DISP_AXI)] =
236                         devm_clk_hw_register_fixed_factor(
237                         priv->dev, "disp_axi",
238                         "u0_dom_vout_top_clk_dom_vout_top_clk_vout_axi",
239                         0, 1, 1);
240         priv->pll[PLL_OFV(JH7110_DISP_AHB)] =
241                         devm_clk_hw_register_fixed_factor(
242                         priv->dev, "disp_ahb",
243                         "u0_dom_vout_top_clk_dom_vout_top_clk_vout_ahb",
244                         0, 1, 1);
245         priv->pll[PLL_OFV(JH7110_HDMI_PHY_REF)] =
246                         devm_clk_hw_register_fixed_factor(
247                         priv->dev, "hdmi_phy_ref",
248                         "u0_dom_vout_top_clk_dom_vout_top_clk_hdmiphy_ref",
249                         0, 1, 1);
250         priv->pll[PLL_OFV(JH7110_HDMITX0_MCLK)] =
251                         devm_clk_hw_register_fixed_factor(
252                         priv->dev, "hdmitx0_mclk",
253                         "u0_dom_vout_top_clk_dom_vout_top_clk_hdmitx0_mclk",
254                         0, 1, 1);
255         priv->pll[PLL_OFV(JH7110_HDMITX0_SCK)] =
256                         devm_clk_hw_register_fixed_factor(
257                         priv->dev, "hdmitx0_sck",
258                         "u0_dom_vout_top_clk_dom_vout_top_clk_hdmitx0_bclk",
259                         0, 1, 1);
260
261         priv->pll[PLL_OFV(JH7110_MIPI_DPHY_REF)] =
262                         devm_clk_hw_register_fixed_factor(
263                         priv->dev, "mipi_dphy_ref",
264                         "u0_dom_vout_top_clk_dom_vout_top_clk_mipiphy_ref",
265                         0, 1, 1);
266         //divider
267         priv->pll[PLL_OFV(JH7110_U0_PCLK_MUX_BIST_PCLK)] =
268                         devm_clk_hw_register_fixed_factor(
269                         priv->dev, "u0_pclk_mux_bist_pclk",
270                         "u0_dom_vout_top_clk_dom_vout_top_bist_pclk",
271                         0, 1, 1);
272         priv->pll[PLL_OFV(JH7110_DISP_APB)] =
273                         clk_hw_register_fixed_rate(priv->dev,
274                         "disp_apb", NULL, 0, 51200000);
275         priv->pll[PLL_OFV(JH7110_U0_PCLK_MUX_FUNC_PCLK)] =
276                         devm_clk_hw_register_fixed_factor(priv->dev,
277                         "u0_pclk_mux_func_pclk", "apb", 0, 1, 1);
278         //bus
279         priv->pll[PLL_OFV(JH7110_U0_DOM_VOUT_CRG_PCLK)] =
280                         devm_clk_hw_register_fixed_factor(priv->dev,
281                         "u0_dom_vout_crg_pclk", "disp_apb", 0, 1, 1);
282         priv->pll[PLL_OFV(JH7110_U0_DOM_VOUT_SYSCON_PCLK)] =
283                         devm_clk_hw_register_fixed_factor(priv->dev,
284                         "u0_dom_vout_syscon_pclk", "disp_apb", 0, 1, 1);
285         priv->pll[PLL_OFV(JH7110_U0_SAIF_AMBA_DOM_VOUT_AHB_DEC_CLK_AHB)] =
286                         devm_clk_hw_register_fixed_factor(priv->dev,
287                         "u0_saif_amba_dom_vout_ahb_dec_clk_ahb",
288                         "disp_ahb", 0, 1, 1);
289         priv->pll[PLL_OFV(JH7110_U0_AHB2APB_CLK_AHB)] =
290                         devm_clk_hw_register_fixed_factor(priv->dev,
291                         "u0_ahb2apb_clk_ahb", "disp_ahb", 0, 1, 1);
292         priv->pll[PLL_OFV(JH7110_U0_P2P_ASYNC_CLK_APBS)] =
293                         devm_clk_hw_register_fixed_factor(priv->dev,
294                         "u0_p2p_async_clk_apbs", "disp_apb", 0, 1, 1);
295         //dsiTx
296         priv->pll[PLL_OFV(JH7110_U0_CDNS_DSITX_CLK_RXESC)] =
297                         devm_clk_hw_register_fixed_factor(priv->dev,
298                         "u0_cdns_dsiTx_clk_rxesc",
299                         "mipitx_dphy_rxesc", 0, 1, 1);
300         priv->pll[PLL_OFV(JH7110_U0_CDNS_DSITX_CLK_TXBYTEHS)] =
301                         devm_clk_hw_register_fixed_factor(priv->dev,
302                         "u0_cdns_dsiTx_clk_txbytehs",
303                         "mipitx_dphy_txbytehs", 0, 1, 1);
304         //mipitx DPHY
305         priv->pll[PLL_OFV(JH7110_U0_MIPITX_DPHY_CLK_SYS)] =
306                         devm_clk_hw_register_fixed_factor(priv->dev,
307                         "u0_mipitx_dphy_clk_sys", "disp_apb", 0, 1, 1);
308         priv->pll[PLL_OFV(JH7110_U0_MIPITX_DPHY_CLK_DPHY_REF)] =
309                         devm_clk_hw_register_fixed_factor(priv->dev,
310                         "u0_mipitx_dphy_clk_dphy_ref",
311                         "mipi_dphy_ref", 0, 1, 1);
312         priv->pll[PLL_OFV(JH7110_U0_MIPITX_APBIF_PCLK)] =
313                         devm_clk_hw_register_fixed_factor(priv->dev,
314                         "u0_mipitx_apbif_pclk", "disp_apb", 0, 1, 1);
315         //hdmi
316         priv->pll[PLL_OFV(JH7110_HDMI_TX_CLK_REF)] =
317                         devm_clk_hw_register_fixed_factor(priv->dev,
318                         "u0_hdmi_tx_clk_ref", "hdmi_phy_ref", 0, 1, 1);
319
320         priv->pll[PLL_OFV(JH7110_U0_DC8200_CLK_PIX0_OUT)] =
321                         devm_clk_hw_register_fixed_factor(priv->dev,
322                         "u0_dc8200_clk_pix0_out",
323                         "u0_dc8200_clk_pix0", 0, 1, 1);
324         priv->pll[PLL_OFV(JH7110_U0_DC8200_CLK_PIX1_OUT)] =
325                         devm_clk_hw_register_fixed_factor(priv->dev,
326                         "u0_dc8200_clk_pix1_out",
327                         "u0_dc8200_clk_pix1", 0, 1, 1);
328
329         for (idx = 0; idx < JH7110_DISP_ROOT; idx++) {
330                 u32 max = jh7110_clk_vout_data[idx].max;
331                 struct clk_parent_data parents[2] = {};
332                 struct clk_init_data init = {
333                         .name = jh7110_clk_vout_data[idx].name,
334                         .ops = starfive_jh7110_clk_ops(max),
335                         .parent_data = parents,
336                         .num_parents = ((max & JH7110_CLK_MUX_MASK) >>
337                                         JH7110_CLK_MUX_SHIFT) + 1,
338                         .flags = jh7110_clk_vout_data[idx].flags,
339                 };
340                 struct jh7110_clk *clk = &priv->reg[idx];
341                 unsigned int i;
342
343                 for (i = 0; i < init.num_parents; i++) {
344                         unsigned int pidx = jh7110_clk_vout_data[idx].parents[i];
345
346                         if (pidx < JH7110_DISP_ROOT)
347                                 parents[i].hw = &priv->reg[pidx].hw;
348                         else if (pidx < JH7110_CLK_VOUT_END)
349                                 parents[i].hw = priv->pll[PLL_OFV(pidx)];
350                         else if (pidx == JH7110_HDMITX0_PIXELCLK)
351                                 parents[i].fw_name = "hdmitx0_pixelclk";
352                         else if (pidx == JH7110_MIPITX_DPHY_RXESC)
353                                 parents[i].fw_name = "mipitx_dphy_rxesc";
354                         else if (pidx == JH7110_MIPITX_DPHY_TXBYTEHS)
355                                 parents[i].fw_name = "mipitx_dphy_txbytehs";
356                         else if (pidx == JH7110_U0_DC8200_CLK_PIX0_OUT)
357                                 parents[i].fw_name = "u0_dc8200_clk_pix0_out";
358                         else if (pidx == JH7110_U0_DC8200_CLK_PIX1_OUT)
359                                 parents[i].fw_name = "u0_dc8200_clk_pix1_out";
360                 }
361
362                 clk->hw.init = &init;
363                 clk->idx = idx;
364                 clk->max_div = max & JH7110_CLK_DIV_MASK;
365                 clk->reg_flags = JH7110_CLK_VOUT_FLAG;
366
367                 ret = devm_clk_hw_register(priv->dev, &clk->hw);
368                 if (ret)
369                         return ret;
370         }
371
372         ret = devm_of_clk_add_hw_provider(priv->dev, jh7110_vout_clk_get, priv);
373         if (ret)
374                 return ret;
375
376         pm_runtime_put_sync(&pdev->dev);
377
378         dev_info(&pdev->dev, "starfive JH7110 clk_vout init successfully.");
379         return 0;
380
381 init_failed:
382         return ret;
383
384 }
385
386 static const struct of_device_id clk_starfive_jh7110_vout_match[] = {
387                 {.compatible = "starfive,jh7110-clk-vout" },
388                 { /* sentinel */ }
389 };
390
391 static struct platform_driver clk_starfive_jh7110_vout_driver = {
392         .probe = clk_starfive_jh7110_vout_probe,
393                 .driver = {
394                 .name = "clk-starfive-jh7110-vout",
395                 .of_match_table = clk_starfive_jh7110_vout_match,
396                 .pm = &clk_vout_pm_ops,
397         },
398 };
399 module_platform_driver(clk_starfive_jh7110_vout_driver);
400
401 MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
402 MODULE_DESCRIPTION("StarFive JH7110 vout clock driver");
403 MODULE_LICENSE("GPL");