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