1/* @TAG(CUSTOM) */
2
3/**
4 * @file - cpswif.c
5 * lwIP Ethernet interface for CPSW port
6 *
7 */
8
9/**
10 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without modification,
14 * are permitted provided that the following conditions are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright notice,
17 *    this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 *    this list of conditions and the following disclaimer in the documentation
20 *    and/or other materials provided with the distribution.
21 * 3. The name of the author may not be used to endorse or promote products
22 *    derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
27 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 * OF SUCH DAMAGE.
34 *
35 * This file is part of the lwIP TCP/IP stack.
36 *
37 * Author: Adam Dunkels <adam@sics.se>
38 *
39 */
40
41/**
42 * Copyright (c) 2010 Texas Instruments Incorporated
43 *
44 * This file is dervied from the "ethernetif.c" skeleton Ethernet network
45 * interface driver for lwIP.
46 */
47#include "../lwiplib.h"
48#include <lwip/opt.h>
49#include <lwip/def.h>
50#include <lwip/mem.h>
51#include <lwip/pbuf.h>
52#include <lwip/sys.h>
53#include <lwip/stats.h>
54#include <lwip/snmp.h>
55#include <netif/etharp.h>
56#include <netif/ppp_oe.h>
57#include <lwip/err.h>
58#include "cpswif.h"
59#include <ethdrivers/helpers.h>
60#include <platsupport/io.h>
61#include <ethdrivers/raw.h>
62
63/* DriverLib Header Files required for this interface driver. */
64#include <ethdrivers/plat/cpsw.h>
65#include <ethdrivers/plat/mdio.h>
66#include <ethdrivers/plat/phy.h>
67
68#define PORT_1                                   0x0
69#define PORT_2                                   0x1
70#define PORT_0_MASK                              0x1
71#define PORT_1_MASK                              0x2
72#define PORT_2_MASK                              0x4
73#define HOST_PORT_MASK                           PORT_0_MASK
74#define SLAVE_PORT_MASK(slv_port_num)            (1 << slv_port_num)
75#define PORT_MASK                                (0x7)
76#define INDV_PORT_MASK(slv_port_num)             (1 << slv_port_num)
77
78#define ENTRY_TYPE                               0x30
79#define ENTRY_TYPE_IDX                           7
80#define ENTRY_FREE                               0
81
82/* MDIO input and output frequencies in Hz */
83#define MDIO_FREQ_INPUT                          125000000
84#define MDIO_FREQ_OUTPUT                         1000000
85
86#define MAX_TRANSFER_UNIT                        1500
87#define PBUF_LEN_MAX                             1520
88
89#define MIN_PKT_LEN                              60
90
91/* Define those to better describe the network interface. */
92#define IFNAME0                                  'e'
93#define IFNAME1                                  'n'
94
95#define MASK_LOWER_4BITS_BYTE                    (0x0F)
96#define MASK UPPER_4BITS_BYTE                    (0xF0)
97
98#define MASK_BROADCAST_ADDR                      (0xFF)
99#define MASK_MULTICAST_ADDR                      (0x01)
100
101#define ALE_ENTRY_VLAN                           0x20
102#define ALE_ENTRY_VLANUCAST                      0x30
103#define ALE_ENTRY_UCAST                          0x10
104#define ALE_ENTRY_MCAST                          0xD0
105#define ALE_ENTRY_OUI                            (0x80)
106#define ALE_ENTRY_ADDR                           (0x10)
107#define ALE_ENTRY_VLAN_ADDR                      (0x30)
108#define ALE_VLAN_ENTRY_MEMBER_LIST               0
109#define ALE_VLAN_ENTRY_FRC_UNTAG_EGR             3
110#define ALE_VLAN_ENTRY_MCAST_UNREG               (1)
111#define ALE_VLAN_ENTRY_MCAST_REG                 (2)
112#define ALE_VLAN_ENTRY_ID                        (3)
113#define ALE_VLAN_ID_MASK                         (0x0FFF)
114#define ALE_VLAN_ENTRY_ID_BIT0_BIT7              6
115#define ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11        7
116#define ALE_VLAN_ENTRY_TYPE_ID_BIT8_BIT11_ALIGN  (0x08)
117#define ALE_VLANUCAST_ENTRY_ID_BIT0_BIT7         6
118#define ALE_VLANUCAST_ENTRY_TYPE_ID_BIT8_BIT11   7
119#define ALE_UCAST_ENTRY_TYPE                     7
120#define ALE_UCAST_TYPE_MASK                      (0xC0)
121#define ALE_UCAST_TYPE_SHIFT                     (6)
122#define ALE_UCAST_TYPE_PERSISTANT                (0x00)
123#define ALE_UCAST_TYPE_UNTOUCHED                 (0x40)
124#define ALE_UCAST_TYPE_OUI                       (0x80)
125#define ALE_UCAST_TYPE_TOUCHED                   (0xC0)
126#define ALE_UCAST_ENTRY_DLR_PORT_BLK_SEC         8
127#define ALE_UCAST_ENTRY_DLR_BLK_SEC_MASK         (0x03)
128#define ALE_UCAST_ENTRY_PORT_SHIFT               2
129#define ALE_MCAST_ENTRY_TYPE_FWD_STATE           7
130#define ALE_MCAST_ENTRY_TYPE_FWD_STATE_SHIFT     (6)
131#define ALE_MCAST_ENTRY_PORTMASK_SUP             8
132#define ALE_MCAST_ENTRY_SUPER_MASK               (0x02)
133#define ALE_MCAST_ENTRY_SUPER_SHIFT              (1)
134#define ALE_MCAST_ENTRY_PORT_MASK                (0x1C)
135#define ALE_MCAST_ENTRY_PORTMASK_SHIFT           2
136
137#define SELECT_10_HALF                          (1 << 0)
138#define SELECT_10_FULL                          (1 << 1)
139#define SELECT_100_HALF                         (1 << 2)
140#define SELECT_100_FULL                         (1 << 3)
141#define SELECT_1000_HALF                        (1 << 4)
142#define SELECT_1000_FULL                        (1 << 5)
143
144#define SELECT_SPEED_10                         (0)
145#define SELECT_SPEED_100                        (1)
146#define SELECT_SPEED_1000                       (2)
147
148#define SELECT_FORCED                           (0)
149#define SELECT_AUTONEG                          (1)
150#define SELECT_BOTH                             (2)
151
152#define SELECT_HALF_DUPLEX                      (0)
153#define SELECT_FULL_DUPLEX                      (1)
154
155static void delay(uint32_t ms)
156{
157    volatile int i;
158    for (; ms > 0; ms--) {
159        for (i = 0; i < 1000000; i++) {
160        }
161    }
162}
163
164/**
165* Function to setup the instance parameters inside the interface
166* @param  driver   ethernet driver data structure
167* @return None.
168*/
169static void
170cpswif_inst_config(struct eth_driver *driver)
171{
172    struct beaglebone_eth_data *eth_data = (struct beaglebone_eth_data*)driver->eth_data;
173    struct cpswinst *cpswinst = ((struct beaglebone_eth_data *) driver->eth_data)->cpswinst;
174
175    /**
176     * Code is added for only instance 0. If more instances
177     * are there, assign base addresses and phy info here
178     */
179    cpswinst->ss_base = eth_data->iomm_address.eth_mmio_cpsw_reg;
180    cpswinst->mdio_base = eth_data->iomm_address.eth_mmio_cpsw_reg + 0x1000;
181    cpswinst->wrpr_base = eth_data->iomm_address.eth_mmio_cpsw_reg + 0x1200;
182    cpswinst->cpdma_base = eth_data->iomm_address.eth_mmio_cpsw_reg + 0x800;
183    cpswinst->ale_base = eth_data->iomm_address.eth_mmio_cpsw_reg + 0xD00;
184    cpswinst->cppi_ram_base = eth_data->iomm_address.eth_mmio_cpsw_reg + 0x2000;
185    cpswinst->host_port_base = eth_data->iomm_address.eth_mmio_cpsw_reg + 0x100;
186    cpswinst->port[PORT_1].port_base = eth_data->iomm_address.eth_mmio_cpsw_reg + 0x200;
187    cpswinst->port[PORT_1].sliver_base = eth_data->iomm_address.eth_mmio_cpsw_reg + 0xD80;
188    cpswinst->port[PORT_2].port_base =  eth_data->iomm_address.eth_mmio_cpsw_reg + 0x300;
189    cpswinst->port[PORT_2].sliver_base = eth_data->iomm_address.eth_mmio_cpsw_reg + 0xDC0;
190}
191
192/**
193 * Gives the index of the ALE entry which is free
194 * @param  cpswinst  The CPSW instance structure pointer
195 *
196 * @return index of the ALE entry which is free
197 *         ERR_VAL if entry not found
198 */
199static err_t
200cpswif_ale_entry_match_free(struct cpswinst *cpswinst)
201{
202    u32_t ale_entry[ALE_ENTRY_NUM_WORDS];
203    s32_t idx;
204
205    /* Check which ALE entry is free starting from 0th entry */
206    for (idx = 0; idx < MAX_ALE_ENTRIES; idx++) {
207        CPSWALETableEntryGet(cpswinst->ale_base, idx, ale_entry);
208
209        /* Break if the table entry is free */
210        if (((*(((u8_t *)ale_entry) + ENTRY_TYPE_IDX))
211                & ENTRY_TYPE) == ENTRY_FREE) {
212            return idx;
213        }
214    }
215
216    return ERR_VAL;
217}
218
219/**
220 * Sets a unicast entry in the ALE table.
221 * @param cpswinst   The CPSW instance structure pointer
222 * @param port_num   The slave port number
223 * @param eth_addr   Ethernet address
224 *
225 * @return None
226 */
227static void
228cpswif_ale_unicastentry_set(struct cpswinst *cpswinst, u32_t port_num,
229                            u8_t *eth_addr)
230{
231    volatile u32_t cnt;
232    volatile s32_t idx;
233    u32_t ale_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
234
235    for (cnt = 0; cnt < ETHARP_HWADDR_LEN; cnt++) {
236        *(((u8_t *)ale_entry) + cnt) = eth_addr[ETHARP_HWADDR_LEN - cnt - 1];
237    }
238
239    *(((u8_t *)ale_entry) + ALE_UCAST_ENTRY_TYPE) = ALE_ENTRY_UCAST;
240    *(((u8_t *)ale_entry) + ALE_UCAST_ENTRY_DLR_PORT_BLK_SEC) =
241        (port_num << ALE_UCAST_ENTRY_PORT_SHIFT);
242
243    idx = cpswif_ale_entry_match_free(cpswinst);
244
245    if (idx < MAX_ALE_ENTRIES ) {
246        CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_entry);
247    }
248}
249
250/**
251 * Sets a multicast entry in the ALE table
252 * @param cpswinst   The CPSW instance structure pointer
253 * @param portmask   The port mask for the port number
254 * @param eth_addr   Ethernet Address
255 *
256 * @return index of the ALE entry added
257 *         ERR_VAL if table entry is not free
258 */
259static void
260cpswif_ale_multicastentry_set(struct cpswinst *cpswinst, u32_t portmask,
261                              u8_t *eth_addr)
262{
263    volatile u32_t cnt;
264    volatile s32_t idx;
265    u32_t ale_entry[ALE_ENTRY_NUM_WORDS] = {0, 0, 0};
266
267    idx = cpswif_ale_entry_match_free(cpswinst);
268    if (idx < MAX_ALE_ENTRIES ) {
269        for (cnt = 0; cnt < ETHARP_HWADDR_LEN; cnt++) {
270            *(((u8_t *)ale_entry) + cnt) = eth_addr[ETHARP_HWADDR_LEN - cnt - 1];
271        }
272
273        *(((u8_t *)ale_entry) + ALE_MCAST_ENTRY_TYPE_FWD_STATE) = ALE_ENTRY_MCAST;
274        *(((u8_t *)ale_entry) + ALE_MCAST_ENTRY_PORTMASK_SUP) |=
275            (portmask << ALE_MCAST_ENTRY_PORTMASK_SHIFT);
276
277        CPSWALETableEntrySet(cpswinst->ale_base, idx, ale_entry);
278    }
279}
280
281/**
282 * AutoNegotiates with phy for link, set it in silver and check for link status.
283 * @param  cpswinst   The CPSW instance structure pointer
284 * @param  port_num    The slave port number
285 * @param  adv         Configuration for advertisement
286 *                     SELECT_10_HALF - 10Base Half Duplex
287 *                     SELECT_10_FULL - 10Base Full Duplex
288 *                     SELECT_100_HALF - 100Base Half Duplex
289 *                     SELECT_100_FULL - 100Base Full Duplex
290 *                     SELECT_1000_HALF - 1000Base Half Duplex
291 *                     SELECT_1000_FULL - 1000Base Full Duplex
292 * @return ERR_OK      If link set up is successful
293 *                     others if not successful
294 */
295static err_t
296cpswif_phy_autoneg(struct cpswinst *cpswinst, u32_t port_num, u32_t adv)
297{
298    err_t linkstat = ERR_CONN;
299    u16_t adv_val = 0, partnr_ablty = 0, gbps_partnr_ablty = 0, gig_adv_val = 0;
300    u32_t aut_neg_cnt = 200, auto_stat, transfer_mode = 0;
301
302    /* Check if ethernet PHY is present or not */
303    if (0 == (MDIOPhyAliveStatusGet(cpswinst->mdio_base)
304              & (1 << cpswinst->port[port_num - 1].phy_addr))) {
305        LWIP_PRINTF("\n\rNo PHY found at addr %d for Port %d of Instance %d.",
306                    cpswinst->port[port_num - 1].phy_addr,
307                    port_num, 0);
308        return linkstat;
309    }
310
311    LWIP_PRINTF("\n\rPHY found at address %d for  Port %d of Instance %d.",
312                cpswinst->port[port_num - 1].phy_addr,
313                port_num, 0);
314
315    if (SELECT_1000_HALF == adv) {
316        LWIP_PRINTF("\n\rCPSW doesnot support Half Duplex for Gigabyte...");
317        return linkstat;
318    }
319
320    /* We advertise for 10/100 Mbps both half and full duplex */
321    if (adv & SELECT_10_HALF) {
322        adv_val |= PHY_10BT;
323    }
324    if (adv & SELECT_10_FULL) {
325        adv_val |= PHY_10BT_FD;
326    }
327    if (adv & SELECT_100_HALF) {
328        adv_val |= PHY_100BTX;
329    }
330    if (adv & SELECT_100_FULL) {
331        adv_val |= PHY_100BTX_FD;
332    }
333
334    gig_adv_val = 0;
335    partnr_ablty = TRUE;
336    gbps_partnr_ablty = FALSE;
337
338    /**
339     * Not all the PHYs can operate at 1000 Mbps. So advertise only
340     * if the PHY is capable
341     */
342    if (cpswinst->port[port_num - 1].phy_gbps) {
343        LWIP_PRINTF("\n\rPhy supports Gigabyte...");
344        if (adv & SELECT_1000_FULL) {
345            gig_adv_val = PHY_1000BT_FD;
346            partnr_ablty = TRUE;
347            gbps_partnr_ablty = TRUE;
348        }
349        if (adv & SELECT_1000_HALF) {
350            LWIP_PRINTF("\n\rCPSW doesnot support Half Duplex for Gigabyte...");
351        }
352    } else {
353        LWIP_PRINTF("\n\rPhy doesnot support Gigabyte...");
354    }
355
356    LWIP_PRINTF("\n\rPerforming Auto-Negotiation...");
357
358    /**
359     * Now start Autonegotiation. PHY will talk to its partner
360     * and give us what the partner can handle
361     */
362    if (PhyAutoNegotiate(cpswinst->mdio_base,
363                         cpswinst->port[port_num - 1].phy_addr,
364                         &adv_val, &gig_adv_val) == TRUE) {
365        while (aut_neg_cnt) {
366            delay(50);
367            auto_stat = PhyAutoNegStatusGet(cpswinst->mdio_base,
368                                            cpswinst->port[port_num - 1].phy_addr);
369            if (TRUE == auto_stat) {
370                break;
371            }
372            aut_neg_cnt--;
373        }
374
375        if (0 != aut_neg_cnt) {
376            linkstat = ERR_OK;
377            LWIP_PRINTF("\n\rAuto-Negotiation Successful.");
378        } else {
379            LWIP_PRINTF("\n\rAuto-Negotiation Not Successful.");
380            return ERR_CONN;
381        }
382
383        /* Get what the partner supports */
384        PhyPartnerAbilityGet(cpswinst->mdio_base,
385                             cpswinst->port[port_num - 1].phy_addr,
386                             &partnr_ablty, &gbps_partnr_ablty);
387        if (gbps_partnr_ablty & PHY_LINK_PARTNER_1000BT_FD) {
388            LWIP_PRINTF("\n\rTransfer Mode : 1000 Mbps.");
389            transfer_mode = CPSW_SLIVER_GIG_FULL_DUPLEX;
390        } else {
391            if ((adv_val & partnr_ablty) & PHY_100BTX_FD) {
392                LWIP_PRINTF("\n\rTransfer Mode : 100 Mbps Full Duplex.");
393                transfer_mode = CPSW_SLIVER_NON_GIG_FULL_DUPLEX;
394            } else if ((adv_val & partnr_ablty) & PHY_100BTX) {
395                LWIP_PRINTF("\n\rTransfer Mode : 100 Mbps Half Duplex.");
396                transfer_mode = CPSW_SLIVER_NON_GIG_HALF_DUPLEX;
397            } else if ((adv_val & partnr_ablty) & PHY_10BT_FD) {
398                LWIP_PRINTF("\n\rTransfer Mode : 10 Mbps Full Duplex.");
399                transfer_mode = CPSW_SLIVER_INBAND | CPSW_SLIVER_NON_GIG_FULL_DUPLEX;
400            } else if ((adv_val & partnr_ablty) & PHY_10BT) {
401                LWIP_PRINTF("\n\rTransfer Mode : 10 Mbps Half Duplex.");
402                transfer_mode = CPSW_SLIVER_INBAND | CPSW_SLIVER_NON_GIG_HALF_DUPLEX;
403            } else {
404                LWIP_PRINTF("\n\rNo Valid Transfer Mode is detected.");
405            }
406        }
407    } else {
408        LWIP_PRINTF("\n\rAuto-Negotiation Not Successful.");
409        linkstat = ERR_CONN;
410    }
411
412    /**
413     * Set the Sliver with the negotiation results if autonegotiation
414     * is successful
415     */
416    if (linkstat == ERR_OK) {
417        CPSWSlTransferModeSet(cpswinst->port[port_num - 1].sliver_base,
418                              transfer_mode);
419    }
420
421    /* Check if PHY link is there or not */
422    if (FALSE == ((PhyLinkStatusGet(cpswinst->mdio_base,
423                                    cpswinst->port[port_num - 1].phy_addr, 1000)))) {
424        LWIP_PRINTF("\n\rPHY link connectivity failed for Port %d of Inst %d.",
425                    port_num, 0);
426        return linkstat;
427    }
428
429    LWIP_PRINTF("\n\rPHY link verified for Port %d of Instance %d.",
430                port_num, 0);
431
432    CPSWSlRGMIIEnable(
433        cpswinst->port[port_num - 1].sliver_base);
434
435    return linkstat;
436}
437
438/**
439 * Manually configure phy, set it in silver and check for link status.
440 * @param  cpswinst   The CPSW instance structure pointer
441 * @param  port_num    The slave port number
442 * @param  speed       Configuration for speed
443 *                     SELECT_SPEED_1000 - 1000 Mbps
444 *                     SELECT_SPEED_100 - 100 Mbps
445 *                     SELECT_SPEED_10 - 10 Mbps
446 * @param  duplex      Configuration for duplex
447 *                     SELECT_HALF_DUPLEX - Half Duplex
448 *                     SELECT_FULL_DUPLEX - Full Duplex
449 * @return ERR_OK      If link set up is successful
450 *                     others if not successful
451 */
452static err_t
453cpswif_phy_forced(struct cpswinst *cpswinst, u32_t port_num, u32_t speed,
454                  u32_t duplex)
455{
456    err_t linkstat = ERR_CONN;
457    u16_t speed_val = 0, duplex_val = 0;
458    u32_t frc_stat_cnt = 200, frc_stat = FALSE, transfer_mode = 0;
459
460    /* Check if ethernet PHY is present or not */
461    if (0 == (MDIOPhyAliveStatusGet(cpswinst->mdio_base)
462              & (1 << cpswinst->port[port_num - 1].phy_addr))) {
463        LWIP_PRINTF("\n\rNo PHY found at addr %d for Port %d of Instance %d.",
464                    cpswinst->port[port_num - 1].phy_addr,
465                    port_num, 0);
466        return linkstat;
467    }
468
469    LWIP_PRINTF("\n\rPHY found at address %d for  Port %d of Instance %d.",
470                cpswinst->port[port_num - 1].phy_addr,
471                port_num, 0);
472
473    /* configure control for speed and duples */
474    if (SELECT_SPEED_1000 == speed) {
475        speed_val = PHY_SPEED_1000MBPS;
476    } else if (SELECT_SPEED_100 == speed) {
477        speed_val = PHY_SPEED_100MBPS;
478    }
479
480    if (TRUE == duplex) {
481        duplex_val = PHY_FULL_DUPLEX;
482    }
483
484    if (SELECT_SPEED_1000 == speed) {
485        LWIP_PRINTF("\n\rManual Configuration not allowed for Gigabyte...");
486        return linkstat;
487    }
488
489    if (FALSE == PhyReset(cpswinst->mdio_base,
490                          cpswinst->port[port_num - 1].phy_addr)) {
491        LWIP_PRINTF("\n\rPHY Reset Failed...");
492        return linkstat;
493    }
494
495    if (TRUE == (PhyLinkStatusGet(cpswinst->mdio_base,
496                                  cpswinst->port[port_num - 1].phy_addr, 1000))) {
497        while (frc_stat_cnt) {
498            delay(50);
499            /* Check if PHY link is there or not */
500            frc_stat = (PhyLinkStatusGet(cpswinst->mdio_base,
501                                         cpswinst->port[port_num - 1].phy_addr, 1000));
502
503            if (TRUE == frc_stat) {
504                LWIP_PRINTF("\n\rPHY Link is Down.");
505                break;
506            }
507            frc_stat_cnt--;
508        }
509    }
510
511    LWIP_PRINTF("\n\rPerforming Manual Configuration...");
512
513    frc_stat_cnt = 200;
514    frc_stat = FALSE;
515
516    if (PhyConfigure(cpswinst->mdio_base, cpswinst->port[port_num - 1].phy_addr,
517                     speed_val, duplex_val)) {
518        while (frc_stat_cnt) {
519            delay(50);
520            frc_stat = PhyLinkStatusGet(cpswinst->mdio_base,
521                                        cpswinst->port[port_num - 1].phy_addr, 1000);
522
523            if (1 == frc_stat) {
524                break;
525            }
526            frc_stat_cnt--;
527        }
528
529        if (0 != frc_stat_cnt) {
530            linkstat = ERR_OK;
531            LWIP_PRINTF("\n\rPhy Configuration Successful.");
532            LWIP_PRINTF("\n\rPHY link verified for Port %d of Instance %d.",
533                        port_num, 0);
534        } else {
535            LWIP_PRINTF("\n\rPhy Configuration Successful.");
536            LWIP_PRINTF("\n\rPHY link connectivity failed for Port %d of Inst %d.",
537                        port_num, 0);
538            return ERR_CONN;
539        }
540
541        if (SELECT_SPEED_1000 == speed) {
542            LWIP_PRINTF("\n\rTransfer Mode : 1000 Mbps.");
543            transfer_mode = CPSW_SLIVER_GIG_FULL_DUPLEX;
544        } else {
545            if (SELECT_SPEED_10 == speed) {
546                LWIP_PRINTF("\n\rTransfer Mode : 10 Mbps ");
547                transfer_mode = CPSW_SLIVER_INBAND;
548            } else {
549                LWIP_PRINTF("\n\rTransfer Mode : 100 Mbps ");
550            }
551            if (TRUE == duplex) {
552                LWIP_PRINTF("Full Duplex.");
553                transfer_mode |= CPSW_SLIVER_NON_GIG_FULL_DUPLEX;
554            } else {
555                LWIP_PRINTF("Half Duplex.");
556                transfer_mode |= CPSW_SLIVER_NON_GIG_HALF_DUPLEX;
557            }
558        }
559    } else {
560        LWIP_PRINTF("\n\rPhy Configuration Not Successful.");
561        LWIP_PRINTF("\n\rPHY link connectivity failed for Port %d of Inst %d.",
562                    port_num, 0);
563        linkstat = ERR_CONN;
564    }
565
566    /**
567     * Set the Sliver with the forced phy configuration
568     */
569    CPSWSlTransferModeSet(cpswinst->port[port_num - 1].sliver_base,
570                          transfer_mode);
571
572    CPSWSlRGMIIEnable(cpswinst->port[port_num - 1].sliver_base);
573
574    return linkstat;
575}
576
577/**
578* Function to setup the link. AutoNegotiates with the phy for link
579* setup and set the CPSW with the result of autonegotiation.
580* @param  driver   ethernet driver data structure
581* @param  cpswportif  The cpsw port interface structure pointer
582* @return ERR_OK      If link set up is successful
583*                     others if not successful
584*/
585static err_t
586cpswif_autoneg_config(struct eth_driver *driver, u32_t inst_num, u32_t port_num)
587{
588    struct cpswinst *cpswinst = ((struct beaglebone_eth_data*)driver->eth_data)->cpswinst;
589    err_t linkstat = ERR_CONN;
590    u16_t adv_val, partnr_ablty, gbps_partnr_ablty, gig_adv_val;
591    u32_t aut_neg_cnt = 200, auto_stat, transfer_mode = 0;
592
593    /* We advertise for 10/100 Mbps both half and full duplex */
594    adv_val = (PHY_100BTX | PHY_100BTX_FD | PHY_10BT | PHY_10BT_FD);
595
596    /**
597     * Not all the PHYs can operate at 1000 Mbps. So advertise only
598     * if the PHY is capable
599     */
600    if (TRUE == cpswinst->port[port_num - 1].phy_gbps) {
601        gig_adv_val = PHY_1000BT_FD;
602        partnr_ablty = TRUE;
603        gbps_partnr_ablty = TRUE;
604    } else {
605        gig_adv_val = 0;
606        partnr_ablty = TRUE;
607        gbps_partnr_ablty = FALSE;
608    }
609
610    LWIP_PRINTF("\n\rPerforming Auto-Negotiation...");
611
612    /**
613     * Now start Autonegotiation. PHY will talk to its partner
614     * and give us what the partner can handle
615     */
616    if (PhyAutoNegotiate(cpswinst->mdio_base,
617                         cpswinst->port[port_num - 1].phy_addr,
618                         &adv_val, &gig_adv_val) == TRUE) {
619        while (aut_neg_cnt) {
620            delay(50);
621            auto_stat = PhyAutoNegStatusGet(cpswinst->mdio_base,
622                                            cpswinst->port[port_num - 1].phy_addr);
623            if (TRUE == auto_stat) {
624                break;
625            }
626            aut_neg_cnt--;
627        }
628
629        if (0 != aut_neg_cnt) {
630            linkstat = ERR_OK;
631            LWIP_PRINTF("\n\rAuto-Negotiation Successful.");
632        } else {
633            LWIP_PRINTF("\n\rAuto-Negotiation Not Successful.");
634            return ERR_CONN;
635        }
636
637        /* Get what the partner supports */
638        PhyPartnerAbilityGet(cpswinst->mdio_base,
639                             cpswinst->port[port_num - 1].phy_addr,
640                             &partnr_ablty, &gbps_partnr_ablty);
641        if (gbps_partnr_ablty & PHY_LINK_PARTNER_1000BT_FD) {
642            LWIP_PRINTF("\n\rTransfer Mode : 1000 Mbps.");
643            transfer_mode = CPSW_SLIVER_GIG_FULL_DUPLEX;
644        } else {
645            if ((adv_val & partnr_ablty) & PHY_100BTX_FD) {
646                LWIP_PRINTF("\n\rTransfer Mode : 100 Mbps Full Duplex.");
647                transfer_mode = CPSW_SLIVER_NON_GIG_FULL_DUPLEX;
648            } else if ((adv_val & partnr_ablty) & PHY_100BTX) {
649                LWIP_PRINTF("\n\rTransfer Mode : 100 Mbps Half Duplex.");
650                transfer_mode = CPSW_SLIVER_NON_GIG_HALF_DUPLEX;
651            } else if ((adv_val & partnr_ablty) & PHY_10BT_FD) {
652                LWIP_PRINTF("\n\rTransfer Mode : 10 Mbps Full Duplex.");
653                transfer_mode = CPSW_SLIVER_INBAND | CPSW_SLIVER_NON_GIG_FULL_DUPLEX;
654            } else if ((adv_val & partnr_ablty) & PHY_10BT) {
655                LWIP_PRINTF("\n\rTransfer Mode : 10 Mbps Half Duplex.");
656                transfer_mode = CPSW_SLIVER_INBAND | CPSW_SLIVER_NON_GIG_HALF_DUPLEX;
657            } else {
658                LWIP_PRINTF("\n\rNo Valid Transfer Mode is detected.");
659            }
660        }
661    } else {
662        LWIP_PRINTF("\n\rAuto-Negotiation Not Successful.");
663        linkstat = ERR_CONN;
664    }
665
666    /**
667     * Set the Sliver with the negotiation results if autonegotiation
668     * is successful
669     */
670    if (linkstat == ERR_OK) {
671        CPSWSlTransferModeSet(cpswinst->port[port_num - 1].sliver_base,
672                              transfer_mode);
673    }
674
675    return linkstat;
676}
677
678/**
679 * Configures PHY link for a port
680 * @param  driver   ethernet driver data structure
681 * @param cpswif  The CPSW interface structure pointer
682 * @param slv_port_num  The slave port number
683 *
684 * @return ERR_OK    if link configurations are successful
685 *                   an error status if failed
686 */
687static err_t
688cpswif_phylink_config(struct eth_driver *driver, struct cpswportif * cpswif, u32_t slv_port_num)
689{
690    struct cpswinst *cpswinst = ((struct beaglebone_eth_data*)driver->eth_data)->cpswinst;
691    err_t err;
692
693    /* Check if ethernet PHY is present or not */
694    if (0 == (MDIOPhyAliveStatusGet(cpswinst->mdio_base)
695              & (1 << cpswinst->port[slv_port_num - 1].phy_addr))) {
696        LWIP_PRINTF("\n\rNo PHY found at address %d for  Port %d of Instance %d.",
697                    cpswinst->port[slv_port_num - 1].phy_addr, slv_port_num,
698                    cpswif->inst_num);
699        return ERR_CONN;
700    }
701
702    LWIP_PRINTF("\n\rPHY found at address %d for  Port %d of Instance %d.",
703                cpswinst->port[slv_port_num - 1].phy_addr, slv_port_num,
704                cpswif->inst_num);
705
706    /**
707     * PHY is alive. So autonegotiate and get the speed and duplex
708     * parameters, set it in the sliver
709     */
710    err = (err_t)(cpswif_autoneg_config(driver, cpswif->inst_num, slv_port_num));
711
712    /* Check if PHY link is there or not */
713    if (FALSE == ((PhyLinkStatusGet(cpswinst->mdio_base,
714                                    cpswinst->port[slv_port_num - 1].phy_addr, 1000)))) {
715        LWIP_PRINTF("\n\rPHY link connectivity failed for Port %d of Instance %d.",
716                    slv_port_num, cpswif->inst_num);
717        return ERR_CONN;
718    }
719
720    LWIP_PRINTF("\n\rPHY link verified for Port %d of Instance %d.",
721                slv_port_num, cpswif->inst_num);
722
723    CPSWSlRGMIIEnable(cpswinst->port[slv_port_num - 1].sliver_base);
724
725    return err;
726}
727
728/**
729 * Initializes the CPSW port
730 * @param driver   ethernet driver data structure
731 *
732 * @return ERR_OK    if port initialization is successful
733 *                   an error status if failed
734 */
735static err_t
736cpswif_port_init(struct eth_driver *driver)
737{
738    struct beaglebone_eth_data *eth_data = (struct beaglebone_eth_data*)driver->eth_data;
739
740    struct cpswportif *cpswif = (struct cpswportif*) eth_data->cpswPortIf;
741
742    /* We only use one interface, comment out the following line if you need another */
743    //err = err & (cpswif_phylink_config(cpswif, 2));
744
745    return cpswif_phylink_config(driver, cpswif, 1);
746}
747
748/**
749 * This function intializes the CPDMA.
750 * The CPPI RAM will be initialized for transmit and receive
751 * buffer descriptor rings.
752 *
753 * @param  driver   ethernet driver data structure
754 * @return None
755 */
756static void
757cpswif_cpdma_init(struct eth_driver *driver)
758{
759    struct beaglebone_eth_data *eth_data = (struct beaglebone_eth_data*)driver->eth_data;
760    struct cpswinst *cpswinst = eth_data->cpswinst;
761    CPSWCPDMARxHdrDescPtrWrite(cpswinst->cpdma_base, ((struct descriptor *) eth_data->rx_ring_phys), 0);
762}
763
764/**
765 * In this function, the hardware should be initialized.
766 * Called from cpswif_init().
767 *
768 * @param driver   ethernet driver data structure
769 * @return None
770 */
771static void
772cpswif_inst_init(struct eth_driver *driver)
773{
774
775    struct beaglebone_eth_data *eth_data = (struct beaglebone_eth_data*)driver->eth_data;
776    struct cpswportif *cpswif = (struct cpswportif*) eth_data->cpswPortIf;
777    u32_t inst_num = cpswif->inst_num;
778
779    struct cpswinst *cpswinst = eth_data->cpswinst;
780
781    /* Reset the different modules */
782    CPSWSSReset(cpswinst->ss_base);
783    CPSWWrReset(cpswinst->wrpr_base);
784    CPSWSlReset(cpswinst->port[PORT_1].sliver_base);
785    CPSWSlReset(cpswinst->port[PORT_2].sliver_base);
786
787    __atomic_thread_fence(__ATOMIC_ACQ_REL);
788
789    CPSWCPDMAReset(cpswinst->cpdma_base);
790
791    /* Initialize MDIO */
792    MDIOInit(cpswinst->mdio_base, MDIO_FREQ_INPUT, MDIO_FREQ_OUTPUT);
793    delay(1);
794
795    __atomic_thread_fence(__ATOMIC_ACQ_REL);
796
797    CPSWALEInit(cpswinst->ale_base);
798
799    /* Set the port 0, 1 and 2 states to FORWARD */
800    CPSWALEPortStateSet(cpswinst->ale_base, 0, CPSW_ALE_PORT_STATE_FWD);
801    CPSWALEPortStateSet(cpswinst->ale_base, 1, CPSW_ALE_PORT_STATE_FWD);
802    CPSWALEPortStateSet(cpswinst->ale_base, 2, CPSW_ALE_PORT_STATE_FWD);
803
804    __atomic_thread_fence(__ATOMIC_ACQ_REL);
805
806    /* For normal CPSW switch mode, set multicast entry. */
807    u8_t bcast_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
808    cpswif_ale_multicastentry_set(cpswinst,
809                                  PORT_0_MASK | PORT_1_MASK | PORT_2_MASK,
810                                  bcast_addr);
811    cpswif_ale_unicastentry_set(cpswinst, 0,
812                                (u8_t *)(&(cpswif->eth_addr)));
813
814    /* Set the ethernet address for both the ports */
815    CPSWPortSrcAddrSet(cpswinst->port[0].port_base,
816                       (u8_t *)(&(cpswif->eth_addr)));
817    CPSWPortSrcAddrSet(cpswinst->port[1].port_base,
818                       (u8_t *)(&(cpswif->eth_addr)));
819
820    /* Enable the statistics. Lets see in case we come across any issues */
821    CPSWStatisticsEnable(cpswinst->ss_base);
822
823    /* Initialize the buffer descriptors for CPDMA */
824    cpswif_cpdma_init(driver);
825
826    __atomic_thread_fence(__ATOMIC_ACQ_REL);
827
828    /* Acknowledge receive and transmit interrupts for proper interrupt pulsing*/
829    CPSWCPDMAEndOfIntVectorWrite(cpswinst->cpdma_base, CPSW_EOI_TX_PULSE);
830    CPSWCPDMAEndOfIntVectorWrite(cpswinst->cpdma_base, CPSW_EOI_RX_PULSE);
831
832    /* Enable the transmission and reception */
833    CPSWCPDMATxEnable(cpswinst->cpdma_base);
834    CPSWCPDMARxEnable(cpswinst->cpdma_base);
835
836    /* Enable the interrupts for channel 0 and for control core 0 */
837    CPSWCPDMATxIntEnable(cpswinst->cpdma_base, 0);
838    CPSWWrCoreIntEnable(cpswinst->wrpr_base, 0, 0, CPSW_CORE_INT_TX_PULSE);
839
840    CPSWCPDMARxIntEnable(cpswinst->cpdma_base, 0);
841    CPSWWrCoreIntEnable(cpswinst->wrpr_base, 0, 0, CPSW_CORE_INT_RX_PULSE);
842
843    __atomic_thread_fence(__ATOMIC_ACQ_REL);
844}
845
846/**
847 * Should be called at the beginning of the program to set up the
848 * network interface. It calls the functions cpswif_inst_init() and
849 * cpswif_port_init() to do low level initializations
850 *
851 * @param driver   ethernet driver data structure
852 * @return ERR_OK   If the interface is initialized
853 *                  any other err_t on error
854 */
855err_t
856cpswif_init(struct eth_driver *driver)
857{
858    static u32_t inst_init_flag = 0;
859
860    struct beaglebone_eth_data *eth_data = (struct beaglebone_eth_data*)driver->eth_data;
861
862    /* We only use one instance */
863    u32_t inst_num = 0;
864
865    /**
866     * Initialize an instance only once. Port initialization will be
867     * done separately.
868     */
869    if (((inst_init_flag >> inst_num) & 0x01) == 0) {
870        cpswif_inst_config(driver);
871        cpswif_inst_init(driver);
872        inst_init_flag |= (1 << inst_num);
873    }
874
875    if (cpswif_port_init(driver) != ERR_OK) {
876        return ERR_CONN;
877    }
878
879    return ERR_OK;
880}
881
882/**
883 * Gets the netif status
884 *
885 * @param   netif   The netif whoes status to be checked
886 * @return  The netif status
887 */
888u32_t
889cpswif_netif_status(struct netif *netif)
890{
891    return ((u32_t)(netif_is_up(netif)));
892}
893
894/**
895 * Returns the link status
896 *
897 * @param   driver        Eth driver control structure
898 * @param   inst_num      The instance number of the module
899 * @param   slv_port_num  The slave port number for the module
900 *
901 * @return  the link status
902 */
903u32_t
904cpswif_link_status(struct eth_driver *driver, u32_t inst_num, u32_t slv_port_num)
905{
906    struct cpswinst *cpswinst = ((struct beaglebone_eth_data*)driver->eth_data)->cpswinst;
907
908    return (PhyLinkStatusGet(cpswinst->mdio_base,
909                             cpswinst->port[slv_port_num - 1].phy_addr, 3));
910}
911
912/**
913 * Checks the value is in the range of min and max
914 *
915 * @param   vlaue      Value
916 * @param   min        Minimum Value
917 * @param   max        Maximum Value
918 *
919 * @return  the status
920 */
921static u32_t
922check_valid(u32_t value, u32_t min, u32_t max)
923{
924    if ((min <= value) && (value <= max)) {
925        return TRUE;
926    } else {
927        return FALSE;
928    }
929}
930
931/*
932 * Executes following CPSW Configutarions
933 * Switch Configuration (CPSW_SWITCH_CONFIG has to be defined)
934 *  1 - Add a multicast entry
935 *  2 - Add a unicast entry
936 *  3 - Add a OUI entry
937 *  4 - Search address in entry list
938 *  5 - Delete a multicast entry
939 *  6 - Delete a unicast entry
940 *  7 - Adds a vlan entry
941 *  8 - Search vlan in entry list
942 *  9 - Delete vlan
943 * 10 - Configure Port Vlan (ID, CFI, PRI)
944 * 11 - Age Out the Untouched entries of ALE Table
945 * 12 - Print Dump of Switch
946 * 13 - Print Dump of Switch Config
947 * 14 - ALE VLAN Aware Config
948 * 15 - Configure Rate Limit for TX or RX
949 * 16 - Enable Engress Check
950 * 17 - Set port unknown VLAN info
951 * 18 - Enable MAC Auth
952 * 19 - Configure Port State
953 * Phy Configuration
954 *  1 - Configure PHY of a port
955 *
956 * @param  driver   ethernet driver data structure
957 * @param   cpsw_switch_config  parameters required for configuration
958 *
959 * @return  None
960*/
961void
962cpsw_switch_configuration(struct eth_driver *driver, struct cpsw_config *cpsw_config)
963{
964    struct cpswinst *cpswinst = ((struct beaglebone_eth_data*) driver->eth_data)->cpswinst;
965    struct cpsw_phy_param *cpsw_phy_param = cpsw_config->phy_param;
966
967    switch (cpsw_config->cmd) {
968    case CONFIG_SWITCH_SET_PORT_CONFIG: {
969        if (!check_valid(cpsw_phy_param->slv_port_num, MIN_SLV_PORT,
970                         MAX_SLV_PORT)) {
971            cpsw_config->ret = ERR_SLV_PORT;
972            break;
973        }
974
975        if (!check_valid(cpsw_phy_param->autoneg, MIN_AUTONEG, MAX_AUTONEG)) {
976            cpsw_config->ret = ERR_AUTONEG;
977            break;
978        }
979
980        if (TRUE == cpsw_phy_param->autoneg) {
981            if (!check_valid(cpsw_phy_param->config, MIN_PHY_CONFIG,
982                             MAX_PHY_CONFIG)) {
983                cpsw_config->ret = ERR_PHY_CONFIG;
984                break;
985            }
986        } else {
987            if (!check_valid(cpsw_phy_param->speed, MIN_SPEED, MAX_SPEED)) {
988                cpsw_config->ret = ERR_SPEED;
989                break;
990            }
991
992            if (!check_valid(cpsw_phy_param->duplex, MIN_DUPLEX, MAX_DUPLEX)) {
993                cpsw_config->ret = ERR_DUPLEX;
994                break;
995            }
996        }
997
998        if (cpsw_phy_param->autoneg)
999            cpswif_phy_autoneg(cpswinst, cpsw_phy_param->slv_port_num,
1000                               cpsw_phy_param->config);
1001        else
1002            cpswif_phy_forced(cpswinst, cpsw_phy_param->slv_port_num,
1003                              cpsw_phy_param->speed,
1004                              cpsw_phy_param->duplex);
1005
1006        cpsw_config->ret = ERR_PASS;
1007        break;
1008    }
1009
1010    default:
1011        cpsw_config->ret = ERR_INVAL;
1012        break;
1013    }
1014}
1015