xref: /linux/drivers/net/ethernet/freescale/fman/mac.c (revision fcc79e1714e8c2b8e216dc3149812edd37884eef)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
2 /*
3  * Copyright 2008 - 2015 Freescale Semiconductor Inc.
4  */
5 
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 
8 #include <linux/init.h>
9 #include <linux/module.h>
10 #include <linux/of_address.h>
11 #include <linux/of_platform.h>
12 #include <linux/of_net.h>
13 #include <linux/of_mdio.h>
14 #include <linux/device.h>
15 #include <linux/phy.h>
16 #include <linux/netdevice.h>
17 #include <linux/phy_fixed.h>
18 #include <linux/phylink.h>
19 #include <linux/etherdevice.h>
20 #include <linux/libfdt_env.h>
21 #include <linux/platform_device.h>
22 
23 #include "mac.h"
24 #include "fman_mac.h"
25 #include "fman_dtsec.h"
26 #include "fman_tgec.h"
27 #include "fman_memac.h"
28 
29 MODULE_LICENSE("Dual BSD/GPL");
30 MODULE_DESCRIPTION("FSL FMan MAC API based driver");
31 
32 struct mac_priv_s {
33 	u8				cell_index;
34 	struct fman			*fman;
35 	struct platform_device		*eth_dev;
36 	u16				speed;
37 };
38 
39 struct mac_address {
40 	u8 addr[ETH_ALEN];
41 	struct list_head list;
42 };
43 
44 static void mac_exception(struct mac_device *mac_dev,
45 			  enum fman_mac_exceptions ex)
46 {
47 	if (ex == FM_MAC_EX_10G_RX_FIFO_OVFL) {
48 		/* don't flag RX FIFO after the first */
49 		mac_dev->set_exception(mac_dev->fman_mac,
50 				       FM_MAC_EX_10G_RX_FIFO_OVFL, false);
51 		dev_err(mac_dev->dev, "10G MAC got RX FIFO Error = %x\n", ex);
52 	}
53 
54 	dev_dbg(mac_dev->dev, "%s:%s() -> %d\n", KBUILD_BASENAME ".c",
55 		__func__, ex);
56 }
57 
58 static DEFINE_MUTEX(eth_lock);
59 
60 static struct platform_device *dpaa_eth_add_device(int fman_id,
61 						   struct mac_device *mac_dev)
62 {
63 	struct platform_device *pdev;
64 	struct dpaa_eth_data data;
65 	struct mac_priv_s	*priv;
66 	static int dpaa_eth_dev_cnt;
67 	int ret;
68 
69 	priv = mac_dev->priv;
70 
71 	data.mac_dev = mac_dev;
72 	data.mac_hw_id = priv->cell_index;
73 	data.fman_hw_id = fman_id;
74 
75 	mutex_lock(&eth_lock);
76 	pdev = platform_device_alloc("dpaa-ethernet", dpaa_eth_dev_cnt);
77 	if (!pdev) {
78 		ret = -ENOMEM;
79 		goto no_mem;
80 	}
81 
82 	pdev->dev.parent = mac_dev->dev;
83 
84 	ret = platform_device_add_data(pdev, &data, sizeof(data));
85 	if (ret)
86 		goto err;
87 
88 	ret = platform_device_add(pdev);
89 	if (ret)
90 		goto err;
91 
92 	dpaa_eth_dev_cnt++;
93 	mutex_unlock(&eth_lock);
94 
95 	return pdev;
96 
97 err:
98 	platform_device_put(pdev);
99 no_mem:
100 	mutex_unlock(&eth_lock);
101 
102 	return ERR_PTR(ret);
103 }
104 
105 static const struct of_device_id mac_match[] = {
106 	{ .compatible   = "fsl,fman-dtsec", .data = dtsec_initialization },
107 	{ .compatible   = "fsl,fman-xgec", .data = tgec_initialization },
108 	{ .compatible	= "fsl,fman-memac", .data = memac_initialization },
109 	{}
110 };
111 MODULE_DEVICE_TABLE(of, mac_match);
112 
113 static int mac_probe(struct platform_device *_of_dev)
114 {
115 	int			 err, i, nph;
116 	int (*init)(struct mac_device *mac_dev, struct device_node *mac_node,
117 		    struct fman_mac_params *params);
118 	struct device		*dev;
119 	struct device_node	*mac_node, *dev_node;
120 	struct mac_device	*mac_dev;
121 	struct platform_device	*of_dev;
122 	struct mac_priv_s	*priv;
123 	struct fman_mac_params	 params;
124 	u32			 val;
125 	u8			fman_id;
126 	phy_interface_t          phy_if;
127 
128 	dev = &_of_dev->dev;
129 	mac_node = dev->of_node;
130 	init = of_device_get_match_data(dev);
131 
132 	mac_dev = devm_kzalloc(dev, sizeof(*mac_dev), GFP_KERNEL);
133 	if (!mac_dev)
134 		return -ENOMEM;
135 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
136 	if (!priv)
137 		return -ENOMEM;
138 	platform_set_drvdata(_of_dev, mac_dev);
139 
140 	/* Save private information */
141 	mac_dev->priv = priv;
142 	mac_dev->dev = dev;
143 
144 	/* Get the FM node */
145 	dev_node = of_get_parent(mac_node);
146 	if (!dev_node) {
147 		dev_err(dev, "of_get_parent(%pOF) failed\n",
148 			mac_node);
149 		return -EINVAL;
150 	}
151 
152 	of_dev = of_find_device_by_node(dev_node);
153 	if (!of_dev) {
154 		dev_err(dev, "of_find_device_by_node(%pOF) failed\n", dev_node);
155 		err = -EINVAL;
156 		goto _return_of_node_put;
157 	}
158 	mac_dev->fman_dev = &of_dev->dev;
159 
160 	/* Get the FMan cell-index */
161 	err = of_property_read_u32(dev_node, "cell-index", &val);
162 	if (err) {
163 		dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
164 		err = -EINVAL;
165 		goto _return_dev_put;
166 	}
167 	/* cell-index 0 => FMan id 1 */
168 	fman_id = (u8)(val + 1);
169 
170 	priv->fman = fman_bind(mac_dev->fman_dev);
171 	if (!priv->fman) {
172 		dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
173 		err = -ENODEV;
174 		goto _return_dev_put;
175 	}
176 
177 	/* Two references have been taken in of_find_device_by_node()
178 	 * and fman_bind(). Release one of them here. The second one
179 	 * will be released in mac_remove().
180 	 */
181 	put_device(mac_dev->fman_dev);
182 	of_node_put(dev_node);
183 	dev_node = NULL;
184 
185 	/* Get the address of the memory mapped registers */
186 	mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
187 	if (!mac_dev->res) {
188 		dev_err(dev, "could not get registers\n");
189 		err = -EINVAL;
190 		goto _return_dev_put;
191 	}
192 
193 	err = devm_request_resource(dev, fman_get_mem_region(priv->fman),
194 				    mac_dev->res);
195 	if (err) {
196 		dev_err_probe(dev, err, "could not request resource\n");
197 		goto _return_dev_put;
198 	}
199 
200 	mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,
201 				      resource_size(mac_dev->res));
202 	if (!mac_dev->vaddr) {
203 		dev_err(dev, "devm_ioremap() failed\n");
204 		err = -EIO;
205 		goto _return_dev_put;
206 	}
207 
208 	if (!of_device_is_available(mac_node)) {
209 		err = -ENODEV;
210 		goto _return_dev_put;
211 	}
212 
213 	/* Get the cell-index */
214 	err = of_property_read_u32(mac_node, "cell-index", &val);
215 	if (err) {
216 		dev_err(dev, "failed to read cell-index for %pOF\n", mac_node);
217 		err = -EINVAL;
218 		goto _return_dev_put;
219 	}
220 	if (val >= MAX_NUM_OF_MACS) {
221 		dev_err(dev, "cell-index value is too big for %pOF\n", mac_node);
222 		err = -EINVAL;
223 		goto _return_dev_put;
224 	}
225 	priv->cell_index = (u8)val;
226 
227 	/* Get the MAC address */
228 	err = of_get_mac_address(mac_node, mac_dev->addr);
229 	if (err)
230 		dev_warn(dev, "of_get_mac_address(%pOF) failed\n", mac_node);
231 
232 	/* Get the port handles */
233 	nph = of_count_phandle_with_args(mac_node, "fsl,fman-ports", NULL);
234 	if (unlikely(nph < 0)) {
235 		dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n",
236 			mac_node);
237 		err = nph;
238 		goto _return_dev_put;
239 	}
240 
241 	if (nph != ARRAY_SIZE(mac_dev->port)) {
242 		dev_err(dev, "Not supported number of fman-ports handles of mac node %pOF from device tree\n",
243 			mac_node);
244 		err = -EINVAL;
245 		goto _return_dev_put;
246 	}
247 
248 	/* PORT_NUM determines the size of the port array */
249 	for (i = 0; i < PORT_NUM; i++) {
250 		/* Find the port node */
251 		dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
252 		if (!dev_node) {
253 			dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n",
254 				mac_node);
255 			err = -EINVAL;
256 			goto _return_dev_arr_put;
257 		}
258 
259 		of_dev = of_find_device_by_node(dev_node);
260 		if (!of_dev) {
261 			dev_err(dev, "of_find_device_by_node(%pOF) failed\n",
262 				dev_node);
263 			err = -EINVAL;
264 			goto _return_dev_arr_put;
265 		}
266 		mac_dev->fman_port_devs[i] = &of_dev->dev;
267 
268 		mac_dev->port[i] = fman_port_bind(mac_dev->fman_port_devs[i]);
269 		if (!mac_dev->port[i]) {
270 			dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
271 				dev_node);
272 			err = -EINVAL;
273 			goto _return_dev_arr_put;
274 		}
275 		/* Two references have been taken in of_find_device_by_node()
276 		 * and fman_port_bind(). Release one of them here. The second
277 		 * one will be released in mac_remove().
278 		 */
279 		put_device(mac_dev->fman_port_devs[i]);
280 		of_node_put(dev_node);
281 		dev_node = NULL;
282 	}
283 
284 	/* Get the PHY connection type */
285 	err = of_get_phy_mode(mac_node, &phy_if);
286 	if (err) {
287 		dev_warn(dev,
288 			 "of_get_phy_mode() for %pOF failed. Defaulting to SGMII\n",
289 			 mac_node);
290 		phy_if = PHY_INTERFACE_MODE_SGMII;
291 	}
292 	mac_dev->phy_if = phy_if;
293 
294 	params.mac_id		= priv->cell_index;
295 	params.fm		= (void *)priv->fman;
296 	params.exception_cb	= mac_exception;
297 	params.event_cb		= mac_exception;
298 
299 	err = init(mac_dev, mac_node, &params);
300 	if (err < 0)
301 		goto _return_dev_arr_put;
302 
303 	if (!is_zero_ether_addr(mac_dev->addr))
304 		dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr);
305 
306 	priv->eth_dev = dpaa_eth_add_device(fman_id, mac_dev);
307 	if (IS_ERR(priv->eth_dev)) {
308 		err = PTR_ERR(priv->eth_dev);
309 		dev_err(dev, "failed to add Ethernet platform device for MAC %d\n",
310 			priv->cell_index);
311 		priv->eth_dev = NULL;
312 	}
313 
314 	return err;
315 
316 _return_dev_arr_put:
317 	/* mac_dev is kzalloc'ed */
318 	for (i = 0; i < PORT_NUM; i++)
319 		put_device(mac_dev->fman_port_devs[i]);
320 _return_dev_put:
321 	put_device(mac_dev->fman_dev);
322 _return_of_node_put:
323 	of_node_put(dev_node);
324 	return err;
325 }
326 
327 static void mac_remove(struct platform_device *pdev)
328 {
329 	struct mac_device *mac_dev = platform_get_drvdata(pdev);
330 	int		   i;
331 
332 	for (i = 0; i < PORT_NUM; i++)
333 		put_device(mac_dev->fman_port_devs[i]);
334 	put_device(mac_dev->fman_dev);
335 
336 	platform_device_unregister(mac_dev->priv->eth_dev);
337 }
338 
339 static struct platform_driver mac_driver = {
340 	.driver = {
341 		.name		= KBUILD_MODNAME,
342 		.of_match_table	= mac_match,
343 	},
344 	.probe		= mac_probe,
345 	.remove		= mac_remove,
346 };
347 
348 builtin_platform_driver(mac_driver);
349