xref: /linux/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c (revision 8f7aa3d3c7323f4ca2768a9e74ebbe359c4f8f88)
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 
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 
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 
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 
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 
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 
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