blob: c3f10a92b62b804294d401c9e4b67618261aa8e4 [file] [log] [blame]
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +09001// 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)
Yuji Ishikawa1ba1a4a92022-01-19 13:46:47 +090025#define ETHER_CLK_SEL_DIV_SEL_20 0
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +090026#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)
Nobuhiro Iwamatsu391e5972021-12-23 16:36:33 +090029#define ETHER_CLK_SEL_FREQ_SEL_2P5M 0
Yuji Ishikawa1ba1a4a92022-01-19 13:46:47 +090030#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN 0
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +090031#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC BIT(10)
32#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV BIT(11)
Yuji Ishikawa1ba1a4a92022-01-19 13:46:47 +090033#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_IN 0
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +090034#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC BIT(12)
35#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV BIT(13)
Yuji Ishikawa1ba1a4a92022-01-19 13:46:47 +090036#define ETHER_CLK_SEL_TX_CLK_O_TX_I 0
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +090037#define ETHER_CLK_SEL_TX_CLK_O_RMII_I BIT(14)
38#define ETHER_CLK_SEL_TX_O_E_N_IN BIT(15)
Yuji Ishikawa1ba1a4a92022-01-19 13:46:47 +090039#define ETHER_CLK_SEL_RMII_CLK_SEL_IN 0
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +090040#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
48struct visconti_eth {
49 void __iomem *reg;
50 u32 phy_intf_sel;
51 struct clk *phy_ref_clk;
Yuji Ishikawa928d6fe2022-01-27 21:17:14 +090052 struct device *dev;
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +090053 spinlock_t lock; /* lock to protect register update */
54};
55
56static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
57{
58 struct visconti_eth *dwmac = priv;
Yuji Ishikawa928d6fe2022-01-27 21:17:14 +090059 struct net_device *netdev = dev_get_drvdata(dwmac->dev);
60 unsigned int val, clk_sel_val = 0;
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +090061 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 */
Yuji Ishikawa928d6fe2022-01-27 21:17:14 +090090 netdev_err(netdev, "Unsupported speed request (%d)", speed);
91 spin_unlock_irqrestore(&dwmac->lock, flags);
92 return;
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +090093 }
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
Yuji Ishikawa0959bc42022-01-19 13:46:48 +0900103 /* Set Clock-Mux, Start clock, Set TX_O direction */
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +0900104 switch (dwmac->phy_intf_sel) {
105 case ETHER_CONFIG_INTF_RGMII:
106 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC;
Yuji Ishikawa0959bc42022-01-19 13:46:48 +0900107 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);
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +0900114 break;
115 case ETHER_CONFIG_INTF_RMII:
116 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV |
Yuji Ishikawa0959bc42022-01-19 13:46:48 +0900117 ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN |
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +0900118 ETHER_CLK_SEL_RMII_CLK_SEL_RX_C;
Yuji Ishikawa0959bc42022-01-19 13:46:48 +0900119 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);
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +0900126 break;
127 case ETHER_CONFIG_INTF_MII:
128 default:
129 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC |
Yuji Ishikawa0959bc42022-01-19 13:46:48 +0900130 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);
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +0900135 break;
136 }
137
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +0900138 spin_unlock_irqrestore(&dwmac->lock, flags);
139}
140
141static 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
181static 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");
Cai Huoqingb20b54f2021-09-16 15:37:36 +0800188 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");
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +0900191
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
201static 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
213static 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
Michael Walle83216e32021-04-12 19:47:17 +0200224 plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +0900225 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
Wei Yongjun17d7fd42021-02-23 10:48:03 +0000234 spin_lock_init(&dwmac->lock);
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +0900235 dwmac->reg = stmmac_res.addr;
Yuji Ishikawa928d6fe2022-01-27 21:17:14 +0900236 dwmac->dev = &pdev->dev;
Nobuhiro Iwamatsub38dd982021-02-16 00:24:36 +0900237 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
254remove:
255 visconti_eth_clock_remove(pdev);
256remove_config:
257 stmmac_remove_config_dt(pdev, plat_dat);
258
259 return ret;
260}
261
262static 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
281static const struct of_device_id visconti_eth_dwmac_match[] = {
282 { .compatible = "toshiba,visconti-dwmac" },
283 { }
284};
285MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match);
286
287static 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};
295module_platform_driver(visconti_eth_dwmac_driver);
296
297MODULE_AUTHOR("Toshiba");
298MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver");
299MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp");
300MODULE_LICENSE("GPL v2");