]> Git Repo - J-linux.git/blob - drivers/net/mdio/mdio-mux-meson-g12a.c
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[J-linux.git] / drivers / net / mdio / mdio-mux-meson-g12a.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 Baylibre, SAS.
3  * Author: Jerome Brunet <[email protected]>
4  */
5
6 #include <linux/bitfield.h>
7 #include <linux/delay.h>
8 #include <linux/clk.h>
9 #include <linux/clk-provider.h>
10 #include <linux/device.h>
11 #include <linux/io.h>
12 #include <linux/iopoll.h>
13 #include <linux/mdio-mux.h>
14 #include <linux/module.h>
15 #include <linux/phy.h>
16 #include <linux/platform_device.h>
17
18 #define ETH_PLL_STS             0x40
19 #define ETH_PLL_CTL0            0x44
20 #define  PLL_CTL0_LOCK_DIG      BIT(30)
21 #define  PLL_CTL0_RST           BIT(29)
22 #define  PLL_CTL0_EN            BIT(28)
23 #define  PLL_CTL0_SEL           BIT(23)
24 #define  PLL_CTL0_N             GENMASK(14, 10)
25 #define  PLL_CTL0_M             GENMASK(8, 0)
26 #define  PLL_LOCK_TIMEOUT       1000000
27 #define  PLL_MUX_NUM_PARENT     2
28 #define ETH_PLL_CTL1            0x48
29 #define ETH_PLL_CTL2            0x4c
30 #define ETH_PLL_CTL3            0x50
31 #define ETH_PLL_CTL4            0x54
32 #define ETH_PLL_CTL5            0x58
33 #define ETH_PLL_CTL6            0x5c
34 #define ETH_PLL_CTL7            0x60
35
36 #define ETH_PHY_CNTL0           0x80
37 #define   EPHY_G12A_ID          0x33010180
38 #define ETH_PHY_CNTL1           0x84
39 #define  PHY_CNTL1_ST_MODE      GENMASK(2, 0)
40 #define  PHY_CNTL1_ST_PHYADD    GENMASK(7, 3)
41 #define   EPHY_DFLT_ADD         8
42 #define  PHY_CNTL1_MII_MODE     GENMASK(15, 14)
43 #define   EPHY_MODE_RMII        0x1
44 #define  PHY_CNTL1_CLK_EN       BIT(16)
45 #define  PHY_CNTL1_CLKFREQ      BIT(17)
46 #define  PHY_CNTL1_PHY_ENB      BIT(18)
47 #define ETH_PHY_CNTL2           0x88
48 #define  PHY_CNTL2_USE_INTERNAL BIT(5)
49 #define  PHY_CNTL2_SMI_SRC_MAC  BIT(6)
50 #define  PHY_CNTL2_RX_CLK_EPHY  BIT(9)
51
52 #define MESON_G12A_MDIO_EXTERNAL_ID 0
53 #define MESON_G12A_MDIO_INTERNAL_ID 1
54
55 struct g12a_mdio_mux {
56         void __iomem *regs;
57         void *mux_handle;
58         struct clk *pll;
59 };
60
61 struct g12a_ephy_pll {
62         void __iomem *base;
63         struct clk_hw hw;
64 };
65
66 #define g12a_ephy_pll_to_dev(_hw)                       \
67         container_of(_hw, struct g12a_ephy_pll, hw)
68
69 static unsigned long g12a_ephy_pll_recalc_rate(struct clk_hw *hw,
70                                                unsigned long parent_rate)
71 {
72         struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
73         u32 val, m, n;
74
75         val = readl(pll->base + ETH_PLL_CTL0);
76         m = FIELD_GET(PLL_CTL0_M, val);
77         n = FIELD_GET(PLL_CTL0_N, val);
78
79         return parent_rate * m / n;
80 }
81
82 static int g12a_ephy_pll_enable(struct clk_hw *hw)
83 {
84         struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
85         u32 val = readl(pll->base + ETH_PLL_CTL0);
86
87         /* Apply both enable an reset */
88         val |= PLL_CTL0_RST | PLL_CTL0_EN;
89         writel(val, pll->base + ETH_PLL_CTL0);
90
91         /* Clear the reset to let PLL lock */
92         val &= ~PLL_CTL0_RST;
93         writel(val, pll->base + ETH_PLL_CTL0);
94
95         /* Poll on the digital lock instead of the usual analog lock
96          * This is done because bit 31 is unreliable on some SoC. Bit
97          * 31 may indicate that the PLL is not lock even though the clock
98          * is actually running
99          */
100         return readl_poll_timeout(pll->base + ETH_PLL_CTL0, val,
101                                   val & PLL_CTL0_LOCK_DIG, 0, PLL_LOCK_TIMEOUT);
102 }
103
104 static void g12a_ephy_pll_disable(struct clk_hw *hw)
105 {
106         struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
107         u32 val;
108
109         val = readl(pll->base + ETH_PLL_CTL0);
110         val &= ~PLL_CTL0_EN;
111         val |= PLL_CTL0_RST;
112         writel(val, pll->base + ETH_PLL_CTL0);
113 }
114
115 static int g12a_ephy_pll_is_enabled(struct clk_hw *hw)
116 {
117         struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
118         unsigned int val;
119
120         val = readl(pll->base + ETH_PLL_CTL0);
121
122         return (val & PLL_CTL0_LOCK_DIG) ? 1 : 0;
123 }
124
125 static int g12a_ephy_pll_init(struct clk_hw *hw)
126 {
127         struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
128
129         /* Apply PLL HW settings */
130         writel(0x29c0040a, pll->base + ETH_PLL_CTL0);
131         writel(0x927e0000, pll->base + ETH_PLL_CTL1);
132         writel(0xac5f49e5, pll->base + ETH_PLL_CTL2);
133         writel(0x00000000, pll->base + ETH_PLL_CTL3);
134         writel(0x00000000, pll->base + ETH_PLL_CTL4);
135         writel(0x20200000, pll->base + ETH_PLL_CTL5);
136         writel(0x0000c002, pll->base + ETH_PLL_CTL6);
137         writel(0x00000023, pll->base + ETH_PLL_CTL7);
138
139         return 0;
140 }
141
142 static const struct clk_ops g12a_ephy_pll_ops = {
143         .recalc_rate    = g12a_ephy_pll_recalc_rate,
144         .is_enabled     = g12a_ephy_pll_is_enabled,
145         .enable         = g12a_ephy_pll_enable,
146         .disable        = g12a_ephy_pll_disable,
147         .init           = g12a_ephy_pll_init,
148 };
149
150 static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv)
151 {
152         u32 value;
153         int ret;
154
155         /* Enable the phy clock */
156         if (!__clk_is_enabled(priv->pll)) {
157                 ret = clk_prepare_enable(priv->pll);
158                 if (ret)
159                         return ret;
160         }
161
162         /* Initialize ephy control */
163         writel(EPHY_G12A_ID, priv->regs + ETH_PHY_CNTL0);
164
165         /* Make sure we get a 0 -> 1 transition on the enable bit */
166         value = FIELD_PREP(PHY_CNTL1_ST_MODE, 3) |
167                 FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) |
168                 FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) |
169                 PHY_CNTL1_CLK_EN |
170                 PHY_CNTL1_CLKFREQ;
171         writel(value, priv->regs + ETH_PHY_CNTL1);
172         writel(PHY_CNTL2_USE_INTERNAL |
173                PHY_CNTL2_SMI_SRC_MAC |
174                PHY_CNTL2_RX_CLK_EPHY,
175                priv->regs + ETH_PHY_CNTL2);
176
177         value |= PHY_CNTL1_PHY_ENB;
178         writel(value, priv->regs + ETH_PHY_CNTL1);
179
180         /* The phy needs a bit of time to power up */
181         mdelay(10);
182
183         return 0;
184 }
185
186 static int g12a_enable_external_mdio(struct g12a_mdio_mux *priv)
187 {
188         /* Reset the mdio bus mux */
189         writel_relaxed(0x0, priv->regs + ETH_PHY_CNTL2);
190
191         /* Disable the phy clock if enabled */
192         if (__clk_is_enabled(priv->pll))
193                 clk_disable_unprepare(priv->pll);
194
195         return 0;
196 }
197
198 static int g12a_mdio_switch_fn(int current_child, int desired_child,
199                                void *data)
200 {
201         struct g12a_mdio_mux *priv = dev_get_drvdata(data);
202
203         if (current_child == desired_child)
204                 return 0;
205
206         switch (desired_child) {
207         case MESON_G12A_MDIO_EXTERNAL_ID:
208                 return g12a_enable_external_mdio(priv);
209         case MESON_G12A_MDIO_INTERNAL_ID:
210                 return g12a_enable_internal_mdio(priv);
211         default:
212                 return -EINVAL;
213         }
214 }
215
216 static const struct of_device_id g12a_mdio_mux_match[] = {
217         { .compatible = "amlogic,g12a-mdio-mux", },
218         {},
219 };
220 MODULE_DEVICE_TABLE(of, g12a_mdio_mux_match);
221
222 static int g12a_ephy_glue_clk_register(struct device *dev)
223 {
224         struct g12a_mdio_mux *priv = dev_get_drvdata(dev);
225         const char *parent_names[PLL_MUX_NUM_PARENT];
226         struct clk_init_data init;
227         struct g12a_ephy_pll *pll;
228         struct clk_mux *mux;
229         struct clk *clk;
230         char *name;
231         int i;
232
233         /* get the mux parents */
234         for (i = 0; i < PLL_MUX_NUM_PARENT; i++) {
235                 char in_name[8];
236
237                 snprintf(in_name, sizeof(in_name), "clkin%d", i);
238                 clk = devm_clk_get(dev, in_name);
239                 if (IS_ERR(clk))
240                         return dev_err_probe(dev, PTR_ERR(clk),
241                                              "Missing clock %s\n", in_name);
242
243                 parent_names[i] = __clk_get_name(clk);
244         }
245
246         /* create the input mux */
247         mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
248         if (!mux)
249                 return -ENOMEM;
250
251         name = kasprintf(GFP_KERNEL, "%s#mux", dev_name(dev));
252         if (!name)
253                 return -ENOMEM;
254
255         init.name = name;
256         init.ops = &clk_mux_ro_ops;
257         init.flags = 0;
258         init.parent_names = parent_names;
259         init.num_parents = PLL_MUX_NUM_PARENT;
260
261         mux->reg = priv->regs + ETH_PLL_CTL0;
262         mux->shift = __ffs(PLL_CTL0_SEL);
263         mux->mask = PLL_CTL0_SEL >> mux->shift;
264         mux->hw.init = &init;
265
266         clk = devm_clk_register(dev, &mux->hw);
267         kfree(name);
268         if (IS_ERR(clk)) {
269                 dev_err(dev, "failed to register input mux\n");
270                 return PTR_ERR(clk);
271         }
272
273         /* create the pll */
274         pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
275         if (!pll)
276                 return -ENOMEM;
277
278         name = kasprintf(GFP_KERNEL, "%s#pll", dev_name(dev));
279         if (!name)
280                 return -ENOMEM;
281
282         init.name = name;
283         init.ops = &g12a_ephy_pll_ops;
284         init.flags = 0;
285         parent_names[0] = __clk_get_name(clk);
286         init.parent_names = parent_names;
287         init.num_parents = 1;
288
289         pll->base = priv->regs;
290         pll->hw.init = &init;
291
292         clk = devm_clk_register(dev, &pll->hw);
293         kfree(name);
294         if (IS_ERR(clk)) {
295                 dev_err(dev, "failed to register input mux\n");
296                 return PTR_ERR(clk);
297         }
298
299         priv->pll = clk;
300
301         return 0;
302 }
303
304 static int g12a_mdio_mux_probe(struct platform_device *pdev)
305 {
306         struct device *dev = &pdev->dev;
307         struct g12a_mdio_mux *priv;
308         struct clk *pclk;
309         int ret;
310
311         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
312         if (!priv)
313                 return -ENOMEM;
314
315         platform_set_drvdata(pdev, priv);
316
317         priv->regs = devm_platform_ioremap_resource(pdev, 0);
318         if (IS_ERR(priv->regs))
319                 return PTR_ERR(priv->regs);
320
321         pclk = devm_clk_get_enabled(dev, "pclk");
322         if (IS_ERR(pclk))
323                 return dev_err_probe(dev, PTR_ERR(pclk),
324                                      "failed to get peripheral clock\n");
325
326         /* Register PLL in CCF */
327         ret = g12a_ephy_glue_clk_register(dev);
328         if (ret)
329                 return ret;
330
331         ret = mdio_mux_init(dev, dev->of_node, g12a_mdio_switch_fn,
332                             &priv->mux_handle, dev, NULL);
333         if (ret)
334                 dev_err_probe(dev, ret, "mdio multiplexer init failed\n");
335
336         return ret;
337 }
338
339 static int g12a_mdio_mux_remove(struct platform_device *pdev)
340 {
341         struct g12a_mdio_mux *priv = platform_get_drvdata(pdev);
342
343         mdio_mux_uninit(priv->mux_handle);
344
345         if (__clk_is_enabled(priv->pll))
346                 clk_disable_unprepare(priv->pll);
347
348         return 0;
349 }
350
351 static struct platform_driver g12a_mdio_mux_driver = {
352         .probe          = g12a_mdio_mux_probe,
353         .remove         = g12a_mdio_mux_remove,
354         .driver         = {
355                 .name   = "g12a-mdio_mux",
356                 .of_match_table = g12a_mdio_mux_match,
357         },
358 };
359 module_platform_driver(g12a_mdio_mux_driver);
360
361 MODULE_DESCRIPTION("Amlogic G12a MDIO multiplexer driver");
362 MODULE_AUTHOR("Jerome Brunet <[email protected]>");
363 MODULE_LICENSE("GPL v2");
This page took 0.049996 seconds and 4 git commands to generate.