1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * NXP S32G/R GMAC glue layer
4  *
5  * Copyright 2019-2024 NXP
6  *
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/clk-provider.h>
11 #include <linux/device.h>
12 #include <linux/ethtool.h>
13 #include <linux/io.h>
14 #include <linux/module.h>
15 #include <linux/of_mdio.h>
16 #include <linux/of_address.h>
17 #include <linux/phy.h>
18 #include <linux/phylink.h>
19 #include <linux/platform_device.h>
20 #include <linux/stmmac.h>
21 
22 #include "stmmac_platform.h"
23 
24 #define GMAC_INTF_RATE_125M	125000000	/* 125MHz */
25 
26 /* SoC PHY interface control register */
27 #define PHY_INTF_SEL_MII	0x00
28 #define PHY_INTF_SEL_SGMII	0x01
29 #define PHY_INTF_SEL_RGMII	0x02
30 #define PHY_INTF_SEL_RMII	0x08
31 
32 struct s32_priv_data {
33 	void __iomem *ioaddr;
34 	void __iomem *ctrl_sts;
35 	struct device *dev;
36 	phy_interface_t *intf_mode;
37 	struct clk *tx_clk;
38 	struct clk *rx_clk;
39 };
40 
s32_gmac_write_phy_intf_select(struct s32_priv_data * gmac)41 static int s32_gmac_write_phy_intf_select(struct s32_priv_data *gmac)
42 {
43 	writel(PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
44 
45 	dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(*gmac->intf_mode));
46 
47 	return 0;
48 }
49 
s32_gmac_init(struct platform_device * pdev,void * priv)50 static int s32_gmac_init(struct platform_device *pdev, void *priv)
51 {
52 	struct s32_priv_data *gmac = priv;
53 	int ret;
54 
55 	/* Set initial TX interface clock */
56 	ret = clk_prepare_enable(gmac->tx_clk);
57 	if (ret) {
58 		dev_err(&pdev->dev, "Can't enable tx clock\n");
59 		return ret;
60 	}
61 	ret = clk_set_rate(gmac->tx_clk, GMAC_INTF_RATE_125M);
62 	if (ret) {
63 		dev_err(&pdev->dev, "Can't set tx clock\n");
64 		goto err_tx_disable;
65 	}
66 
67 	/* Set initial RX interface clock */
68 	ret = clk_prepare_enable(gmac->rx_clk);
69 	if (ret) {
70 		dev_err(&pdev->dev, "Can't enable rx clock\n");
71 		goto err_tx_disable;
72 	}
73 	ret = clk_set_rate(gmac->rx_clk, GMAC_INTF_RATE_125M);
74 	if (ret) {
75 		dev_err(&pdev->dev, "Can't set rx clock\n");
76 		goto err_txrx_disable;
77 	}
78 
79 	/* Set interface mode */
80 	ret = s32_gmac_write_phy_intf_select(gmac);
81 	if (ret) {
82 		dev_err(&pdev->dev, "Can't set PHY interface mode\n");
83 		goto err_txrx_disable;
84 	}
85 
86 	return 0;
87 
88 err_txrx_disable:
89 	clk_disable_unprepare(gmac->rx_clk);
90 err_tx_disable:
91 	clk_disable_unprepare(gmac->tx_clk);
92 	return ret;
93 }
94 
s32_gmac_exit(struct platform_device * pdev,void * priv)95 static void s32_gmac_exit(struct platform_device *pdev, void *priv)
96 {
97 	struct s32_priv_data *gmac = priv;
98 
99 	clk_disable_unprepare(gmac->tx_clk);
100 	clk_disable_unprepare(gmac->rx_clk);
101 }
102 
s32_fix_mac_speed(void * priv,unsigned int speed,unsigned int mode)103 static void s32_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
104 {
105 	struct s32_priv_data *gmac = priv;
106 	long tx_clk_rate;
107 	int ret;
108 
109 	tx_clk_rate = rgmii_clock(speed);
110 	if (tx_clk_rate < 0) {
111 		dev_err(gmac->dev, "Unsupported/Invalid speed: %d\n", speed);
112 		return;
113 	}
114 
115 	dev_dbg(gmac->dev, "Set tx clock to %ld Hz\n", tx_clk_rate);
116 	ret = clk_set_rate(gmac->tx_clk, tx_clk_rate);
117 	if (ret)
118 		dev_err(gmac->dev, "Can't set tx clock\n");
119 }
120 
s32_dwmac_probe(struct platform_device * pdev)121 static int s32_dwmac_probe(struct platform_device *pdev)
122 {
123 	struct plat_stmmacenet_data *plat;
124 	struct device *dev = &pdev->dev;
125 	struct stmmac_resources res;
126 	struct s32_priv_data *gmac;
127 	int ret;
128 
129 	gmac = devm_kzalloc(&pdev->dev, sizeof(*gmac), GFP_KERNEL);
130 	if (!gmac)
131 		return -ENOMEM;
132 
133 	gmac->dev = &pdev->dev;
134 
135 	ret = stmmac_get_platform_resources(pdev, &res);
136 	if (ret)
137 		return dev_err_probe(dev, ret,
138 				     "Failed to get platform resources\n");
139 
140 	plat = devm_stmmac_probe_config_dt(pdev, res.mac);
141 	if (IS_ERR(plat))
142 		return dev_err_probe(dev, PTR_ERR(plat),
143 				     "dt configuration failed\n");
144 
145 	/* PHY interface mode control reg */
146 	gmac->ctrl_sts = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
147 	if (IS_ERR(gmac->ctrl_sts))
148 		return dev_err_probe(dev, PTR_ERR(gmac->ctrl_sts),
149 				     "S32CC config region is missing\n");
150 
151 	/* tx clock */
152 	gmac->tx_clk = devm_clk_get(&pdev->dev, "tx");
153 	if (IS_ERR(gmac->tx_clk))
154 		return dev_err_probe(dev, PTR_ERR(gmac->tx_clk),
155 				     "tx clock not found\n");
156 
157 	/* rx clock */
158 	gmac->rx_clk = devm_clk_get(&pdev->dev, "rx");
159 	if (IS_ERR(gmac->rx_clk))
160 		return dev_err_probe(dev, PTR_ERR(gmac->rx_clk),
161 				     "rx clock not found\n");
162 
163 	gmac->intf_mode = &plat->phy_interface;
164 	gmac->ioaddr = res.addr;
165 
166 	/* S32CC core feature set */
167 	plat->has_gmac4 = true;
168 	plat->pmt = 1;
169 	plat->flags |= STMMAC_FLAG_SPH_DISABLE;
170 	plat->rx_fifo_size = 20480;
171 	plat->tx_fifo_size = 20480;
172 
173 	plat->init = s32_gmac_init;
174 	plat->exit = s32_gmac_exit;
175 	plat->fix_mac_speed = s32_fix_mac_speed;
176 
177 	plat->bsp_priv = gmac;
178 
179 	return stmmac_pltfr_probe(pdev, plat, &res);
180 }
181 
182 static const struct of_device_id s32_dwmac_match[] = {
183 	{ .compatible = "nxp,s32g2-dwmac" },
184 	{ }
185 };
186 MODULE_DEVICE_TABLE(of, s32_dwmac_match);
187 
188 static struct platform_driver s32_dwmac_driver = {
189 	.probe = s32_dwmac_probe,
190 	.remove = stmmac_pltfr_remove,
191 	.driver = {
192 		.name = "s32-dwmac",
193 		.pm = &stmmac_pltfr_pm_ops,
194 		.of_match_table = s32_dwmac_match,
195 	},
196 };
197 module_platform_driver(s32_dwmac_driver);
198 
199 MODULE_AUTHOR("Jan Petrous (OSS) <[email protected]>");
200 MODULE_DESCRIPTION("NXP S32G/R common chassis GMAC driver");
201 MODULE_LICENSE("GPL");
202 
203