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