ARM: omapl138_lcdk: Remove dead code
[oweals/u-boot.git] / drivers / net / mscc_eswitch / serval_switch.c
1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2 /*
3  * Copyright (c) 2019 Microsemi Corporation
4  */
5
6 #include <common.h>
7 #include <config.h>
8 #include <dm.h>
9 #include <dm/of_access.h>
10 #include <dm/of_addr.h>
11 #include <fdt_support.h>
12 #include <linux/io.h>
13 #include <linux/ioport.h>
14 #include <miiphy.h>
15 #include <net.h>
16 #include <wait_bit.h>
17
18 #include "mscc_xfer.h"
19 #include "mscc_mac_table.h"
20 #include "mscc_miim.h"
21
22 #define ANA_PORT_VLAN_CFG(x)                    (0xc000 + 0x100 * (x))
23 #define         ANA_PORT_VLAN_CFG_AWARE_ENA             BIT(20)
24 #define         ANA_PORT_VLAN_CFG_POP_CNT(x)            ((x) << 18)
25 #define ANA_PORT_PORT_CFG(x)                    (0xc070 + 0x100 * (x))
26 #define         ANA_PORT_PORT_CFG_RECV_ENA              BIT(6)
27 #define ANA_PGID(x)                             (0x9c00 + 4 * (x))
28
29 #define HSIO_ANA_SERDES1G_DES_CFG               0x3c
30 #define         HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x)            ((x) << 1)
31 #define         HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x)             ((x) << 5)
32 #define         HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x)          ((x) << 8)
33 #define         HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x)           ((x) << 13)
34 #define HSIO_ANA_SERDES1G_IB_CFG                0x40
35 #define         HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x)       (x)
36 #define         HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x)             ((x) << 6)
37 #define         HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP        BIT(9)
38 #define         HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV             BIT(11)
39 #define         HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM           BIT(13)
40 #define         HSIO_ANA_SERDES1G_IB_CFG_DET_LEV(x)             ((x) << 19)
41 #define         HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x)         ((x) << 24)
42 #define HSIO_ANA_SERDES1G_OB_CFG                0x44
43 #define         HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x)       (x)
44 #define         HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x)            ((x) << 4)
45 #define         HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x)       ((x) << 10)
46 #define         HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x)            ((x) << 13)
47 #define         HSIO_ANA_SERDES1G_OB_CFG_SLP(x)                 ((x) << 17)
48 #define HSIO_ANA_SERDES1G_SER_CFG               0x48
49 #define HSIO_ANA_SERDES1G_COMMON_CFG            0x4c
50 #define         HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE            BIT(0)
51 #define         HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE           BIT(18)
52 #define         HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST            BIT(31)
53 #define HSIO_ANA_SERDES1G_PLL_CFG               0x50
54 #define         HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA               BIT(7)
55 #define         HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x)      ((x) << 8)
56 #define         HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2           BIT(21)
57 #define HSIO_DIG_SERDES1G_DFT_CFG0              0x58
58 #define HSIO_DIG_SERDES1G_MISC_CFG              0x6c
59 #define         HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST             BIT(0)
60 #define HSIO_MCB_SERDES1G_CFG                   0x74
61 #define         HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT       BIT(31)
62 #define         HSIO_MCB_SERDES1G_CFG_ADDR(x)           (x)
63
64 #define SYS_FRM_AGING                           0x584
65 #define         SYS_FRM_AGING_ENA                       BIT(20)
66 #define SYS_SYSTEM_RST_CFG                      0x518
67 #define         SYS_SYSTEM_RST_MEM_INIT                 BIT(5)
68 #define         SYS_SYSTEM_RST_MEM_ENA                  BIT(6)
69 #define         SYS_SYSTEM_RST_CORE_ENA                 BIT(7)
70 #define SYS_PORT_MODE(x)                        (0x524 + 0x4 * (x))
71 #define         SYS_PORT_MODE_INCL_INJ_HDR(x)           ((x) << 4)
72 #define         SYS_PORT_MODE_INCL_XTR_HDR(x)           ((x) << 2)
73 #define SYS_PAUSE_CFG(x)                        (0x65c + 0x4 * (x))
74 #define         SYS_PAUSE_CFG_PAUSE_ENA                 BIT(0)
75
76 #define QSYS_SWITCH_PORT_MODE(x)                (0x15a34 + 0x4 * (x))
77 #define         QSYS_SWITCH_PORT_MODE_PORT_ENA          BIT(13)
78 #define QSYS_EGR_NO_SHARING                     0x15a9c
79 #define QSYS_QMAP                               0x15adc
80
81 /* Port registers */
82 #define DEV_CLOCK_CFG                           0x0
83 #define DEV_CLOCK_CFG_LINK_SPEED_1000                   1
84 #define DEV_MAC_ENA_CFG                         0x10
85 #define         DEV_MAC_ENA_CFG_RX_ENA                  BIT(4)
86 #define         DEV_MAC_ENA_CFG_TX_ENA                  BIT(0)
87 #define DEV_MAC_IFG_CFG                         0x24
88 #define         DEV_MAC_IFG_CFG_TX_IFG(x)               ((x) << 8)
89 #define         DEV_MAC_IFG_CFG_RX_IFG2(x)              ((x) << 4)
90 #define         DEV_MAC_IFG_CFG_RX_IFG1(x)              (x)
91 #define PCS1G_CFG                               0x3c
92 #define         PCS1G_MODE_CFG_SGMII_MODE_ENA           BIT(0)
93 #define PCS1G_MODE_CFG                          0x40
94 #define PCS1G_SD_CFG                            0x44
95 #define PCS1G_ANEG_CFG                          0x48
96 #define         PCS1G_ANEG_CFG_ADV_ABILITY(x)           ((x) << 16)
97
98 #define QS_XTR_GRP_CFG(x)                       (4 * (x))
99 #define         QS_XTR_GRP_CFG_MODE(x)                  ((x) << 2)
100 #define         QS_XTR_GRP_CFG_BYTE_SWAP                BIT(0)
101 #define QS_INJ_GRP_CFG(x)                       (0x24 + (x) * 4)
102 #define         QS_INJ_GRP_CFG_MODE(x)                  ((x) << 2)
103 #define         QS_INJ_GRP_CFG_BYTE_SWAP                BIT(0)
104
105 #define IFH_INJ_BYPASS          BIT(31)
106 #define IFH_TAG_TYPE_C          0
107 #define MAC_VID                 1
108 #define CPU_PORT                11
109 #define INTERNAL_PORT_MSK       0xFF
110 #define IFH_LEN                 4
111 #define ETH_ALEN                6
112 #define PGID_BROADCAST          13
113 #define PGID_UNICAST            14
114
115 static const char *const regs_names[] = {
116         "port0", "port1", "port2", "port3", "port4", "port5", "port6",
117         "port7", "port8", "port9", "port10",
118         "ana", "qs", "qsys", "rew", "sys", "hsio",
119 };
120
121 #define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
122 #define MAX_PORT 11
123
124 enum serval_ctrl_regs {
125         ANA = MAX_PORT,
126         QS,
127         QSYS,
128         REW,
129         SYS,
130         HSIO,
131 };
132
133 #define SERVAL_MIIM_BUS_COUNT 2
134
135 struct serval_phy_port_t {
136         size_t phy_addr;
137         struct mii_dev *bus;
138         u8 serdes_index;
139         u8 phy_mode;
140 };
141
142 struct serval_private {
143         void __iomem *regs[REGS_NAMES_COUNT];
144         struct mii_dev *bus[SERVAL_MIIM_BUS_COUNT];
145         struct serval_phy_port_t ports[MAX_PORT];
146 };
147
148 static const unsigned long serval_regs_qs[] = {
149         [MSCC_QS_XTR_RD] = 0x8,
150         [MSCC_QS_XTR_FLUSH] = 0x18,
151         [MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
152         [MSCC_QS_INJ_WR] = 0x2c,
153         [MSCC_QS_INJ_CTRL] = 0x34,
154 };
155
156 static const unsigned long serval_regs_ana_table[] = {
157         [MSCC_ANA_TABLES_MACHDATA] = 0x9b34,
158         [MSCC_ANA_TABLES_MACLDATA] = 0x9b38,
159         [MSCC_ANA_TABLES_MACACCESS] = 0x9b3c,
160 };
161
162 static struct mscc_miim_dev miim[SERVAL_MIIM_BUS_COUNT];
163 static int miim_count = -1;
164
165 static void serval_cpu_capture_setup(struct serval_private *priv)
166 {
167         int i;
168
169         /* map the 8 CPU extraction queues to CPU port 11 */
170         writel(0, priv->regs[QSYS] + QSYS_QMAP);
171
172         for (i = 0; i <= 1; i++) {
173                 /*
174                  * Do byte-swap and expect status after last data word
175                  * Extraction: Mode: manual extraction) | Byte_swap
176                  */
177                 writel(QS_XTR_GRP_CFG_MODE(1) | QS_XTR_GRP_CFG_BYTE_SWAP,
178                        priv->regs[QS] + QS_XTR_GRP_CFG(i));
179                 /*
180                  * Injection: Mode: manual extraction | Byte_swap
181                  */
182                 writel(QS_INJ_GRP_CFG_MODE(1) | QS_INJ_GRP_CFG_BYTE_SWAP,
183                        priv->regs[QS] + QS_INJ_GRP_CFG(i));
184         }
185
186         for (i = 0; i <= 1; i++)
187                 /* Enable IFH insertion/parsing on CPU ports */
188                 writel(SYS_PORT_MODE_INCL_INJ_HDR(1) |
189                        SYS_PORT_MODE_INCL_XTR_HDR(1),
190                        priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i));
191         /*
192          * Setup the CPU port as VLAN aware to support switching frames
193          * based on tags
194          */
195         writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
196                MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
197
198         /* Disable learning (only RECV_ENA must be set) */
199         writel(ANA_PORT_PORT_CFG_RECV_ENA,
200                priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
201
202         /* Enable switching to/from cpu port */
203         setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(CPU_PORT),
204                      QSYS_SWITCH_PORT_MODE_PORT_ENA);
205
206         /* No pause on CPU port - not needed (off by default) */
207         clrbits_le32(priv->regs[SYS] + SYS_PAUSE_CFG(CPU_PORT),
208                      SYS_PAUSE_CFG_PAUSE_ENA);
209
210         setbits_le32(priv->regs[QSYS] + QSYS_EGR_NO_SHARING, BIT(CPU_PORT));
211 }
212
213 static void serval_port_init(struct serval_private *priv, int port)
214 {
215         void __iomem *regs = priv->regs[port];
216
217         /* Enable PCS */
218         writel(PCS1G_MODE_CFG_SGMII_MODE_ENA, regs + PCS1G_CFG);
219
220         /* Disable Signal Detect */
221         writel(0, regs + PCS1G_SD_CFG);
222
223         /* Enable MAC RX and TX */
224         writel(DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA,
225                regs + DEV_MAC_ENA_CFG);
226
227         /* Clear sgmii_mode_ena */
228         writel(0, regs + PCS1G_MODE_CFG);
229
230         /*
231          * Clear sw_resolve_ena(bit 0) and set adv_ability to
232          * something meaningful just in case
233          */
234         writel(PCS1G_ANEG_CFG_ADV_ABILITY(0x20), regs + PCS1G_ANEG_CFG);
235
236         /* Set MAC IFG Gaps */
237         writel(DEV_MAC_IFG_CFG_TX_IFG(5) | DEV_MAC_IFG_CFG_RX_IFG1(5) |
238                DEV_MAC_IFG_CFG_RX_IFG2(1), regs + DEV_MAC_IFG_CFG);
239
240         /* Set link speed and release all resets */
241         writel(DEV_CLOCK_CFG_LINK_SPEED_1000, regs + DEV_CLOCK_CFG);
242
243         /* Make VLAN aware for CPU traffic */
244         writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
245                MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
246
247         /* Enable the port in the core */
248         setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port),
249                      QSYS_SWITCH_PORT_MODE_PORT_ENA);
250 }
251
252 static void serdes_write(void __iomem *base, u32 addr)
253 {
254         u32 data;
255
256         writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT |
257                HSIO_MCB_SERDES1G_CFG_ADDR(addr),
258                base + HSIO_MCB_SERDES1G_CFG);
259
260         do {
261                 data = readl(base + HSIO_MCB_SERDES1G_CFG);
262         } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
263 }
264
265 static void serdes1g_setup(void __iomem *base, uint32_t addr,
266                            phy_interface_t interface)
267 {
268         writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG);
269         writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0);
270         writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) |
271                HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) |
272                HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP |
273                HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM |
274                HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1),
275                base + HSIO_ANA_SERDES1G_IB_CFG);
276         writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) |
277                HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) |
278                HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) |
279                HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6),
280                base + HSIO_ANA_SERDES1G_DES_CFG);
281         writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) |
282                HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) |
283                HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) |
284                HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) |
285                HSIO_ANA_SERDES1G_OB_CFG_SLP(3),
286                base + HSIO_ANA_SERDES1G_OB_CFG);
287         writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
288                HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE,
289                base + HSIO_ANA_SERDES1G_COMMON_CFG);
290         writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA |
291                HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) |
292                HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2,
293                base + HSIO_ANA_SERDES1G_PLL_CFG);
294         writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST,
295                base + HSIO_DIG_SERDES1G_MISC_CFG);
296         serdes_write(base, addr);
297
298         writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
299                HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE |
300                HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST,
301                base + HSIO_ANA_SERDES1G_COMMON_CFG);
302         serdes_write(base, addr);
303
304         writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG);
305         serdes_write(base, addr);
306 }
307
308 static void serdes_setup(struct serval_private *priv)
309 {
310         size_t mask;
311         int i = 0;
312
313         for (i = 0; i < MAX_PORT; ++i) {
314                 if (!priv->ports[i].bus)
315                         continue;
316
317                 mask = BIT(priv->ports[i].serdes_index);
318                 serdes1g_setup(priv->regs[HSIO], mask,
319                                priv->ports[i].phy_mode);
320         }
321 }
322
323 static int serval_switch_init(struct serval_private *priv)
324 {
325         /* Reset switch & memories */
326         writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
327                priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
328
329         if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
330                               SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
331                 pr_err("Timeout in memory reset\n");
332                 return -EIO;
333         }
334
335         /* Enable switch core */
336         setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
337                      SYS_SYSTEM_RST_CORE_ENA);
338
339         serdes_setup(priv);
340
341         return 0;
342 }
343
344 static int serval_initialize(struct serval_private *priv)
345 {
346         int ret, i;
347
348         /* Initialize switch memories, enable core */
349         ret = serval_switch_init(priv);
350         if (ret)
351                 return ret;
352
353         /* Flush queues */
354         mscc_flush(priv->regs[QS], serval_regs_qs);
355
356         /* Setup frame ageing - "2 sec" - The unit is 6.5us on serval */
357         writel(SYS_FRM_AGING_ENA | (20000000 / 65),
358                priv->regs[SYS] + SYS_FRM_AGING);
359
360         for (i = 0; i < MAX_PORT; i++)
361                 serval_port_init(priv, i);
362
363         serval_cpu_capture_setup(priv);
364
365         debug("Ports enabled\n");
366
367         return 0;
368 }
369
370 static int serval_write_hwaddr(struct udevice *dev)
371 {
372         struct serval_private *priv = dev_get_priv(dev);
373         struct eth_pdata *pdata = dev_get_platdata(dev);
374
375         mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table,
376                            pdata->enetaddr, PGID_UNICAST);
377
378         writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
379
380         return 0;
381 }
382
383 static int serval_start(struct udevice *dev)
384 {
385         struct serval_private *priv = dev_get_priv(dev);
386         struct eth_pdata *pdata = dev_get_platdata(dev);
387         const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
388                                               0xff };
389         int ret;
390
391         ret = serval_initialize(priv);
392         if (ret)
393                 return ret;
394
395         /* Set MAC address tables entries for CPU redirection */
396         mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table, mac,
397                            PGID_BROADCAST);
398
399         writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
400                priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
401
402         /* It should be setup latter in serval_write_hwaddr */
403         mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table,
404                            pdata->enetaddr, PGID_UNICAST);
405
406         writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
407         return 0;
408 }
409
410 static void serval_stop(struct udevice *dev)
411 {
412         writel(ICPU_RESET_CORE_RST_PROTECT, BASE_CFG + ICPU_RESET);
413         writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_DEVCPU_GCB + PERF_SOFT_RST);
414 }
415
416 static int serval_send(struct udevice *dev, void *packet, int length)
417 {
418         struct serval_private *priv = dev_get_priv(dev);
419         u32 ifh[IFH_LEN];
420         u32 *buf = packet;
421
422         /*
423          * Generate the IFH for frame injection
424          *
425          * The IFH is a 128bit-value
426          * bit 127: bypass the analyzer processing
427          * bit 57-67: destination mask
428          * bit 28-29: pop_cnt: 3 disables all rewriting of the frame
429          * bit 20-27: cpu extraction queue mask
430          * bit 16: tag type 0: C-tag, 1: S-tag
431          * bit 0-11: VID
432          */
433         ifh[0] = IFH_INJ_BYPASS;
434         ifh[1] = (0x07);
435         ifh[2] = (0x7f) << 25;
436         ifh[3] = (IFH_TAG_TYPE_C << 16);
437
438         return mscc_send(priv->regs[QS], serval_regs_qs,
439                          ifh, IFH_LEN, buf, length);
440 }
441
442 static int serval_recv(struct udevice *dev, int flags, uchar **packetp)
443 {
444         struct serval_private *priv = dev_get_priv(dev);
445         u32 *rxbuf = (u32 *)net_rx_packets[0];
446         int byte_cnt = 0;
447
448         byte_cnt = mscc_recv(priv->regs[QS], serval_regs_qs, rxbuf, IFH_LEN,
449                              false);
450
451         *packetp = net_rx_packets[0];
452
453         return byte_cnt;
454 }
455
456 static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
457 {
458         int i = 0;
459
460         for (i = 0; i < SERVAL_MIIM_BUS_COUNT; ++i)
461                 if (miim[i].miim_base == base && miim[i].miim_size == size)
462                         return miim[i].bus;
463
464         return NULL;
465 }
466
467 static void add_port_entry(struct serval_private *priv, size_t index,
468                            size_t phy_addr, struct mii_dev *bus,
469                            u8 serdes_index, u8 phy_mode)
470 {
471         priv->ports[index].phy_addr = phy_addr;
472         priv->ports[index].bus = bus;
473         priv->ports[index].serdes_index = serdes_index;
474         priv->ports[index].phy_mode = phy_mode;
475 }
476
477 static int serval_probe(struct udevice *dev)
478 {
479         struct serval_private *priv = dev_get_priv(dev);
480         int i, ret;
481         struct resource res;
482         fdt32_t faddr;
483         phys_addr_t addr_base;
484         unsigned long addr_size;
485         ofnode eth_node, node, mdio_node;
486         size_t phy_addr;
487         struct mii_dev *bus;
488         struct ofnode_phandle_args phandle;
489         struct phy_device *phy;
490
491         if (!priv)
492                 return -EINVAL;
493
494         /* Get registers and map them to the private structure */
495         for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
496                 priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
497                 if (!priv->regs[i]) {
498                         debug
499                             ("Error can't get regs base addresses for %s\n",
500                              regs_names[i]);
501                         return -ENOMEM;
502                 }
503         }
504
505         /* Initialize miim buses */
506         memset(&miim, 0x0, sizeof(miim) * SERVAL_MIIM_BUS_COUNT);
507
508         /* iterate all the ports and find out on which bus they are */
509         i = 0;
510         eth_node = dev_read_first_subnode(dev);
511         for (node = ofnode_first_subnode(eth_node);
512              ofnode_valid(node);
513              node = ofnode_next_subnode(node)) {
514                 if (ofnode_read_resource(node, 0, &res))
515                         return -ENOMEM;
516                 i = res.start;
517
518                 ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
519                                                      0, 0, &phandle);
520                 if (ret)
521                         continue;
522
523                 /* Get phy address on mdio bus */
524                 if (ofnode_read_resource(phandle.node, 0, &res))
525                         return -ENOMEM;
526                 phy_addr = res.start;
527
528                 /* Get mdio node */
529                 mdio_node = ofnode_get_parent(phandle.node);
530
531                 if (ofnode_read_resource(mdio_node, 0, &res))
532                         return -ENOMEM;
533                 faddr = cpu_to_fdt32(res.start);
534
535                 addr_base = ofnode_translate_address(mdio_node, &faddr);
536                 addr_size = res.end - res.start;
537
538                 /* If the bus is new then create a new bus */
539                 if (!get_mdiobus(addr_base, addr_size))
540                         priv->bus[miim_count] =
541                                 mscc_mdiobus_init(miim, &miim_count, addr_base,
542                                                   addr_size);
543
544                 /* Connect mdio bus with the port */
545                 bus = get_mdiobus(addr_base, addr_size);
546
547                 /* Get serdes info */
548                 ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
549                                                      3, 0, &phandle);
550                 if (ret)
551                         return -ENOMEM;
552
553                 add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
554                                phandle.args[2]);
555         }
556
557         for (i = 0; i < MAX_PORT; i++) {
558                 if (!priv->ports[i].bus)
559                         continue;
560
561                 phy = phy_connect(priv->ports[i].bus,
562                                   priv->ports[i].phy_addr, dev,
563                                   PHY_INTERFACE_MODE_NONE);
564                 if (phy)
565                         board_phy_config(phy);
566         }
567
568         return 0;
569 }
570
571 static int serval_remove(struct udevice *dev)
572 {
573         struct serval_private *priv = dev_get_priv(dev);
574         int i;
575
576         for (i = 0; i < SERVAL_MIIM_BUS_COUNT; i++) {
577                 mdio_unregister(priv->bus[i]);
578                 mdio_free(priv->bus[i]);
579         }
580
581         return 0;
582 }
583
584 static const struct eth_ops serval_ops = {
585         .start        = serval_start,
586         .stop         = serval_stop,
587         .send         = serval_send,
588         .recv         = serval_recv,
589         .write_hwaddr = serval_write_hwaddr,
590 };
591
592 static const struct udevice_id mscc_serval_ids[] = {
593         {.compatible = "mscc,vsc7418-switch"},
594         { /* Sentinel */ }
595 };
596
597 U_BOOT_DRIVER(serval) = {
598         .name                           = "serval-switch",
599         .id                             = UCLASS_ETH,
600         .of_match                       = mscc_serval_ids,
601         .probe                          = serval_probe,
602         .remove                         = serval_remove,
603         .ops                            = &serval_ops,
604         .priv_auto_alloc_size           = sizeof(struct serval_private),
605         .platdata_auto_alloc_size       = sizeof(struct eth_pdata),
606 };