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 BIT(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	BIT(0)
30 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN BIT(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  BIT(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	 BIT(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	 BIT(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 	spinlock_t lock; /* lock to protect register update */
53 };
54 
55 static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
56 {
57 	struct visconti_eth *dwmac = priv;
58 	unsigned int val, clk_sel_val;
59 	unsigned long flags;
60 
61 	spin_lock_irqsave(&dwmac->lock, flags);
62 
63 	/* adjust link */
64 	val = readl(dwmac->reg + MAC_CTRL_REG);
65 	val &= ~(GMAC_CONFIG_PS | GMAC_CONFIG_FES);
66 
67 	switch (speed) {
68 	case SPEED_1000:
69 		if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII)
70 			clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M;
71 		break;
72 	case SPEED_100:
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;
78 		break;
79 	case SPEED_10:
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;
85 		break;
86 	default:
87 		/* No bit control */
88 		break;
89 	}
90 
91 	writel(val, dwmac->reg + MAC_CTRL_REG);
92 
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);
98 
99 	switch (dwmac->phy_intf_sel) {
100 	case ETHER_CONFIG_INTF_RGMII:
101 		val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC;
102 		break;
103 	case ETHER_CONFIG_INTF_RMII:
104 		val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV |
105 			ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN |
106 			ETHER_CLK_SEL_RMII_CLK_SEL_RX_C;
107 		break;
108 	case ETHER_CONFIG_INTF_MII:
109 	default:
110 		val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC |
111 			ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN |
112 			ETHER_CLK_SEL_RMII_CLK_EN;
113 		break;
114 	}
115 
116 	/* Start clock */
117 	writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
118 	val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
119 	writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
120 
121 	val &= ~ETHER_CLK_SEL_TX_O_E_N_IN;
122 	writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
123 
124 	spin_unlock_irqrestore(&dwmac->lock, flags);
125 }
126 
127 static int visconti_eth_init_hw(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat)
128 {
129 	struct visconti_eth *dwmac = plat_dat->bsp_priv;
130 	unsigned int reg_val, clk_sel_val;
131 
132 	switch (plat_dat->phy_interface) {
133 	case PHY_INTERFACE_MODE_RGMII:
134 	case PHY_INTERFACE_MODE_RGMII_ID:
135 	case PHY_INTERFACE_MODE_RGMII_RXID:
136 	case PHY_INTERFACE_MODE_RGMII_TXID:
137 		dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RGMII;
138 		break;
139 	case PHY_INTERFACE_MODE_MII:
140 		dwmac->phy_intf_sel = ETHER_CONFIG_INTF_MII;
141 		break;
142 	case PHY_INTERFACE_MODE_RMII:
143 		dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RMII;
144 		break;
145 	default:
146 		dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n", plat_dat->phy_interface);
147 		return -EOPNOTSUPP;
148 	}
149 
150 	reg_val = dwmac->phy_intf_sel;
151 	writel(reg_val, dwmac->reg + REG_ETHER_CONTROL);
152 
153 	/* Enable TX/RX clock */
154 	clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M;
155 	writel(clk_sel_val, dwmac->reg + REG_ETHER_CLOCK_SEL);
156 
157 	writel((clk_sel_val | ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN),
158 	       dwmac->reg + REG_ETHER_CLOCK_SEL);
159 
160 	/* release internal-reset */
161 	reg_val |= ETHER_ETH_CONTROL_RESET;
162 	writel(reg_val, dwmac->reg + REG_ETHER_CONTROL);
163 
164 	return 0;
165 }
166 
167 static int visconti_eth_clock_probe(struct platform_device *pdev,
168 				    struct plat_stmmacenet_data *plat_dat)
169 {
170 	struct visconti_eth *dwmac = plat_dat->bsp_priv;
171 	int err;
172 
173 	dwmac->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk");
174 	if (IS_ERR(dwmac->phy_ref_clk)) {
175 		dev_err(&pdev->dev, "phy_ref_clk clock not found.\n");
176 		return PTR_ERR(dwmac->phy_ref_clk);
177 	}
178 
179 	err = clk_prepare_enable(dwmac->phy_ref_clk);
180 	if (err < 0) {
181 		dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n", err);
182 		return err;
183 	}
184 
185 	return 0;
186 }
187 
188 static int visconti_eth_clock_remove(struct platform_device *pdev)
189 {
190 	struct visconti_eth *dwmac = get_stmmac_bsp_priv(&pdev->dev);
191 	struct net_device *ndev = platform_get_drvdata(pdev);
192 	struct stmmac_priv *priv = netdev_priv(ndev);
193 
194 	clk_disable_unprepare(dwmac->phy_ref_clk);
195 	clk_disable_unprepare(priv->plat->stmmac_clk);
196 
197 	return 0;
198 }
199 
200 static int visconti_eth_dwmac_probe(struct platform_device *pdev)
201 {
202 	struct plat_stmmacenet_data *plat_dat;
203 	struct stmmac_resources stmmac_res;
204 	struct visconti_eth *dwmac;
205 	int ret;
206 
207 	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
208 	if (ret)
209 		return ret;
210 
211 	plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
212 	if (IS_ERR(plat_dat))
213 		return PTR_ERR(plat_dat);
214 
215 	dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
216 	if (!dwmac) {
217 		ret = -ENOMEM;
218 		goto remove_config;
219 	}
220 
221 	spin_lock_init(&dwmac->lock);
222 	dwmac->reg = stmmac_res.addr;
223 	plat_dat->bsp_priv = dwmac;
224 	plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed;
225 
226 	ret = visconti_eth_clock_probe(pdev, plat_dat);
227 	if (ret)
228 		goto remove_config;
229 
230 	visconti_eth_init_hw(pdev, plat_dat);
231 
232 	plat_dat->dma_cfg->aal = 1;
233 
234 	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
235 	if (ret)
236 		goto remove;
237 
238 	return ret;
239 
240 remove:
241 	visconti_eth_clock_remove(pdev);
242 remove_config:
243 	stmmac_remove_config_dt(pdev, plat_dat);
244 
245 	return ret;
246 }
247 
248 static int visconti_eth_dwmac_remove(struct platform_device *pdev)
249 {
250 	struct net_device *ndev = platform_get_drvdata(pdev);
251 	struct stmmac_priv *priv = netdev_priv(ndev);
252 	int err;
253 
254 	err = stmmac_pltfr_remove(pdev);
255 	if (err < 0)
256 		dev_err(&pdev->dev, "failed to remove platform: %d\n", err);
257 
258 	err = visconti_eth_clock_remove(pdev);
259 	if (err < 0)
260 		dev_err(&pdev->dev, "failed to remove clock: %d\n", err);
261 
262 	stmmac_remove_config_dt(pdev, priv->plat);
263 
264 	return err;
265 }
266 
267 static const struct of_device_id visconti_eth_dwmac_match[] = {
268 	{ .compatible = "toshiba,visconti-dwmac" },
269 	{ }
270 };
271 MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match);
272 
273 static struct platform_driver visconti_eth_dwmac_driver = {
274 	.probe  = visconti_eth_dwmac_probe,
275 	.remove = visconti_eth_dwmac_remove,
276 	.driver = {
277 		.name           = "visconti-eth-dwmac",
278 		.of_match_table = visconti_eth_dwmac_match,
279 	},
280 };
281 module_platform_driver(visconti_eth_dwmac_driver);
282 
283 MODULE_AUTHOR("Toshiba");
284 MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver");
285 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp");
286 MODULE_LICENSE("GPL v2");
287