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