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