Merge tag 'phy-for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux...
[linux-2.6-microblaze.git] / drivers / net / ethernet / stmicro / stmmac / dwmac-visconti.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Toshiba Visconti Ethernet Support
3  *
4  * (C) Copyright 2020 TOSHIBA CORPORATION
5  * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation
6  */
7
8 #include <linux/module.h>
9 #include <linux/of_device.h>
10 #include <linux/of_net.h>
11 #include <linux/stmmac.h>
12
13 #include "stmmac_platform.h"
14 #include "dwmac4.h"
15
16 #define REG_ETHER_CONTROL       0x52D4
17 #define ETHER_ETH_CONTROL_RESET BIT(17)
18
19 #define REG_ETHER_CLOCK_SEL     0x52D0
20 #define ETHER_CLK_SEL_TX_CLK_EN BIT(0)
21 #define ETHER_CLK_SEL_RX_CLK_EN BIT(1)
22 #define ETHER_CLK_SEL_RMII_CLK_EN BIT(2)
23 #define ETHER_CLK_SEL_RMII_CLK_RST BIT(3)
24 #define ETHER_CLK_SEL_DIV_SEL_2 BIT(4)
25 #define ETHER_CLK_SEL_DIV_SEL_20 0
26 #define ETHER_CLK_SEL_FREQ_SEL_125M     (BIT(9) | BIT(8))
27 #define ETHER_CLK_SEL_FREQ_SEL_50M      BIT(9)
28 #define ETHER_CLK_SEL_FREQ_SEL_25M      BIT(8)
29 #define ETHER_CLK_SEL_FREQ_SEL_2P5M     0
30 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN 0
31 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC BIT(10)
32 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV BIT(11)
33 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_IN  0
34 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC BIT(12)
35 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV BIT(13)
36 #define ETHER_CLK_SEL_TX_CLK_O_TX_I      0
37 #define ETHER_CLK_SEL_TX_CLK_O_RMII_I    BIT(14)
38 #define ETHER_CLK_SEL_TX_O_E_N_IN        BIT(15)
39 #define ETHER_CLK_SEL_RMII_CLK_SEL_IN    0
40 #define ETHER_CLK_SEL_RMII_CLK_SEL_RX_C  BIT(16)
41
42 #define ETHER_CLK_SEL_RX_TX_CLK_EN (ETHER_CLK_SEL_RX_CLK_EN | ETHER_CLK_SEL_TX_CLK_EN)
43
44 #define ETHER_CONFIG_INTF_MII 0
45 #define ETHER_CONFIG_INTF_RGMII BIT(0)
46 #define ETHER_CONFIG_INTF_RMII BIT(2)
47
48 struct visconti_eth {
49         void __iomem *reg;
50         u32 phy_intf_sel;
51         struct clk *phy_ref_clk;
52         struct device *dev;
53         spinlock_t lock; /* lock to protect register update */
54 };
55
56 static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
57 {
58         struct visconti_eth *dwmac = priv;
59         struct net_device *netdev = dev_get_drvdata(dwmac->dev);
60         unsigned int val, clk_sel_val = 0;
61         unsigned long flags;
62
63         spin_lock_irqsave(&dwmac->lock, flags);
64
65         /* adjust link */
66         val = readl(dwmac->reg + MAC_CTRL_REG);
67         val &= ~(GMAC_CONFIG_PS | GMAC_CONFIG_FES);
68
69         switch (speed) {
70         case SPEED_1000:
71                 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII)
72                         clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M;
73                 break;
74         case SPEED_100:
75                 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII)
76                         clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_25M;
77                 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII)
78                         clk_sel_val = ETHER_CLK_SEL_DIV_SEL_2;
79                 val |= GMAC_CONFIG_PS | GMAC_CONFIG_FES;
80                 break;
81         case SPEED_10:
82                 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII)
83                         clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_2P5M;
84                 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII)
85                         clk_sel_val = ETHER_CLK_SEL_DIV_SEL_20;
86                 val |= GMAC_CONFIG_PS;
87                 break;
88         default:
89                 /* No bit control */
90                 netdev_err(netdev, "Unsupported speed request (%d)", speed);
91                 spin_unlock_irqrestore(&dwmac->lock, flags);
92                 return;
93         }
94
95         writel(val, dwmac->reg + MAC_CTRL_REG);
96
97         /* Stop internal clock */
98         val = readl(dwmac->reg + REG_ETHER_CLOCK_SEL);
99         val &= ~(ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN);
100         val |= ETHER_CLK_SEL_TX_O_E_N_IN;
101         writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
102
103         /* Set Clock-Mux, Start clock, Set TX_O direction */
104         switch (dwmac->phy_intf_sel) {
105         case ETHER_CONFIG_INTF_RGMII:
106                 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC;
107                 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
108
109                 val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
110                 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
111
112                 val &= ~ETHER_CLK_SEL_TX_O_E_N_IN;
113                 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
114                 break;
115         case ETHER_CONFIG_INTF_RMII:
116                 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV |
117                         ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN |
118                         ETHER_CLK_SEL_RMII_CLK_SEL_RX_C;
119                 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
120
121                 val |= ETHER_CLK_SEL_RMII_CLK_RST;
122                 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
123
124                 val |= ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN;
125                 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
126                 break;
127         case ETHER_CONFIG_INTF_MII:
128         default:
129                 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC |
130                         ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN;
131                 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
132
133                 val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
134                 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
135                 break;
136         }
137
138         spin_unlock_irqrestore(&dwmac->lock, flags);
139 }
140
141 static int visconti_eth_init_hw(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat)
142 {
143         struct visconti_eth *dwmac = plat_dat->bsp_priv;
144         unsigned int reg_val, clk_sel_val;
145
146         switch (plat_dat->phy_interface) {
147         case PHY_INTERFACE_MODE_RGMII:
148         case PHY_INTERFACE_MODE_RGMII_ID:
149         case PHY_INTERFACE_MODE_RGMII_RXID:
150         case PHY_INTERFACE_MODE_RGMII_TXID:
151                 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RGMII;
152                 break;
153         case PHY_INTERFACE_MODE_MII:
154                 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_MII;
155                 break;
156         case PHY_INTERFACE_MODE_RMII:
157                 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RMII;
158                 break;
159         default:
160                 dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n", plat_dat->phy_interface);
161                 return -EOPNOTSUPP;
162         }
163
164         reg_val = dwmac->phy_intf_sel;
165         writel(reg_val, dwmac->reg + REG_ETHER_CONTROL);
166
167         /* Enable TX/RX clock */
168         clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M;
169         writel(clk_sel_val, dwmac->reg + REG_ETHER_CLOCK_SEL);
170
171         writel((clk_sel_val | ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN),
172                dwmac->reg + REG_ETHER_CLOCK_SEL);
173
174         /* release internal-reset */
175         reg_val |= ETHER_ETH_CONTROL_RESET;
176         writel(reg_val, dwmac->reg + REG_ETHER_CONTROL);
177
178         return 0;
179 }
180
181 static int visconti_eth_clock_probe(struct platform_device *pdev,
182                                     struct plat_stmmacenet_data *plat_dat)
183 {
184         struct visconti_eth *dwmac = plat_dat->bsp_priv;
185         int err;
186
187         dwmac->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk");
188         if (IS_ERR(dwmac->phy_ref_clk))
189                 return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->phy_ref_clk),
190                                      "phy_ref_clk clock not found.\n");
191
192         err = clk_prepare_enable(dwmac->phy_ref_clk);
193         if (err < 0) {
194                 dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n", err);
195                 return err;
196         }
197
198         return 0;
199 }
200
201 static int visconti_eth_clock_remove(struct platform_device *pdev)
202 {
203         struct visconti_eth *dwmac = get_stmmac_bsp_priv(&pdev->dev);
204         struct net_device *ndev = platform_get_drvdata(pdev);
205         struct stmmac_priv *priv = netdev_priv(ndev);
206
207         clk_disable_unprepare(dwmac->phy_ref_clk);
208         clk_disable_unprepare(priv->plat->stmmac_clk);
209
210         return 0;
211 }
212
213 static int visconti_eth_dwmac_probe(struct platform_device *pdev)
214 {
215         struct plat_stmmacenet_data *plat_dat;
216         struct stmmac_resources stmmac_res;
217         struct visconti_eth *dwmac;
218         int ret;
219
220         ret = stmmac_get_platform_resources(pdev, &stmmac_res);
221         if (ret)
222                 return ret;
223
224         plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
225         if (IS_ERR(plat_dat))
226                 return PTR_ERR(plat_dat);
227
228         dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
229         if (!dwmac) {
230                 ret = -ENOMEM;
231                 goto remove_config;
232         }
233
234         spin_lock_init(&dwmac->lock);
235         dwmac->reg = stmmac_res.addr;
236         dwmac->dev = &pdev->dev;
237         plat_dat->bsp_priv = dwmac;
238         plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed;
239
240         ret = visconti_eth_clock_probe(pdev, plat_dat);
241         if (ret)
242                 goto remove_config;
243
244         visconti_eth_init_hw(pdev, plat_dat);
245
246         plat_dat->dma_cfg->aal = 1;
247
248         ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
249         if (ret)
250                 goto remove;
251
252         return ret;
253
254 remove:
255         visconti_eth_clock_remove(pdev);
256 remove_config:
257         stmmac_remove_config_dt(pdev, plat_dat);
258
259         return ret;
260 }
261
262 static int visconti_eth_dwmac_remove(struct platform_device *pdev)
263 {
264         struct net_device *ndev = platform_get_drvdata(pdev);
265         struct stmmac_priv *priv = netdev_priv(ndev);
266         int err;
267
268         err = stmmac_pltfr_remove(pdev);
269         if (err < 0)
270                 dev_err(&pdev->dev, "failed to remove platform: %d\n", err);
271
272         err = visconti_eth_clock_remove(pdev);
273         if (err < 0)
274                 dev_err(&pdev->dev, "failed to remove clock: %d\n", err);
275
276         stmmac_remove_config_dt(pdev, priv->plat);
277
278         return err;
279 }
280
281 static const struct of_device_id visconti_eth_dwmac_match[] = {
282         { .compatible = "toshiba,visconti-dwmac" },
283         { }
284 };
285 MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match);
286
287 static struct platform_driver visconti_eth_dwmac_driver = {
288         .probe  = visconti_eth_dwmac_probe,
289         .remove = visconti_eth_dwmac_remove,
290         .driver = {
291                 .name           = "visconti-eth-dwmac",
292                 .of_match_table = visconti_eth_dwmac_match,
293         },
294 };
295 module_platform_driver(visconti_eth_dwmac_driver);
296
297 MODULE_AUTHOR("Toshiba");
298 MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver");
299 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp");
300 MODULE_LICENSE("GPL v2");