GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / net / ethernet / stmicro / stmmac / dwmac-meson8b.c
1 /*
2  * Amlogic Meson8b, Meson8m2 and GXBB DWMAC glue layer
3  *
4  * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * You should have received a copy of the GNU General Public License
11  * along with this program. If not, see <http://www.gnu.org/licenses/>.
12  */
13
14 #include <linux/clk.h>
15 #include <linux/clk-provider.h>
16 #include <linux/device.h>
17 #include <linux/ethtool.h>
18 #include <linux/io.h>
19 #include <linux/ioport.h>
20 #include <linux/module.h>
21 #include <linux/of_device.h>
22 #include <linux/of_net.h>
23 #include <linux/mfd/syscon.h>
24 #include <linux/platform_device.h>
25 #include <linux/stmmac.h>
26
27 #include "stmmac_platform.h"
28
29 #define PRG_ETH0                        0x0
30
31 #define PRG_ETH0_RGMII_MODE             BIT(0)
32
33 #define PRG_ETH0_EXT_PHY_MODE_MASK      GENMASK(2, 0)
34 #define PRG_ETH0_EXT_RGMII_MODE         1
35 #define PRG_ETH0_EXT_RMII_MODE          4
36
37 /* mux to choose between fclk_div2 (bit unset) and mpll2 (bit set) */
38 #define PRG_ETH0_CLK_M250_SEL_MASK      GENMASK(4, 4)
39
40 #define PRG_ETH0_TXDLY_SHIFT            5
41 #define PRG_ETH0_TXDLY_MASK             GENMASK(6, 5)
42
43 /* divider for the result of m250_sel */
44 #define PRG_ETH0_CLK_M250_DIV_SHIFT     7
45 #define PRG_ETH0_CLK_M250_DIV_WIDTH     3
46
47 #define PRG_ETH0_RGMII_TX_CLK_EN        10
48
49 #define PRG_ETH0_INVERTED_RMII_CLK      BIT(11)
50 #define PRG_ETH0_TX_AND_PHY_REF_CLK     BIT(12)
51
52 #define MUX_CLK_NUM_PARENTS             2
53
54 struct meson8b_dwmac;
55
56 struct meson8b_dwmac_data {
57         int (*set_phy_mode)(struct meson8b_dwmac *dwmac);
58 };
59
60 struct meson8b_dwmac {
61         struct device                   *dev;
62         void __iomem                    *regs;
63
64         const struct meson8b_dwmac_data *data;
65         phy_interface_t                 phy_mode;
66         struct clk                      *rgmii_tx_clk;
67         u32                             tx_delay_ns;
68 };
69
70 struct meson8b_dwmac_clk_configs {
71         struct clk_mux          m250_mux;
72         struct clk_divider      m250_div;
73         struct clk_fixed_factor fixed_div2;
74         struct clk_gate         rgmii_tx_en;
75 };
76
77 static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
78                                     u32 mask, u32 value)
79 {
80         u32 data;
81
82         data = readl(dwmac->regs + reg);
83         data &= ~mask;
84         data |= (value & mask);
85
86         writel(data, dwmac->regs + reg);
87 }
88
89 static struct clk *meson8b_dwmac_register_clk(struct meson8b_dwmac *dwmac,
90                                               const char *name_suffix,
91                                               const char **parent_names,
92                                               int num_parents,
93                                               const struct clk_ops *ops,
94                                               struct clk_hw *hw)
95 {
96         struct clk_init_data init;
97         char clk_name[32];
98
99         snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(dwmac->dev),
100                  name_suffix);
101
102         init.name = clk_name;
103         init.ops = ops;
104         init.flags = CLK_SET_RATE_PARENT;
105         init.parent_names = parent_names;
106         init.num_parents = num_parents;
107
108         hw->init = &init;
109
110         return devm_clk_register(dwmac->dev, hw);
111 }
112
113 static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
114 {
115         int i, ret;
116         struct clk *clk;
117         struct device *dev = dwmac->dev;
118         const char *parent_name, *mux_parent_names[MUX_CLK_NUM_PARENTS];
119         struct meson8b_dwmac_clk_configs *clk_configs;
120         static const struct clk_div_table div_table[] = {
121                 { .div = 2, .val = 2, },
122                 { .div = 3, .val = 3, },
123                 { .div = 4, .val = 4, },
124                 { .div = 5, .val = 5, },
125                 { .div = 6, .val = 6, },
126                 { .div = 7, .val = 7, },
127                 { /* end of array */ }
128         };
129
130         clk_configs = devm_kzalloc(dev, sizeof(*clk_configs), GFP_KERNEL);
131         if (!clk_configs)
132                 return -ENOMEM;
133
134         /* get the mux parents from DT */
135         for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) {
136                 char name[16];
137
138                 snprintf(name, sizeof(name), "clkin%d", i);
139                 clk = devm_clk_get(dev, name);
140                 if (IS_ERR(clk)) {
141                         ret = PTR_ERR(clk);
142                         if (ret != -EPROBE_DEFER)
143                                 dev_err(dev, "Missing clock %s\n", name);
144                         return ret;
145                 }
146
147                 mux_parent_names[i] = __clk_get_name(clk);
148         }
149
150         clk_configs->m250_mux.reg = dwmac->regs + PRG_ETH0;
151         clk_configs->m250_mux.shift = __ffs(PRG_ETH0_CLK_M250_SEL_MASK);
152         clk_configs->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK >>
153                                      clk_configs->m250_mux.shift;
154         clk = meson8b_dwmac_register_clk(dwmac, "m250_sel", mux_parent_names,
155                                          MUX_CLK_NUM_PARENTS, &clk_mux_ops,
156                                          &clk_configs->m250_mux.hw);
157         if (WARN_ON(IS_ERR(clk)))
158                 return PTR_ERR(clk);
159
160         parent_name = __clk_get_name(clk);
161         clk_configs->m250_div.reg = dwmac->regs + PRG_ETH0;
162         clk_configs->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT;
163         clk_configs->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH;
164         clk_configs->m250_div.table = div_table;
165         clk_configs->m250_div.flags = CLK_DIVIDER_ALLOW_ZERO |
166                                       CLK_DIVIDER_ROUND_CLOSEST;
167         clk = meson8b_dwmac_register_clk(dwmac, "m250_div", &parent_name, 1,
168                                          &clk_divider_ops,
169                                          &clk_configs->m250_div.hw);
170         if (WARN_ON(IS_ERR(clk)))
171                 return PTR_ERR(clk);
172
173         parent_name = __clk_get_name(clk);
174         clk_configs->fixed_div2.mult = 1;
175         clk_configs->fixed_div2.div = 2;
176         clk = meson8b_dwmac_register_clk(dwmac, "fixed_div2", &parent_name, 1,
177                                          &clk_fixed_factor_ops,
178                                          &clk_configs->fixed_div2.hw);
179         if (WARN_ON(IS_ERR(clk)))
180                 return PTR_ERR(clk);
181
182         parent_name = __clk_get_name(clk);
183         clk_configs->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0;
184         clk_configs->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN;
185         clk = meson8b_dwmac_register_clk(dwmac, "rgmii_tx_en", &parent_name, 1,
186                                          &clk_gate_ops,
187                                          &clk_configs->rgmii_tx_en.hw);
188         if (WARN_ON(IS_ERR(clk)))
189                 return PTR_ERR(clk);
190
191         dwmac->rgmii_tx_clk = clk;
192
193         return 0;
194 }
195
196 static int meson8b_set_phy_mode(struct meson8b_dwmac *dwmac)
197 {
198         switch (dwmac->phy_mode) {
199         case PHY_INTERFACE_MODE_RGMII:
200         case PHY_INTERFACE_MODE_RGMII_RXID:
201         case PHY_INTERFACE_MODE_RGMII_ID:
202         case PHY_INTERFACE_MODE_RGMII_TXID:
203                 /* enable RGMII mode */
204                 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
205                                         PRG_ETH0_RGMII_MODE,
206                                         PRG_ETH0_RGMII_MODE);
207                 break;
208         case PHY_INTERFACE_MODE_RMII:
209                 /* disable RGMII mode -> enables RMII mode */
210                 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
211                                         PRG_ETH0_RGMII_MODE, 0);
212                 break;
213         default:
214                 dev_err(dwmac->dev, "fail to set phy-mode %s\n",
215                         phy_modes(dwmac->phy_mode));
216                 return -EINVAL;
217         }
218
219         return 0;
220 }
221
222 static int meson_axg_set_phy_mode(struct meson8b_dwmac *dwmac)
223 {
224         switch (dwmac->phy_mode) {
225         case PHY_INTERFACE_MODE_RGMII:
226         case PHY_INTERFACE_MODE_RGMII_RXID:
227         case PHY_INTERFACE_MODE_RGMII_ID:
228         case PHY_INTERFACE_MODE_RGMII_TXID:
229                 /* enable RGMII mode */
230                 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
231                                         PRG_ETH0_EXT_PHY_MODE_MASK,
232                                         PRG_ETH0_EXT_RGMII_MODE);
233                 break;
234         case PHY_INTERFACE_MODE_RMII:
235                 /* disable RGMII mode -> enables RMII mode */
236                 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
237                                         PRG_ETH0_EXT_PHY_MODE_MASK,
238                                         PRG_ETH0_EXT_RMII_MODE);
239                 break;
240         default:
241                 dev_err(dwmac->dev, "fail to set phy-mode %s\n",
242                         phy_modes(dwmac->phy_mode));
243                 return -EINVAL;
244         }
245
246         return 0;
247 }
248
249 static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
250 {
251         int ret;
252         u8 tx_dly_val = 0;
253
254         switch (dwmac->phy_mode) {
255         case PHY_INTERFACE_MODE_RGMII:
256         case PHY_INTERFACE_MODE_RGMII_RXID:
257                 /* TX clock delay in ns = "8ns / 4 * tx_dly_val" (where
258                  * 8ns are exactly one cycle of the 125MHz RGMII TX clock):
259                  * 0ns = 0x0, 2ns = 0x1, 4ns = 0x2, 6ns = 0x3
260                  */
261                 tx_dly_val = dwmac->tx_delay_ns >> 1;
262                 /* fall through */
263
264         case PHY_INTERFACE_MODE_RGMII_ID:
265         case PHY_INTERFACE_MODE_RGMII_TXID:
266                 /* only relevant for RMII mode -> disable in RGMII mode */
267                 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
268                                         PRG_ETH0_INVERTED_RMII_CLK, 0);
269
270                 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK,
271                                         tx_dly_val << PRG_ETH0_TXDLY_SHIFT);
272
273                 /* Configure the 125MHz RGMII TX clock, the IP block changes
274                  * the output automatically (= without us having to configure
275                  * a register) based on the line-speed (125MHz for Gbit speeds,
276                  * 25MHz for 100Mbit/s and 2.5MHz for 10Mbit/s).
277                  */
278                 ret = clk_set_rate(dwmac->rgmii_tx_clk, 125 * 1000 * 1000);
279                 if (ret) {
280                         dev_err(dwmac->dev,
281                                 "failed to set RGMII TX clock\n");
282                         return ret;
283                 }
284
285                 ret = clk_prepare_enable(dwmac->rgmii_tx_clk);
286                 if (ret) {
287                         dev_err(dwmac->dev,
288                                 "failed to enable the RGMII TX clock\n");
289                         return ret;
290                 }
291
292                 devm_add_action_or_reset(dwmac->dev,
293                                         (void(*)(void *))clk_disable_unprepare,
294                                         dwmac->rgmii_tx_clk);
295                 break;
296
297         case PHY_INTERFACE_MODE_RMII:
298                 /* invert internal clk_rmii_i to generate 25/2.5 tx_rx_clk */
299                 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
300                                         PRG_ETH0_INVERTED_RMII_CLK,
301                                         PRG_ETH0_INVERTED_RMII_CLK);
302
303                 /* TX clock delay cannot be configured in RMII mode */
304                 meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK,
305                                         0);
306
307                 break;
308
309         default:
310                 dev_err(dwmac->dev, "unsupported phy-mode %s\n",
311                         phy_modes(dwmac->phy_mode));
312                 return -EINVAL;
313         }
314
315         /* enable TX_CLK and PHY_REF_CLK generator */
316         meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TX_AND_PHY_REF_CLK,
317                                 PRG_ETH0_TX_AND_PHY_REF_CLK);
318
319         return 0;
320 }
321
322 static int meson8b_dwmac_probe(struct platform_device *pdev)
323 {
324         struct plat_stmmacenet_data *plat_dat;
325         struct stmmac_resources stmmac_res;
326         struct resource *res;
327         struct meson8b_dwmac *dwmac;
328         int ret;
329
330         ret = stmmac_get_platform_resources(pdev, &stmmac_res);
331         if (ret)
332                 return ret;
333
334         plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
335         if (IS_ERR(plat_dat))
336                 return PTR_ERR(plat_dat);
337
338         dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
339         if (!dwmac) {
340                 ret = -ENOMEM;
341                 goto err_remove_config_dt;
342         }
343
344         dwmac->data = (const struct meson8b_dwmac_data *)
345                 of_device_get_match_data(&pdev->dev);
346         if (!dwmac->data) {
347                 ret = -EINVAL;
348                 goto err_remove_config_dt;
349         }
350         res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
351         dwmac->regs = devm_ioremap_resource(&pdev->dev, res);
352         if (IS_ERR(dwmac->regs)) {
353                 ret = PTR_ERR(dwmac->regs);
354                 goto err_remove_config_dt;
355         }
356
357         dwmac->dev = &pdev->dev;
358         dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node);
359         if ((int)dwmac->phy_mode < 0) {
360                 dev_err(&pdev->dev, "missing phy-mode property\n");
361                 ret = -EINVAL;
362                 goto err_remove_config_dt;
363         }
364
365         /* use 2ns as fallback since this value was previously hardcoded */
366         if (of_property_read_u32(pdev->dev.of_node, "amlogic,tx-delay-ns",
367                                  &dwmac->tx_delay_ns))
368                 dwmac->tx_delay_ns = 2;
369
370         ret = meson8b_init_rgmii_tx_clk(dwmac);
371         if (ret)
372                 goto err_remove_config_dt;
373
374         ret = dwmac->data->set_phy_mode(dwmac);
375         if (ret)
376                 goto err_remove_config_dt;
377
378         ret = meson8b_init_prg_eth(dwmac);
379         if (ret)
380                 goto err_remove_config_dt;
381
382         plat_dat->bsp_priv = dwmac;
383
384         ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
385         if (ret)
386                 goto err_remove_config_dt;
387
388         return 0;
389
390 err_remove_config_dt:
391         stmmac_remove_config_dt(pdev, plat_dat);
392
393         return ret;
394 }
395
396 static const struct meson8b_dwmac_data meson8b_dwmac_data = {
397         .set_phy_mode = meson8b_set_phy_mode,
398 };
399
400 static const struct meson8b_dwmac_data meson_axg_dwmac_data = {
401         .set_phy_mode = meson_axg_set_phy_mode,
402 };
403
404 static const struct of_device_id meson8b_dwmac_match[] = {
405         {
406                 .compatible = "amlogic,meson8b-dwmac",
407                 .data = &meson8b_dwmac_data,
408         },
409         {
410                 .compatible = "amlogic,meson8m2-dwmac",
411                 .data = &meson8b_dwmac_data,
412         },
413         {
414                 .compatible = "amlogic,meson-gxbb-dwmac",
415                 .data = &meson8b_dwmac_data,
416         },
417         {
418                 .compatible = "amlogic,meson-axg-dwmac",
419                 .data = &meson_axg_dwmac_data,
420         },
421         { }
422 };
423 MODULE_DEVICE_TABLE(of, meson8b_dwmac_match);
424
425 static struct platform_driver meson8b_dwmac_driver = {
426         .probe  = meson8b_dwmac_probe,
427         .remove = stmmac_pltfr_remove,
428         .driver = {
429                 .name           = "meson8b-dwmac",
430                 .pm             = &stmmac_pltfr_pm_ops,
431                 .of_match_table = meson8b_dwmac_match,
432         },
433 };
434 module_platform_driver(meson8b_dwmac_driver);
435
436 MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
437 MODULE_DESCRIPTION("Amlogic Meson8b, Meson8m2 and GXBB DWMAC glue layer");
438 MODULE_LICENSE("GPL v2");