blob: 2b77213001f5a2d7c48bf1e05a9ee56fbad9928c [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>
Keerthy9d0dca12019-07-09 10:30:34 +053011#include <asm/io.h>
12#include <asm/processor.h>
13#include <clk.h>
14#include <dm.h>
Simon Glass336d4612020-02-03 07:36:16 -070015#include <dm/device_compat.h>
Keerthy9d0dca12019-07-09 10:30:34 +053016#include <dm/lists.h>
17#include <dma-uclass.h>
18#include <dm/of_access.h>
19#include <miiphy.h>
20#include <net.h>
21#include <phy.h>
22#include <power-domain.h>
23#include <linux/soc/ti/ti-udma.h>
24
25#include "cpsw_mdio.h"
26
27#define AM65_CPSW_CPSWNU_MAX_PORTS 2
28
29#define AM65_CPSW_SS_BASE 0x0
30#define AM65_CPSW_SGMII_BASE 0x100
31#define AM65_CPSW_MDIO_BASE 0xf00
32#define AM65_CPSW_XGMII_BASE 0x2100
33#define AM65_CPSW_CPSW_NU_BASE 0x20000
34#define AM65_CPSW_CPSW_NU_ALE_BASE 0x1e000
35
36#define AM65_CPSW_CPSW_NU_PORTS_OFFSET 0x1000
37#define AM65_CPSW_CPSW_NU_PORT_MACSL_OFFSET 0x330
38
39#define AM65_CPSW_MDIO_BUS_FREQ_DEF 1000000
40
41#define AM65_CPSW_CTL_REG 0x4
42#define AM65_CPSW_STAT_PORT_EN_REG 0x14
43#define AM65_CPSW_PTYPE_REG 0x18
44
45#define AM65_CPSW_CTL_REG_P0_ENABLE BIT(2)
46#define AM65_CPSW_CTL_REG_P0_TX_CRC_REMOVE BIT(13)
47#define AM65_CPSW_CTL_REG_P0_RX_PAD BIT(14)
48
49#define AM65_CPSW_P0_FLOW_ID_REG 0x8
50#define AM65_CPSW_PN_RX_MAXLEN_REG 0x24
51#define AM65_CPSW_PN_REG_SA_L 0x308
52#define AM65_CPSW_PN_REG_SA_H 0x30c
53
54#define AM65_CPSW_ALE_CTL_REG 0x8
55#define AM65_CPSW_ALE_CTL_REG_ENABLE BIT(31)
56#define AM65_CPSW_ALE_CTL_REG_RESET_TBL BIT(30)
57#define AM65_CPSW_ALE_CTL_REG_BYPASS BIT(4)
58#define AM65_CPSW_ALE_PN_CTL_REG(x) (0x40 + (x) * 4)
59#define AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD 0x3
60#define AM65_CPSW_ALE_PN_CTL_REG_MAC_ONLY BIT(11)
61
62#define AM65_CPSW_MACSL_CTL_REG 0x0
63#define AM65_CPSW_MACSL_CTL_REG_IFCTL_A BIT(15)
64#define AM65_CPSW_MACSL_CTL_REG_GIG BIT(7)
65#define AM65_CPSW_MACSL_CTL_REG_GMII_EN BIT(5)
66#define AM65_CPSW_MACSL_CTL_REG_LOOPBACK BIT(1)
67#define AM65_CPSW_MACSL_CTL_REG_FULL_DUPLEX BIT(0)
68#define AM65_CPSW_MACSL_RESET_REG 0x8
69#define AM65_CPSW_MACSL_RESET_REG_RESET BIT(0)
70#define AM65_CPSW_MACSL_STATUS_REG 0x4
71#define AM65_CPSW_MACSL_RESET_REG_PN_IDLE BIT(31)
72#define AM65_CPSW_MACSL_RESET_REG_PN_E_IDLE BIT(30)
73#define AM65_CPSW_MACSL_RESET_REG_PN_P_IDLE BIT(29)
74#define AM65_CPSW_MACSL_RESET_REG_PN_TX_IDLE BIT(28)
75#define AM65_CPSW_MACSL_RESET_REG_IDLE_MASK \
76 (AM65_CPSW_MACSL_RESET_REG_PN_IDLE | \
77 AM65_CPSW_MACSL_RESET_REG_PN_E_IDLE | \
78 AM65_CPSW_MACSL_RESET_REG_PN_P_IDLE | \
79 AM65_CPSW_MACSL_RESET_REG_PN_TX_IDLE)
80
81#define AM65_CPSW_CPPI_PKT_TYPE 0x7
82
83struct am65_cpsw_port {
84 fdt_addr_t port_base;
85 fdt_addr_t macsl_base;
86 bool disabled;
87 u32 mac_control;
88};
89
90struct am65_cpsw_common {
91 struct udevice *dev;
92 fdt_addr_t ss_base;
93 fdt_addr_t cpsw_base;
94 fdt_addr_t mdio_base;
95 fdt_addr_t ale_base;
96 fdt_addr_t gmii_sel;
97 fdt_addr_t mac_efuse;
98
99 struct clk fclk;
100 struct power_domain pwrdmn;
101
102 u32 port_num;
103 struct am65_cpsw_port ports[AM65_CPSW_CPSWNU_MAX_PORTS];
Keerthy9d0dca12019-07-09 10:30:34 +0530104
105 struct mii_dev *bus;
106 u32 bus_freq;
107
108 struct dma dma_tx;
109 struct dma dma_rx;
110 u32 rx_next;
111 u32 rx_pend;
112 bool started;
113};
114
115struct am65_cpsw_priv {
116 struct udevice *dev;
117 struct am65_cpsw_common *cpsw_common;
118 u32 port_id;
119
120 struct phy_device *phydev;
121 bool has_phy;
122 ofnode phy_node;
123 u32 phy_addr;
124};
125
126#ifdef PKTSIZE_ALIGN
127#define UDMA_RX_BUF_SIZE PKTSIZE_ALIGN
128#else
129#define UDMA_RX_BUF_SIZE ALIGN(1522, ARCH_DMA_MINALIGN)
130#endif
131
132#ifdef PKTBUFSRX
133#define UDMA_RX_DESC_NUM PKTBUFSRX
134#else
135#define UDMA_RX_DESC_NUM 4
136#endif
137
138#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \
139 ((mac)[2] << 16) | ((mac)[3] << 24))
140#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8))
141
142static void am65_cpsw_set_sl_mac(struct am65_cpsw_port *slave,
143 unsigned char *addr)
144{
145 writel(mac_hi(addr),
146 slave->port_base + AM65_CPSW_PN_REG_SA_H);
147 writel(mac_lo(addr),
148 slave->port_base + AM65_CPSW_PN_REG_SA_L);
149}
150
151int am65_cpsw_macsl_reset(struct am65_cpsw_port *slave)
152{
153 u32 i = 100;
154
155 /* Set the soft reset bit */
156 writel(AM65_CPSW_MACSL_RESET_REG_RESET,
157 slave->macsl_base + AM65_CPSW_MACSL_RESET_REG);
158
159 while ((readl(slave->macsl_base + AM65_CPSW_MACSL_RESET_REG) &
160 AM65_CPSW_MACSL_RESET_REG_RESET) && i--)
161 cpu_relax();
162
163 /* Timeout on the reset */
164 return i;
165}
166
167static int am65_cpsw_macsl_wait_for_idle(struct am65_cpsw_port *slave)
168{
169 u32 i = 100;
170
171 while ((readl(slave->macsl_base + AM65_CPSW_MACSL_STATUS_REG) &
172 AM65_CPSW_MACSL_RESET_REG_IDLE_MASK) && i--)
173 cpu_relax();
174
175 return i;
176}
177
178static int am65_cpsw_update_link(struct am65_cpsw_priv *priv)
179{
180 struct am65_cpsw_common *common = priv->cpsw_common;
181 struct am65_cpsw_port *port = &common->ports[priv->port_id];
182 struct phy_device *phy = priv->phydev;
183 u32 mac_control = 0;
184
185 if (phy->link) { /* link up */
186 mac_control = /*AM65_CPSW_MACSL_CTL_REG_LOOPBACK |*/
187 AM65_CPSW_MACSL_CTL_REG_GMII_EN;
188 if (phy->speed == 1000)
189 mac_control |= AM65_CPSW_MACSL_CTL_REG_GIG;
190 if (phy->duplex == DUPLEX_FULL)
191 mac_control |= AM65_CPSW_MACSL_CTL_REG_FULL_DUPLEX;
192 if (phy->speed == 100)
193 mac_control |= AM65_CPSW_MACSL_CTL_REG_IFCTL_A;
194 }
195
196 if (mac_control == port->mac_control)
197 goto out;
198
199 if (mac_control) {
200 printf("link up on port %d, speed %d, %s duplex\n",
201 priv->port_id, phy->speed,
202 (phy->duplex == DUPLEX_FULL) ? "full" : "half");
203 } else {
204 printf("link down on port %d\n", priv->port_id);
205 }
206
207 writel(mac_control, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
208 port->mac_control = mac_control;
209
210out:
211 return phy->link;
212}
213
214#define AM65_GMII_SEL_MODE_MII 0
215#define AM65_GMII_SEL_MODE_RMII 1
216#define AM65_GMII_SEL_MODE_RGMII 2
217
218#define AM65_GMII_SEL_RGMII_IDMODE BIT(4)
219
220static void am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv,
221 phy_interface_t phy_mode, int slave)
222{
223 struct am65_cpsw_common *common = priv->cpsw_common;
224 u32 reg;
225 u32 mode = 0;
226 bool rgmii_id = false;
227
228 reg = readl(common->gmii_sel);
229
230 dev_dbg(common->dev, "old gmii_sel: %08x\n", reg);
231
232 switch (phy_mode) {
233 case PHY_INTERFACE_MODE_RMII:
234 mode = AM65_GMII_SEL_MODE_RMII;
235 break;
236
237 case PHY_INTERFACE_MODE_RGMII:
Grygorii Strashkoda6a7282019-09-19 11:16:41 +0300238 case PHY_INTERFACE_MODE_RGMII_RXID:
Keerthy9d0dca12019-07-09 10:30:34 +0530239 mode = AM65_GMII_SEL_MODE_RGMII;
240 break;
241
242 case PHY_INTERFACE_MODE_RGMII_ID:
Keerthy9d0dca12019-07-09 10:30:34 +0530243 case PHY_INTERFACE_MODE_RGMII_TXID:
244 mode = AM65_GMII_SEL_MODE_RGMII;
245 rgmii_id = true;
246 break;
247
248 default:
249 dev_warn(common->dev,
250 "Unsupported PHY mode: %u. Defaulting to MII.\n",
251 phy_mode);
252 /* fallthrough */
253 case PHY_INTERFACE_MODE_MII:
254 mode = AM65_GMII_SEL_MODE_MII;
255 break;
256 };
257
258 if (rgmii_id)
259 mode |= AM65_GMII_SEL_RGMII_IDMODE;
260
261 reg = mode;
262 dev_dbg(common->dev, "gmii_sel PHY mode: %u, new gmii_sel: %08x\n",
263 phy_mode, reg);
264 writel(reg, common->gmii_sel);
265
266 reg = readl(common->gmii_sel);
267 if (reg != mode)
268 dev_err(common->dev,
269 "gmii_sel PHY mode NOT SET!: requested: %08x, gmii_sel: %08x\n",
270 mode, reg);
271}
272
273static int am65_cpsw_start(struct udevice *dev)
274{
275 struct eth_pdata *pdata = dev_get_platdata(dev);
276 struct am65_cpsw_priv *priv = dev_get_priv(dev);
277 struct am65_cpsw_common *common = priv->cpsw_common;
278 struct am65_cpsw_port *port = &common->ports[priv->port_id];
279 struct am65_cpsw_port *port0 = &common->ports[0];
Vignesh Raghavendra461a2902019-12-04 22:17:22 +0530280 struct ti_udma_drv_chan_cfg_data *dma_rx_cfg_data;
Keerthy9d0dca12019-07-09 10:30:34 +0530281 int ret, i;
282
283 ret = power_domain_on(&common->pwrdmn);
284 if (ret) {
285 dev_err(dev, "power_domain_on() failed %d\n", ret);
286 goto out;
287 }
288
289 ret = clk_enable(&common->fclk);
290 if (ret) {
291 dev_err(dev, "clk enabled failed %d\n", ret);
292 goto err_off_pwrdm;
293 }
294
295 common->rx_next = 0;
296 common->rx_pend = 0;
297 ret = dma_get_by_name(common->dev, "tx0", &common->dma_tx);
298 if (ret) {
299 dev_err(dev, "TX dma get failed %d\n", ret);
300 goto err_off_clk;
301 }
302 ret = dma_get_by_name(common->dev, "rx", &common->dma_rx);
303 if (ret) {
304 dev_err(dev, "RX dma get failed %d\n", ret);
305 goto err_free_tx;
306 }
307
308 for (i = 0; i < UDMA_RX_DESC_NUM; i++) {
309 ret = dma_prepare_rcv_buf(&common->dma_rx,
310 net_rx_packets[i],
311 UDMA_RX_BUF_SIZE);
312 if (ret) {
313 dev_err(dev, "RX dma add buf failed %d\n", ret);
314 goto err_free_tx;
315 }
316 }
317
318 ret = dma_enable(&common->dma_tx);
319 if (ret) {
320 dev_err(dev, "TX dma_enable failed %d\n", ret);
321 goto err_free_rx;
322 }
323 ret = dma_enable(&common->dma_rx);
324 if (ret) {
325 dev_err(dev, "RX dma_enable failed %d\n", ret);
326 goto err_dis_tx;
327 }
328
329 /* Control register */
330 writel(AM65_CPSW_CTL_REG_P0_ENABLE |
331 AM65_CPSW_CTL_REG_P0_TX_CRC_REMOVE |
332 AM65_CPSW_CTL_REG_P0_RX_PAD,
333 common->cpsw_base + AM65_CPSW_CTL_REG);
334
335 /* disable priority elevation */
336 writel(0, common->cpsw_base + AM65_CPSW_PTYPE_REG);
337
338 /* enable statistics */
339 writel(BIT(0) | BIT(priv->port_id),
340 common->cpsw_base + AM65_CPSW_STAT_PORT_EN_REG);
341
342 /* Port 0 length register */
343 writel(PKTSIZE_ALIGN, port0->port_base + AM65_CPSW_PN_RX_MAXLEN_REG);
344
345 /* set base flow_id */
Vignesh Raghavendra461a2902019-12-04 22:17:22 +0530346 dma_get_cfg(&common->dma_rx, 0, (void **)&dma_rx_cfg_data);
347 writel(dma_rx_cfg_data->flow_id_base,
Keerthy9d0dca12019-07-09 10:30:34 +0530348 port0->port_base + AM65_CPSW_P0_FLOW_ID_REG);
Vignesh Raghavendra461a2902019-12-04 22:17:22 +0530349 dev_info(dev, "K3 CPSW: rflow_id_base: %u\n",
350 dma_rx_cfg_data->flow_id_base);
Keerthy9d0dca12019-07-09 10:30:34 +0530351
352 /* Reset and enable the ALE */
353 writel(AM65_CPSW_ALE_CTL_REG_ENABLE | AM65_CPSW_ALE_CTL_REG_RESET_TBL |
354 AM65_CPSW_ALE_CTL_REG_BYPASS,
355 common->ale_base + AM65_CPSW_ALE_CTL_REG);
356
357 /* port 0 put into forward mode */
358 writel(AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD,
359 common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
360
361 /* PORT x configuration */
362
363 /* Port x Max length register */
364 writel(PKTSIZE_ALIGN, port->port_base + AM65_CPSW_PN_RX_MAXLEN_REG);
365
366 /* Port x set mac */
367 am65_cpsw_set_sl_mac(port, pdata->enetaddr);
368
369 /* Port x ALE: mac_only, Forwarding */
370 writel(AM65_CPSW_ALE_PN_CTL_REG_MAC_ONLY |
371 AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD,
372 common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
373
374 port->mac_control = 0;
375 if (!am65_cpsw_macsl_reset(port)) {
376 dev_err(dev, "mac_sl reset failed\n");
377 ret = -EFAULT;
378 goto err_dis_rx;
379 }
380
381 ret = phy_startup(priv->phydev);
382 if (ret) {
383 dev_err(dev, "phy_startup failed\n");
384 goto err_dis_rx;
385 }
386
387 ret = am65_cpsw_update_link(priv);
388 if (!ret) {
389 ret = -ENODEV;
390 goto err_phy_shutdown;
391 }
392
393 common->started = true;
394
395 return 0;
396
397err_phy_shutdown:
398 phy_shutdown(priv->phydev);
399err_dis_rx:
400 /* disable ports */
401 writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
402 writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
403 if (!am65_cpsw_macsl_wait_for_idle(port))
404 dev_err(dev, "mac_sl idle timeout\n");
405 writel(0, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
406 writel(0, common->ale_base + AM65_CPSW_ALE_CTL_REG);
407 writel(0, common->cpsw_base + AM65_CPSW_CTL_REG);
408
409 dma_disable(&common->dma_rx);
410err_dis_tx:
411 dma_disable(&common->dma_tx);
412err_free_rx:
413 dma_free(&common->dma_rx);
414err_free_tx:
415 dma_free(&common->dma_tx);
416err_off_clk:
417 clk_disable(&common->fclk);
418err_off_pwrdm:
419 power_domain_off(&common->pwrdmn);
420out:
421 dev_err(dev, "%s end error\n", __func__);
422
423 return ret;
424}
425
426static int am65_cpsw_send(struct udevice *dev, void *packet, int length)
427{
428 struct am65_cpsw_priv *priv = dev_get_priv(dev);
429 struct am65_cpsw_common *common = priv->cpsw_common;
430 struct ti_udma_drv_packet_data packet_data;
431 int ret;
432
433 packet_data.pkt_type = AM65_CPSW_CPPI_PKT_TYPE;
434 packet_data.dest_tag = priv->port_id;
435 ret = dma_send(&common->dma_tx, packet, length, &packet_data);
436 if (ret) {
437 dev_err(dev, "TX dma_send failed %d\n", ret);
438 return ret;
439 }
440
441 return 0;
442}
443
444static int am65_cpsw_recv(struct udevice *dev, int flags, uchar **packetp)
445{
446 struct am65_cpsw_priv *priv = dev_get_priv(dev);
447 struct am65_cpsw_common *common = priv->cpsw_common;
448
449 /* try to receive a new packet */
450 return dma_receive(&common->dma_rx, (void **)packetp, NULL);
451}
452
453static int am65_cpsw_free_pkt(struct udevice *dev, uchar *packet, int length)
454{
455 struct am65_cpsw_priv *priv = dev_get_priv(dev);
456 struct am65_cpsw_common *common = priv->cpsw_common;
457 int ret;
458
459 if (length > 0) {
460 u32 pkt = common->rx_next % UDMA_RX_DESC_NUM;
461
462 ret = dma_prepare_rcv_buf(&common->dma_rx,
463 net_rx_packets[pkt],
464 UDMA_RX_BUF_SIZE);
465 if (ret)
466 dev_err(dev, "RX dma free_pkt failed %d\n", ret);
467 common->rx_next++;
468 }
469
470 return 0;
471}
472
473static void am65_cpsw_stop(struct udevice *dev)
474{
475 struct am65_cpsw_priv *priv = dev_get_priv(dev);
476 struct am65_cpsw_common *common = priv->cpsw_common;
477 struct am65_cpsw_port *port = &common->ports[priv->port_id];
478
479 if (!common->started)
480 return;
481
482 phy_shutdown(priv->phydev);
483
484 writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id));
485 writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0));
486 if (!am65_cpsw_macsl_wait_for_idle(port))
487 dev_err(dev, "mac_sl idle timeout\n");
488 writel(0, port->macsl_base + AM65_CPSW_MACSL_CTL_REG);
489 writel(0, common->ale_base + AM65_CPSW_ALE_CTL_REG);
490 writel(0, common->cpsw_base + AM65_CPSW_CTL_REG);
491
492 dma_disable(&common->dma_tx);
493 dma_free(&common->dma_tx);
494
495 dma_disable(&common->dma_rx);
496 dma_free(&common->dma_rx);
497
498 common->started = false;
499}
500
501static int am65_cpsw_read_rom_hwaddr(struct udevice *dev)
502{
503 struct am65_cpsw_priv *priv = dev_get_priv(dev);
504 struct am65_cpsw_common *common = priv->cpsw_common;
505 struct eth_pdata *pdata = dev_get_platdata(dev);
506 u32 mac_hi, mac_lo;
507
508 if (common->mac_efuse == FDT_ADDR_T_NONE)
509 return -1;
510
511 mac_lo = readl(common->mac_efuse);
512 mac_hi = readl(common->mac_efuse + 4);
513 pdata->enetaddr[0] = (mac_hi >> 8) & 0xff;
514 pdata->enetaddr[1] = mac_hi & 0xff;
515 pdata->enetaddr[2] = (mac_lo >> 24) & 0xff;
516 pdata->enetaddr[3] = (mac_lo >> 16) & 0xff;
517 pdata->enetaddr[4] = (mac_lo >> 8) & 0xff;
518 pdata->enetaddr[5] = mac_lo & 0xff;
519
520 return 0;
521}
522
523static const struct eth_ops am65_cpsw_ops = {
524 .start = am65_cpsw_start,
525 .send = am65_cpsw_send,
526 .recv = am65_cpsw_recv,
527 .free_pkt = am65_cpsw_free_pkt,
528 .stop = am65_cpsw_stop,
529 .read_rom_hwaddr = am65_cpsw_read_rom_hwaddr,
530};
531
532static int am65_cpsw_mdio_init(struct udevice *dev)
533{
534 struct am65_cpsw_priv *priv = dev_get_priv(dev);
535 struct am65_cpsw_common *cpsw_common = priv->cpsw_common;
536
537 if (!priv->has_phy || cpsw_common->bus)
538 return 0;
539
540 cpsw_common->bus = cpsw_mdio_init(dev->name,
541 cpsw_common->mdio_base,
542 cpsw_common->bus_freq,
543 clk_get_rate(&cpsw_common->fclk));
544 if (!cpsw_common->bus)
545 return -EFAULT;
546
547 return 0;
548}
549
550static int am65_cpsw_phy_init(struct udevice *dev)
551{
552 struct am65_cpsw_priv *priv = dev_get_priv(dev);
553 struct am65_cpsw_common *cpsw_common = priv->cpsw_common;
554 struct eth_pdata *pdata = dev_get_platdata(dev);
555 struct phy_device *phydev;
556 u32 supported = PHY_GBIT_FEATURES;
557 int ret;
558
559 phydev = phy_connect(cpsw_common->bus,
560 priv->phy_addr,
561 priv->dev,
562 pdata->phy_interface);
563
564 if (!phydev) {
565 dev_err(dev, "phy_connect() failed\n");
566 return -ENODEV;
567 }
568
569 phydev->supported &= supported;
570 if (pdata->max_speed) {
571 ret = phy_set_supported(phydev, pdata->max_speed);
572 if (ret)
573 return ret;
574 }
575 phydev->advertising = phydev->supported;
576
577 if (ofnode_valid(priv->phy_node))
578 phydev->node = priv->phy_node;
579
580 priv->phydev = phydev;
581 ret = phy_config(phydev);
582 if (ret < 0)
583 pr_err("phy_config() failed: %d", ret);
584
585 return ret;
586}
587
588static int am65_cpsw_ofdata_parse_phy(struct udevice *dev, ofnode port_np)
589{
590 struct eth_pdata *pdata = dev_get_platdata(dev);
591 struct am65_cpsw_priv *priv = dev_get_priv(dev);
592 struct ofnode_phandle_args out_args;
593 const char *phy_mode;
594 int ret = 0;
595
596 phy_mode = ofnode_read_string(port_np, "phy-mode");
597 if (phy_mode) {
598 pdata->phy_interface =
599 phy_get_interface_by_name(phy_mode);
600 if (pdata->phy_interface == -1) {
601 dev_err(dev, "Invalid PHY mode '%s', port %u\n",
602 phy_mode, priv->port_id);
603 ret = -EINVAL;
604 goto out;
605 }
606 }
607
608 ofnode_read_u32(port_np, "max-speed", (u32 *)&pdata->max_speed);
609 if (pdata->max_speed)
610 dev_err(dev, "Port %u speed froced to %uMbit\n",
611 priv->port_id, pdata->max_speed);
612
613 priv->has_phy = true;
614 ret = ofnode_parse_phandle_with_args(port_np, "phy-handle",
615 NULL, 0, 0, &out_args);
616 if (ret) {
617 dev_err(dev, "can't parse phy-handle port %u (%d)\n",
618 priv->port_id, ret);
619 priv->has_phy = false;
620 ret = 0;
621 }
622
623 priv->phy_node = out_args.node;
624 if (priv->has_phy) {
625 ret = ofnode_read_u32(priv->phy_node, "reg", &priv->phy_addr);
626 if (ret) {
627 dev_err(dev, "failed to get phy_addr port %u (%d)\n",
628 priv->port_id, ret);
629 goto out;
630 }
631 }
632
633out:
634 return ret;
635}
636
637static int am65_cpsw_probe_cpsw(struct udevice *dev)
638{
639 struct am65_cpsw_priv *priv = dev_get_priv(dev);
640 struct eth_pdata *pdata = dev_get_platdata(dev);
641 struct am65_cpsw_common *cpsw_common;
642 ofnode ports_np, node;
643 int ret, i;
644
645 priv->dev = dev;
646
647 cpsw_common = calloc(1, sizeof(*priv->cpsw_common));
648 if (!cpsw_common)
649 return -ENOMEM;
650 priv->cpsw_common = cpsw_common;
651
652 cpsw_common->dev = dev;
653 cpsw_common->ss_base = dev_read_addr(dev);
654 if (cpsw_common->ss_base == FDT_ADDR_T_NONE)
655 return -EINVAL;
656 cpsw_common->mac_efuse = devfdt_get_addr_name(dev, "mac_efuse");
657 /* no err check - optional */
658
659 ret = power_domain_get_by_index(dev, &cpsw_common->pwrdmn, 0);
660 if (ret) {
661 dev_err(dev, "failed to get pwrdmn: %d\n", ret);
662 return ret;
663 }
664
665 ret = clk_get_by_name(dev, "fck", &cpsw_common->fclk);
666 if (ret) {
667 power_domain_free(&cpsw_common->pwrdmn);
668 dev_err(dev, "failed to get clock %d\n", ret);
669 return ret;
670 }
671
672 cpsw_common->cpsw_base = cpsw_common->ss_base + AM65_CPSW_CPSW_NU_BASE;
673 cpsw_common->ale_base = cpsw_common->cpsw_base +
674 AM65_CPSW_CPSW_NU_ALE_BASE;
675 cpsw_common->mdio_base = cpsw_common->ss_base + AM65_CPSW_MDIO_BASE;
676
Keerthy9d0dca12019-07-09 10:30:34 +0530677 ports_np = dev_read_subnode(dev, "ports");
678 if (!ofnode_valid(ports_np)) {
679 ret = -ENOENT;
680 goto out;
681 }
682
683 ofnode_for_each_subnode(node, ports_np) {
684 const char *node_name;
685 u32 port_id;
686 bool disabled;
687
688 node_name = ofnode_get_name(node);
689
690 disabled = !ofnode_is_available(node);
691
692 ret = ofnode_read_u32(node, "reg", &port_id);
693 if (ret) {
694 dev_err(dev, "%s: failed to get port_id (%d)\n",
695 node_name, ret);
696 goto out;
697 }
698
699 if (port_id >= AM65_CPSW_CPSWNU_MAX_PORTS) {
700 dev_err(dev, "%s: invalid port_id (%d)\n",
701 node_name, port_id);
702 ret = -EINVAL;
703 goto out;
704 }
705 cpsw_common->port_num++;
706
707 if (!port_id)
708 continue;
709
710 priv->port_id = port_id;
711 cpsw_common->ports[port_id].disabled = disabled;
712 if (disabled)
713 continue;
714
715 ret = am65_cpsw_ofdata_parse_phy(dev, node);
716 if (ret)
717 goto out;
718 }
719
720 for (i = 0; i < AM65_CPSW_CPSWNU_MAX_PORTS; i++) {
721 struct am65_cpsw_port *port = &cpsw_common->ports[i];
722
723 port->port_base = cpsw_common->cpsw_base +
724 AM65_CPSW_CPSW_NU_PORTS_OFFSET +
725 (i * AM65_CPSW_CPSW_NU_PORTS_OFFSET);
726 port->macsl_base = port->port_base +
727 AM65_CPSW_CPSW_NU_PORT_MACSL_OFFSET;
728 }
729
730 node = dev_read_subnode(dev, "cpsw-phy-sel");
731 if (!ofnode_valid(node)) {
732 dev_err(dev, "can't find cpsw-phy-sel\n");
733 ret = -ENOENT;
734 goto out;
735 }
736
737 cpsw_common->gmii_sel = ofnode_get_addr(node);
738 if (cpsw_common->gmii_sel == FDT_ADDR_T_NONE) {
739 dev_err(dev, "failed to get gmii_sel base\n");
740 goto out;
741 }
742
743 node = dev_read_subnode(dev, "mdio");
744 if (!ofnode_valid(node)) {
745 dev_err(dev, "can't find mdio\n");
746 ret = -ENOENT;
747 goto out;
748 }
749
750 cpsw_common->bus_freq =
751 dev_read_u32_default(dev, "bus_freq",
752 AM65_CPSW_MDIO_BUS_FREQ_DEF);
753
754 am65_cpsw_gmii_sel_k3(priv, pdata->phy_interface, priv->port_id);
755
756 ret = am65_cpsw_mdio_init(dev);
757 if (ret)
758 goto out;
759
760 ret = am65_cpsw_phy_init(dev);
761 if (ret)
762 goto out;
763
Vignesh Raghavendra461a2902019-12-04 22:17:22 +0530764 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 +0530765 readl(cpsw_common->ss_base),
766 readl(cpsw_common->cpsw_base),
767 readl(cpsw_common->ale_base),
768 cpsw_common->port_num,
Keerthy9d0dca12019-07-09 10:30:34 +0530769 cpsw_common->bus_freq);
770
771out:
772 clk_free(&cpsw_common->fclk);
773 power_domain_free(&cpsw_common->pwrdmn);
774 return ret;
775}
776
777static const struct udevice_id am65_cpsw_nuss_ids[] = {
778 { .compatible = "ti,am654-cpsw-nuss" },
Vignesh Raghavendra382c0c62019-12-04 22:17:23 +0530779 { .compatible = "ti,j721e-cpsw-nuss" },
Keerthy9d0dca12019-07-09 10:30:34 +0530780 { }
781};
782
783U_BOOT_DRIVER(am65_cpsw_nuss_slave) = {
784 .name = "am65_cpsw_nuss_slave",
785 .id = UCLASS_ETH,
786 .of_match = am65_cpsw_nuss_ids,
787 .probe = am65_cpsw_probe_cpsw,
788 .ops = &am65_cpsw_ops,
789 .priv_auto_alloc_size = sizeof(struct am65_cpsw_priv),
790 .platdata_auto_alloc_size = sizeof(struct eth_pdata),
791 .flags = DM_FLAG_ALLOC_PRIV_DMA,
792};