4bd1036fcaef6af092bd8e6b45ea88863ad48d62
[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
21 #include <dt-bindings/clock/starfive-jh7110-vout.h>
22 #include "clk-starfive-jh7110.h"
23
24 static const struct jh7110_clk_data jh7110_clk_vout_data[] __initconst = {
25         //divider
26         JH7110__DIV(JH7110_APB, "apb", 8, JH7110_DISP_AHB),
27         JH7110__DIV(JH7110_DC8200_PIX0, "dc8200_pix0", 63, JH7110_DISP_ROOT),
28         JH7110__DIV(JH7110_DSI_SYS, "dsi_sys", 31, JH7110_DISP_ROOT),
29         JH7110__DIV(JH7110_TX_ESC, "tx_esc", 31, JH7110_DISP_AHB),
30         //dc8200
31         JH7110_GATE(JH7110_U0_DC8200_CLK_AXI, "u0_dc8200_clk_axi",
32                         0, JH7110_DISP_AXI),
33         JH7110_GATE(JH7110_U0_DC8200_CLK_CORE, "u0_dc8200_clk_core",
34                         0, JH7110_DISP_AXI),
35         JH7110_GATE(JH7110_U0_DC8200_CLK_AHB, "u0_dc8200_clk_ahb",
36                         0, JH7110_DISP_AHB),
37         JH7110_GMUX(JH7110_U0_DC8200_CLK_PIX0, "u0_dc8200_clk_pix0", 0, 2,
38                         JH7110_DC8200_PIX0,
39                         JH7110_HDMITX0_PIXELCLK),
40         JH7110_GMUX(JH7110_U0_DC8200_CLK_PIX1, "u0_dc8200_clk_pix1", 0, 2,
41                         JH7110_DC8200_PIX0,
42                         JH7110_HDMITX0_PIXELCLK),
43         
44         JH7110_GMUX(JH7110_DOM_VOUT_TOP_LCD_CLK, "dom_vout_top_lcd_clk", 0, 2,
45                         JH7110_U0_DC8200_CLK_PIX0_OUT,
46                         JH7110_U0_DC8200_CLK_PIX1_OUT),
47         //dsiTx
48         JH7110_GATE(JH7110_U0_CDNS_DSITX_CLK_APB, "u0_cdns_dsiTx_clk_apb",
49                         0, JH7110_DSI_SYS),
50         JH7110_GATE(JH7110_U0_CDNS_DSITX_CLK_SYS, "u0_cdns_dsiTx_clk_sys",
51                         0, JH7110_DSI_SYS),
52         JH7110_GMUX(JH7110_U0_CDNS_DSITX_CLK_DPI, "u0_cdns_dsiTx_clk_api", 0, 2,
53                         JH7110_DC8200_PIX0,
54                         JH7110_HDMITX0_PIXELCLK),
55         JH7110_GATE(JH7110_U0_CDNS_DSITX_CLK_TXESC, "u0_cdns_dsiTx_clk_txesc",
56                         0, JH7110_TX_ESC),
57         //mipitx DPHY
58         JH7110_GATE(JH7110_U0_MIPITX_DPHY_CLK_TXESC, "u0_mipitx_dphy_clk_txesc",
59                         0, JH7110_TX_ESC),
60         //hdmi
61         JH7110_GATE(JH7110_U0_HDMI_TX_CLK_MCLK, "u0_hdmi_tx_clk_mclk",
62                         0, JH7110_HDMITX0_MCLK),
63         JH7110_GATE(JH7110_U0_HDMI_TX_CLK_BCLK, "u0_hdmi_tx_clk_bclk",
64                         0, JH7110_HDMITX0_SCK),
65         JH7110_GATE(JH7110_U0_HDMI_TX_CLK_SYS, "u0_hdmi_tx_clk_sys",
66                         0, JH7110_DISP_APB),
67 };
68
69 static struct clk_hw *jh7110_vout_clk_get(struct of_phandle_args *clkspec,
70                                         void *data)
71 {
72         struct jh7110_clk_priv *priv = data;
73         unsigned int idx = clkspec->args[0];
74
75         if (idx < JH7110_CLK_VOUT_REG_END)
76                 return &priv->reg[idx].hw;
77
78         if (idx < JH7110_CLK_VOUT_END)
79                 return priv->pll[PLL_OFV(idx)];
80
81         return ERR_PTR(-EINVAL);
82 }
83
84 static int __init clk_starfive_jh7110_vout_probe(struct platform_device *pdev)
85 {
86         struct jh7110_clk_priv *priv;
87         unsigned int idx;
88         int ret = 0;
89
90         priv = devm_kzalloc(&pdev->dev, struct_size(priv,
91                                 reg, JH7110_DISP_ROOT), GFP_KERNEL);
92         if (!priv)
93                 return -ENOMEM;
94
95         spin_lock_init(&priv->rmw_lock);
96         priv->dev = &pdev->dev;
97         priv->vout_base = devm_platform_ioremap_resource(pdev, 0);
98         if (IS_ERR(priv->vout_base))
99                 return PTR_ERR(priv->vout_base);
100
101         //source
102         priv->pll[PLL_OFV(JH7110_DISP_ROOT)] =
103                         devm_clk_hw_register_fixed_factor(
104                         priv->dev, "disp_root",
105                         "u0_dom_vout_top_clk_dom_vout_top_clk_vout_src",
106                         0, 1, 1);
107         priv->pll[PLL_OFV(JH7110_DISP_AXI)] =
108                         devm_clk_hw_register_fixed_factor(
109                         priv->dev, "disp_axi",
110                         "u0_dom_vout_top_clk_dom_vout_top_clk_vout_axi",
111                         0, 1, 1);
112         priv->pll[PLL_OFV(JH7110_DISP_AHB)] =
113                         devm_clk_hw_register_fixed_factor(
114                         priv->dev, "disp_ahb",
115                         "u0_dom_vout_top_clk_dom_vout_top_clk_vout_ahb",
116                         0, 1, 1);
117         priv->pll[PLL_OFV(JH7110_HDMI_PHY_REF)] =
118                         devm_clk_hw_register_fixed_factor(
119                         priv->dev, "hdmi_phy_ref",
120                         "u0_dom_vout_top_clk_dom_vout_top_clk_hdmiphy_ref",
121                         0, 1, 1);
122         priv->pll[PLL_OFV(JH7110_HDMITX0_MCLK)] =
123                         devm_clk_hw_register_fixed_factor(
124                         priv->dev, "hdmitx0_mclk",
125                         "u0_dom_vout_top_clk_dom_vout_top_clk_hdmitx0_mclk",
126                         0, 1, 1);
127         priv->pll[PLL_OFV(JH7110_HDMITX0_SCK)] =
128                         devm_clk_hw_register_fixed_factor(
129                         priv->dev, "hdmitx0_sck",
130                         "u0_dom_vout_top_clk_dom_vout_top_clk_hdmitx0_bclk",
131                         0, 1, 1);
132         
133         priv->pll[PLL_OFV(JH7110_MIPI_DPHY_REF)] =
134                         devm_clk_hw_register_fixed_factor(
135                         priv->dev, "mipi_dphy_ref",
136                         "u0_dom_vout_top_clk_dom_vout_top_clk_mipiphy_ref",
137                         0, 1, 1);
138         //divider
139         priv->pll[PLL_OFV(JH7110_U0_PCLK_MUX_BIST_PCLK)] =
140                         devm_clk_hw_register_fixed_factor(
141                         priv->dev, "u0_pclk_mux_bist_pclk",
142                         "u0_dom_vout_top_clk_dom_vout_top_bist_pclk",
143                         0, 1, 1);
144         priv->pll[PLL_OFV(JH7110_DISP_APB)] =
145                         clk_hw_register_fixed_rate(priv->dev,
146                         "disp_apb", NULL, 0, 51200000);
147         priv->pll[PLL_OFV(JH7110_U0_PCLK_MUX_FUNC_PCLK)] =
148                         devm_clk_hw_register_fixed_factor(priv->dev,
149                         "u0_pclk_mux_func_pclk", "apb", 0, 1, 1);
150         //bus
151         priv->pll[PLL_OFV(JH7110_U0_DOM_VOUT_CRG_PCLK)] =
152                         devm_clk_hw_register_fixed_factor(priv->dev,
153                         "u0_dom_vout_crg_pclk", "disp_apb", 0, 1, 1);
154         priv->pll[PLL_OFV(JH7110_U0_DOM_VOUT_SYSCON_PCLK)] =
155                         devm_clk_hw_register_fixed_factor(priv->dev,
156                         "u0_dom_vout_syscon_pclk", "disp_apb", 0, 1, 1);
157         priv->pll[PLL_OFV(JH7110_U0_SAIF_AMBA_DOM_VOUT_AHB_DEC_CLK_AHB)] =
158                         devm_clk_hw_register_fixed_factor(priv->dev,
159                         "u0_saif_amba_dom_vout_ahb_dec_clk_ahb",
160                         "disp_ahb", 0, 1, 1);
161         priv->pll[PLL_OFV(JH7110_U0_AHB2APB_CLK_AHB)] =
162                         devm_clk_hw_register_fixed_factor(priv->dev,
163                         "u0_ahb2apb_clk_ahb", "disp_ahb", 0, 1, 1);
164         priv->pll[PLL_OFV(JH7110_U0_P2P_ASYNC_CLK_APBS)] =
165                         devm_clk_hw_register_fixed_factor(priv->dev,
166                         "u0_p2p_async_clk_apbs", "disp_apb", 0, 1, 1);
167         //dsiTx
168         priv->pll[PLL_OFV(JH7110_U0_CDNS_DSITX_CLK_RXESC)] =
169                         devm_clk_hw_register_fixed_factor(priv->dev,
170                         "u0_cdns_dsiTx_clk_rxesc",
171                         "mipitx_dphy_rxesc", 0, 1, 1);
172         priv->pll[PLL_OFV(JH7110_U0_CDNS_DSITX_CLK_TXBYTEHS)] =
173                         devm_clk_hw_register_fixed_factor(priv->dev,
174                         "u0_cdns_dsiTx_clk_txbytehs",
175                         "mipitx_dphy_txbytehs", 0, 1, 1);
176         //mipitx DPHY
177         priv->pll[PLL_OFV(JH7110_U0_MIPITX_DPHY_CLK_SYS)] =
178                         devm_clk_hw_register_fixed_factor(priv->dev,
179                         "u0_mipitx_dphy_clk_sys", "disp_apb", 0, 1, 1);
180         priv->pll[PLL_OFV(JH7110_U0_MIPITX_DPHY_CLK_DPHY_REF)] =
181                         devm_clk_hw_register_fixed_factor(priv->dev,
182                         "u0_mipitx_dphy_clk_dphy_ref",
183                         "mipi_dphy_ref", 0, 1, 1);
184         priv->pll[PLL_OFV(JH7110_U0_MIPITX_APBIF_PCLK)] =
185                         devm_clk_hw_register_fixed_factor(priv->dev,
186                         "u0_mipitx_apbif_pclk", "disp_apb", 0, 1, 1);
187         //hdmi
188         priv->pll[PLL_OFV(JH7110_HDMI_TX_CLK_REF)] =
189                         devm_clk_hw_register_fixed_factor(priv->dev,
190                         "u0_hdmi_tx_clk_ref", "hdmi_phy_ref", 0, 1, 1);
191         
192         priv->pll[PLL_OFV(JH7110_U0_DC8200_CLK_PIX0_OUT)] =
193                         devm_clk_hw_register_fixed_factor(priv->dev,
194                         "u0_dc8200_clk_pix0_out",
195                         "u0_dc8200_clk_pix0", 0, 1, 1);
196         priv->pll[PLL_OFV(JH7110_U0_DC8200_CLK_PIX1_OUT)] =
197                         devm_clk_hw_register_fixed_factor(priv->dev,
198                         "u0_dc8200_clk_pix1_out",
199                         "u0_dc8200_clk_pix1", 0, 1, 1);
200
201         for (idx = 0; idx < JH7110_DISP_ROOT; idx++) {
202                 u32 max = jh7110_clk_vout_data[idx].max;
203                 struct clk_parent_data parents[2] = {};
204                 struct clk_init_data init = {
205                         .name = jh7110_clk_vout_data[idx].name,
206                         .ops = starfive_jh7110_clk_ops(max),
207                         .parent_data = parents,
208                         .num_parents = ((max & JH7110_CLK_MUX_MASK) \
209                                         >> JH7110_CLK_MUX_SHIFT) + 1,
210                         .flags = jh7110_clk_vout_data[idx].flags,
211                 };
212                 struct jh7110_clk *clk = &priv->reg[idx];
213                 unsigned int i;
214
215                 for (i = 0; i < init.num_parents; i++) {
216                         unsigned int pidx = jh7110_clk_vout_data[idx].parents[i];
217
218                         if (pidx < JH7110_DISP_ROOT)
219                                 parents[i].hw = &priv->reg[pidx].hw;
220                         else if (pidx < JH7110_CLK_VOUT_END)
221                                 parents[i].hw = \
222                                         priv->pll[PLL_OFV(pidx)];
223                         else if (pidx == JH7110_HDMITX0_PIXELCLK)
224                                 parents[i].fw_name = "hdmitx0_pixelclk";
225                         else if (pidx == JH7110_MIPITX_DPHY_RXESC)
226                                 parents[i].fw_name = "mipitx_dphy_rxesc";
227                         else if (pidx == JH7110_MIPITX_DPHY_TXBYTEHS)
228                                 parents[i].fw_name = "mipitx_dphy_txbytehs";
229                         else if (pidx == JH7110_U0_DC8200_CLK_PIX0_OUT)
230                                 parents[i].fw_name = "u0_dc8200_clk_pix0_out";
231                         else if (pidx == JH7110_U0_DC8200_CLK_PIX1_OUT)
232                                 parents[i].fw_name = "u0_dc8200_clk_pix1_out";
233                 }
234
235                 clk->hw.init = &init;
236                 clk->idx = idx;
237                 clk->max_div = max & JH7110_CLK_DIV_MASK;
238                 clk->reg_flags = JH7110_CLK_VOUT_FLAG;
239
240                 ret = devm_clk_hw_register(priv->dev, &clk->hw);
241                 if (ret)
242                         return ret;
243         }
244
245         ret = devm_of_clk_add_hw_provider(priv->dev, jh7110_vout_clk_get, priv);
246         if (ret)
247                 return ret;
248         
249         dev_info(&pdev->dev,"starfive JH7110 clk_vout init successfully.");
250         return 0;
251 }
252
253 static const struct of_device_id clk_starfive_jh7110_vout_match[] = {   
254                 {.compatible = "starfive,jh7110-clk-vout" },
255                 { /* sentinel */ }
256 };
257
258 static struct platform_driver clk_starfive_jh7110_vout_driver = {
259         .probe = clk_starfive_jh7110_vout_probe,
260                 .driver = {
261                 .name = "clk-starfive-jh7110-vout",
262                 .of_match_table = clk_starfive_jh7110_vout_match,
263         },
264 };
265 module_platform_driver(clk_starfive_jh7110_vout_driver);
266
267 MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
268 MODULE_DESCRIPTION("StarFive JH7110 vout clock driver");
269 MODULE_LICENSE("GPL");