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 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)
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 	struct device *dev;
53 	spinlock_t lock; /* lock to protect register update */
54 };
55 
56 static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
57 {
58 	struct visconti_eth *dwmac = priv;
59 	struct net_device *netdev = dev_get_drvdata(dwmac->dev);
60 	unsigned int val, clk_sel_val = 0;
61 	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 */
90 		netdev_err(netdev, "Unsupported speed request (%d)", speed);
91 		spin_unlock_irqrestore(&dwmac->lock, flags);
92 		return;
93 	}
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 
103 	/* Set Clock-Mux, Start clock, Set TX_O direction */
104 	switch (dwmac->phy_intf_sel) {
105 	case ETHER_CONFIG_INTF_RGMII:
106 		val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC;
107 		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);
114 		break;
115 	case ETHER_CONFIG_INTF_RMII:
116 		val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV |
117 			ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN |
118 			ETHER_CLK_SEL_RMII_CLK_SEL_RX_C;
119 		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);
126 		break;
127 	case ETHER_CONFIG_INTF_MII:
128 	default:
129 		val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC |
130 			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);
135 		break;
136 	}
137 
138 	spin_unlock_irqrestore(&dwmac->lock, flags);
139 }
140 
141 static 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 
181 static 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");
188 	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");
191 
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 
201 static void 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 
211 static int visconti_eth_dwmac_probe(struct platform_device *pdev)
212 {
213 	struct plat_stmmacenet_data *plat_dat;
214 	struct stmmac_resources stmmac_res;
215 	struct visconti_eth *dwmac;
216 	int ret;
217 
218 	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
219 	if (ret)
220 		return ret;
221 
222 	plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
223 	if (IS_ERR(plat_dat))
224 		return PTR_ERR(plat_dat);
225 
226 	dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
227 	if (!dwmac) {
228 		ret = -ENOMEM;
229 		goto remove_config;
230 	}
231 
232 	spin_lock_init(&dwmac->lock);
233 	dwmac->reg = stmmac_res.addr;
234 	dwmac->dev = &pdev->dev;
235 	plat_dat->bsp_priv = dwmac;
236 	plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed;
237 
238 	ret = visconti_eth_clock_probe(pdev, plat_dat);
239 	if (ret)
240 		goto remove_config;
241 
242 	visconti_eth_init_hw(pdev, plat_dat);
243 
244 	plat_dat->dma_cfg->aal = 1;
245 
246 	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
247 	if (ret)
248 		goto remove;
249 
250 	return ret;
251 
252 remove:
253 	visconti_eth_clock_remove(pdev);
254 remove_config:
255 	stmmac_remove_config_dt(pdev, plat_dat);
256 
257 	return ret;
258 }
259 
260 static void visconti_eth_dwmac_remove(struct platform_device *pdev)
261 {
262 	struct net_device *ndev = platform_get_drvdata(pdev);
263 	struct stmmac_priv *priv = netdev_priv(ndev);
264 
265 	stmmac_pltfr_remove(pdev);
266 
267 	visconti_eth_clock_remove(pdev);
268 
269 	stmmac_remove_config_dt(pdev, priv->plat);
270 }
271 
272 static const struct of_device_id visconti_eth_dwmac_match[] = {
273 	{ .compatible = "toshiba,visconti-dwmac" },
274 	{ }
275 };
276 MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match);
277 
278 static struct platform_driver visconti_eth_dwmac_driver = {
279 	.probe  = visconti_eth_dwmac_probe,
280 	.remove_new = visconti_eth_dwmac_remove,
281 	.driver = {
282 		.name           = "visconti-eth-dwmac",
283 		.of_match_table = visconti_eth_dwmac_match,
284 	},
285 };
286 module_platform_driver(visconti_eth_dwmac_driver);
287 
288 MODULE_AUTHOR("Toshiba");
289 MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver");
290 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp");
291 MODULE_LICENSE("GPL v2");
292