blob: f674b0baa35933ff972c324270eb10b255665178 [file] [log] [blame]
Keerthy9d0dca12019-07-09 10:30:34 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Texas Instruments K3 AM65 Ethernet Switch SubSystem Driver
4 *
5 * Copyright (C) 2019, Texas Instruments, Incorporated
6 *
7 */
8
9#include <common.h>
Simon Glass336d4612020-02-03 07:36:16 -070010#include <malloc.h>
Simon Glass90526e92020-05-10 11:39:56 -060011#include <asm/cache.h>
Keerthy9d0dca12019-07-09 10:30:34 +053012#include <asm/io.h>
13#include <asm/processor.h>
14#include <clk.h>
15#include <dm.h>
Simon Glass336d4612020-02-03 07:36:16 -070016#include <dm/device_compat.h>
Keerthy9d0dca12019-07-09 10:30:34 +053017#include <dm/lists.h>
18#include <dma-uclass.h>
19#include <dm/of_access.h>
20#include <miiphy.h>
21#include <net.h>
22#include <phy.h>
23#include <power-domain.h>
Ravi Gunasekarand0fc8182022-09-22 15:21:24 +053024#include <soc.h>
Simon Glasscd93d622020-05-10 11:40:13 -060025#include <linux/bitops.h>
Keerthy9d0dca12019-07-09 10:30:34 +053026#include <linux/soc/ti/ti-udma.h>
27
28#include "cpsw_mdio.h"
29
Vignesh Raghavendra8441d492021-05-10 20:06:09 +053030#define AM65_CPSW_CPSWNU_MAX_PORTS 9
Keerthy9d0dca12019-07-09 10:30:34 +053031
32#define AM65_CPSW_SS_BASE 0x0
33#define AM65_CPSW_SGMII_BASE 0x100
34#define AM65_CPSW_MDIO_BASE 0xf00
35#define AM65_CPSW_XGMII_BASE 0x2100
36#define AM65_CPSW_CPSW_NU_BASE 0x20000
37#define AM65_CPSW_CPSW_NU_ALE_BASE 0x1e000
38
39#define AM65_CPSW_CPSW_NU_PORTS_OFFSET 0x1000
40#define AM65_CPSW_CPSW_NU_PORT_MACSL_OFFSET 0x330
41
42#define AM65_CPSW_MDIO_BUS_FREQ_DEF 1000000
43
44#define AM65_CPSW_CTL_REG 0x4
45#define AM65_CPSW_STAT_PORT_EN_REG 0x14
46#define AM65_CPSW_PTYPE_REG 0x18
47
48#define AM65_CPSW_CTL_REG_P0_ENABLE BIT(2)
49#define AM65_CPSW_CTL_REG_P0_TX_CRC_REMOVE BIT(13)
50#define AM65_CPSW_CTL_REG_P0_RX_PAD BIT(14)
51
52#define AM65_CPSW_P0_FLOW_ID_REG 0x8
53#define AM65_CPSW_PN_RX_MAXLEN_REG 0x24
54#define AM65_CPSW_PN_REG_SA_L 0x308
55#define AM65_CPSW_PN_REG_SA_H 0x30c
56
57#define AM65_CPSW_ALE_CTL_REG 0x8
58#define AM65_CPSW_ALE_CTL_REG_ENABLE BIT(31)
59#define AM65_CPSW_ALE_CTL_REG_RESET_TBL BIT(30)
60#define AM65_CPSW_ALE_CTL_REG_BYPASS BIT(4)
61#define AM65_CPSW_ALE_PN_CTL_REG(x) (0x40 + (x) * 4)
62#define AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD 0x3
63#define AM65_CPSW_ALE_PN_CTL_REG_MAC_ONLY BIT(11)
64
Vignesh Raghavendra9eab6fd2020-07-06 13:36:53 +053065#define AM65_CPSW_ALE_THREADMAPDEF_REG 0x134
66#define AM65_CPSW_ALE_DEFTHREAD_EN BIT(15)
67
Keerthy9d0dca12019-07-09 10:30:34 +053068#define AM65_CPSW_MACSL_CTL_REG 0x0
69#define AM65_CPSW_MACSL_CTL_REG_IFCTL_A BIT(15)
Murali Karicheri39821d52020-04-17 11:12:09 -040070#define AM65_CPSW_MACSL_CTL_EXT_EN BIT(18)
Keerthy9d0dca12019-07-09 10:30:34 +053071#define AM65_CPSW_MACSL_CTL_REG_GIG BIT(7)
72#define AM65_CPSW_MACSL_CTL_REG_GMII_EN BIT(5)
73#define AM65_CPSW_MACSL_CTL_REG_LOOPBACK BIT(1)
74#define AM65_CPSW_MACSL_CTL_REG_FULL_DUPLEX BIT(0)
75#define AM65_CPSW_MACSL_RESET_REG 0x8
76#define AM65_CPSW_MACSL_RESET_REG_RESET BIT(0)
77#define AM65_CPSW_MACSL_STATUS_REG 0x4
78#define AM65_CPSW_MACSL_RESET_REG_PN_IDLE BIT(31)
79#define AM65_CPSW_MACSL_RESET_REG_PN_E_IDLE BIT(30)
80#define AM65_CPSW_MACSL_RESET_REG_PN_P_IDLE BIT(29)
81#define AM65_CPSW_MACSL_RESET_REG_PN_TX_IDLE BIT(28)
82#define AM65_CPSW_MACSL_RESET_REG_IDLE_MASK \
83 (AM65_CPSW_MACSL_RESET_REG_PN_IDLE | \
84 AM65_CPSW_MACSL_RESET_REG_PN_E_IDLE | \
85 AM65_CPSW_MACSL_RESET_REG_PN_P_IDLE | \
86 AM65_CPSW_MACSL_RESET_REG_PN_TX_IDLE)
87
88#define AM65_CPSW_CPPI_PKT_TYPE 0x7
89
90struct am65_cpsw_port {
91 fdt_addr_t port_base;
92 fdt_addr_t macsl_base;
93 bool disabled;
94 u32 mac_control;
95};
96
97struct am65_cpsw_common {
98 struct udevice *dev;
99 fdt_addr_t ss_base;
100 fdt_addr_t cpsw_base;
101 fdt_addr_t mdio_base;
102 fdt_addr_t ale_base;
103 fdt_addr_t gmii_sel;
104 fdt_addr_t mac_efuse;
105
106 struct clk fclk;
107 struct power_domain pwrdmn;
108
109 u32 port_num;
110 struct am65_cpsw_port ports[AM65_CPSW_CPSWNU_MAX_PORTS];
Keerthy9d0dca12019-07-09 10:30:34 +0530111
112 struct mii_dev *bus;
113 u32 bus_freq;
114
115 struct dma dma_tx;
116 struct dma dma_rx;
117 u32 rx_next;
118 u32 rx_pend;
119 bool started;
120};
121
122struct am65_cpsw_priv {
123 struct udevice *dev;
124 struct am65_cpsw_common *cpsw_common;
125 u32 port_id;
126
127 struct phy_device *phydev;
128 bool has_phy;
129 ofnode phy_node;
130 u32 phy_addr;
Ravi Gunasekarand0fc8182022-09-22 15:21:24 +0530131
132 bool mdio_manual_mode;
Keerthy9d0dca12019-07-09 10:30:34 +0530133};
134
135#ifdef PKTSIZE_ALIGN
136#define UDMA_RX_BUF_SIZE PKTSIZE_ALIGN
137#else
138#define UDMA_RX_BUF_SIZE ALIGN(1522, ARCH_DMA_MINALIGN)
139#endif
140
141#ifdef PKTBUFSRX
142#define UDMA_RX_DESC_NUM PKTBUFSRX
143#else
144#define UDMA_RX_DESC_NUM 4
145#endif
146
147#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \
148 ((mac)[2] << 16) | ((mac)[3] << 24))
149#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8))
150
151static void am65_cpsw_set_sl_mac(struct am65_cpsw_port *slave,
152 unsigned char *addr)
153{
154 writel(mac_hi(addr),
155 slave->port_base + AM65_CPSW_PN_REG_SA_H);
156 writel(mac_lo(addr),
157 slave->port_base + AM65_CPSW_PN_REG_SA_L);
158}
159
160int am65_cpsw_macsl_reset(struct am65_cpsw_port *slave)
161{
162 u32 i = 100;
163
164 /* Set the soft reset bit */
165 writel(AM65_CPSW_MACSL_RESET_REG_RESET,
166 slave->macsl_base + AM65_CPSW_MACSL_RESET_REG);
167
168 while ((readl(slave->macsl_base + AM65_CPSW_MACSL_RESET_REG) &
169 AM65_CPSW_MACSL_RESET_REG_RESET) && i--)
170 cpu_relax();
171
172 /* Timeout on the reset */
173 return i;
174}
175
176static int am65_cpsw_macsl_wait_for_idle(struct am65_cpsw_port *slave)
177{
178 u32 i = 100;
179
180 while ((readl(slave->macsl_base + AM65_CPSW_MACSL_STATUS_REG) &
181 AM65_CPSW_MACSL_RESET_REG_IDLE_MASK) && i--)
182 cpu_relax();
183
184 return i;
185}
186
187static int am65_cpsw_update_link(struct am65_cpsw_priv *priv)
188{
189 struct am65_cpsw_common *common = priv->cpsw_common;
190 struct am65_cpsw_port *port = &common->ports[priv->port_id];
191 struct phy_device *phy = priv->phydev;
192 u32 mac_control = 0;
193
194 if (phy->link) { /* link up */
195 mac_control = /*AM65_CPSW_MACSL_CTL_REG_LOOPBACK |*/
196 AM65_CPSW_MACSL_CTL_REG_GMII_EN;
197 if (phy->speed == 1000)
198 mac_control |= AM65_CPSW_MACSL_CTL_REG_GIG;
Murali Karicheri39821d52020-04-17 11:12:09 -0400199 if (phy->speed == 10 && phy_interface_is_rgmii(phy))
200 /* Can be used with in band mode only */
201 mac_control |= AM65_CPSW_MACSL_CTL_EXT_EN;
Keerthy9d0dca12019-07-09 10:30:34 +0530202 if (phy->duplex == DUPLEX_FULL)
203 mac_control |= AM65_CPSW_MACSL_CTL_REG_FULL_DUPLEX;
204 if (phy->speed == 100)
205 mac_control |= AM65_CPSW_MACSL_CTL_REG_IFCTL_A;
206 }
207
208 if (mac_control == port->mac_control)
209 goto out;
210
211 if (mac_control) {
212 printf("link up on port %d, speed %d, %s duplex\n",
213 priv->port_id, phy->speed,
214 (phy->duplex == DUPLEX_FULL) ? "full" : "half");
215 } else {
216 printf("link down on port %d\n", priv->port_id);
217 }
218
219 writel(mac_control, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
220 port->mac_control = mac_control;
221
222out:
223 return phy->link;
224}
225
226#define AM65_GMII_SEL_MODE_MII 0
227#define AM65_GMII_SEL_MODE_RMII 1
228#define AM65_GMII_SEL_MODE_RGMII 2
229
230#define AM65_GMII_SEL_RGMII_IDMODE BIT(4)
231
232static void am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv,
233 phy_interface_t phy_mode, int slave)
234{
235 struct am65_cpsw_common *common = priv->cpsw_common;
236 u32 reg;
237 u32 mode = 0;
238 bool rgmii_id = false;
239
240 reg = readl(common->gmii_sel);
241
242 dev_dbg(common->dev, "old gmii_sel: %08x\n", reg);
243
244 switch (phy_mode) {
245 case PHY_INTERFACE_MODE_RMII:
246 mode = AM65_GMII_SEL_MODE_RMII;
247 break;
248
249 case PHY_INTERFACE_MODE_RGMII:
Grygorii Strashkoda6a7282019-09-19 11:16:41 +0300250 case PHY_INTERFACE_MODE_RGMII_RXID:
Keerthy9d0dca12019-07-09 10:30:34 +0530251 mode = AM65_GMII_SEL_MODE_RGMII;
252 break;
253
254 case PHY_INTERFACE_MODE_RGMII_ID:
Keerthy9d0dca12019-07-09 10:30:34 +0530255 case PHY_INTERFACE_MODE_RGMII_TXID:
256 mode = AM65_GMII_SEL_MODE_RGMII;
257 rgmii_id = true;
258 break;
259
260 default:
261 dev_warn(common->dev,
262 "Unsupported PHY mode: %u. Defaulting to MII.\n",
263 phy_mode);
264 /* fallthrough */
265 case PHY_INTERFACE_MODE_MII:
266 mode = AM65_GMII_SEL_MODE_MII;
267 break;
268 };
269
270 if (rgmii_id)
271 mode |= AM65_GMII_SEL_RGMII_IDMODE;
272
273 reg = mode;
274 dev_dbg(common->dev, "gmii_sel PHY mode: %u, new gmii_sel: %08x\n",
275 phy_mode, reg);
276 writel(reg, common->gmii_sel);
277
278 reg = readl(common->gmii_sel);
279 if (reg != mode)
280 dev_err(common->dev,
281 "gmii_sel PHY mode NOT SET!: requested: %08x, gmii_sel: %08x\n",
282 mode, reg);
283}
284
285static int am65_cpsw_start(struct udevice *dev)
286{
Simon Glassc69cda22020-12-03 16:55:20 -0700287 struct eth_pdata *pdata = dev_get_plat(dev);
Keerthy9d0dca12019-07-09 10:30:34 +0530288 struct am65_cpsw_priv *priv = dev_get_priv(dev);
289 struct am65_cpsw_common *common = priv->cpsw_common;
290 struct am65_cpsw_port *port = &common->ports[priv->port_id];
291 struct am65_cpsw_port *port0 = &common->ports[0];
Vignesh Raghavendra461a2902019-12-04 22:17:22 +0530292 struct ti_udma_drv_chan_cfg_data *dma_rx_cfg_data;
Keerthy9d0dca12019-07-09 10:30:34 +0530293 int ret, i;
294
295 ret = power_domain_on(&common->pwrdmn);
296 if (ret) {
297 dev_err(dev, "power_domain_on() failed %d\n", ret);
298 goto out;
299 }
300
301 ret = clk_enable(&common->fclk);
302 if (ret) {
303 dev_err(dev, "clk enabled failed %d\n", ret);
304 goto err_off_pwrdm;
305 }
306
307 common->rx_next = 0;
308 common->rx_pend = 0;
309 ret = dma_get_by_name(common->dev, "tx0", &common->dma_tx);
310 if (ret) {
311 dev_err(dev, "TX dma get failed %d\n", ret);
312 goto err_off_clk;
313 }
314 ret = dma_get_by_name(common->dev, "rx", &common->dma_rx);
315 if (ret) {
316 dev_err(dev, "RX dma get failed %d\n", ret);
317 goto err_free_tx;
318 }
319
320 for (i = 0; i < UDMA_RX_DESC_NUM; i++) {
321 ret = dma_prepare_rcv_buf(&common->dma_rx,
322 net_rx_packets[i],
323 UDMA_RX_BUF_SIZE);
324 if (ret) {
325 dev_err(dev, "RX dma add buf failed %d\n", ret);
326 goto err_free_tx;
327 }
328 }
329
330 ret = dma_enable(&common->dma_tx);
331 if (ret) {
332 dev_err(dev, "TX dma_enable failed %d\n", ret);
333 goto err_free_rx;
334 }
335 ret = dma_enable(&common->dma_rx);
336 if (ret) {
337 dev_err(dev, "RX dma_enable failed %d\n", ret);
338 goto err_dis_tx;
339 }
340
341 /* Control register */
342 writel(AM65_CPSW_CTL_REG_P0_ENABLE |
343 AM65_CPSW_CTL_REG_P0_TX_CRC_REMOVE |
344 AM65_CPSW_CTL_REG_P0_RX_PAD,
345 common->cpsw_base + AM65_CPSW_CTL_REG);
346
347 /* disable priority elevation */
348 writel(0, common->cpsw_base + AM65_CPSW_PTYPE_REG);
349
350 /* enable statistics */
351 writel(BIT(0) | BIT(priv->port_id),
352 common->cpsw_base + AM65_CPSW_STAT_PORT_EN_REG);
353
354 /* Port 0 length register */
355 writel(PKTSIZE_ALIGN, port0->port_base + AM65_CPSW_PN_RX_MAXLEN_REG);
356
357 /* set base flow_id */
Vignesh Raghavendra461a2902019-12-04 22:17:22 +0530358 dma_get_cfg(&common->dma_rx, 0, (void **)&dma_rx_cfg_data);
359 writel(dma_rx_cfg_data->flow_id_base,
Keerthy9d0dca12019-07-09 10:30:34 +0530360 port0->port_base + AM65_CPSW_P0_FLOW_ID_REG);
Vignesh Raghavendra461a2902019-12-04 22:17:22 +0530361 dev_info(dev, "K3 CPSW: rflow_id_base: %u\n",
362 dma_rx_cfg_data->flow_id_base);
Keerthy9d0dca12019-07-09 10:30:34 +0530363
364 /* Reset and enable the ALE */
365 writel(AM65_CPSW_ALE_CTL_REG_ENABLE | AM65_CPSW_ALE_CTL_REG_RESET_TBL |
366 AM65_CPSW_ALE_CTL_REG_BYPASS,
367 common->ale_base + AM65_CPSW_ALE_CTL_REG);
368
369 /* port 0 put into forward mode */
370 writel(AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD,
371 common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
372
Vignesh Raghavendra9eab6fd2020-07-06 13:36:53 +0530373 writel(AM65_CPSW_ALE_DEFTHREAD_EN,
374 common->ale_base + AM65_CPSW_ALE_THREADMAPDEF_REG);
375
Keerthy9d0dca12019-07-09 10:30:34 +0530376 /* PORT x configuration */
377
378 /* Port x Max length register */
379 writel(PKTSIZE_ALIGN, port->port_base + AM65_CPSW_PN_RX_MAXLEN_REG);
380
381 /* Port x set mac */
382 am65_cpsw_set_sl_mac(port, pdata->enetaddr);
383
384 /* Port x ALE: mac_only, Forwarding */
385 writel(AM65_CPSW_ALE_PN_CTL_REG_MAC_ONLY |
386 AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD,
387 common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
388
389 port->mac_control = 0;
390 if (!am65_cpsw_macsl_reset(port)) {
391 dev_err(dev, "mac_sl reset failed\n");
392 ret = -EFAULT;
393 goto err_dis_rx;
394 }
395
396 ret = phy_startup(priv->phydev);
397 if (ret) {
398 dev_err(dev, "phy_startup failed\n");
399 goto err_dis_rx;
400 }
401
402 ret = am65_cpsw_update_link(priv);
403 if (!ret) {
404 ret = -ENODEV;
405 goto err_phy_shutdown;
406 }
407
408 common->started = true;
409
410 return 0;
411
412err_phy_shutdown:
413 phy_shutdown(priv->phydev);
414err_dis_rx:
415 /* disable ports */
416 writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
417 writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
418 if (!am65_cpsw_macsl_wait_for_idle(port))
419 dev_err(dev, "mac_sl idle timeout\n");
420 writel(0, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
421 writel(0, common->ale_base + AM65_CPSW_ALE_CTL_REG);
422 writel(0, common->cpsw_base + AM65_CPSW_CTL_REG);
423
424 dma_disable(&common->dma_rx);
425err_dis_tx:
426 dma_disable(&common->dma_tx);
427err_free_rx:
428 dma_free(&common->dma_rx);
429err_free_tx:
430 dma_free(&common->dma_tx);
431err_off_clk:
432 clk_disable(&common->fclk);
433err_off_pwrdm:
434 power_domain_off(&common->pwrdmn);
435out:
436 dev_err(dev, "%s end error\n", __func__);
437
438 return ret;
439}
440
441static int am65_cpsw_send(struct udevice *dev, void *packet, int length)
442{
443 struct am65_cpsw_priv *priv = dev_get_priv(dev);
444 struct am65_cpsw_common *common = priv->cpsw_common;
445 struct ti_udma_drv_packet_data packet_data;
446 int ret;
447
448 packet_data.pkt_type = AM65_CPSW_CPPI_PKT_TYPE;
449 packet_data.dest_tag = priv->port_id;
450 ret = dma_send(&common->dma_tx, packet, length, &packet_data);
451 if (ret) {
452 dev_err(dev, "TX dma_send failed %d\n", ret);
453 return ret;
454 }
455
456 return 0;
457}
458
459static int am65_cpsw_recv(struct udevice *dev, int flags, uchar **packetp)
460{
461 struct am65_cpsw_priv *priv = dev_get_priv(dev);
462 struct am65_cpsw_common *common = priv->cpsw_common;
463
464 /* try to receive a new packet */
465 return dma_receive(&common->dma_rx, (void **)packetp, NULL);
466}
467
468static int am65_cpsw_free_pkt(struct udevice *dev, uchar *packet, int length)
469{
470 struct am65_cpsw_priv *priv = dev_get_priv(dev);
471 struct am65_cpsw_common *common = priv->cpsw_common;
472 int ret;
473
474 if (length > 0) {
475 u32 pkt = common->rx_next % UDMA_RX_DESC_NUM;
476
477 ret = dma_prepare_rcv_buf(&common->dma_rx,
478 net_rx_packets[pkt],
479 UDMA_RX_BUF_SIZE);
480 if (ret)
481 dev_err(dev, "RX dma free_pkt failed %d\n", ret);
482 common->rx_next++;
483 }
484
485 return 0;
486}
487
488static void am65_cpsw_stop(struct udevice *dev)
489{
490 struct am65_cpsw_priv *priv = dev_get_priv(dev);
491 struct am65_cpsw_common *common = priv->cpsw_common;
492 struct am65_cpsw_port *port = &common->ports[priv->port_id];
493
494 if (!common->started)
495 return;
496
497 phy_shutdown(priv->phydev);
498
499 writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
500 writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
501 if (!am65_cpsw_macsl_wait_for_idle(port))
502 dev_err(dev, "mac_sl idle timeout\n");
503 writel(0, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
504 writel(0, common->ale_base + AM65_CPSW_ALE_CTL_REG);
505 writel(0, common->cpsw_base + AM65_CPSW_CTL_REG);
506
507 dma_disable(&common->dma_tx);
508 dma_free(&common->dma_tx);
509
510 dma_disable(&common->dma_rx);
511 dma_free(&common->dma_rx);
512
513 common->started = false;
514}
515
516static int am65_cpsw_read_rom_hwaddr(struct udevice *dev)
517{
518 struct am65_cpsw_priv *priv = dev_get_priv(dev);
519 struct am65_cpsw_common *common = priv->cpsw_common;
Simon Glassc69cda22020-12-03 16:55:20 -0700520 struct eth_pdata *pdata = dev_get_plat(dev);
Keerthy9d0dca12019-07-09 10:30:34 +0530521 u32 mac_hi, mac_lo;
522
523 if (common->mac_efuse == FDT_ADDR_T_NONE)
524 return -1;
525
526 mac_lo = readl(common->mac_efuse);
527 mac_hi = readl(common->mac_efuse + 4);
528 pdata->enetaddr[0] = (mac_hi >> 8) & 0xff;
529 pdata->enetaddr[1] = mac_hi & 0xff;
530 pdata->enetaddr[2] = (mac_lo >> 24) & 0xff;
531 pdata->enetaddr[3] = (mac_lo >> 16) & 0xff;
532 pdata->enetaddr[4] = (mac_lo >> 8) & 0xff;
533 pdata->enetaddr[5] = mac_lo & 0xff;
534
535 return 0;
536}
537
538static const struct eth_ops am65_cpsw_ops = {
539 .start = am65_cpsw_start,
540 .send = am65_cpsw_send,
541 .recv = am65_cpsw_recv,
542 .free_pkt = am65_cpsw_free_pkt,
543 .stop = am65_cpsw_stop,
544 .read_rom_hwaddr = am65_cpsw_read_rom_hwaddr,
545};
546
Ravi Gunasekarand0fc8182022-09-22 15:21:24 +0530547static const struct soc_attr k3_mdio_soc_data[] = {
548 { .family = "AM62X", .revision = "SR1.0" },
549 { .family = "AM64X", .revision = "SR1.0" },
550 { .family = "AM64X", .revision = "SR2.0" },
551 { .family = "AM65X", .revision = "SR1.0" },
552 { .family = "AM65X", .revision = "SR2.0" },
553 { .family = "J7200", .revision = "SR1.0" },
554 { .family = "J7200", .revision = "SR2.0" },
555 { .family = "J721E", .revision = "SR1.0" },
556 { .family = "J721E", .revision = "SR1.1" },
557 { .family = "J721S2", .revision = "SR1.0" },
558 { /* sentinel */ },
559};
560
Keerthy9d0dca12019-07-09 10:30:34 +0530561static int am65_cpsw_mdio_init(struct udevice *dev)
562{
563 struct am65_cpsw_priv *priv = dev_get_priv(dev);
564 struct am65_cpsw_common *cpsw_common = priv->cpsw_common;
565
566 if (!priv->has_phy || cpsw_common->bus)
567 return 0;
568
569 cpsw_common->bus = cpsw_mdio_init(dev->name,
570 cpsw_common->mdio_base,
571 cpsw_common->bus_freq,
Ravi Gunasekaran9ea30ea2022-09-22 15:21:23 +0530572 clk_get_rate(&cpsw_common->fclk),
Ravi Gunasekarand0fc8182022-09-22 15:21:24 +0530573 priv->mdio_manual_mode);
Keerthy9d0dca12019-07-09 10:30:34 +0530574 if (!cpsw_common->bus)
575 return -EFAULT;
576
577 return 0;
578}
579
580static int am65_cpsw_phy_init(struct udevice *dev)
581{
582 struct am65_cpsw_priv *priv = dev_get_priv(dev);
583 struct am65_cpsw_common *cpsw_common = priv->cpsw_common;
Simon Glassc69cda22020-12-03 16:55:20 -0700584 struct eth_pdata *pdata = dev_get_plat(dev);
Keerthy9d0dca12019-07-09 10:30:34 +0530585 struct phy_device *phydev;
586 u32 supported = PHY_GBIT_FEATURES;
587 int ret;
588
589 phydev = phy_connect(cpsw_common->bus,
590 priv->phy_addr,
591 priv->dev,
592 pdata->phy_interface);
593
594 if (!phydev) {
595 dev_err(dev, "phy_connect() failed\n");
596 return -ENODEV;
597 }
598
599 phydev->supported &= supported;
600 if (pdata->max_speed) {
601 ret = phy_set_supported(phydev, pdata->max_speed);
602 if (ret)
603 return ret;
604 }
605 phydev->advertising = phydev->supported;
606
607 if (ofnode_valid(priv->phy_node))
608 phydev->node = priv->phy_node;
609
610 priv->phydev = phydev;
611 ret = phy_config(phydev);
612 if (ret < 0)
613 pr_err("phy_config() failed: %d", ret);
614
615 return ret;
616}
617
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530618static int am65_cpsw_ofdata_parse_phy(struct udevice *dev)
Keerthy9d0dca12019-07-09 10:30:34 +0530619{
Simon Glassc69cda22020-12-03 16:55:20 -0700620 struct eth_pdata *pdata = dev_get_plat(dev);
Keerthy9d0dca12019-07-09 10:30:34 +0530621 struct am65_cpsw_priv *priv = dev_get_priv(dev);
622 struct ofnode_phandle_args out_args;
Keerthy9d0dca12019-07-09 10:30:34 +0530623 int ret = 0;
624
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530625 dev_read_u32(dev, "reg", &priv->port_id);
626
Marek Behún123ca112022-04-07 00:33:01 +0200627 pdata->phy_interface = dev_read_phy_mode(dev);
Marek Behúnffb0f6f2022-04-07 00:33:03 +0200628 if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
Marek Behún123ca112022-04-07 00:33:01 +0200629 dev_err(dev, "Invalid PHY mode, port %u\n", priv->port_id);
630 return -EINVAL;
Keerthy9d0dca12019-07-09 10:30:34 +0530631 }
632
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530633 dev_read_u32(dev, "max-speed", (u32 *)&pdata->max_speed);
Keerthy9d0dca12019-07-09 10:30:34 +0530634 if (pdata->max_speed)
635 dev_err(dev, "Port %u speed froced to %uMbit\n",
636 priv->port_id, pdata->max_speed);
637
638 priv->has_phy = true;
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530639 ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "phy-handle",
Keerthy9d0dca12019-07-09 10:30:34 +0530640 NULL, 0, 0, &out_args);
641 if (ret) {
642 dev_err(dev, "can't parse phy-handle port %u (%d)\n",
643 priv->port_id, ret);
644 priv->has_phy = false;
645 ret = 0;
646 }
647
648 priv->phy_node = out_args.node;
649 if (priv->has_phy) {
650 ret = ofnode_read_u32(priv->phy_node, "reg", &priv->phy_addr);
651 if (ret) {
652 dev_err(dev, "failed to get phy_addr port %u (%d)\n",
653 priv->port_id, ret);
654 goto out;
655 }
656 }
657
658out:
659 return ret;
660}
661
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530662static int am65_cpsw_port_probe(struct udevice *dev)
Keerthy9d0dca12019-07-09 10:30:34 +0530663{
664 struct am65_cpsw_priv *priv = dev_get_priv(dev);
Simon Glassc69cda22020-12-03 16:55:20 -0700665 struct eth_pdata *pdata = dev_get_plat(dev);
Keerthy9d0dca12019-07-09 10:30:34 +0530666 struct am65_cpsw_common *cpsw_common;
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530667 char portname[15];
668 int ret;
Keerthy9d0dca12019-07-09 10:30:34 +0530669
670 priv->dev = dev;
671
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530672 cpsw_common = dev_get_priv(dev->parent);
Keerthy9d0dca12019-07-09 10:30:34 +0530673 priv->cpsw_common = cpsw_common;
674
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530675 sprintf(portname, "%s%s", dev->parent->name, dev->name);
676 device_set_name(dev, portname);
677
Ravi Gunasekarand0fc8182022-09-22 15:21:24 +0530678 priv->mdio_manual_mode = false;
679 if (soc_device_match(k3_mdio_soc_data))
680 priv->mdio_manual_mode = true;
681
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530682 ret = am65_cpsw_ofdata_parse_phy(dev);
683 if (ret)
684 goto out;
685
686 am65_cpsw_gmii_sel_k3(priv, pdata->phy_interface, priv->port_id);
687
688 ret = am65_cpsw_mdio_init(dev);
689 if (ret)
690 goto out;
691
692 ret = am65_cpsw_phy_init(dev);
693 if (ret)
694 goto out;
695out:
696 return ret;
697}
698
699static int am65_cpsw_probe_nuss(struct udevice *dev)
700{
701 struct am65_cpsw_common *cpsw_common = dev_get_priv(dev);
702 ofnode ports_np, node;
703 int ret, i;
704 struct udevice *port_dev;
705
Keerthy9d0dca12019-07-09 10:30:34 +0530706 cpsw_common->dev = dev;
707 cpsw_common->ss_base = dev_read_addr(dev);
708 if (cpsw_common->ss_base == FDT_ADDR_T_NONE)
709 return -EINVAL;
710 cpsw_common->mac_efuse = devfdt_get_addr_name(dev, "mac_efuse");
711 /* no err check - optional */
712
713 ret = power_domain_get_by_index(dev, &cpsw_common->pwrdmn, 0);
714 if (ret) {
715 dev_err(dev, "failed to get pwrdmn: %d\n", ret);
716 return ret;
717 }
718
719 ret = clk_get_by_name(dev, "fck", &cpsw_common->fclk);
720 if (ret) {
721 power_domain_free(&cpsw_common->pwrdmn);
722 dev_err(dev, "failed to get clock %d\n", ret);
723 return ret;
724 }
725
726 cpsw_common->cpsw_base = cpsw_common->ss_base + AM65_CPSW_CPSW_NU_BASE;
727 cpsw_common->ale_base = cpsw_common->cpsw_base +
728 AM65_CPSW_CPSW_NU_ALE_BASE;
729 cpsw_common->mdio_base = cpsw_common->ss_base + AM65_CPSW_MDIO_BASE;
730
Vignesh Raghavendra84228942020-07-06 13:36:54 +0530731 ports_np = dev_read_subnode(dev, "ethernet-ports");
Keerthy9d0dca12019-07-09 10:30:34 +0530732 if (!ofnode_valid(ports_np)) {
733 ret = -ENOENT;
734 goto out;
735 }
736
737 ofnode_for_each_subnode(node, ports_np) {
738 const char *node_name;
739 u32 port_id;
740 bool disabled;
741
742 node_name = ofnode_get_name(node);
743
Simon Glass89090662022-09-06 20:27:17 -0600744 disabled = !ofnode_is_enabled(node);
Keerthy9d0dca12019-07-09 10:30:34 +0530745
746 ret = ofnode_read_u32(node, "reg", &port_id);
747 if (ret) {
748 dev_err(dev, "%s: failed to get port_id (%d)\n",
749 node_name, ret);
750 goto out;
751 }
752
753 if (port_id >= AM65_CPSW_CPSWNU_MAX_PORTS) {
754 dev_err(dev, "%s: invalid port_id (%d)\n",
755 node_name, port_id);
756 ret = -EINVAL;
757 goto out;
758 }
759 cpsw_common->port_num++;
760
761 if (!port_id)
762 continue;
763
Keerthy9d0dca12019-07-09 10:30:34 +0530764 cpsw_common->ports[port_id].disabled = disabled;
765 if (disabled)
766 continue;
767
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530768 ret = device_bind_driver_to_node(dev, "am65_cpsw_nuss_port", ofnode_get_name(node), node, &port_dev);
Keerthy9d0dca12019-07-09 10:30:34 +0530769 if (ret)
Vignesh Raghavendra5022a2e2022-01-21 12:47:51 +0530770 dev_err(dev, "Failed to bind to %s node\n", ofnode_get_name(node));
Keerthy9d0dca12019-07-09 10:30:34 +0530771 }
772
773 for (i = 0; i < AM65_CPSW_CPSWNU_MAX_PORTS; i++) {
774 struct am65_cpsw_port *port = &cpsw_common->ports[i];
775
776 port->port_base = cpsw_common->cpsw_base +
777 AM65_CPSW_CPSW_NU_PORTS_OFFSET +
778 (i * AM65_CPSW_CPSW_NU_PORTS_OFFSET);
779 port->macsl_base = port->port_base +
780 AM65_CPSW_CPSW_NU_PORT_MACSL_OFFSET;
781 }
782
783 node = dev_read_subnode(dev, "cpsw-phy-sel");
784 if (!ofnode_valid(node)) {
785 dev_err(dev, "can't find cpsw-phy-sel\n");
786 ret = -ENOENT;
787 goto out;
788 }
789
790 cpsw_common->gmii_sel = ofnode_get_addr(node);
791 if (cpsw_common->gmii_sel == FDT_ADDR_T_NONE) {
792 dev_err(dev, "failed to get gmii_sel base\n");
793 goto out;
794 }
795
Keerthy9d0dca12019-07-09 10:30:34 +0530796 cpsw_common->bus_freq =
797 dev_read_u32_default(dev, "bus_freq",
798 AM65_CPSW_MDIO_BUS_FREQ_DEF);
799
Vignesh Raghavendra461a2902019-12-04 22:17:22 +0530800 dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u mdio_freq:%u\n",
Keerthy9d0dca12019-07-09 10:30:34 +0530801 readl(cpsw_common->ss_base),
802 readl(cpsw_common->cpsw_base),
803 readl(cpsw_common->ale_base),
804 cpsw_common->port_num,
Keerthy9d0dca12019-07-09 10:30:34 +0530805 cpsw_common->bus_freq);
806
807out:
808 clk_free(&cpsw_common->fclk);
809 power_domain_free(&cpsw_common->pwrdmn);
810 return ret;
811}
812
813static const struct udevice_id am65_cpsw_nuss_ids[] = {
814 { .compatible = "ti,am654-cpsw-nuss" },
Vignesh Raghavendra382c0c62019-12-04 22:17:23 +0530815 { .compatible = "ti,j721e-cpsw-nuss" },
Vignesh Raghavendra845e1062021-05-10 20:06:11 +0530816 { .compatible = "ti,am642-cpsw-nuss" },
Keerthy9d0dca12019-07-09 10:30:34 +0530817 { }
818};
819
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530820U_BOOT_DRIVER(am65_cpsw_nuss) = {
821 .name = "am65_cpsw_nuss",
822 .id = UCLASS_MISC,
Keerthy9d0dca12019-07-09 10:30:34 +0530823 .of_match = am65_cpsw_nuss_ids,
Vignesh Raghavendra38922b12021-12-24 12:55:30 +0530824 .probe = am65_cpsw_probe_nuss,
825 .priv_auto = sizeof(struct am65_cpsw_common),
826};
827
828U_BOOT_DRIVER(am65_cpsw_nuss_port) = {
829 .name = "am65_cpsw_nuss_port",
830 .id = UCLASS_ETH,
831 .probe = am65_cpsw_port_probe,
Keerthy9d0dca12019-07-09 10:30:34 +0530832 .ops = &am65_cpsw_ops,
Simon Glass41575d82020-12-03 16:55:17 -0700833 .priv_auto = sizeof(struct am65_cpsw_priv),
Simon Glasscaa4daa2020-12-03 16:55:18 -0700834 .plat_auto = sizeof(struct eth_pdata),
Vignesh Raghavendra83fe92f2022-01-28 11:21:19 +0530835 .flags = DM_FLAG_ALLOC_PRIV_DMA | DM_FLAG_OS_PREPARE,
Keerthy9d0dca12019-07-09 10:30:34 +0530836};