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