1 // SPDX-License-Identifier: GPL-2.0
2 /* Toshiba Visconti Ethernet Support
4 * (C) Copyright 2020 TOSHIBA CORPORATION
5 * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation
8 #include <linux/module.h>
9 #include <linux/of_device.h>
10 #include <linux/of_net.h>
11 #include <linux/stmmac.h>
13 #include "stmmac_platform.h"
16 #define REG_ETHER_CONTROL 0x52D4
17 #define ETHER_ETH_CONTROL_RESET BIT(17)
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)
42 #define ETHER_CLK_SEL_RX_TX_CLK_EN (ETHER_CLK_SEL_RX_CLK_EN | ETHER_CLK_SEL_TX_CLK_EN)
44 #define ETHER_CONFIG_INTF_MII 0
45 #define ETHER_CONFIG_INTF_RGMII BIT(0)
46 #define ETHER_CONFIG_INTF_RMII BIT(2)
51 struct clk *phy_ref_clk;
52 spinlock_t lock; /* lock to protect register update */
55 static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
57 struct visconti_eth *dwmac = priv;
58 unsigned int val, clk_sel_val;
61 spin_lock_irqsave(&dwmac->lock, flags);
64 val = readl(dwmac->reg + MAC_CTRL_REG);
65 val &= ~(GMAC_CONFIG_PS | GMAC_CONFIG_FES);
69 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII)
70 clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M;
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;
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;
91 writel(val, dwmac->reg + MAC_CTRL_REG);
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);
99 /* Set Clock-Mux, Start clock, Set TX_O direction */
100 switch (dwmac->phy_intf_sel) {
101 case ETHER_CONFIG_INTF_RGMII:
102 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC;
103 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
105 val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
106 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
108 val &= ~ETHER_CLK_SEL_TX_O_E_N_IN;
109 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
111 case ETHER_CONFIG_INTF_RMII:
112 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV |
113 ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN |
114 ETHER_CLK_SEL_RMII_CLK_SEL_RX_C;
115 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
117 val |= ETHER_CLK_SEL_RMII_CLK_RST;
118 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
120 val |= ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN;
121 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
123 case ETHER_CONFIG_INTF_MII:
125 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC |
126 ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN;
127 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
129 val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
130 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
134 spin_unlock_irqrestore(&dwmac->lock, flags);
137 static int visconti_eth_init_hw(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat)
139 struct visconti_eth *dwmac = plat_dat->bsp_priv;
140 unsigned int reg_val, clk_sel_val;
142 switch (plat_dat->phy_interface) {
143 case PHY_INTERFACE_MODE_RGMII:
144 case PHY_INTERFACE_MODE_RGMII_ID:
145 case PHY_INTERFACE_MODE_RGMII_RXID:
146 case PHY_INTERFACE_MODE_RGMII_TXID:
147 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RGMII;
149 case PHY_INTERFACE_MODE_MII:
150 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_MII;
152 case PHY_INTERFACE_MODE_RMII:
153 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RMII;
156 dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n", plat_dat->phy_interface);
160 reg_val = dwmac->phy_intf_sel;
161 writel(reg_val, dwmac->reg + REG_ETHER_CONTROL);
163 /* Enable TX/RX clock */
164 clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M;
165 writel(clk_sel_val, dwmac->reg + REG_ETHER_CLOCK_SEL);
167 writel((clk_sel_val | ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN),
168 dwmac->reg + REG_ETHER_CLOCK_SEL);
170 /* release internal-reset */
171 reg_val |= ETHER_ETH_CONTROL_RESET;
172 writel(reg_val, dwmac->reg + REG_ETHER_CONTROL);
177 static int visconti_eth_clock_probe(struct platform_device *pdev,
178 struct plat_stmmacenet_data *plat_dat)
180 struct visconti_eth *dwmac = plat_dat->bsp_priv;
183 dwmac->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk");
184 if (IS_ERR(dwmac->phy_ref_clk))
185 return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->phy_ref_clk),
186 "phy_ref_clk clock not found.\n");
188 err = clk_prepare_enable(dwmac->phy_ref_clk);
190 dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n", err);
197 static int visconti_eth_clock_remove(struct platform_device *pdev)
199 struct visconti_eth *dwmac = get_stmmac_bsp_priv(&pdev->dev);
200 struct net_device *ndev = platform_get_drvdata(pdev);
201 struct stmmac_priv *priv = netdev_priv(ndev);
203 clk_disable_unprepare(dwmac->phy_ref_clk);
204 clk_disable_unprepare(priv->plat->stmmac_clk);
209 static int visconti_eth_dwmac_probe(struct platform_device *pdev)
211 struct plat_stmmacenet_data *plat_dat;
212 struct stmmac_resources stmmac_res;
213 struct visconti_eth *dwmac;
216 ret = stmmac_get_platform_resources(pdev, &stmmac_res);
220 plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
221 if (IS_ERR(plat_dat))
222 return PTR_ERR(plat_dat);
224 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
230 spin_lock_init(&dwmac->lock);
231 dwmac->reg = stmmac_res.addr;
232 plat_dat->bsp_priv = dwmac;
233 plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed;
235 ret = visconti_eth_clock_probe(pdev, plat_dat);
239 visconti_eth_init_hw(pdev, plat_dat);
241 plat_dat->dma_cfg->aal = 1;
243 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
250 visconti_eth_clock_remove(pdev);
252 stmmac_remove_config_dt(pdev, plat_dat);
257 static int visconti_eth_dwmac_remove(struct platform_device *pdev)
259 struct net_device *ndev = platform_get_drvdata(pdev);
260 struct stmmac_priv *priv = netdev_priv(ndev);
263 err = stmmac_pltfr_remove(pdev);
265 dev_err(&pdev->dev, "failed to remove platform: %d\n", err);
267 err = visconti_eth_clock_remove(pdev);
269 dev_err(&pdev->dev, "failed to remove clock: %d\n", err);
271 stmmac_remove_config_dt(pdev, priv->plat);
276 static const struct of_device_id visconti_eth_dwmac_match[] = {
277 { .compatible = "toshiba,visconti-dwmac" },
280 MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match);
282 static struct platform_driver visconti_eth_dwmac_driver = {
283 .probe = visconti_eth_dwmac_probe,
284 .remove = visconti_eth_dwmac_remove,
286 .name = "visconti-eth-dwmac",
287 .of_match_table = visconti_eth_dwmac_match,
290 module_platform_driver(visconti_eth_dwmac_driver);
292 MODULE_AUTHOR("Toshiba");
293 MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver");
294 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp");
295 MODULE_LICENSE("GPL v2");