1 // SPDX-License-Identifier: GPL-2.0
3 * StarFive JH7110 vout Clock Driver
5 * Copyright (C) 2022 Xingyu Wu <xingyu.wu@starfivetech.com>
8 #include <linux/bits.h>
10 #include <linux/clk-provider.h>
11 #include <linux/debugfs.h>
12 #include <linux/device.h>
13 #include <linux/init.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>
23 #include <dt-bindings/clock/starfive-jh7110-vout.h>
24 #include "clk-starfive-jh7110.h"
26 static const struct jh7110_clk_data jh7110_clk_vout_data[] __initconst = {
28 JH7110__DIV(JH7110_APB, "apb", 8, JH7110_DISP_AHB),
29 JH7110__DIV(JH7110_DC8200_PIX0, "dc8200_pix0", 63, JH7110_DISP_ROOT),
30 JH7110__DIV(JH7110_DSI_SYS, "dsi_sys", 31, JH7110_DISP_ROOT),
31 JH7110__DIV(JH7110_TX_ESC, "tx_esc", 31, JH7110_DISP_AHB),
33 JH7110_GATE(JH7110_U0_DC8200_CLK_AXI, "u0_dc8200_clk_axi",
34 GATE_FLAG_NORMAL, JH7110_DISP_AXI),
35 JH7110_GATE(JH7110_U0_DC8200_CLK_CORE, "u0_dc8200_clk_core",
36 GATE_FLAG_NORMAL, JH7110_DISP_AXI),
37 JH7110_GATE(JH7110_U0_DC8200_CLK_AHB, "u0_dc8200_clk_ahb",
38 GATE_FLAG_NORMAL, JH7110_DISP_AHB),
39 JH7110_GMUX(JH7110_U0_DC8200_CLK_PIX0, "u0_dc8200_clk_pix0",
40 GATE_FLAG_NORMAL, PARENT_NUMS_2,
42 JH7110_HDMITX0_PIXELCLK),
43 JH7110_GMUX(JH7110_U0_DC8200_CLK_PIX1, "u0_dc8200_clk_pix1",
44 GATE_FLAG_NORMAL, PARENT_NUMS_2,
46 JH7110_HDMITX0_PIXELCLK),
48 JH7110_GMUX(JH7110_DOM_VOUT_TOP_LCD_CLK, "dom_vout_top_lcd_clk",
49 GATE_FLAG_NORMAL, PARENT_NUMS_2,
50 JH7110_U0_DC8200_CLK_PIX0_OUT,
51 JH7110_U0_DC8200_CLK_PIX1_OUT),
53 JH7110_GATE(JH7110_U0_CDNS_DSITX_CLK_APB, "u0_cdns_dsiTx_clk_apb",
54 GATE_FLAG_NORMAL, JH7110_DSI_SYS),
55 JH7110_GATE(JH7110_U0_CDNS_DSITX_CLK_SYS, "u0_cdns_dsiTx_clk_sys",
56 GATE_FLAG_NORMAL, JH7110_DSI_SYS),
57 JH7110_GMUX(JH7110_U0_CDNS_DSITX_CLK_DPI, "u0_cdns_dsiTx_clk_api",
58 GATE_FLAG_NORMAL, PARENT_NUMS_2,
60 JH7110_HDMITX0_PIXELCLK),
61 JH7110_GATE(JH7110_U0_CDNS_DSITX_CLK_TXESC, "u0_cdns_dsiTx_clk_txesc",
62 GATE_FLAG_NORMAL, JH7110_TX_ESC),
64 JH7110_GATE(JH7110_U0_MIPITX_DPHY_CLK_TXESC, "u0_mipitx_dphy_clk_txesc",
65 GATE_FLAG_NORMAL, JH7110_TX_ESC),
67 JH7110_GATE(JH7110_U0_HDMI_TX_CLK_MCLK, "u0_hdmi_tx_clk_mclk",
68 GATE_FLAG_NORMAL, JH7110_HDMITX0_MCLK),
69 JH7110_GATE(JH7110_U0_HDMI_TX_CLK_BCLK, "u0_hdmi_tx_clk_bclk",
70 GATE_FLAG_NORMAL, JH7110_HDMITX0_SCK),
71 JH7110_GATE(JH7110_U0_HDMI_TX_CLK_SYS, "u0_hdmi_tx_clk_sys",
72 GATE_FLAG_NORMAL, JH7110_DISP_APB),
75 static struct clk_hw *jh7110_vout_clk_get(struct of_phandle_args *clkspec,
78 struct jh7110_clk_priv *priv = data;
79 unsigned int idx = clkspec->args[0];
81 if (idx < JH7110_CLK_VOUT_REG_END)
82 return &priv->reg[idx].hw;
84 if (idx < JH7110_CLK_VOUT_END)
85 return priv->pll[PLL_OFV(idx)];
87 return ERR_PTR(-EINVAL);
90 static int __init clk_starfive_jh7110_vout_probe(struct platform_device *pdev)
92 struct jh7110_clk_priv *priv;
94 struct clk *clk_vout_src;
95 struct clk *clk_vout_top_ahb;
96 struct reset_control *rst_vout_src;
99 priv = devm_kzalloc(&pdev->dev, struct_size(priv,
100 reg, JH7110_DISP_ROOT), GFP_KERNEL);
104 spin_lock_init(&priv->rmw_lock);
105 priv->dev = &pdev->dev;
106 priv->vout_base = devm_platform_ioremap_resource(pdev, 0);
107 if (IS_ERR(priv->vout_base))
108 return PTR_ERR(priv->vout_base);
110 pm_runtime_enable(&pdev->dev);
111 ret = pm_runtime_get_sync(&pdev->dev);
113 dev_err(&pdev->dev, "failed to get pm runtime: %d\n", ret);
117 clk_vout_src = devm_clk_get(priv->dev, "vout_src");
118 if (!IS_ERR(clk_vout_src)){
119 ret = clk_prepare_enable(clk_vout_src);
121 dev_err(priv->dev, "clk_vout_src enable failed\n");
122 goto clk_src_enable_failed;
125 dev_err(priv->dev, "clk_vout_src get failed\n");
126 return PTR_ERR(clk_vout_src);
129 rst_vout_src = devm_reset_control_get_exclusive(
130 priv->dev, "vout_src");
131 if (!IS_ERR(rst_vout_src)) {
132 ret = reset_control_deassert(rst_vout_src);
134 dev_err(priv->dev, "rst_vout_src deassert failed.\n");
135 goto rst_src_deassert_failed;
138 dev_err(priv->dev, "rst_vout_src get failed.\n");
139 ret = PTR_ERR(rst_vout_src);
140 goto rst_src_get_failed;
143 clk_vout_top_ahb = devm_clk_get(priv->dev, "vout_top_ahb");
144 if (!IS_ERR(clk_vout_top_ahb)){
145 ret = clk_prepare_enable(clk_vout_top_ahb);
147 dev_err(priv->dev, "clk_vout_top_ahb enable failed\n");
148 goto clk_ahb_enable_failed;
151 dev_err(priv->dev, "clk_vout_top_ahb get failed\n");
152 ret = PTR_ERR(clk_vout_top_ahb);
153 goto clk_ahb_get_failed;
157 priv->pll[PLL_OFV(JH7110_DISP_ROOT)] =
158 devm_clk_hw_register_fixed_factor(
159 priv->dev, "disp_root",
160 "u0_dom_vout_top_clk_dom_vout_top_clk_vout_src",
162 priv->pll[PLL_OFV(JH7110_DISP_AXI)] =
163 devm_clk_hw_register_fixed_factor(
164 priv->dev, "disp_axi",
165 "u0_dom_vout_top_clk_dom_vout_top_clk_vout_axi",
167 priv->pll[PLL_OFV(JH7110_DISP_AHB)] =
168 devm_clk_hw_register_fixed_factor(
169 priv->dev, "disp_ahb",
170 "u0_dom_vout_top_clk_dom_vout_top_clk_vout_ahb",
172 priv->pll[PLL_OFV(JH7110_HDMI_PHY_REF)] =
173 devm_clk_hw_register_fixed_factor(
174 priv->dev, "hdmi_phy_ref",
175 "u0_dom_vout_top_clk_dom_vout_top_clk_hdmiphy_ref",
177 priv->pll[PLL_OFV(JH7110_HDMITX0_MCLK)] =
178 devm_clk_hw_register_fixed_factor(
179 priv->dev, "hdmitx0_mclk",
180 "u0_dom_vout_top_clk_dom_vout_top_clk_hdmitx0_mclk",
182 priv->pll[PLL_OFV(JH7110_HDMITX0_SCK)] =
183 devm_clk_hw_register_fixed_factor(
184 priv->dev, "hdmitx0_sck",
185 "u0_dom_vout_top_clk_dom_vout_top_clk_hdmitx0_bclk",
188 priv->pll[PLL_OFV(JH7110_MIPI_DPHY_REF)] =
189 devm_clk_hw_register_fixed_factor(
190 priv->dev, "mipi_dphy_ref",
191 "u0_dom_vout_top_clk_dom_vout_top_clk_mipiphy_ref",
194 priv->pll[PLL_OFV(JH7110_U0_PCLK_MUX_BIST_PCLK)] =
195 devm_clk_hw_register_fixed_factor(
196 priv->dev, "u0_pclk_mux_bist_pclk",
197 "u0_dom_vout_top_clk_dom_vout_top_bist_pclk",
199 priv->pll[PLL_OFV(JH7110_DISP_APB)] =
200 clk_hw_register_fixed_rate(priv->dev,
201 "disp_apb", NULL, 0, 51200000);
202 priv->pll[PLL_OFV(JH7110_U0_PCLK_MUX_FUNC_PCLK)] =
203 devm_clk_hw_register_fixed_factor(priv->dev,
204 "u0_pclk_mux_func_pclk", "apb", 0, 1, 1);
206 priv->pll[PLL_OFV(JH7110_U0_DOM_VOUT_CRG_PCLK)] =
207 devm_clk_hw_register_fixed_factor(priv->dev,
208 "u0_dom_vout_crg_pclk", "disp_apb", 0, 1, 1);
209 priv->pll[PLL_OFV(JH7110_U0_DOM_VOUT_SYSCON_PCLK)] =
210 devm_clk_hw_register_fixed_factor(priv->dev,
211 "u0_dom_vout_syscon_pclk", "disp_apb", 0, 1, 1);
212 priv->pll[PLL_OFV(JH7110_U0_SAIF_AMBA_DOM_VOUT_AHB_DEC_CLK_AHB)] =
213 devm_clk_hw_register_fixed_factor(priv->dev,
214 "u0_saif_amba_dom_vout_ahb_dec_clk_ahb",
215 "disp_ahb", 0, 1, 1);
216 priv->pll[PLL_OFV(JH7110_U0_AHB2APB_CLK_AHB)] =
217 devm_clk_hw_register_fixed_factor(priv->dev,
218 "u0_ahb2apb_clk_ahb", "disp_ahb", 0, 1, 1);
219 priv->pll[PLL_OFV(JH7110_U0_P2P_ASYNC_CLK_APBS)] =
220 devm_clk_hw_register_fixed_factor(priv->dev,
221 "u0_p2p_async_clk_apbs", "disp_apb", 0, 1, 1);
223 priv->pll[PLL_OFV(JH7110_U0_CDNS_DSITX_CLK_RXESC)] =
224 devm_clk_hw_register_fixed_factor(priv->dev,
225 "u0_cdns_dsiTx_clk_rxesc",
226 "mipitx_dphy_rxesc", 0, 1, 1);
227 priv->pll[PLL_OFV(JH7110_U0_CDNS_DSITX_CLK_TXBYTEHS)] =
228 devm_clk_hw_register_fixed_factor(priv->dev,
229 "u0_cdns_dsiTx_clk_txbytehs",
230 "mipitx_dphy_txbytehs", 0, 1, 1);
232 priv->pll[PLL_OFV(JH7110_U0_MIPITX_DPHY_CLK_SYS)] =
233 devm_clk_hw_register_fixed_factor(priv->dev,
234 "u0_mipitx_dphy_clk_sys", "disp_apb", 0, 1, 1);
235 priv->pll[PLL_OFV(JH7110_U0_MIPITX_DPHY_CLK_DPHY_REF)] =
236 devm_clk_hw_register_fixed_factor(priv->dev,
237 "u0_mipitx_dphy_clk_dphy_ref",
238 "mipi_dphy_ref", 0, 1, 1);
239 priv->pll[PLL_OFV(JH7110_U0_MIPITX_APBIF_PCLK)] =
240 devm_clk_hw_register_fixed_factor(priv->dev,
241 "u0_mipitx_apbif_pclk", "disp_apb", 0, 1, 1);
243 priv->pll[PLL_OFV(JH7110_HDMI_TX_CLK_REF)] =
244 devm_clk_hw_register_fixed_factor(priv->dev,
245 "u0_hdmi_tx_clk_ref", "hdmi_phy_ref", 0, 1, 1);
247 priv->pll[PLL_OFV(JH7110_U0_DC8200_CLK_PIX0_OUT)] =
248 devm_clk_hw_register_fixed_factor(priv->dev,
249 "u0_dc8200_clk_pix0_out",
250 "u0_dc8200_clk_pix0", 0, 1, 1);
251 priv->pll[PLL_OFV(JH7110_U0_DC8200_CLK_PIX1_OUT)] =
252 devm_clk_hw_register_fixed_factor(priv->dev,
253 "u0_dc8200_clk_pix1_out",
254 "u0_dc8200_clk_pix1", 0, 1, 1);
256 for (idx = 0; idx < JH7110_DISP_ROOT; idx++) {
257 u32 max = jh7110_clk_vout_data[idx].max;
258 struct clk_parent_data parents[2] = {};
259 struct clk_init_data init = {
260 .name = jh7110_clk_vout_data[idx].name,
261 .ops = starfive_jh7110_clk_ops(max),
262 .parent_data = parents,
263 .num_parents = ((max & JH7110_CLK_MUX_MASK) \
264 >> JH7110_CLK_MUX_SHIFT) + 1,
265 .flags = jh7110_clk_vout_data[idx].flags,
267 struct jh7110_clk *clk = &priv->reg[idx];
270 for (i = 0; i < init.num_parents; i++) {
271 unsigned int pidx = jh7110_clk_vout_data[idx].parents[i];
273 if (pidx < JH7110_DISP_ROOT)
274 parents[i].hw = &priv->reg[pidx].hw;
275 else if (pidx < JH7110_CLK_VOUT_END)
277 priv->pll[PLL_OFV(pidx)];
278 else if (pidx == JH7110_HDMITX0_PIXELCLK)
279 parents[i].fw_name = "hdmitx0_pixelclk";
280 else if (pidx == JH7110_MIPITX_DPHY_RXESC)
281 parents[i].fw_name = "mipitx_dphy_rxesc";
282 else if (pidx == JH7110_MIPITX_DPHY_TXBYTEHS)
283 parents[i].fw_name = "mipitx_dphy_txbytehs";
284 else if (pidx == JH7110_U0_DC8200_CLK_PIX0_OUT)
285 parents[i].fw_name = "u0_dc8200_clk_pix0_out";
286 else if (pidx == JH7110_U0_DC8200_CLK_PIX1_OUT)
287 parents[i].fw_name = "u0_dc8200_clk_pix1_out";
290 clk->hw.init = &init;
292 clk->max_div = max & JH7110_CLK_DIV_MASK;
293 clk->reg_flags = JH7110_CLK_VOUT_FLAG;
295 ret = devm_clk_hw_register(priv->dev, &clk->hw);
300 ret = devm_of_clk_add_hw_provider(priv->dev, jh7110_vout_clk_get, priv);
304 devm_clk_put(priv->dev, clk_vout_src);
305 reset_control_put(rst_vout_src);
306 devm_clk_put(priv->dev, clk_vout_top_ahb);
308 dev_info(&pdev->dev,"starfive JH7110 clk_vout init successfully.");
311 clk_ahb_enable_failed:
312 devm_clk_put(priv->dev, clk_vout_top_ahb);
314 reset_control_assert(rst_vout_src);
315 rst_src_deassert_failed:
316 reset_control_put(rst_vout_src);
318 clk_disable_unprepare(clk_vout_src);
319 clk_src_enable_failed:
320 devm_clk_put(priv->dev, clk_vout_src);
326 static const struct of_device_id clk_starfive_jh7110_vout_match[] = {
327 {.compatible = "starfive,jh7110-clk-vout" },
331 static struct platform_driver clk_starfive_jh7110_vout_driver = {
332 .probe = clk_starfive_jh7110_vout_probe,
334 .name = "clk-starfive-jh7110-vout",
335 .of_match_table = clk_starfive_jh7110_vout_match,
338 module_platform_driver(clk_starfive_jh7110_vout_driver);
340 MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
341 MODULE_DESCRIPTION("StarFive JH7110 vout clock driver");
342 MODULE_LICENSE("GPL");