Merge 5.16-rc8 into usb-next
[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 BIT(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 BIT(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  BIT(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      BIT(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    BIT(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         spinlock_t lock; /* lock to protect register update */
53 };
54
55 static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
56 {
57         struct visconti_eth *dwmac = priv;
58         unsigned int val, clk_sel_val;
59         unsigned long flags;
60
61         spin_lock_irqsave(&dwmac->lock, flags);
62
63         /* adjust link */
64         val = readl(dwmac->reg + MAC_CTRL_REG);
65         val &= ~(GMAC_CONFIG_PS | GMAC_CONFIG_FES);
66
67         switch (speed) {
68         case SPEED_1000:
69                 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII)
70                         clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M;
71                 break;
72         case SPEED_100:
73                 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII)
74                         clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_25M;
75                 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII)
76                         clk_sel_val = ETHER_CLK_SEL_DIV_SEL_2;
77                 val |= GMAC_CONFIG_PS | GMAC_CONFIG_FES;
78                 break;
79         case SPEED_10:
80                 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII)
81                         clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_2P5M;
82                 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII)
83                         clk_sel_val = ETHER_CLK_SEL_DIV_SEL_20;
84                 val |= GMAC_CONFIG_PS;
85                 break;
86         default:
87                 /* No bit control */
88                 break;
89         }
90
91         writel(val, dwmac->reg + MAC_CTRL_REG);
92
93         /* Stop internal clock */
94         val = readl(dwmac->reg + REG_ETHER_CLOCK_SEL);
95         val &= ~(ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN);
96         val |= ETHER_CLK_SEL_TX_O_E_N_IN;
97         writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
98
99         switch (dwmac->phy_intf_sel) {
100         case ETHER_CONFIG_INTF_RGMII:
101                 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC;
102                 break;
103         case ETHER_CONFIG_INTF_RMII:
104                 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV |
105                         ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN |
106                         ETHER_CLK_SEL_RMII_CLK_SEL_RX_C;
107                 break;
108         case ETHER_CONFIG_INTF_MII:
109         default:
110                 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC |
111                         ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN |
112                         ETHER_CLK_SEL_RMII_CLK_EN;
113                 break;
114         }
115
116         /* Start clock */
117         writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
118         val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
119         writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
120
121         val &= ~ETHER_CLK_SEL_TX_O_E_N_IN;
122         writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
123
124         spin_unlock_irqrestore(&dwmac->lock, flags);
125 }
126
127 static int visconti_eth_init_hw(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat)
128 {
129         struct visconti_eth *dwmac = plat_dat->bsp_priv;
130         unsigned int reg_val, clk_sel_val;
131
132         switch (plat_dat->phy_interface) {
133         case PHY_INTERFACE_MODE_RGMII:
134         case PHY_INTERFACE_MODE_RGMII_ID:
135         case PHY_INTERFACE_MODE_RGMII_RXID:
136         case PHY_INTERFACE_MODE_RGMII_TXID:
137                 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RGMII;
138                 break;
139         case PHY_INTERFACE_MODE_MII:
140                 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_MII;
141                 break;
142         case PHY_INTERFACE_MODE_RMII:
143                 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RMII;
144                 break;
145         default:
146                 dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n", plat_dat->phy_interface);
147                 return -EOPNOTSUPP;
148         }
149
150         reg_val = dwmac->phy_intf_sel;
151         writel(reg_val, dwmac->reg + REG_ETHER_CONTROL);
152
153         /* Enable TX/RX clock */
154         clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M;
155         writel(clk_sel_val, dwmac->reg + REG_ETHER_CLOCK_SEL);
156
157         writel((clk_sel_val | ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN),
158                dwmac->reg + REG_ETHER_CLOCK_SEL);
159
160         /* release internal-reset */
161         reg_val |= ETHER_ETH_CONTROL_RESET;
162         writel(reg_val, dwmac->reg + REG_ETHER_CONTROL);
163
164         return 0;
165 }
166
167 static int visconti_eth_clock_probe(struct platform_device *pdev,
168                                     struct plat_stmmacenet_data *plat_dat)
169 {
170         struct visconti_eth *dwmac = plat_dat->bsp_priv;
171         int err;
172
173         dwmac->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk");
174         if (IS_ERR(dwmac->phy_ref_clk))
175                 return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->phy_ref_clk),
176                                      "phy_ref_clk clock not found.\n");
177
178         err = clk_prepare_enable(dwmac->phy_ref_clk);
179         if (err < 0) {
180                 dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n", err);
181                 return err;
182         }
183
184         return 0;
185 }
186
187 static int visconti_eth_clock_remove(struct platform_device *pdev)
188 {
189         struct visconti_eth *dwmac = get_stmmac_bsp_priv(&pdev->dev);
190         struct net_device *ndev = platform_get_drvdata(pdev);
191         struct stmmac_priv *priv = netdev_priv(ndev);
192
193         clk_disable_unprepare(dwmac->phy_ref_clk);
194         clk_disable_unprepare(priv->plat->stmmac_clk);
195
196         return 0;
197 }
198
199 static int visconti_eth_dwmac_probe(struct platform_device *pdev)
200 {
201         struct plat_stmmacenet_data *plat_dat;
202         struct stmmac_resources stmmac_res;
203         struct visconti_eth *dwmac;
204         int ret;
205
206         ret = stmmac_get_platform_resources(pdev, &stmmac_res);
207         if (ret)
208                 return ret;
209
210         plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
211         if (IS_ERR(plat_dat))
212                 return PTR_ERR(plat_dat);
213
214         dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
215         if (!dwmac) {
216                 ret = -ENOMEM;
217                 goto remove_config;
218         }
219
220         spin_lock_init(&dwmac->lock);
221         dwmac->reg = stmmac_res.addr;
222         plat_dat->bsp_priv = dwmac;
223         plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed;
224
225         ret = visconti_eth_clock_probe(pdev, plat_dat);
226         if (ret)
227                 goto remove_config;
228
229         visconti_eth_init_hw(pdev, plat_dat);
230
231         plat_dat->dma_cfg->aal = 1;
232
233         ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
234         if (ret)
235                 goto remove;
236
237         return ret;
238
239 remove:
240         visconti_eth_clock_remove(pdev);
241 remove_config:
242         stmmac_remove_config_dt(pdev, plat_dat);
243
244         return ret;
245 }
246
247 static int visconti_eth_dwmac_remove(struct platform_device *pdev)
248 {
249         struct net_device *ndev = platform_get_drvdata(pdev);
250         struct stmmac_priv *priv = netdev_priv(ndev);
251         int err;
252
253         err = stmmac_pltfr_remove(pdev);
254         if (err < 0)
255                 dev_err(&pdev->dev, "failed to remove platform: %d\n", err);
256
257         err = visconti_eth_clock_remove(pdev);
258         if (err < 0)
259                 dev_err(&pdev->dev, "failed to remove clock: %d\n", err);
260
261         stmmac_remove_config_dt(pdev, priv->plat);
262
263         return err;
264 }
265
266 static const struct of_device_id visconti_eth_dwmac_match[] = {
267         { .compatible = "toshiba,visconti-dwmac" },
268         { }
269 };
270 MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match);
271
272 static struct platform_driver visconti_eth_dwmac_driver = {
273         .probe  = visconti_eth_dwmac_probe,
274         .remove = visconti_eth_dwmac_remove,
275         .driver = {
276                 .name           = "visconti-eth-dwmac",
277                 .of_match_table = visconti_eth_dwmac_match,
278         },
279 };
280 module_platform_driver(visconti_eth_dwmac_driver);
281
282 MODULE_AUTHOR("Toshiba");
283 MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver");
284 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp");
285 MODULE_LICENSE("GPL v2");