diff options
author | Kinsey Moore <kinsey.moore@oarcorp.com> | 2022-04-14 12:32:14 -0500 |
---|---|---|
committer | Vijay Kumar Banerjee <vijay@rtems.org> | 2022-06-01 21:23:41 -0600 |
commit | 0b367b535083535896607710bbe8a46f8f6e0c74 (patch) | |
tree | ab3a45915a3a3400365c9842a2dd9a1647b510dc /uLan | |
parent | 5ad5279ca879c3cf0faf3141c84067bdf232c3a2 (diff) |
lwip: Split sources into origin directories
Moving forward, each origin directory should have its own top-level
COPYING.origin file to describe its license as well as a ORIGIN.origin
file to describe where the code is sourced from.
Diffstat (limited to 'uLan')
-rw-r--r-- | uLan/ports/driver/tms570_emac/eth_lwip.c | 188 | ||||
-rw-r--r-- | uLan/ports/driver/tms570_emac/eth_lwip.h | 100 | ||||
-rw-r--r-- | uLan/ports/driver/tms570_emac/eth_lwip_default.h | 48 | ||||
-rw-r--r-- | uLan/ports/driver/tms570_emac/phy_dp83848h.c | 179 | ||||
-rw-r--r-- | uLan/ports/driver/tms570_emac/phy_dp83848h.h | 225 | ||||
-rw-r--r-- | uLan/ports/driver/tms570_emac/ti_drv_emac.h | 472 | ||||
-rw-r--r-- | uLan/ports/driver/tms570_emac/ti_drv_mdio.h | 165 | ||||
-rw-r--r-- | uLan/ports/driver/tms570_emac/tms570_emac.h | 117 | ||||
-rw-r--r-- | uLan/ports/driver/tms570_emac/tms570_netif.c | 1227 | ||||
-rw-r--r-- | uLan/ports/driver/tms570_emac/tms570_netif.h | 60 | ||||
-rw-r--r-- | uLan/ports/os/lwipopts.h | 64 | ||||
-rw-r--r-- | uLan/ports/os/rtems/arch/cc.h | 177 | ||||
-rw-r--r-- | uLan/ports/os/rtems/arch/perf.h | 12 | ||||
-rw-r--r-- | uLan/ports/os/rtems/arch/sys_arch.c | 378 | ||||
-rw-r--r-- | uLan/ports/os/rtems/arch/sys_arch.h | 108 |
15 files changed, 3520 insertions, 0 deletions
diff --git a/uLan/ports/driver/tms570_emac/eth_lwip.c b/uLan/ports/driver/tms570_emac/eth_lwip.c new file mode 100644 index 0000000..b1ae4bb --- /dev/null +++ b/uLan/ports/driver/tms570_emac/eth_lwip.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2013, 2015 Czech Technical University in Prague + * Czech Republic + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Premysl Houdek <houdepre@fel.cvut.cz> + * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz> + * Industrial Informatics Group, FEE, Czech Technical University in Prague + * + * Based on work of Carlos Jenkins, Rostislav Lisovy, Jan Dolezal + */ + +//#define DEBUG 1 +#include "lwip/tcpip.h" /* includes - lwip/opt.h, lwip/api_msg.h, lwip/netifapi.h, lwip/pbuf.h, lwip/api.h, lwip/sys.h, lwip/timers.h, lwip/netif.h */ +#include "lwip/stats.h" +#include "lwip/dhcp.h" +#include "lwip/netifapi.h" +#include "netif/etharp.h" /* includes - lwip/ip.h, lwip/netif.h, lwip/ip_addr.h, lwip/pbuf.h */ +#include "eth_lwip_default.h" +#include "eth_lwip.h" +#include "tms570_netif.h" +#include <stdio.h> + +/* The lwIP network interface structure for the Ethernet EMAC. */ +#ifndef MAX_EMAC_INSTANCE +#define MAX_EMAC_INSTANCE 1 +#endif /*MAX_EMAC_INSTANCE*/ + +#define SUCCESS ERR_OK +#define FAILURE ERR_IF + +static struct netif eth_lwip_netifs[MAX_EMAC_INSTANCE]; +static void eth_lwip_conv_IP_decimal_Str(ip_addr_t ip, uint8_t *ipStr); + + +void +eth_lwip_get_dhcp_info(void) +{ + struct netif *netif = eth_lwip_get_netif(0); + + if (dhcp_supplied_address(netif)) { + uint8_t ipString[16]; // FIXME change the functions to use char + eth_lwip_conv_IP_decimal_Str(netif->ip_addr, ipString); + printf("Address: %s\n", ipString); + eth_lwip_conv_IP_decimal_Str(netif->netmask, ipString); + printf("Netmask: %s\n", ipString); + eth_lwip_conv_IP_decimal_Str(netif->gw, ipString); + printf("Gateway: %s\n", ipString); + } else { + printf("dhcp not bound\n"); + } +} + +int8_t +eth_lwip_init(uint8_t *mac_addr) +{ + unsigned int instance_number = 0; + int8_t retVal = SUCCESS; + + + ip4_addr_t ip_addr; + ip4_addr_t net_mask; + ip4_addr_t gw_addr; + struct netif *netif = ð_lwip_netifs[instance_number]; + struct netif *netif_tmp; + u8_t default_mac[MAC_ADDR_LEN] = ETH_MAC_ADDR; + + if (mac_addr == NULL) + mac_addr = default_mac; /* use default MAC */ + + eth_lwip_set_hwaddr(netif, mac_addr); + tcpip_init(NULL, NULL); + +#if STATIC_IP_ADDRESS + ip_addr.addr = htonl(ETH_IP_ADDR); + net_mask.addr = htonl(ETH_NETMASK); + gw_addr.addr = htonl(ETH_GW); +#else + ip_addr.addr = 0; + net_mask.addr = 0; + gw_addr.addr = 0; +#endif + + netif_tmp = netif_add(netif, &ip_addr, &net_mask, &gw_addr, + NULL, ETH_LWIP_INIT_NETIF_FNC, tcpip_input); + + if (netif_tmp == NULL) + return NETIF_ADD_ERR; + + netif_set_default(netif); + netifapi_netif_set_up(netif); +#if !STATIC_IP_ADDRESS + netifapi_dhcp_start(netif); +#endif + + return retVal; +} + +int +eth_lwip_get_netif_status_cmd(int argc, char *arg[]) +{ + stats_display(); + return 0; +} + +struct netif * +eth_lwip_get_netif(uint32_t instance_number) +{ + if (instance_number >= MAX_EMAC_INSTANCE) + return NULL; + return ð_lwip_netifs[instance_number]; +} + +static void +eth_lwip_conv_IP_decimal_Str(ip_addr_t ip, uint8_t *ipStr) +{ + uint32_t addr; + #if LWIP_IPV6 + addr = ip.u_addr.ip4.addr; + #else + addr = ip.addr; + #endif + + snprintf((char *)ipStr, 16, "%lu.%lu.%lu.%lu", + (addr >> 24), ((addr >> 16) & 0xff), ((addr >> 8) & 0xff), (addr & 0xff)); +} + +/* +* Function to set the MAC address to the interface +* @param inst_num the instance number +* +* @note mac_addr[0] is considered MSB +*/ +void +eth_lwip_set_hwaddr(struct netif *netif, uint8_t *mac_addr) +{ + int i; + + /* set MAC hardware address */ + for (i = 0; i < MAC_ADDR_LEN; i++) { + netif->hwaddr[i] = mac_addr[i]; + } + netif->hwaddr_len = MAC_ADDR_LEN; + +#ifdef DEBUG + uint8_t macStr[18]; + eth_lwip_get_hwaddr_str(netif, macStr); + printf("Setting MAC... %s\r\n", macStr); +#endif +} + +void +eth_lwip_get_hwaddr_str(struct netif *netif, uint8_t *macStr) +{ + uint8_t index, outindex = 0; + char ch; + + for (index = 0; index < netif->hwaddr_len; index++) { + if (index) + macStr[outindex++] = ':'; + ch = (netif->hwaddr[index] >> 4); + macStr[outindex++] = (ch < 10) ? (ch + '0') : (ch - 10 + 'A'); + ch = (netif->hwaddr[index] & 0xf); + macStr[outindex++] = (ch < 10) ? (ch + '0') : (ch - 10 + 'A'); + } + macStr[outindex] = 0; +} diff --git a/uLan/ports/driver/tms570_emac/eth_lwip.h b/uLan/ports/driver/tms570_emac/eth_lwip.h new file mode 100644 index 0000000..a9c0325 --- /dev/null +++ b/uLan/ports/driver/tms570_emac/eth_lwip.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2013, 2015 Czech Technical University in Prague + * Czech Republic + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Premysl Houdek <houdepre@fel.cvut.cz> + * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz> + * Industrial Informatics Group, FEE, Czech Technical University in Prague + * + * Based on work of Carlos Jenkins, Rostislav Lisovy, Jan Dolezal + */ + +#ifndef __ETH_LWIP_H +#define __ETH_LWIP_H + +#include <stdio.h> +#include <stdbool.h> +#include "lwip/netif.h" + + +/** + * While scanning phy addresses no alive phy was found. + * Return value of rpp_eth_hw_init() function. + */ +#define NO_PHY_ALIVE -1 +/** + * Scanning default phy address, it was found it's not alive. + * Return value of rpp_eth_hw_init() function. + */ +#define DFLT_PHY_NOT_ALIVE -1 +/** + * When setting autonegotiation parameters to EMAC module, there was found impossible mode (usually on timeout of autonegotiation). + * Return value of rpp_eth_hw_init_postInit() function. + */ +#define UNKN_DUPLEX_MODE -2 /* this could mean that autonegotiation was not completed yet */ +/** + * Phy is down error. + * Return value of rpp_eth_init_postInit() function. + */ +#define PHY_LINK_DOWN -3 + +/** + * LwIP netif couldn't be added, it is likely that there was an error during initialization of the hardware. + */ +#define NETIF_ADD_ERR -10 /* could be one of previous, except PHY_LINK_DOWN - currently */ +/** + * Memory requirements couldn't be satisfied. + */ +#define DHCP_MEM_ERR -11 + +/** + * configures whether rpp_eth_get_macAddrStr() creates string with big or small latin letters + */ +#define MAC_BIG_LETTERS 1 + +/** + * ETH module system startup initialization. + * + * Call this method before using this module. + * This method starts autonegotiation and doesn't check for end of autoneg. + * When eth module is about to be used, you have to run rpp_eth_init_postInit() + * first and you should check whether link is up. + * + * @return SUCCESS if initialization successful.\n + * FAILURE if module already initialized. + */ +int8_t eth_lwip_init(uint8_t *mac_addr); +void eth_lwip_get_dhcp_info(void); +int eth_lwip_get_netif_status_cmd(int argc, char *arg[]); +void eth_lwip_set_hwaddr(struct netif *netif, uint8_t *mac_addr); +void eth_lwip_get_hwaddr_str(struct netif *netif, uint8_t *macStr); +struct netif *eth_lwip_get_netif(uint32_t instance_number); + + + + + + +#endif /* __ETH_LWIP_H */ diff --git a/uLan/ports/driver/tms570_emac/eth_lwip_default.h b/uLan/ports/driver/tms570_emac/eth_lwip_default.h new file mode 100644 index 0000000..6194d06 --- /dev/null +++ b/uLan/ports/driver/tms570_emac/eth_lwip_default.h @@ -0,0 +1,48 @@ +#ifndef __ETH_LWIP_DEFAULT_H +#define __ETH_LWIP_DEFAULT_H + +/* #define DEBUG 1 */ +/* #define STATIC_IP_ADDRESS 1 */ + +void tms570_eth_memp_avaible(int type); + +#define ETH_LWIP_INIT_NETIF_FNC tms570_eth_init_netif +/*called from memp_free() when a memp pool was empty and an item is now available*/ +#define LWIP_HOOK_MEMP_AVAILABLE tms570_eth_memp_avaible + +/* this MAC address is used when user put NULL on the right place when calling postInit function */ +/** + * Default MAC address for interface. + */ +#define MAC_ADDR_LEN ETHARP_HWADDR_LEN + +#ifndef ETH_MAC_ADDR +#define ETH_MAC_ADDR { 0x12 /* Unicast, Locally administered */, 0x34, 0x56, 0x78, 0x9A, 0xBC } +#endif + +#if STATIC_IP_ADDRESS + +/** + * When static IP is configured in lwipopts.h, this IP address is used for interface. + */ +#ifndef ETH_IP_ADDR +#define ETH_IP_ADDR 0xC0A8F701 /* 192.168.247.1 */ +#endif + +/** + * When static IP is configured in lwipopts.h, this NETMASK address is used for interface. + */ +#ifndef ETH_NETMASK +#define ETH_NETMASK 0xFFFFFF00 /* 255.255.255.0 */ +#endif + +/** + * When static IP is configured in lwipopts.h, this Gateway address is used for interface. + */ +#ifndef ETH_GW +#define ETH_GW 0xC0A8F7FE /* 192.168.247.254*/ +#endif + +#endif /* STATIC_IP_ADDRESS */ + +#endif /* __ETH_LWIP_DEFAULT_H */ diff --git a/uLan/ports/driver/tms570_emac/phy_dp83848h.c b/uLan/ports/driver/tms570_emac/phy_dp83848h.c new file mode 100644 index 0000000..d20f669 --- /dev/null +++ b/uLan/ports/driver/tms570_emac/phy_dp83848h.c @@ -0,0 +1,179 @@ +/* +* Copyright (C) 2009-2015 Texas Instruments Incorporated - www.ti.com +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#include "ti_drv_mdio.h" +#include "phy_dp83848h.h" + +#ifndef TRUE +/** + * Boolean definition for TRUE + */ +#define TRUE 1 +#endif + + +#ifndef FALSE +/** + * Boolean definition for FALSE + */ +#define FALSE 0 +#endif + +void +PHY_reset(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr) +{ + volatile unsigned short regContent; + + MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BMCR, PHY_RESET_m); + while (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMCR, ®Content) & PHY_RESET_m); +} + +uint32_t +PHY_partner_ability_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short *regContent) +{ + return (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_ANLPAR, regContent)); +} + +uint32_t +PHY_start_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short advVal) +{ + volatile unsigned short regContent = 0; + + /* Enable Auto Negotiation */ + if (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMCR, ®Content) != TRUE) { + return FALSE; + } + regContent |= PHY_AUTONEG_EN_m; + MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BMCR, regContent); /* originally ...HY_BMCR, PHY_RESET_m | PHY_AUTONEG_EN_m); */ + + /* Write Auto Negotiation capabilities */ + if (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_ANAR, ®Content) != TRUE) { + return FALSE; + } + regContent |= advVal; + MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_ANAR, regContent); + + /* Start Auto Negotiation */ + MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMCR, ®Content); + regContent |= PHY_AUTONEG_REST; + MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BMCR, regContent); + + return TRUE; /* request to PHY through EMAC for autonegotiation established */ +} + +uint32_t +PHY_is_done_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr) +{ + volatile unsigned short regContent; + + if (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMSR, ®Content) != TRUE) { + return FALSE; + } + if ((regContent & PHY_A_NEG_COMPLETE_m) == 0) + return FALSE; + return TRUE; +} + +uint32_t +PHY_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short advVal) +{ + if (PHY_start_auto_negotiate(mdioBaseAddr, phyAddr, advVal) == FALSE) + return FALSE; + + while (PHY_is_done_auto_negotiate(mdioBaseAddr, phyAddr) == FALSE); + + return TRUE; +} + +uint32_t +PHY_link_status_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, volatile uint32_t retries) +{ + volatile unsigned short linkStatus; + volatile uint32_t retVal = TRUE; + + while (retVal == TRUE) { + /* Read the BSR of the PHY */ + MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMSR, &linkStatus); + + if (linkStatus & PHY_LINK_STATUS_m) { + break; + } else + { + (retries != 0) ? retries-- : (retVal = FALSE); + } + } + + return retVal; +} + +uint32_t +PHY_RMII_mode_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr) +{ + volatile unsigned short regContent; + + /* Read the RBR of the PHY */ + MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_RBR, ®Content); + return (regContent & PHY_RMII_MODE); +} + +void +PHY_MII_mode_set(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, uint32_t mode) +{ + volatile unsigned short regContent; + + /* Read the RBR of the PHY */ + MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_RBR, ®Content); + /* Write the RBR of the PHY */ + regContent &= 0x1f; + regContent |= ( mode << 5 ); + MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_RBR, regContent); +} + +void +PHY_Power_Down(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr) +{ + volatile unsigned short regContent; + + MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMCR, ®Content); + MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BMCR, regContent | PHY_POWERDOWN_m); +} + +void +PHY_Power_Up(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr) +{ + volatile unsigned short regContent; + + MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMCR, ®Content); + MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BMCR, regContent & ~PHY_POWERDOWN_m); +} diff --git a/uLan/ports/driver/tms570_emac/phy_dp83848h.h b/uLan/ports/driver/tms570_emac/phy_dp83848h.h new file mode 100644 index 0000000..58d9f04 --- /dev/null +++ b/uLan/ports/driver/tms570_emac/phy_dp83848h.h @@ -0,0 +1,225 @@ +/* +* Copyright (C) 2009-2015 Texas Instruments Incorporated - www.ti.com +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef __DRV_PHY_H +#define __DRV_PHY_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* ************************************************* */ +/* PHY - register offset definition */ +/* ************************************************* */ +#define PHY_BMCR 0x00u /* Basic Mode Control Register */ /*RW*/ +#define PHY_BMSR 0x01u /* Basic Mode Status Register */ /*RO*/ +#define PHY_IDR1 0x02u /* PHY Identifier Register #1 */ /*RO*/ +#define PHY_IDR2 0x03u /* PHY Identifier Register #2 */ /*RO*/ +#define PHY_ANAR 0x04u /* Auto-Negotiation Advertisement Register */ /*RW*/ +#define PHY_ANLPAR 0x05u /* Auto-Negotiation Link Partner Ability Register */ /*RW*/ +#define PHY_ANER 0x06u /* Auto-Negotiation Expansion Register */ /*RW*/ +#define PHY_ANNPTR 0x07u /* Auto-Negotiation Next Page TX */ /*RW*/ +/*Extended Registers*/ +#define PHY_STS 0x10u /* PHY Status Register */ /*RO*/ +#define PHY_RBR 0x17u /* RMII and Bypass Register */ +#define PHY_LEDCR 0x18u /* LED Direct Control Register */ /*RW*/ +#define PHY_PHYCR 0x19u /* PHY Control Register */ /*RW*/ +/* #define PHY_PHYCR2 0x1C */ /* PHY Control Register 2 */ /*RW*/ /* in doc offset 0x1C marked as RESERVED */ +#define PHY_EDCR 0x1Du /* Energy detect control register */ /*RW*/ + +/* PHY_BMCR - bit position definition */ +#define PHY_RESET_m (1 << 15) +#define PHY_LPBK_m (1 << 14) +#define PHY_SPEED_m (1 << 13) +#define PHY_AUTONEG_EN_m (1 << 12) /* ! */ +#define PHY_POWERDOWN_m (1 << 11) +#define PHY_DUPLEX_m (1 << 8) +#define PHY_AUTONEG_REST (1 << 9) + +/* PHY_BMSR - bit position definition */ +#define PHY_A_NEG_COMPLETE_m (1 << 5) +#define PHY_A_NEG_ABLE_m (1 << 3) +#define PHY_LINK_STATUS_m (1 << 2) + +/* PHY_ANAR & PHY_ANLPAR - bit position definition */ +#define PHY_PAUSE_ASYM (1 << 11) +#define PHY_PAUSE_SYM (1 << 10) +#define PHY_100BASET4_m (1 << 9) +#define PHY_100BASETXDUPL_m (1 << 8) +#define PHY_100BASETX_m (1 << 7) +#define PHY_10BASETDUPL_m (1 << 6) +#define PHY_10BASET_m (1 << 5) + +/* RBR */ +#define PHY_RMII_MODE (1 << 5) /* Reduced Media Independent Interface mode */ +#define PHY_MII_MODE (0) /* Standard Media Independent Interface mode */ +#define PHY_RMII_REV1_0 (1 << 4) +#define PHY_RMII_REV1_2 (0) + +/* ************************************************* */ +/* API - function prototypes */ +/* ************************************************* */ + +/** + * Resets PHY + * + * @param mdioBaseAddr Base Address of MDIO Module Megisters. + * @param phyAddr PHY Address (0-31). + * + * @note Software driver code must wait 3 μs following a software + * reset before allowing further serial MII operations with the DP83848H. + * This must be implemented in the layer above. + * @note Calling this function is blocking until PHY indicates the reset process is complete. + */ +void PHY_reset(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr); + +/** + * Reads link partner ability register from the PHY + * + * @param mdioBaseAddr Base Address of MDIO Module Megisters. + * @param phyAddr PHY Address (0-31). + * @param regContent The partner abilities of the EMAC. + * + * @return TRUE if reading succesful, FALSE if reading failed + */ +uint32_t PHY_partner_ability_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short *regContent); + +/** + * This function does Autonegotiates with the EMAC device connected + * to the PHY. It will wait till the autonegotiation completes. + * + * @param mdioBaseAddr Base Address of MDIO Module Megisters. + * @param phyAddr PHY Address (0-31). + * @param advValue Autonegotiation advertisement value \n + * advVal can take the following any OR combination of the values: + * PHY_100BASETXDUPL_m - full duplex capability for 100BaseTX + * PHY_100BASETX_m - half duplex capability for 100BaseTX + * PHY_10BASETDUPL_m - full duplex capability for 10BaseT + * PHY_10BASET_m - half duplex capability for 10BaseT + * + * @return TRUE if autonegotiation succesful, FALSE if autonegotiation failed + * + * @note this function is blocking, waits till link is established + */ +uint32_t PHY_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short advVal); + +/** + * This function starts autonegotiaon with the EMAC device connected + * to the PHY. For examining, whether autonegotiation is done see + * PHY_start_auto_negotiate function. + * + * @param mdioBaseAddr Base Address of MDIO Module Megisters. + * @param phyAddr PHY Address (0-31). + * @param advValue Autonegotiation advertisement value \n + * advVal can take the following any OR combination of the values: + * PHY_100BASETXDUPL_m - full duplex capability for 100BaseTX + * PHY_100BASETX_m - half duplex capability for 100BaseTX + * PHY_10BASETDUPL_m - full duplex capability for 10BaseT + * PHY_10BASET_m - half duplex capability for 10BaseT + * + * @return TRUE if setting autonegotiation startup succesful, + * FALSE if starting autonegotiation failed + */ +uint32_t PHY_start_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short advVal); + +/** + * This function examines, whether autonegotiation is done. + * Must be called after PHY_start_auto_negotiate. + * + * @param mdioBaseAddr Base Address of MDIO Module Megisters. + * @param phyAddr PHY Address (0-31). + * + * @return TRUE if autonegotiation succesfull and done, FALSE if autonegotiation failed. + */ +uint32_t PHY_is_done_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr); + +/** + * Reads the link status of the PHY. + * + * @param mdioBaseAddr Base Address of the MDIO Module Registers. + * @param phyAddr PHY Address (0-31). + * @param retries The number of retries before indicating down status. + * + * @return link status after reading \n + * TRUE if link is up + * FALSE if link is down \n + * + * @note This reads both the basic status register of the PHY and the + * link register of MDIO for double check + **/ +uint32_t PHY_link_status_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, volatile uint32_t retries); + +/** + * Fetches RMII/MII mode of PHY. + * + * @param mdioBaseAddr Base Address of the MDIO Module Registers. + * @param phyAddr PHY Address (0-31). + * + * @return TRUE if mode of PHY is set to RMII \ + * FALSE if mode of PHY is set to MII + */ +uint32_t PHY_RMII_mode_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr); + +/** + * Sets RMII/MII mode of PHY. + * + * @param mdioBaseAddr Base Address of the MDIO Module Registers. + * @param phyAddr PHY Address (0-31). + * @param mode Mode to set. \ + * 1 - RMII \ + * 0 - MII + */ +void PHY_MII_mode_set(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, uint32_t mode); + +/** + * Powers down the PHY. + * + * @param mdioBaseAddr Base Address of the MDIO Module Registers. + * @param phyAddr PHY Address (0-31). + */ +void PHY_Power_Down(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr); + + +/** + * Powers up the PHY. + * + * @param mdioBaseAddr Base Address of the MDIO Module Registers. + * @param phyAddr PHY Address (0-31). + */ +void PHY_Power_Up(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr); + +#ifdef __cplusplus +} +#endif +#endif /* __DRV_PHY_H */ diff --git a/uLan/ports/driver/tms570_emac/ti_drv_emac.h b/uLan/ports/driver/tms570_emac/ti_drv_emac.h new file mode 100644 index 0000000..54f22c8 --- /dev/null +++ b/uLan/ports/driver/tms570_emac/ti_drv_emac.h @@ -0,0 +1,472 @@ +/* +* Copyright (C) 2009-2015 Texas Instruments Incorporated - www.ti.com +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +/*****************************************************************************/ +#include <stdint.h> +#include <bsp/tms570.h> +/* +** Macros which can be used as matchFilt parameters to the API +** EMACMACAddrSet +*/ + +/* +** Macros which can be passed as eoiFlag to EMACRxThreshIntAckToClear API +*/ +#define EMAC_INT_CORE0_RX_THRSH (0x0u) +#define EMAC_INT_CORE1_RX_THRSH (0x4u) +#define EMAC_INT_CORE2_RX_THRSH (0x8u) + +/* +** Macros which can be passed as eoiFlag to EMACRxIntAckToClear API +*/ +#define EMAC_INT_CORE0_RX (0x1u) +#define EMAC_INT_CORE1_RX (0x5u) +#define EMAC_INT_CORE2_RX (0x9u) + +/* +** Macros which can be passed as eoiFlag to EMACTxIntAckToClear API +*/ +#define EMAC_INT_CORE0_TX (0x2u) +#define EMAC_INT_CORE1_TX (0x6u) +#define EMAC_INT_CORE2_TX (0xAu) + +/* +** Macros which can be passed as eoiFlag to EMACMiscIntAckToClear API +** STATPEND, HOSTPEND, MDIO LINKINT0, MDIO USERINT0 +*/ +#define EMAC_INT_CORE0_MISC (0x3u) +#define EMAC_INT_CORE1_MISC (0x7u) +#define EMAC_INT_CORE2_MISC (0xBu) + +/*****************************************************************************/ +/** + * \brief Enables the TXPULSE Interrupt Generation. + * + * \param emacBase Base address of the EMAC Module registers. + * \param emacCtrlBase Base address of the EMAC CONTROL module registers + * \param ctrlCore Control core for which the interrupt to be enabled. + * \param channel Channel number for which interrupt to be enabled + * + * \return None + * + **/ +static inline void +EMACTxIntPulseEnable(volatile tms570_emacm_t *emacBase, volatile tms570_emacc_t *emacCtrlBase, + unsigned int ctrlCore, unsigned int channel) +{ + emacBase->TXINTMASKSET |= (1 << channel); + emacCtrlBase->C0TXEN |= (1 << channel); +} + +/** + * \brief Disables the TXPULSE Interrupt Generation. + * + * \param emacBase Base address of the EMAC Module registers. + * \param emacCtrlBase Base address of the EMAC CONTROL module registers + * \param ctrlCore Control core for which the interrupt to be disabled. + * \param channel Channel number for which interrupt to be disabled + * + * \return None + * + **/ +static inline void +EMACTxIntPulseDisable(volatile tms570_emacm_t *emacBase, volatile tms570_emacc_t *emacCtrlBase, + unsigned int ctrlCore, unsigned int channel) +{ + emacBase->TXINTMASKCLEAR |= (1 << channel); + emacCtrlBase->C0TXEN &= ~(1 << channel); +} + +/** + * \brief Enables the RXPULSE Interrupt Generation. + * + * \param emacBase Base address of the EMAC Module registers. + * \param emacCtrlBase Base address of the EMAC CONTROL module registers + * \param ctrlCore Control core for which the interrupt to be enabled. + * \param channel Channel number for which interrupt to be enabled + * + * \return None + * + **/ +static inline void +EMACRxIntPulseEnable(volatile tms570_emacm_t *emacBase, volatile tms570_emacc_t *emacCtrlBase, + unsigned int ctrlCore, unsigned int channel) +{ + emacBase->RXINTMASKSET |= (1 << channel); + emacCtrlBase->C0RXEN |= (1 << channel); +} + +/** + * \brief This API enables the MII control block + * + * \param emacBase Base address of the EMAC Module registers. + * + * \return None + * + **/ +static inline void +EMACMIIEnable(volatile tms570_emacm_t *emacBase) +{ + emacBase->MACCONTROL |= TMS570_EMACM_MACCONTROL_GMIIEN; +} + +/** + * \brief This API sets the duplex mode of operation(full/half) for MAC. + * + * \param emacBase Base address of the EMAC Module registers. + * \param duplexMode duplex mode of operation. + * duplexMode can take the following values. \n + * nonZero - Full Duplex \n + * 0 - Half Duplex. + * + * \return None + * + **/ +static inline void +EMACDuplexSet(volatile tms570_emacm_t *emacBase, int duplexMode) +{ + if (duplexMode) { + emacBase->MACCONTROL |= TMS570_EMACM_MACCONTROL_FULLDUPLEX; + } else { + emacBase->MACCONTROL &= ~TMS570_EMACM_MACCONTROL_FULLDUPLEX; + } +} + +/** + * \brief API to enable the transmit in the TX Control Register + * After the transmit is enabled, any write to TXHDP of + * a channel will start transmission + * + * \param emacBase Base Address of the EMAC Module Registers. + * + * \return None + * + **/ +static inline void +EMACTxEnable(volatile tms570_emacm_t *emacBase) +{ + emacBase->TXCONTROL = TMS570_EMACM_TXCONTROL_TXEN; +} + +/** + * \brief API to enable the receive in the RX Control Register + * After the transmit is enabled, and write to RXHDP of + * a channel, the data can be received in the destination + * specified by the corresponding RX buffer descriptor. + * + * \param emacBase Base Address of the EMAC Module Registers. + * + * \return None + * + **/ +static inline void +EMACRxEnable(volatile tms570_emacm_t *emacBase) +{ + emacBase->RXCONTROL = TMS570_EMACM_RXCONTROL_RXEN; +} + +/** + * \brief API to write the TX HDP register. If transmit is enabled, + * write to the TX HDP will immediately start transmission. + * The data will be taken from the buffer pointer of the TX buffer + * descriptor written to the TX HDP + * + * \param emacBase Base Address of the EMAC Module Registers.\n + * \param descHdr Address of the TX buffer descriptor + * \param channel Channel Number + * + * \return None + * + **/ +static inline void +EMACTxHdrDescPtrWrite(volatile tms570_emacm_t *emacBase, unsigned int descHdr, + unsigned int channel) +{ + emacBase->TXHDP[channel] = descHdr; +} + +/** + * \brief API to write the RX HDP register. If receive is enabled, + * write to the RX HDP will enable data reception to point to + * the corresponding RX buffer descriptor's buffer pointer. + * + * \param emacBase Base Address of the EMAC Module Registers.\n + * \param descHdr Address of the RX buffer descriptor + * \param channel Channel Number + * + * \return None + * + **/ +static inline void +EMACRxHdrDescPtrWrite(volatile tms570_emacm_t *emacBase, unsigned int descHdr, + unsigned int channel) +{ + emacBase->RXHDP[channel] = descHdr; +} + +/** + * \brief Sets the MAC Address in MACSRCADDR registers. + * + * \param emacBase Base Address of the EMAC module registers. + * \param macAddr Start address of a MAC address array. + * The array[0] shall be the LSB of the MAC address + * + * \return None + * + **/ +static inline void +EMACMACSrcAddrSet(volatile tms570_emacm_t *emacBase, unsigned char *macAddr) +{ + emacBase->MACSRCADDRHI = macAddr[5] |(macAddr[4] << 8) + |(macAddr[3] << 16) |(macAddr[2] << 24); + emacBase->MACSRCADDRLO = macAddr[1] | (macAddr[0] << 8); +} + +/** + * \brief Sets the MAC Address in MACADDR registers. + * + * \param emacBase Base Address of the EMAC module registers. + * \param channel Channel Number + * \param matchFilt Match or Filter + * \param macAddr Start address of a MAC address array. + * The array[0] shall be the LSB of the MAC address + * matchFilt can take the following values \n + * EMAC_MACADDR_NO_MATCH_NO_FILTER - Address is not used to match + * or filter incoming packet. \n + * EMAC_MACADDR_FILTER - Address is used to filter incoming packets \n + * EMAC_MACADDR_MATCH - Address is used to match incoming packets \n + * + * \return None + * + **/ +static inline void +EMACMACAddrSet(volatile tms570_emacm_t *emacBase, unsigned int channel, + unsigned char *macAddr, unsigned int matchFilt) +{ + emacBase->MACINDEX = channel; + + emacBase->MACADDRHI = macAddr[5] |(macAddr[4] << 8) + |(macAddr[3] << 16) |(macAddr[2] << 24); + emacBase->MACADDRLO = macAddr[1] | (macAddr[0] << 8) + | matchFilt | (channel << 16); +} + +/** + * \brief Acknowledges an interrupt processed to the EMAC Control Core. + * + * \param emacBase Base Address of the EMAC module registers. + * \param eoiFlag Type of interrupt to acknowledge to the EMAC Control + * module. + * eoiFlag can take the following values \n + * EMAC_INT_CORE0_TX - Core 0 TX Interrupt + * EMAC_INT_CORE1_TX - Core 1 TX Interrupt + * EMAC_INT_CORE2_TX - Core 2 TX Interrupt + * EMAC_INT_CORE0_RX - Core 0 RX Interrupt + * EMAC_INT_CORE1_RX - Core 1 RX Interrupt + * EMAC_INT_CORE2_RX - Core 2 RX Interrupt + * \return None + * + **/ +static inline void +EMACCoreIntAck(volatile tms570_emacm_t *emacBase, unsigned int eoiFlag) +{ + /* Acknowledge the EMAC Control Core */ + emacBase->MACEOIVECTOR = eoiFlag; +} + +/** + * \brief Writes the the RX Completion Pointer for a specific channel + * + * \param emacBase Base Address of the EMAC module registers. + * \param channel Channel Number. + * \param comPtr Completion Pointer Value to be written + * + * \return None + * + **/ +static inline void +EMACRxCPWrite(volatile tms570_emacm_t *emacBase, unsigned int channel, unsigned int comPtr) +{ + emacBase->RXCP[channel] = comPtr; +} + +/** + * \brief Acknowledges an interrupt processed to the EMAC module. After + * processing an interrupt, the last processed buffer descriptor is + * written to the completion pointer. Also this API acknowledges + * the EMAC Control Module that the RX interrupt is processed for + * a specified core + * + * \param emacBase Base Address of the EMAC module registers. + * \param channel Channel Number + * \param comPtr Completion Pointer value. This shall be the buffer + * descriptor address last processed. + * \param eoiFlag Type of interrupt to acknowledge to the EMAC Control + module. + * eoiFlag can take the following values \n + * EMAC_INT_CORE0_RX - Core 0 RX Interrupt + * EMAC_INT_CORE1_RX - Core 1 RX Interrupt + * EMAC_INT_CORE2_RX - Core 2 RX Interrupt + * \return None + * + **/ +static inline void +EMACRxIntAckToClear(volatile tms570_emacm_t *emacBase, unsigned int channel, + unsigned int comPtr, unsigned eoiFlag) +{ + emacBase->RXCP[channel] = comPtr; + + /* Acknowledge the EMAC Control Core */ + emacBase->MACEOIVECTOR = eoiFlag; +} + +/** + * \brief Enables a specific channel to receive broadcast frames + * + * \param emacBase Base Address of the EMAC module registers. + * \param channel Channel Number. + * + * \return None + * + **/ +static inline void +EMACRxBroadCastEnable(volatile tms570_emacm_t *emacBase, unsigned int channel) +{ + emacBase->RXMBPENABLE &= ~TMS570_EMACM_RXMBPENABLE_RXBROADCH(-1); //CHECK + + emacBase->RXMBPENABLE |= + TMS570_EMACM_RXMBPENABLE_RXBROADEN | + TMS570_EMACM_RXMBPENABLE_RXBROADCH(channel); +} + +static inline void +EMACRxPromiscEnable(volatile tms570_emacm_t *emacBase, unsigned int channel) +{ + emacBase->RXMBPENABLE |= TMS570_EMACM_RXMBPENABLE_RXCAFEN | TMS570_EMACM_RXMBPENABLE_RXCEFEN; + emacBase->RXMBPENABLE |= TMS570_EMACM_RXMBPENABLE_RXPROMCH(channel); +} +/** + * \brief Enables unicast for a specific channel + * + * \param emacBase Base Address of the EMAC module registers. + * \param channel Channel Number. + * + * \return None + * + **/ +static inline void +EMACRxUnicastSet(volatile tms570_emacm_t *emacBase, unsigned int channel) +{ + emacBase->RXUNICASTSET |= (1 << channel); +} + + +/** + * \brief Gets the interrupt vectors of EMAC, which are pending + * + * \param emacBase Base Address of the EMAC module registers. + * + * \return Vectors + * + **/ +static inline unsigned int +EMACIntVectorGet(volatile tms570_emacm_t *emacBase) +{ + return (emacBase->MACINVECTOR); +} + +/** + * \brief Writes the the TX Completion Pointer for a specific channel + * + * \param emacBase Base Address of the EMAC module registers. + * \param channel Channel Number. + * \param comPtr Completion Pointer Value to be written + * + * \return None + * + **/ +static inline void +EMACTxCPWrite(volatile tms570_emacm_t *emacBase, unsigned int channel, unsigned int comPtr) +{ + emacBase->TXCP[channel] = comPtr; +} + +/** + * \brief This API Initializes the EMAC and EMAC Control modules. The + * EMAC Control module is reset, the CPPI RAM is cleared. also, + * all the interrupts are disabled. This API doesnot enable any + * interrupt or operation of the EMAC. + * + * \param emacCtrlBase Base Address of the EMAC Control module + * registers.\n + * \param emacBase Base address of the EMAC module registers + * + * \return None + * + **/ +static inline void +EMACInit(volatile tms570_emacc_t *emacCtrlBase, volatile tms570_emacm_t *emacBase) +{ + unsigned int cnt; + + /* Reset the EMAC Control Module. This clears the CPPI RAM also */ + emacCtrlBase->SOFTRESET = TMS570_EMACC_SOFTRESET_RESET; + while (emacCtrlBase->SOFTRESET & TMS570_EMACC_SOFTRESET_RESET); + + /* Reset the EMAC Control Module. This clears the CPPI RAM also */ + emacBase->SOFTRESET = TMS570_EMACM_SOFTRESET_SOFTRESET; + + while (emacBase->SOFTRESET & TMS570_EMACM_SOFTRESET_SOFTRESET); + + emacBase->MACCONTROL = 0; + emacBase->RXCONTROL = 0; + emacBase->TXCONTROL = 0; + + /* Initialize all the header descriptor pointer registers */ + for (cnt = 0; cnt < sizeof(emacBase->RXHDP)/sizeof(emacBase->RXHDP[0]); cnt++) { //CHECK + emacBase->RXHDP[cnt] = 0; + emacBase->TXHDP[cnt] = 0; + emacBase->RXCP[cnt] = 0; + emacBase->TXCP[cnt] = 0; + emacBase->RXFREEBUFFER[cnt] = 0xFF; + } + /* Clear the interrupt enable for all the channels */ + emacBase->TXINTMASKCLEAR = 0xFF; + emacBase->RXINTMASKCLEAR = 0xFF; + + emacBase->MACHASH1 = 0; + emacBase->MACHASH2 = 0; + + emacBase->RXBUFFEROFFSET = 0; +} diff --git a/uLan/ports/driver/tms570_emac/ti_drv_mdio.h b/uLan/ports/driver/tms570_emac/ti_drv_mdio.h new file mode 100644 index 0000000..e115231 --- /dev/null +++ b/uLan/ports/driver/tms570_emac/ti_drv_mdio.h @@ -0,0 +1,165 @@ +/* +* Copyright (C) 2009-2015 Texas Instruments Incorporated - www.ti.com +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef __MDIO_H__ +#define __MDIO_H__ + +#include <bsp/tms570.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif +/*****************************************************************************/ +/** + * \brief Reads a PHY register using MDIO. + * + * \param baseAddr Base Address of the MDIO Module Registers. + * \param phyAddr PHY Adress. + * \param regNum Register Number to be read. + * \param dataPtr Pointer where the read value shall be written. + * + * \return status of the read \n + * TRUE - read is successful.\n + * FALSE - read is not acknowledged properly. + * + **/ + +static inline uint32_t +MDIOPhyRegRead(volatile tms570_mdio_t *baseAddr, uint32_t phyAddr, + uint32_t regNum, volatile unsigned short *dataPtr) +{ + /* Wait till transaction completion if any */ + while (baseAddr->USERACCESS0 & TMS570_MDIO_USERACCESS0_GO); + + baseAddr->USERACCESS0 + = (TMS570_MDIO_USERACCESS0_GO + |TMS570_MDIO_USERACCESS0_REGADR(regNum) + |TMS570_MDIO_USERACCESS0_PHYADR(phyAddr)); + + /* wait for command completion */ + while (baseAddr->USERACCESS0 & TMS570_MDIO_USERACCESS0_GO); + + /* Store the data if the read is acknowledged */ + if (baseAddr->USERACCESS0 & TMS570_MDIO_USERACCESS0_ACK) { + *dataPtr = (unsigned short)TMS570_MDIO_USERACCESS0_DATA_GET(baseAddr->USERACCESS0); + return true; + } + + return false; +} + +/** + * \brief Writes a PHY register using MDIO. + * + * \param baseAddr Base Address of the MDIO Module Registers. + * \param phyAddr PHY Adress. + * \param regNum Register Number to be read. + * \param RegVal Value to be written. + * + * \return None + * + **/ +static inline void +MDIOPhyRegWrite(volatile tms570_mdio_t *baseAddr, uint32_t phyAddr, + uint32_t regNum, unsigned short RegVal) +{ + /* Wait till transaction completion if any */ + while (baseAddr->USERACCESS0 & TMS570_MDIO_USERACCESS0_GO); + + baseAddr->USERACCESS0 = + (TMS570_MDIO_USERACCESS0_WRITE + | TMS570_MDIO_USERACCESS0_GO + |TMS570_MDIO_USERACCESS0_REGADR(regNum) + |TMS570_MDIO_USERACCESS0_PHYADR(phyAddr) + | RegVal); + + /* wait for command completion*/ + while (baseAddr->USERACCESS0 & TMS570_MDIO_USERACCESS0_GO); +} +/** + * \brief Reads the alive status of all PHY connected to this MDIO. + * The bit correponding to the PHY address will be set if the PHY + * is alive. + * + * \param baseAddr Base Address of the MDIO Module Registers. + * + * \return MDIO alive register state + * + **/ +static inline uint32_t +MDIOPhyAliveStatusGet(volatile tms570_mdio_t *baseAddr) +{ + return (baseAddr->ALIVE); +} + +/** + * \brief Reads the link status of all PHY connected to this MDIO. + * The bit correponding to the PHY address will be set if the PHY + * link is active. + * + * \param baseAddr Base Address of the MDIO Module Registers. + * + * \return MDIO link register state + * + **/ +static inline uint32_t +MDIOPhyLinkStatusGet(volatile tms570_mdio_t *baseAddr) +{ + return (baseAddr->LINK); +} + +/** + * \brief Initializes the MDIO peripheral. This enables the MDIO state + * machine, uses standard pre-amble and set the clock divider value. + * + * \param baseAddr Base Address of the MDIO Module Registers. + * \param mdioInputFreq The clock input to the MDIO module + * \param mdioOutputFreq The clock output required on the MDIO bus + * \return None + * + **/ +static inline void +MDIOInit(volatile tms570_mdio_t *baseAddr, uint32_t mdioInputFreq, + uint32_t mdioOutputFreq) +{ + baseAddr->CONTROL = TMS570_MDIO_CONTROL_HIGHEST_USER_CHANNEL(1) | + TMS570_MDIO_CONTROL_ENABLE | + TMS570_MDIO_CONTROL_CLKDIV(0x60); +} + +#ifdef __cplusplus +} +#endif +#endif /* __MDIO_H__ */ diff --git a/uLan/ports/driver/tms570_emac/tms570_emac.h b/uLan/ports/driver/tms570_emac/tms570_emac.h new file mode 100644 index 0000000..26993e9 --- /dev/null +++ b/uLan/ports/driver/tms570_emac/tms570_emac.h @@ -0,0 +1,117 @@ +#ifndef EMAC_H_ +#define EMAC_H_ + +#include <stdbool.h> +#include "netif/etharp.h" +#include "lwip/sys.h" +#include "bsp/tms570.h" + +/*to rtems*/ +#define EMAC_CTRL_RAM_BASE (0xFC520000U) +#define SIZE_EMAC_CTRL_RAM 0x2000U + + + + +/* Packet Flags EMAC_Desc - tx and rx */ +#define EMAC_DSC_FLAG_SOP 0x80000000u +#define EMAC_DSC_FLAG_EOP 0x40000000u +#define EMAC_DSC_FLAG_OWNER 0x20000000u +#define EMAC_DSC_FLAG_EOQ 0x10000000u +#define EMAC_DSC_FLAG_TDOWNCMPLT 0x08000000u +#define EMAC_DSC_FLAG_PASSCRC 0x04000000u +/* Packet Flags - in addition to rx */ +#define EMAC_DSC_FLAG_JABBER 0x02000000u +#define EMAC_DSC_FLAG_OVERSIZE 0x01000000u +#define EMAC_DSC_FLAG_FRAGMENT 0x00800000u +#define EMAC_DSC_FLAG_UNDERSIZED 0x00400000u +#define EMAC_DSC_FLAG_CONTROL 0x00200000u +#define EMAC_DSC_FLAG_OVERRUN 0x00100000u +#define EMAC_DSC_FLAG_CODEERROR 0x00080000u +#define EMAC_DSC_FLAG_ALIGNERROR 0x00040000u +#define EMAC_DSC_FLAG_CRCERROR 0x00020000u +#define EMAC_DSC_FLAG_NOMATCH 0x00010000u + +/********** TI structs ***********/ + +/* EMAC TX Buffer descriptor data structure */ +struct emac_tx_bd { + volatile struct emac_tx_bd *next; + volatile u8_t *bufptr; + volatile u32_t bufoff_len; + volatile u32_t flags_pktlen; + + /* helper to know which pbuf this tx bd corresponds to */ + struct pbuf *pbuf; +}; + +/* EMAC RX Buffer descriptor data structure */ +struct emac_rx_bd { + volatile struct emac_rx_bd *next; + volatile u8_t *bufptr; + volatile u32_t bufoff_len; + volatile u32_t flags_pktlen; + + /* helper to know which pbuf this rx bd corresponds to */ + struct pbuf *pbuf; +}; + +/** + * Helper struct to hold the data used to operate on a particular + * receive channel + */ +struct rxch{ + volatile struct emac_rx_bd *active_head; + volatile struct emac_rx_bd *active_tail; + volatile struct emac_rx_bd *inactive_head; + volatile struct emac_rx_bd *inactive_tail; + s32_t freed_pbuf_len; +}; + +/** + * Helper struct to hold the data used to operate on a particular + * transmit channel + */ +struct txch { + volatile struct emac_tx_bd *active_head; + volatile struct emac_tx_bd *active_tail; + volatile struct emac_tx_bd *inactive_head; + volatile struct emac_tx_bd *inactive_tail; +}; + +/** + * Helper struct to hold private data used to operate the ethernet interface. + */ +struct tms570_netif_state { + /* emac instance number */ + u32_t inst_num; + + /* EMAC configuration register-window base address */ + volatile tms570_emacm_t *emac_base; + + /* EMAC controller base address */ + volatile tms570_emacc_t *emac_ctrl_base; + volatile u32_t emac_ctrl_ram; + + /* MDIO base address */ + volatile tms570_mdio_t *mdio_base; + + /* The RX/TX channel 0 state description + * (keeps track of used/freed Buffer Descriptors) + */ + struct txch txch; + struct rxch rxch; + + /* Semaphores used for waking up the threads processing + * RX/TX packets in teh deferred manner. + * Semgive is called in particular RX/TX interrupt + */ + sys_sem_t intPend_sem; + + u32_t phy_addr; + uint32_t waitTicksForPHYAneg; +}; + +/********************************************** End of Statistics **********************************************/ + +#endif /* EMAC_H_ */ diff --git a/uLan/ports/driver/tms570_emac/tms570_netif.c b/uLan/ports/driver/tms570_emac/tms570_netif.c new file mode 100644 index 0000000..8d14687 --- /dev/null +++ b/uLan/ports/driver/tms570_emac/tms570_netif.c @@ -0,0 +1,1227 @@ +/* + * Copyright (c) 2013, 2015 Czech Technical University in Prague + * Czech Republic + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Premysl Houdek <houdepre@fel.cvut.cz> + * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz> + * Industrial Informatics Group, FEE, Czech Technical University in Prague + * + * Based on work of Carlos Jenkins, Rostislav Lisovy, Jan Dolezal + */ + +/* lwIP headers */ +#include "lwip/init.h" +#if LWIP_VERSION_MAJOR >= 2 +#include "lwip/timeouts.h" +#else /*LWIP_VERSION_MAJOR*/ +#include "lwip/timers.h" /* for DHCP binding in NO_SYS mode */ +#endif /*LWIP_VERSION_MAJOR*/ +#include "lwip/sys.h" /* includes - lwip/opt.h, lwip/err.h, arch/sys_arch.h */ +#include "lwip/tcpip.h" /* includes - lwip/opt.h, lwip/api_msg.h, lwip/netifapi.h, lwip/pbuf.h, lwip/api.h, lwip/sys.h, lwip/timers.h, lwip/netif.h */ +#include "lwip/stats.h" /* includes - lwip/mem.h, lwip/memp.h, lwip/opt.h */ +#include "lwip/snmp.h" +#include "netif/etharp.h" /* includes - lwip/ip.h, lwip/netif.h, lwip/ip_addr.h, lwip/pbuf.h */ +#include <lwip/netifapi.h> +/* end - lwIP headers */ + +//--------moje +#include <strings.h> +#include <stdbool.h> +#include <stdlib.h> +#include <bsp/irq.h> +#include <bsp/tms570.h> +#include <bsp/tms570-pinmux.h> +#include "arch/cc.h" +#include "eth_lwip.h" +#include "tms570_netif.h" +#include "ti_drv_emac.h" +#include "ti_drv_mdio.h" +#include "phy_dp83848h.h" +#include "tms570_emac.h" + +#define LINK_SPEED_OF_YOUR_NETIF_IN_BPS 10000000 + +/* Number of EMAC Instances */ + +#define DEFAULT_PHY_ADDR 0x1 +#define FIND_FIRST_PHY_ALIVE 1 /* or use default (phy_address: 1) */ +#define NUM_OF_PHYs 32 + +/* Size of the Buffer descriptor defined by the EMAC in bytes */ +#define SIZE_OF_DESC 16 + +/* Channel number used for for RX, TX, unicast, broadcast or damaged frames; + * there are different channels for rx and tx operations (i.e. RXCH0 != TXCH0) */ +#define CHANNEL 0 + +/* take in account oversized frames */ +#define MAX_TRANSFER_UNIT 1500 + +#ifndef TMS570_MMR_SELECT_GMII_SEL + #define TMS570_MMR_SELECT_GMII_SEL TMS570_BALL_XX_GMII_SEL +#endif + +#ifndef TMS570_BALL_K19_MII_RXCLK + #define TMS570_BALL_K19_MII_RXCLK TMS570_BALL_K19_MII_RX_CLK +#endif + +/* WARNING! + * Be very carefull when setting this value. We have to keep in mind + * that pbuf_alloc(..., PBUF_POOL) will usualy return a chain of PBUFs + * pointing to the statically preallocated buffers (of the same size). + * The problem is that if we ask to allocate 300 bytes whereby the size + * of the statically preallocated PBUFs (PBUF_POOL_BUFSIZE) is 256, we + * will get a chain containing two PBUFs -- one *reporting* its size to + * be 256 bytes, the other one 44 bytes. + * Everything seems to be just fine however during RX, after we call + * netif->input(pbuf, netif) we have to newly allocate the PBUF(s) and + * properly set the apropriate BDs. This will however work only if the + * number of the freed BDs is the same as the number of the BDs newly + * initialized. One possible situation when this may fail is when multiple + * non-256 byte sized PBUFs will move near to each other, i.e. 3 BDs: + * 256 B, 44 B, 44 B -- 344 bytes will be freed (3 BDs) but the new call + * to pbuf_alloc(...) will return a chain comprising only two PBUFs + * (256 B, 88 B). + * This is the implementation limitation. The PBUF_LEN_MAX should therefore + * be multiple of PBUF_POOL_BUFSIZE + */ +#define PBUF_LEN_MAX (PBUF_POOL_BUFSIZE * 6) + +/* Maximum number of PBUFs preallocated in the driver + * init function to be used for the RX + */ +#define MAX_RX_PBUF_ALLOC 10 +#define MIN_PKT_LEN 60 + +/* Define those to better describe the network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +/* Time to wait for autonegotiation in ticks. */ +#define TICKS_PHY_AUTONEG 4000 + +/* startup init indicator */ +static bool initialized = false; + +/*private?*/ +#if !defined(__TI_COMPILER_VERSION__) +static +#endif /*__TI_COMPILER_VERSION__*/ +SYS_IRQ_HANDLER_FNC(tms570_eth_irq); +static void tms570_eth_rx_pbuf_refill(struct tms570_netif_state *nf_state, int); +static void tms570_eth_rx_pbuf_refill_single(struct netif *); +static void tms570_eth_hw_set_RX_HDP(struct tms570_netif_state *nf_state, volatile struct emac_rx_bd *new_head); +static void tms570_eth_hw_set_TX_HDP(struct tms570_netif_state *nf_state, volatile struct emac_tx_bd *new_head); +static void tms570_eth_hw_set_hwaddr(struct tms570_netif_state *nf_state, uint8_t *mac_addr); +static void tms570_eth_process_irq_rx(void *arg); +static void tms570_eth_process_irq_tx(void *arg); +static void tms570_eth_process_irq_request(void *argument); +static void tms570_eth_process_irq(void *argument); +struct netif *tms570_eth_get_netif(uint32_t instance_number); +static err_t tms570_eth_send(struct netif *netif, struct pbuf *p); +static err_t tms570_eth_send_raw(struct netif *netif, struct pbuf *pbuf); +static err_t tms570_eth_init_hw(struct tms570_netif_state *nf_state); +static err_t tms570_eth_init_hw_post_init(struct tms570_netif_state *nf_state); +static err_t tms570_eth_init_interrupt(struct tms570_netif_state *nf_state); +static err_t tms570_eth_init_find_PHY(struct tms570_netif_state *nf_state); +static err_t tms570_eth_init_control_structures(struct netif *netif); +static void tms570_eth_init_netif_fill(struct netif *netif); +static void tms570_eth_init_buffer_descriptors(struct tms570_netif_state *nf_state); +static void tms570_eth_init_set_pinmux(); + +/***** initializing functions **********************************************/ + + +struct tms570_netif_state * +tms570_eth_init_state(void) +{ + struct tms570_netif_state *nf_state = (struct tms570_netif_state *)malloc(sizeof(struct tms570_netif_state)); + + nf_state->emac_base = &TMS570_EMACM; + nf_state->emac_ctrl_base = &TMS570_EMACC; + nf_state->emac_ctrl_ram = EMAC_CTRL_RAM_BASE; + nf_state->mdio_base = &TMS570_MDIO; + nf_state->phy_addr = DEFAULT_PHY_ADDR; +#if !NO_SYS + nf_state->waitTicksForPHYAneg = TICKS_PHY_AUTONEG; +#endif + return nf_state; +} + +static void +tms570_eth_init_netif_fill(struct netif *netif) +{ +#if LWIP_NETIF_HOSTNAME + netif->hostname = "tms570"; +#endif + + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + + /* + * Initialize the snmp variables and counters inside the struct netif. + * The last argument should be replaced with your link speed, in units + * of bits per second. + */ + NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + + /* We directly use etharp_output() here to save a function call. + * You can instead declare yo_SKIP_TO_HWur own function an call etharp_output() + * from it if you have to do some checks before sending (e.g. if link + * is available...) + */ + netif->output = etharp_output; + netif->linkoutput = tms570_eth_send; + + /* maximum transfer unit */ + netif->mtu = MAX_TRANSFER_UNIT; + + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; +} + +static err_t +tms570_eth_init_control_structures(struct netif *netif) +{ + err_t res; + sys_thread_t tx_thread_id; + struct tms570_netif_state *nf_state; + + nf_state = netif->state; + + res = sys_sem_new(&nf_state->intPend_sem, 0); + if (res != ERR_OK) { + sys_arch_printk("ERROR! semaphore creation error - 0x%08lx\n", (long)res); + } + tx_thread_id = sys_thread_new(0, tms570_eth_process_irq_request, netif, 1024, 3); //zkontrolovat priorita 0 + if (tx_thread_id == 0) { + sys_arch_printk("ERROR! lwip interrupt thread not created"); + res = !ERR_OK; + } + return res; +} + +err_t +tms570_eth_init_netif(struct netif *netif) +{ + err_t retVal; + struct tms570_netif_state *nf_state = (struct tms570_netif_state *)netif->state; + + if (initialized) + return ERR_IF; + + if (nf_state == NULL) { + /* nf_state needs to be freed */ + if ((nf_state = tms570_eth_init_state()) == 0) { + return ERR_IF; + } + netif->state = nf_state; + } + + tms570_eth_init_netif_fill(netif); + + if ((retVal = tms570_eth_init_hw(nf_state)) != ERR_OK) { + tms570_eth_debug_printf("tms570_eth_init_hw: %d", retVal); + return retVal; + } + if ((retVal = tms570_eth_init_control_structures(netif)) != ERR_OK) { + tms570_eth_debug_printf("tms570_eth_init_control_structures: %d", retVal); + return retVal; + } + tms570_eth_init_buffer_descriptors(nf_state); + tms570_eth_rx_pbuf_refill(nf_state, 0); + tms570_eth_hw_set_hwaddr(nf_state, netif->hwaddr); + tms570_eth_init_interrupt(nf_state); + if ((retVal = tms570_eth_init_hw_post_init(nf_state)) != ERR_OK) { + tms570_eth_debug_printf("tms570_eth_init_hw_post_init: %d", retVal); + return retVal; + } + initialized = true; +#if TMS570_NETIF_DEBUG + tms570_eth_debug_print_HDP(nf_state); +#endif + return ERR_OK; +} + +static err_t +tms570_eth_init_interrupt(struct tms570_netif_state *nf_state) +{ + int res; + + res = sys_request_irq(TMS570_IRQ_EMAC_TX, tms570_eth_irq, + 0, "emac_tx", nf_state); + if (res < 0) { + sys_arch_printk("Failed to install tx handler\n"); + return ERR_IF; + } + + res = sys_request_irq(TMS570_IRQ_EMAC_RX, tms570_eth_irq, + 0, "emac_rx", nf_state); + if (res < 0) { + sys_arch_printk("Failed to install rx handler\n"); + return ERR_IF; + } + return ERR_OK; +} +static err_t +tms570_eth_init_find_PHY(struct tms570_netif_state *nf_state) +{ + uint8_t index; + uint16_t regContent; + uint32_t physAlive; + + MDIOPhyRegRead(nf_state->mdio_base, nf_state->phy_addr, PHY_BMSR, ®Content); + physAlive = MDIOPhyAliveStatusGet(nf_state->mdio_base); + /* Find first alive PHY -- or use default if alive */ + if (!(physAlive & (1 << nf_state->phy_addr))) { + for (index = 0; index < NUM_OF_PHYs; index++) { + if (physAlive & (1 << index)) { + nf_state->phy_addr = index; + break; + } else { + /* + * Try to 'wake up' PHY on 'index' address by + * reading random register, making MDIO set + * alive bit for current PHY + */ + MDIOPhyRegRead(nf_state->mdio_base, index, + PHY_BMCR, ®Content); + + /* Get updated register */ + physAlive = MDIOPhyAliveStatusGet(nf_state->mdio_base); + if (physAlive & (1 << index)) { + nf_state->phy_addr = index; + break; + } + } + } + + if (!physAlive) { /* FIXME je to ok? */ + tms570_eth_debug_printf("no phy found, phys: %d\n", physAlive); + return NO_PHY_ALIVE; + } + } + return ERR_OK; +} + +static void +tms570_eth_init_set_pinmux(void) +{ +#if defined(__rtems__) + TMS570_IOMM.KICK_REG0 = 0x83E70B13U; + TMS570_IOMM.KICK_REG1 = 0x95A4F1E0U; + + tms570_bsp_pin_set_function(TMS570_BALL_V5_MDCLK, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_G3_MDIO, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_H19_MII_TXEN, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_E18_MII_TXD_3, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_R2_MII_TXD_2, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_J19_MII_TXD_1, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_J18_MII_TXD_0, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_D19_MII_TX_CLK, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_H18_MII_RXD_3, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_G19_MII_RXD_2, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_A14_MII_RXD_1, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_P1_MII_RXD_0, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_K19_MII_RXCLK, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_N19_MII_RX_ER, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_B11_MII_RX_DV, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_B4_MII_CRS, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_set_function(TMS570_BALL_F3_MII_COL, TMS570_PIN_FNC_AUTO); + tms570_bsp_pin_clear_function(TMS570_MMR_SELECT_GMII_SEL, TMS570_PIN_FNC_AUTO); + + TMS570_IOMM.KICK_REG0 = 0; + TMS570_IOMM.KICK_REG1 = 0; +#endif /*__rtems__*/ +} + +static err_t +tms570_eth_init_hw(struct tms570_netif_state *nf_state) +{ + err_t retVal; + + tms570_eth_init_set_pinmux(); + + /* Initialize EMAC control module and EMAC module */ + EMACInit(nf_state->emac_ctrl_base, nf_state->emac_base); + /* Initialize MDIO module (reset) */ + MDIOInit(nf_state->mdio_base, 0x0, 0x0); + + if ((retVal = tms570_eth_init_find_PHY(nf_state)) != ERR_OK) { + tms570_eth_debug_printf("tms570_eth_init_find_PHY: %d", retVal); + return retVal; + } + /* + * Start autonegotiation and check on completion later or + * when complete link register will be updated + */ + PHY_auto_negotiate(nf_state->mdio_base, nf_state->phy_addr, + PHY_100BASETXDUPL_m | PHY_100BASETX_m | + PHY_10BASETDUPL_m | PHY_10BASET_m); + tms570_eth_debug_printf("autoneg started -- check on cable if it's connected!\r\n"); + + /* + * TODO: you can implement init of receive flow control somewhere + * here if desired - set RXBUFFERFLOWEN in MACCONTROL + */ + + /* Acknowledge EMAC control module RX, TX and MISC interrupts */ + EMACCoreIntAck(nf_state->emac_base, EMAC_INT_CORE0_RX); + EMACCoreIntAck(nf_state->emac_base, EMAC_INT_CORE0_TX); + EMACCoreIntAck(nf_state->emac_base, EMAC_INT_CORE0_MISC); + + /* Sets which channel will receive broadcasts */ + EMACRxBroadCastEnable(nf_state->emac_base, CHANNEL); + + /* + * Sets channel where all frames will be copied to -- + * either with MAC address different from local device address, + * either packets with error will be copied; appropriate error + * will be set in the frame EOP buffer descriptor + */ + EMACRxPromiscEnable(nf_state->emac_base, CHANNEL); + + /* Enable unicast */ + EMACRxUnicastSet(nf_state->emac_base, CHANNEL); + + /* Enable TX and RX interrupts in both EMAC module and EMAC control module */ + EMACTxIntPulseEnable(nf_state->emac_base, nf_state->emac_ctrl_base, 0, CHANNEL); + EMACRxIntPulseEnable(nf_state->emac_base, nf_state->emac_ctrl_base, 0, CHANNEL); + + return ERR_OK; +} +static void +tms570_eth_hw_set_hwaddr(struct tms570_netif_state *nf_state, uint8_t *mac_addr) +{ + uint8_t mac[ETHARP_HWADDR_LEN]; + int i; + + for (i = 0; i < ETHARP_HWADDR_LEN; i++) { + mac[i] = mac_addr[ETHARP_HWADDR_LEN - i - 1]; + } + /* for flow control frames */ + EMACMACSrcAddrSet(nf_state->emac_base, mac); + + /* Be sure to program all eight MAC address registers - + * whether the receive channel is to be enabled or not. + */ + for (i = 0; i < 8; i++) { + EMACMACAddrSet(nf_state->emac_base, i, mac, 0); + } +} + +static err_t +tms570_eth_init_hw_post_init(struct tms570_netif_state *nf_state) +{ + /* 0x3FFFFFFF is for 80MHz aproximately 13s */ + uint16_t regContent; + + /* wait for autonegotiation to be done or continue, when delay was reached */ + uint32_t timeToWake = nf_state->waitTicksForPHYAneg + sys_jiffies(); + + while (PHY_is_done_auto_negotiate(nf_state->mdio_base, nf_state->phy_addr) == false && + timeToWake > sys_jiffies()) + sys_arch_delay(20); + /* XXX: if init is not done at the startup, + * but couple days later, this might cause troubles */ + + if (PHY_is_done_auto_negotiate(nf_state->mdio_base, nf_state->phy_addr) != false) + tms570_eth_debug_printf("autoneg finished\n"); + else + tms570_eth_debug_printf("autoneg timeout\n"); + + /* provide informations retrieved from autoneg to EMAC module */ + PHY_partner_ability_get(nf_state->mdio_base, nf_state->phy_addr, ®Content); + if (regContent & (PHY_100BASETXDUPL_m | PHY_10BASETDUPL_m)) { + EMACDuplexSet(nf_state->emac_base, 1); + /* this is right place to implement transmit flow control if desired -- + * set TXFLOWEN in MACCONTROL + */ + } else if (regContent & (PHY_100BASETX_m | PHY_10BASET_m)) { + EMACDuplexSet(nf_state->emac_base, 0); + } else { + tms570_eth_debug_printf("Unknown duplex mode\r\n"); + return UNKN_DUPLEX_MODE; + } + + /* enable hostpend interrupts in emac module */ + nf_state->emac_base->MACINTMASKSET |= TMS570_EMACM_MACINTMASKSET_HOSTMASK; + + /* enable hostpend interrupts in emac control module */ + nf_state->emac_ctrl_base->C0MISCEN |= TMS570_EMACC_C0MISCEN_HOSTPENDEN; + + EMACMIIEnable(nf_state->emac_base); + EMACTxEnable(nf_state->emac_base); + EMACRxEnable(nf_state->emac_base); + + return ERR_OK; +} +static void +tms570_eth_init_buffer_descriptors(struct tms570_netif_state *nf_state) +{ + uint32_t num_bd; + volatile struct emac_tx_bd *curr_txbd; + volatile struct emac_rx_bd *curr_rxbd; + + struct rxch *rxch; + struct txch *txch; + + rxch = &(nf_state->rxch); + txch = &(nf_state->txch); + + + /* + * Use the CPPI RAM to store RX/TX Buffer Descriptors (= BD). + * 1/2 of CPPI RAM is used for TX BDs, another 1/2 for RX BDs. + * All the TX BDs are 'owned' by the software. They are initialized + * as a linked-list forming a ring. They are awaiting the application + * to append pbuf payload to the them and correctly configure for + * actual transmission. + * Only such number of RX BDs is configured that the pbufs can be + * allocated for (i.e. MAX_RX_PBUF_ALLOC). Pbufs are allocated from + * the PBUF_POOL (thus the allocated pbufs might be chained). + * Each payload part of a payload is them used to initialize single + * RX BD. The RX BDs are then configured to be 'owned' bythe EMAC + */ + + /* + * Initialize the Descriptor Memory For TX and RX + * Only Channel 0 is supported for both TX and RX + */ + txch->inactive_head = (volatile struct emac_tx_bd *)nf_state->emac_ctrl_ram; + txch->inactive_tail = NULL; + txch->active_head = NULL; + txch->active_tail = NULL; + + /* Set the number of descriptors for the channel */ + /* take half of CPPI ram for TX BDs */ + + num_bd = ((SIZE_EMAC_CTRL_RAM >> 1) / sizeof(struct emac_tx_bd))-1; +#if TMS570_NETIF_DEBUG + tms570_eth_debug_printf("pocet bd %d\n", num_bd); +#endif + + curr_txbd = txch->inactive_head; + + /* Initialize all the TX buffer Descriptors */ + while (num_bd > 0) { + curr_txbd->next = curr_txbd + 1; + curr_txbd->flags_pktlen = 0; + txch->inactive_tail = curr_txbd; + curr_txbd = curr_txbd->next; + num_bd--; + } + curr_txbd->next = NULL; + + /* Initialize the descriptors for the RX channel */ + rxch->inactive_head = ((volatile struct emac_rx_bd *)curr_txbd)+2; + rxch->freed_pbuf_len = MAX_RX_PBUF_ALLOC*PBUF_LEN_MAX; + rxch->inactive_head->flags_pktlen = EMAC_DSC_FLAG_OWNER; + rxch->inactive_head->next = rxch->inactive_head + 1; + curr_rxbd = rxch->inactive_head; + + num_bd = ((SIZE_EMAC_CTRL_RAM >> 1) / sizeof(struct emac_rx_bd))-1; + + while (num_bd > 0) { + curr_rxbd = curr_rxbd->next; + curr_rxbd->next = curr_rxbd + 1; + curr_rxbd->flags_pktlen = EMAC_DSC_FLAG_OWNER; + curr_rxbd->pbuf = NULL; + num_bd--; + } + curr_rxbd->next = NULL; + rxch->inactive_tail = curr_rxbd; + rxch->active_tail = NULL; + rxch->active_head = NULL; +#if TMS570_NETIF_DEBUG + tms570_eth_debug_show_rx(nf_state); + tms570_eth_debug_show_tx(nf_state); +#endif + +} + +/* send and receive functions / ISRs ******************************************/ + +static err_t +tms570_eth_send(struct netif *netif, struct pbuf *p) +{ + err_t retVal = ERR_OK; + + SYS_ARCH_DECL_PROTECT(lev); + + /** + * This entire function must be protected to preserve + * the integrity of the transmit pbuf queue. + */ + SYS_ARCH_PROTECT(lev); +#if !SYS_LIGHTWEIGHT_PROT + sys_prot_t prevProt = sys_arch_protect() + /* + uint32_t prevProt = (uint32_t) _get_CPSR() & 0x80; + _disable_IRQ(); + */ +#endif + + /** + * Bump the reference count on the pbuf to prevent it from being + * freed until we are done with it. + */ + pbuf_ref(p); + + /* call the actual transmit function */ + retVal = tms570_eth_send_raw(netif, p); + + /* Return to prior interrupt state and return. */ + SYS_ARCH_UNPROTECT(lev); +#if !SYS_LIGHTWEIGHT_PROT + sys_arch_unprotect(prevProt); + /* + if (!prevProt) + _enable_IRQ(); + */ +#endif + + return retVal; +} + +/** + * When called from tms570_eth_send(), the 'lev' lock is held + */ +static err_t +tms570_eth_send_raw(struct netif *netif, struct pbuf *pbuf) +{ + struct pbuf *q; + struct txch *txch; + struct tms570_netif_state *nf_state; + unsigned int pktlen; + unsigned int padlen = 0; + volatile struct emac_tx_bd *curr_bd; + volatile struct emac_tx_bd *packet_head; + volatile struct emac_tx_bd *packet_tail; + + nf_state = (struct tms570_netif_state *)netif->state; + txch = &(nf_state->txch); + + /* Get the first BD that is unused and will be used for TX */ + curr_bd = txch->inactive_head; + if (curr_bd == NULL) + goto error_out_of_descriptors; + + packet_head = curr_bd; + packet_tail = curr_bd; + + /* adjust the packet length if less than minimum required */ + pktlen = pbuf->tot_len; + if (pktlen < MIN_PKT_LEN) { + padlen = MIN_PKT_LEN - pktlen; + pktlen = MIN_PKT_LEN; + } + + /* First 'part' of packet flags */ + curr_bd->flags_pktlen = pktlen | EMAC_DSC_FLAG_SOP | + EMAC_DSC_FLAG_OWNER; + + /* Copy pbuf information into TX BDs -- + * remember that the pbuf for a single packet might be chained! + */ + for (q = pbuf; q != NULL; q = q->next) { + if (curr_bd == NULL) + goto error_out_of_descriptors; + + curr_bd->bufptr = (uint8_t *)(q->payload); + curr_bd->bufoff_len = (q->len) & 0xFFFF; + + /* This is an extra field that is not par of the in-HW BD. + * This is used when freeing the pbuf after the TX processing + * is done in EMAC + */ + curr_bd->pbuf = pbuf; + packet_tail = curr_bd; + curr_bd = curr_bd->next; + } + if (padlen) { + if (curr_bd == NULL) + goto error_out_of_descriptors; + + /* If the ETHERNET packet is smaller than 64 bytes, it has + * to be padded. We need some data and do not want to leak + * random memory. Reuse IP and possibly TCP/UDP header + * of given frame as padding + */ + curr_bd->bufptr = packet_head->bufptr; + curr_bd->bufoff_len = padlen; + curr_bd->pbuf = pbuf; + packet_tail = curr_bd; + curr_bd = curr_bd->next; + } + /* Indicate the end of the packet */ + packet_tail->next = NULL; + packet_tail->flags_pktlen |= EMAC_DSC_FLAG_EOP; + + txch->inactive_head = curr_bd; + if (curr_bd == NULL) + txch->inactive_tail = curr_bd; + + sys_arch_data_sync_barier(); + + if (txch->active_tail == NULL) { + txch->active_head = packet_head; + tms570_eth_hw_set_TX_HDP(nf_state, packet_head); + } else { + /* Chain the bd's. If the DMA engine already reached the + * end of the chain, the EOQ will be set. In that case, + * the HDP shall be written again. + */ + txch->active_tail->next = packet_head; + curr_bd = txch->active_tail; + + /* We were too slow and the EMAC already read the + * 'pNext = NULL' of the former txch->active_tail. In this + * case the transmission stopped and we need to write the + * pointer to newly added BDs to the TX HDP + */ + if (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOQ) { + tms570_eth_hw_set_TX_HDP(nf_state, packet_head); + } + } + txch->active_tail = packet_tail; + + return ERR_OK; + +error_out_of_descriptors: + pbuf_free(pbuf); + return ERR_IF; +} + +/* EMAC Packet Buffer Sizes and Placement */ +#ifdef CONFIG_EMAC_PKT_FRAG_SIZE + #define EMAC_FRAG_SIZE CONFIG_EMAC_PKT_FRAG_SIZE +#else + #define EMAC_FRAG_SIZE 1536 +#endif + +#ifdef CONFIG_EMAC_ETH_FRAME_SIZE + #define EMAC_MAX_FLEN CONFIG_EMAC_ETH_FRAME_SIZE +#else + #define EMAC_MAX_FLEN 1536 +#endif + +#ifdef CONFIG_EMAC_NUM_RX_FRAGS + #define EMAC_NUM_RX_FRAG CONFIG_EMAC_NUM_RX_FRAGS +#else + #define EMAC_NUM_RX_FRAG 4 +#endif + +#ifdef CONFIG_EMAC_NUM_TX_FRAGS + #define EMAC_NUM_TX_FRAG CONFIG_EMAC_NUM_TX_FRAGS +#else + #define EMAC_NUM_TX_FRAG 2 +#endif + +static void +tms570_eth_process_irq_rx(void *arg) +{ + struct tms570_netif_state *nf_state; + struct rxch *rxch; + struct netif *netif = (struct netif *)arg; + volatile struct emac_rx_bd *curr_bd; + struct pbuf *pbuf; + struct pbuf *q; + + nf_state = netif->state; + rxch = &(nf_state->rxch); + /* Get the bd which contains the earliest filled data */ + curr_bd = rxch->active_head; + if (curr_bd == NULL) { + tms570_eth_rx_pbuf_refill(nf_state, 0); + return; + } + + /* For each valid frame */ + while ((curr_bd->flags_pktlen & EMAC_DSC_FLAG_SOP) && + !(curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER)) { + unsigned int total_rx_len; + unsigned int processed_rx_len = 0; + int corrupt_fl = 0; + + sys_arch_data_sync_barier(); + + pbuf = curr_bd->pbuf; + total_rx_len = curr_bd->flags_pktlen & 0xFFFF; + tms570_eth_debug_printf("recieve packet. L = %d ", total_rx_len); + /* The received frame might be fragmented into muliple + * pieces -- each one referenced by a separate BD. + * To further process the data, we need to 'make' a + * proper PBUF out of it -- that means linking each + * buffer together, copy the length information form + * the DB to PBUF, calculate the 'tot_len' etc. + */ + for (;; ) { + q = curr_bd->pbuf; + /* Since this pbuf will be freed, we need to + * keep track of its size to be able to + * allocate it back again + */ + rxch->freed_pbuf_len += q->len; + tms570_eth_debug_printf("bd - %d ", tms570_eth_debug_get_BD_num(curr_bd, nf_state)); + tms570_eth_debug_printf("pbuf len - %d ", q->len); + tms570_eth_debug_printf("A - 0x%08x ", q); + /* This is the size of the "received data" not the PBUF */ + q->tot_len = total_rx_len - processed_rx_len; + q->len = curr_bd->bufoff_len & 0xFFFF; + + if (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOP) + break; + /* + * If we are executing here, it means this + * packet is being split over multiple BDs + */ + tms570_eth_debug_printf("MB"); + /* chain the pbufs since they belong + * to the same packet + */ + if (curr_bd->next == NULL) { + corrupt_fl = 1; + break; + } + curr_bd = curr_bd->next; + q->next = curr_bd->pbuf; + + processed_rx_len += q->len; + } + tms570_eth_debug_printf("\n"); + /* Close the chain */ + q->next = NULL; + if (rxch->inactive_tail == NULL) { + rxch->inactive_head = rxch->active_head; + } else { + rxch->inactive_tail->next = rxch->active_head; + } + rxch->inactive_tail = curr_bd; + rxch->active_head = curr_bd->next; + if (curr_bd->next == NULL) + rxch->active_tail = NULL; + rxch->inactive_tail->next = NULL; + + + LINK_STATS_INC(link.recv); + + /* Process the packet */ + /* ethernet_input((struct pbuf *)pbuf, netif) */ + if (!corrupt_fl) + if (netif->input(pbuf, netif) != ERR_OK) + corrupt_fl = 1; + if (corrupt_fl) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + pbuf_free(pbuf); + } + + /* Acknowledge that this packet is processed */ + EMACRxCPWrite(nf_state->emac_base, 0, (unsigned int)curr_bd); + + /* The earlier PBUF chain is freed from the upper layer. + * So, we need to allocate a new pbuf chain and update + * the descriptors with the PBUF info. + * Care should be taken even if the allocation fails. + */ + tms570_eth_rx_pbuf_refill(nf_state, 0); + //tms570_eth_debug_print_rxch(); + curr_bd = rxch->active_head; + if (curr_bd == NULL) { + return; + } + } +} + +static void +tms570_eth_process_irq_tx(void *arg) +{ + + struct txch *txch; + volatile struct emac_tx_bd *curr_bd; + volatile struct emac_tx_bd *start_of_packet_bd; + struct netif *netif = (struct netif *)arg; + struct tms570_netif_state *nf_state; + + nf_state = netif->state; + txch = &(nf_state->txch); + + start_of_packet_bd = txch->active_head; + curr_bd = txch->active_head; + + /* Traverse the list of BDs used for transmission -- + * stop on the first unused + */ + while ((curr_bd != NULL) && (curr_bd->flags_pktlen & EMAC_DSC_FLAG_SOP)) { + /* Make sure the transmission is over */ + if (curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER) { + tms570_eth_debug_printf("TXthread ownership not transfered!!!!\n"); + break; + } + + /* Find the last chunk of the packet */ + while (!(curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOP)) + curr_bd = curr_bd->next; + + /* Remove flags for the transmitted BDs */ + start_of_packet_bd->flags_pktlen &= (~EMAC_DSC_FLAG_SOP); + curr_bd->flags_pktlen &= (~EMAC_DSC_FLAG_EOP); + + /* + * Return processed BDs to inactive list + */ + if (txch->inactive_tail == NULL) { + txch->inactive_head = start_of_packet_bd; + } else { + txch->inactive_tail->next = start_of_packet_bd; + } + txch->inactive_tail = curr_bd; + + /* + * Remove BDs from active list + */ + txch->active_head = curr_bd->next; + if (curr_bd->next == NULL) { + txch->active_tail = NULL; + } + + /* + * Insert null element at the end of the inactive list + */ + txch->inactive_tail->next = NULL; + + + /* Ack the Interrupt in the EMAC peripheral */ + EMACTxCPWrite(nf_state->emac_base, CHANNEL, + (uint32_t)curr_bd); + + /* Free the corresponding pbuf + * Sidenote: Each fragment of the single packet points + * to the same pbuf + */ + pbuf_free(start_of_packet_bd->pbuf); + + LINK_STATS_INC(link.xmit); + + /* Move to the next packet */ + start_of_packet_bd = txch->active_head; + curr_bd = txch->active_head; + } +} + +static void +tms570_eth_process_irq(void *argument) +{ + struct netif *netif = (struct netif *)argument; + struct tms570_netif_state *nf_state; + uint32_t macints; + + nf_state = netif->state; + + if (nf_state == NULL) + return; + + while (1) { + macints = nf_state->emac_base->MACINVECTOR; + if ((macints & 0xffff) == 0) { + break; + } + if (macints & (0xff<<16)) { //TX interrupt + tms570_eth_process_irq_tx(netif); + EMACCoreIntAck(nf_state->emac_base, EMAC_INT_CORE0_TX); + } + if (macints & (0xff<<0)) { //RX interrupt + tms570_eth_process_irq_rx(netif); + EMACCoreIntAck(nf_state->emac_base, EMAC_INT_CORE0_RX); + } + } + sys_arch_unmask_interrupt_source(TMS570_IRQ_EMAC_RX); + sys_arch_unmask_interrupt_source(TMS570_IRQ_EMAC_TX); +} + +void static +tms570_eth_process_irq_request(void *argument) +{ + struct netif *netif = (struct netif *)argument; + struct tms570_netif_state *nf_state; + + nf_state = netif->state; + + for (;; ) { + sys_arch_sem_wait(&nf_state->intPend_sem, 0); + tcpip_callback((tcpip_callback_fn)tms570_eth_process_irq, netif); + } +} + +static void +tms570_eth_hw_set_RX_HDP(struct tms570_netif_state *nf_state, volatile struct emac_rx_bd *new_head) +{ + /* Writes to RX HDP are allowed + * only when it is 0 + */ + while (nf_state->emac_base->RXHDP[CHANNEL] != 0) { + tms570_eth_debug_printf("HW -RX- is slacking!!!\n"); + sys_arch_delay(10); + } + tms570_eth_debug_printf("setting RX HDP"); + EMACRxHdrDescPtrWrite( + nf_state->emac_base, + (uint32_t)new_head, + CHANNEL); +} +static void +tms570_eth_hw_set_TX_HDP(struct tms570_netif_state *nf_state, volatile struct emac_tx_bd *new_head) +{ + /* Writes to RX HDP are allowed + * only when it is 0 + */ + while (nf_state->emac_base->TXHDP[CHANNEL] != 0) { + tms570_eth_debug_printf("HW -TX- is slacking!!!\n"); + sys_arch_delay(10); + } + tms570_eth_debug_printf("setting TX HDP"); + EMACTxHdrDescPtrWrite( + nf_state->emac_base, + (uint32_t)new_head, + CHANNEL); +} + +static void +tms570_eth_rx_pbuf_refill_single(struct netif *netif) +{ + tms570_eth_rx_pbuf_refill(netif->state, 1); +} + +static void +tms570_eth_rx_pbuf_refill(struct tms570_netif_state *nf_state, int single_fl) +{ + struct rxch *rxch; + volatile struct emac_rx_bd *curr_bd; + volatile struct emac_rx_bd *curr_head; + struct pbuf *new_pbuf; + struct pbuf *q; + uint32_t alloc_rq_bytes; + + rxch = &(nf_state->rxch); + if (single_fl) { + alloc_rq_bytes = PBUF_POOL_BUFSIZE; + } else { + alloc_rq_bytes = rxch->freed_pbuf_len; + } + + for (; (rxch->freed_pbuf_len > 0) && (rxch->inactive_head != NULL); ) { + //stats_display(); + + curr_bd = rxch->inactive_head; + curr_head = rxch->inactive_head; + tms570_eth_debug_printf("attempt to allocate %d bytes from pbuf pool (RX)\n", alloc_rq_bytes); + new_pbuf = pbuf_alloc(PBUF_RAW, + alloc_rq_bytes, + PBUF_POOL); + if (new_pbuf == NULL) { + #if defined(__GNUC__) && !defined(__TI_COMPILER_VERSION__) + alloc_rq_bytes = (1 << (30-__builtin_clz(alloc_rq_bytes))); + #else /*__GNUC__*/ + { + int n = 0; + while ((1 << n) < alloc_rq_bytes) + n++; + alloc_rq_bytes = 1 << (n - 1); + } + #endif /*__GNUC__*/ + if (alloc_rq_bytes <= PBUF_POOL_BUFSIZE) { + tms570_eth_debug_printf("not enough memory\n"); + break; + } + alloc_rq_bytes = rxch->freed_pbuf_len > alloc_rq_bytes ? + alloc_rq_bytes : rxch->freed_pbuf_len; + continue; + } else { + q = new_pbuf; + for (;; ) { + curr_bd->bufptr = (uint8_t *)q->payload; + curr_bd->bufoff_len = q->len; + curr_bd->flags_pktlen = EMAC_DSC_FLAG_OWNER; + curr_bd->pbuf = q; + rxch->freed_pbuf_len -= q->len; + q = q->next; + if (q == NULL) + break; + if (curr_bd->next == NULL) { + rxch->inactive_tail = NULL; + break; + } + curr_bd = curr_bd->next; + } + + if (q != NULL) + pbuf_free((struct pbuf *)q); + /* Add the newly allocated BDs to the + * end of the list + */ + rxch->inactive_head = curr_bd->next; + + curr_bd->next = NULL; + sys_arch_data_sync_barier(); + + if (rxch->active_head == NULL) { + rxch->active_head = curr_head; + rxch->active_tail = curr_bd; + tms570_eth_hw_set_RX_HDP(nf_state, rxch->active_head); + } else { + rxch->active_tail->next = curr_head; + sys_arch_data_sync_barier(); + if ((rxch->active_tail->flags_pktlen & EMAC_DSC_FLAG_EOQ) != 0) + tms570_eth_hw_set_RX_HDP(nf_state, rxch->active_head); + rxch->active_tail = curr_bd; + } + } + } +} + +#if !defined(__TI_COMPILER_VERSION__) +static +#endif /*__TI_COMPILER_VERSION__*/ +SYS_IRQ_HANDLER_FNC(tms570_eth_irq){ + struct tms570_netif_state *nf_state = (struct tms570_netif_state *)sys_irq_handler_get_context(); + + sys_arch_mask_interrupt_source(TMS570_IRQ_EMAC_RX); + sys_arch_mask_interrupt_source(TMS570_IRQ_EMAC_TX); + if (nf_state != NULL) + sys_sem_signal_from_ISR(&nf_state->intPend_sem); +} + +void +tms570_eth_memp_avaible(int type) +{ + if (!initialized) + return; + if (type != MEMP_PBUF_POOL) + return; + netifapi_netif_common(eth_lwip_get_netif(0), tms570_eth_rx_pbuf_refill_single, NULL); +} + + + +#if TMS570_NETIF_DEBUG + +void +tms570_eth_debug_print_info(struct netif *netif) +{ + struct tms570_netif_state *nf_state = netif->state; + + tms570_eth_debug_show_rx(nf_state); + tms570_eth_debug_show_tx(nf_state); + tms570_eth_debug_print_HDP(nf_state); +} + +void +tms570_eth_debug_print_HDP(struct tms570_netif_state *nf_state) +{ + tms570_eth_debug_printf("RX HDP = %d\n", tms570_eth_debug_get_BD_num( + (void *)nf_state->emac_base->RXHDP[0], nf_state)); + tms570_eth_debug_printf("TX HDP = %d\n", tms570_eth_debug_get_BD_num( + (void *)nf_state->emac_base->TXHDP[0], nf_state)); +} + +int +tms570_eth_debug_get_BD_num(volatile void *ptr, struct tms570_netif_state *nf_state) +{ + if (ptr == NULL) + return -1; + return ((uintptr_t)ptr-nf_state->emac_ctrl_ram)/sizeof(struct emac_rx_bd); +} + +void +tms570_eth_debug_print_rxch(struct tms570_netif_state *nf_state) +{ + tms570_eth_debug_printf("inactive_head = %d, inactive_tail = %d, active_head = %d, active_tail = %d, freed_pbuf_len = %d\n", + tms570_eth_debug_get_BD_num(nf_state->rxch.inactive_head, nf_state), + tms570_eth_debug_get_BD_num(nf_state->rxch.inactive_tail, nf_state), + tms570_eth_debug_get_BD_num(nf_state->rxch.active_head, nf_state), + tms570_eth_debug_get_BD_num(nf_state->rxch.active_tail, nf_state), + nf_state->rxch.freed_pbuf_len); +} +void +tms570_eth_debug_print_txch(struct tms570_netif_state *nf_state) +{ + tms570_eth_debug_printf("inactive_head = %d, inactive_tail = %d, active_head = %d, active_tail = %d\n", + tms570_eth_debug_get_BD_num(nf_state->txch.inactive_head, nf_state), + tms570_eth_debug_get_BD_num(nf_state->txch.inactive_tail, nf_state), + tms570_eth_debug_get_BD_num(nf_state->txch.active_head, nf_state), + tms570_eth_debug_get_BD_num(nf_state->txch.active_tail, nf_state)); +} +void +tms570_eth_debug_show_BD_chain_rx(volatile struct emac_rx_bd *curr_bd, + struct tms570_netif_state *nf_state) +{ + int count = 0; + + while (curr_bd != NULL) { + tms570_eth_debug_printf("%d ", tms570_eth_debug_get_BD_num(curr_bd, nf_state)); + curr_bd = curr_bd->next; + count++; + } + tms570_eth_debug_printf(" count = %d\n", count); +} + +void +tms570_eth_debug_show_BD_chain_tx(volatile struct emac_tx_bd *curr_bd, + struct tms570_netif_state *nf_state) +{ + int count = 0; + + while (curr_bd != NULL) { + tms570_eth_debug_printf("%d ", tms570_eth_debug_get_BD_num(curr_bd, nf_state)); + curr_bd = curr_bd->next; + count++; + } + tms570_eth_debug_printf(" count = %d\n", count); +} + +void +tms570_eth_debug_show_rx(struct tms570_netif_state *nf_state) +{ + tms570_eth_debug_printf("!!!RX!!!\n"); + tms570_eth_debug_print_rxch(nf_state); + tms570_eth_debug_printf("inactive chain\n"); + tms570_eth_debug_show_BD_chain_rx(nf_state->rxch.inactive_head, nf_state); + tms570_eth_debug_printf("active chain\n"); + tms570_eth_debug_show_BD_chain_rx(nf_state->rxch.active_head, nf_state); +} +void +tms570_eth_debug_show_tx(struct tms570_netif_state *nf_state) +{ + + tms570_eth_debug_printf("!!!TX!!!\n"); + tms570_eth_debug_print_txch(nf_state); + tms570_eth_debug_printf("inactive chain\n"); + tms570_eth_debug_show_BD_chain_tx(nf_state->txch.inactive_head, nf_state); + tms570_eth_debug_printf("active chain\n"); + tms570_eth_debug_show_BD_chain_tx(nf_state->txch.active_head, nf_state); +} +#endif /* if TMS570_NETIF_DEBUG */ diff --git a/uLan/ports/driver/tms570_emac/tms570_netif.h b/uLan/ports/driver/tms570_emac/tms570_netif.h new file mode 100644 index 0000000..325249a --- /dev/null +++ b/uLan/ports/driver/tms570_emac/tms570_netif.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, 2015 Czech Technical University in Prague + * Czech Republic + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Premysl Houdek <houdepre@fel.cvut.cz> + * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz> + * Industrial Informatics Group, FEE, Czech Technical University in Prague + * + * Based on work of Carlos Jenkins, Rostislav Lisovy, Jan Dolezal + */ + +#ifndef __TMS570_NETIF_H +#define __TMS570_NETIF_H + +//#define TMS570_NETIF_DEBUG 1 + +#ifdef TMS570_NETIF_DEBUG +#define tms570_eth_debug_printf sys_arch_printk +#else +#define tms570_eth_debug_printf(...) +#endif + +err_t tms570_eth_init_netif(struct netif *netif); +struct tms570_netif_state *tms570_eth_init_state(); + +#if TMS570_NETIF_DEBUG +struct emac_rx_bd; +int tms570_eth_debug_get_BD_num(volatile void *ptr, struct tms570_netif_state *nf_state); +void tms570_eth_debug_print_rxch(struct tms570_netif_state *nf_state); +void tms570_eth_debug_print_txch(struct tms570_netif_state *nf_state); +void tms570_eth_debug_show_BD_chain(volatile struct emac_rx_bd *curr_bd, struct tms570_netif_state *nf_state); +void tms570_eth_debug_show_rx(struct tms570_netif_state *nf_state); +void tms570_eth_debug_show_tx(struct tms570_netif_state *nf_state); +void tms570_eth_debug_print_HDP(struct tms570_netif_state *nf_state); +void tms570_eth_debug_print_info(struct netif *netif); +#endif /* TMS570_NETIF_DEBUG */ + +#endif /* __TMS570_NETIF_H */ diff --git a/uLan/ports/os/lwipopts.h b/uLan/ports/os/lwipopts.h new file mode 100644 index 0000000..50ac639 --- /dev/null +++ b/uLan/ports/os/lwipopts.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ +#ifndef LWIP_HDR_LWIPOPTS_H__ +#define LWIP_HDR_LWIPOPTS_H__ + +/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */ +#define NO_SYS 0 +#define LWIP_NETCONN 1 +#define LWIP_SOCKET 1 +#define LWIP_DNS 1 + +#define LWIP_IPV6 1 +#define LWIP_IPV4 1 + +#define LWIP_ETHERNET 1 +#define LWIP_NETIF_API 1 +/* Enable DHCP to test it, disable UDP checksum to easier inject packets */ +#define LWIP_DHCP 1 +#define LWIP_TIMEVAL_PRIVATE 0 +#define LWIP_POSIX_SOCKETS_IO_NAMES 0 + +/* Minimal changes to opt.h required for tcp unit tests: */ +#define MEM_SIZE 16000 +#define TCP_SND_QUEUELEN 40 +#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN +#define TCP_SND_BUF (12 * TCP_MSS) +#define TCP_WND (10 * TCP_MSS) +#define LWIP_WND_SCALE 1 +#define TCP_RCV_SCALE 0 +#define PBUF_POOL_SIZE 400 // pbuf tests need ~200KByte + +/* Minimal changes to opt.h required for etharp unit tests: */ +#define ETHARP_SUPPORT_STATIC_ENTRIES 1 + +#endif /* LWIP_HDR_LWIPOPTS_H__ */ diff --git a/uLan/ports/os/rtems/arch/cc.h b/uLan/ports/os/rtems/arch/cc.h new file mode 100644 index 0000000..84138ff --- /dev/null +++ b/uLan/ports/os/rtems/arch/cc.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is system adaptation of the lwIP TCP/IP stack + * by Adam Dunkels <adam@sics.se> for RTEMS system. + * + * Author: Premysl Houdek <houdepre@fel.cvut.cz> + * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz> + * Industrial Informatics Group, FEE, Czech Technical University in Prague + * + */ +/* + * settings to adapt lwIP for compiler and machine architecture for RTEMS/GCC + * DETAILS: ./lwip/doc/sys_arch.txt + */ +#ifndef __CC_H__ +#define __CC_H__ + +#include <stdio.h> +#include <rtems/malloc.h> /*printk*/ +#include <inttypes.h> +#include <malloc.h> +#include <sys/time.h> +#include <rtems.h> +#include <sys/errno.h> +#include <endian.h> +#include <stdlib.h> +#include <stdint.h> + +#include <sys/uio.h> /*struct iovec*/ + +#ifndef iovec +#define iovec iovec +#endif + +/* This file must either include a system-local <errno.h> which defines + the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO + to make lwip/arch.h define the codes which are used throughout. */ +#undef LWIP_PROVIDE_ERRNO + +#if !defined(LWIP_NO_STDINT_H) +#define LWIP_NO_STDINT_H 0 +#endif + +#if LWIP_NO_STDINT_H +/* type definitions */ +typedef uint8_t u8_t; +typedef int8_t s8_t; +typedef uint16_t u16_t; +typedef int16_t s16_t; +typedef uint32_t u32_t; +typedef int32_t s32_t; +typedef u32_t mem_ptr_t; + +#endif /*LWIP_NO_STDINT_H*/ + +#if !defined(LWIP_NO_INTTYPES_H) +#define LWIP_NO_INTTYPES_H 0 +#endif + +#if LWIP_NO_INTTYPES_H +/* Define (sn)printf formatters for these lwIP types */ +#define U16_F PRIu16 +#define S16_F PRId16 +#define X16_F PRIx16 +#define U32_F PRIu32 +#define S32_F PRId32 +#define X32_F PRIx32 +#endif /*LWIP_NO_INTTYPES_H*/ + +#if defined(__arm__) && defined(__ARMCC_VERSION) +// +// Setup PACKing macros for KEIL/RVMDK Tools +// + #define PACK_STRUCT_BEGIN __packed + #define PACK_STRUCT_STRUCT + #define PACK_STRUCT_END + #define PACK_STRUCT_FIELD(x) x +#elif defined (__IAR_SYSTEMS_ICC__) +// +// Setup PACKing macros for IAR Tools +// + #define PACK_STRUCT_BEGIN + #define PACK_STRUCT_STRUCT + #define PACK_STRUCT_END + #define PACK_STRUCT_FIELD(x) x + #define PACK_STRUCT_USE_INCLUDES +#elif defined (__TMS470__) + #define PACK_STRUCT_BEGIN + #define PACK_STRUCT_STRUCT + #define PACK_STRUCT_END + #define PACK_STRUCT_FIELD(x) x +#else +// +// Setup PACKing macros for GCC Tools +// + #define PACK_STRUCT_BEGIN + #define PACK_STRUCT_STRUCT __attribute__ ((__packed__)) + #define PACK_STRUCT_END + #define PACK_STRUCT_FIELD(x) x +#endif + +/* + * 1 - load byte by byte, construct 16 bits word and add: not efficient for most platforms + * 2 - load first byte if odd address, loop processing 16 bits words, add last byte. + * 3 - load first byte and word if not 4 byte aligned, loop processing 32 bits words, add last word/byte. + * + * see inet_chksum.c + */ +#ifndef LWIP_CHKSUM_ALGORITHM +#define LWIP_CHKSUM_ALGORITHM 2 +#endif + +/* this is used for 1) displaying statistics and 2) lwip debugging (set appropriate debugging level in lwipopts.h) */ +//#ifdef LWIP_DEBUG + + +#define LWIP_PLATFORM_DIAG(expr) printk expr + +//#else +//#define LWIP_PLATFORM_DIAG(expr) +//#endif + +//#define DEBUG +#ifdef DEBUG + +/* for passing arguments to print function */ +#define CC_ASSERT(message, assertion) do { if (!(assertion)) \ + LWIP_PLATFORM_DIAG(message); } while (0) + +//extern void __error__(char *pcFilename, unsigned long ulLine); +#define LWIP_PLATFORM_ASSERT(expr) printk((const char *)expr) +/* +{ \ + if(!(expr)) \ + { \ + __error__(__FILE__, __LINE__); \ + } \ +} +*/ +#else +#define LWIP_PLATFORM_ASSERT(expr) +#define CC_ASSERT(message, assertion) +#endif /* DEBUG */ + +/* "lightweight" synchronization mechanisms */ +/* #define SYS_ARCH_DECL_PROTECT(x) */ /* declare a protection state variable */ +/* #define SYS_ARCH_PROTECT(x) */ /* enter protection mode */ +/* #define SYS_ARCH_UNPROTECT(x) */ /* leave protection mode */ + +/* 32-bit random value used by igmp and others */ +#define LWIP_RAND() ((uint32_t)random()) + +#endif /* __CC_H__ */ diff --git a/uLan/ports/os/rtems/arch/perf.h b/uLan/ports/os/rtems/arch/perf.h new file mode 100644 index 0000000..1f799b3 --- /dev/null +++ b/uLan/ports/os/rtems/arch/perf.h @@ -0,0 +1,12 @@ +#ifndef _LWIP_ARCH_PERF_H_ +#define _LWIP_ARCH_PERF_H_ + +//perf.h - Architecture specific performance measurement. +//Measurement calls made throughout lwip, these can be defined to nothing. + +#define PERF_START + +#define PERF_STOP(x) + + +#endif /* _LWIP_ARCH_PERF_H_ */ diff --git a/uLan/ports/os/rtems/arch/sys_arch.c b/uLan/ports/os/rtems/arch/sys_arch.c new file mode 100644 index 0000000..ca7f8be --- /dev/null +++ b/uLan/ports/os/rtems/arch/sys_arch.c @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is system adaptation of the lwIP TCP/IP stack + * by Adam Dunkels <adam@sics.se> for RTEMS system. + * + * Author: Premysl Houdek <houdepre@fel.cvut.cz> + * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz> + * Industrial Informatics Group, FEE, Czech Technical University in Prague + * + */ +/* + * mapping of lwIP system dependencies to RTEMS system services and types. + * DETAILS: ./lwip/doc/sys_arch.txt + */ + +#include <stdint.h> +#include <arch/cc.h> +#include <rtems/rtems/clock.h> +#include <rtems/rtems/sem.h> +#include <rtems.h> +#include "sys_arch.h" +#include "lwip/err.h" +#include "lwip/tcpip.h" +#include "lwipopts.h" + +#define SYS_LWIP_MBOX_SIZE (sizeof(void *)) + +uint32_t +sys_now() +{ + uint64_t temp = rtems_clock_get_uptime_nanoseconds() / (1000 * 1000); + + return temp; +} + +void +sys_init(void) +{ + // Is called to initialize the sys_arch layer. + return; +} + +err_t +sys_sem_new(sys_sem_t *sem, u8_t count) +{ + rtems_status_code ret = rtems_semaphore_create( + rtems_build_name('L', 'W', 'I', 'P'), + count, + RTEMS_COUNTING_SEMAPHORE, + 0, + &sem->semaphore + ); + + if (ret != RTEMS_SUCCESSFUL) { + sem->semaphore = RTEMS_ID_NONE; + return ret; + } + return ERR_OK; +} + + +void +sys_sem_free(sys_sem_t *sem) +{ + rtems_semaphore_delete( + sem->semaphore + ); + sem->semaphore = RTEMS_ID_NONE; +} + +void +sys_sem_signal(sys_sem_t *sem) +{ + rtems_semaphore_release(sem->semaphore); +} + +void +sys_sem_signal_from_ISR(sys_sem_t *sem) +{ + rtems_semaphore_release(sem->semaphore); +} + + +u32_t +sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) +{ + rtems_status_code status; + rtems_interval tps = rtems_clock_get_ticks_per_second(); + rtems_interval tick_timeout; + uint64_t start_time; + uint64_t wait_time; + + start_time = rtems_clock_get_uptime_nanoseconds(); + if (timeout == 0) { + tick_timeout = RTEMS_NO_TIMEOUT; + } else { + tick_timeout = (timeout * tps + 999) / 1000; + } + status = rtems_semaphore_obtain(sem->semaphore, RTEMS_WAIT, tick_timeout); + if (status == RTEMS_TIMEOUT) { + return SYS_ARCH_TIMEOUT; + } + if (status != RTEMS_SUCCESSFUL) { + return SYS_ARCH_TIMEOUT; + } + wait_time = rtems_clock_get_uptime_nanoseconds() - start_time; + return wait_time / (1000 * 1000); +} + +int +sys_sem_valid(sys_sem_t *sem) +{ + return sem->semaphore == RTEMS_ID_NONE ? 0 : 1; +} + +void +sys_sem_set_invalid(sys_sem_t *sem) +{ + sem->semaphore = RTEMS_ID_NONE; +} + +err_t +sys_mbox_new(sys_mbox_t *mbox, int size) +{ + rtems_status_code ret; + + ret = rtems_message_queue_create( + rtems_build_name('L', 'W', 'I', 'P'), + size, + SYS_LWIP_MBOX_SIZE, + 0, + &mbox->mailbox + ); + ret |= rtems_semaphore_create( + rtems_build_name('L', 'W', 'I', 'P'), + size, + RTEMS_COUNTING_SEMAPHORE, + 0, + &mbox->sem + ); + if (ret != RTEMS_SUCCESSFUL) { + mbox->mailbox = RTEMS_ID_NONE; + mbox->sem = RTEMS_ID_NONE; + return ret; + } + return ERR_OK; +} + +void +sys_mbox_free(sys_mbox_t *mbox) +{ + rtems_message_queue_delete(mbox->mailbox); + rtems_semaphore_delete(mbox->sem); + sys_mbox_set_invalid(mbox); +} + +void +sys_mbox_post(sys_mbox_t *mbox, void *msg) +{ + rtems_semaphore_obtain(mbox->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + rtems_message_queue_send(mbox->mailbox, &msg, SYS_LWIP_MBOX_SIZE); +} +err_t +sys_mbox_trypost(sys_mbox_t *mbox, void *msg) +{ + rtems_status_code status = rtems_semaphore_obtain(mbox->sem, + RTEMS_NO_WAIT, 0); + + if (status != RTEMS_SUCCESSFUL) { + return ERR_MEM; + } else { + rtems_message_queue_send(mbox->mailbox, &msg, SYS_LWIP_MBOX_SIZE); + return ERR_OK; + } +} + +u32_t +sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) +{ + rtems_status_code status; + rtems_interval tps = rtems_clock_get_ticks_per_second(); + rtems_interval tick_timeout; + uint64_t start_time; + uint64_t wait_time; + size_t dummy; + + start_time = rtems_clock_get_uptime_nanoseconds(); + if (timeout == 0) { + tick_timeout = RTEMS_NO_TIMEOUT; + } else { + tick_timeout = (timeout * tps + 999) / 1000; + } + status = rtems_message_queue_receive(mbox->mailbox, + msg, + &dummy, + RTEMS_WAIT, + tick_timeout + ); + if (status == RTEMS_TIMEOUT) { + return SYS_ARCH_TIMEOUT; + } + if (status != RTEMS_SUCCESSFUL) { + return SYS_ARCH_TIMEOUT; + } + wait_time = rtems_clock_get_uptime_nanoseconds() - start_time; + rtems_semaphore_release(mbox->sem); + return wait_time / (1000 * 1000); +} + +u32_t +sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) +{ + rtems_status_code status; + size_t dummy; + + status = rtems_message_queue_receive(mbox->mailbox, msg, + &dummy, + RTEMS_NO_WAIT, + 0 + ); + + if (status != RTEMS_SUCCESSFUL) { + return SYS_MBOX_EMPTY; + } else { + rtems_semaphore_release(mbox->sem); + return 0; + } +} +int +sys_mbox_valid(sys_mbox_t *mbox) +{ + return mbox->mailbox == RTEMS_ID_NONE ? 0 : 1; +} +void +sys_mbox_set_invalid(sys_mbox_t *mbox) +{ + mbox->sem = RTEMS_ID_NONE; + mbox->mailbox = RTEMS_ID_NONE; +} + +sys_thread_t +sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stack_size, int prio) +{ + rtems_id id; + rtems_status_code res; + + res = rtems_task_create( + rtems_build_name('L', 'W', 'I', 'P'), + prio, + stack_size, + RTEMS_PREEMPT, + 0, + &id + ); + + if (res != RTEMS_SUCCESSFUL) { + return 0; + } + + res = rtems_task_start(id, (rtems_task_entry)function, (rtems_task_argument)arg); + + if (res != RTEMS_SUCCESSFUL) { + rtems_task_delete(id); + return 0; + } + return id; +} + +err_t +sys_mutex_new(sys_mutex_t *mutex) +{ + rtems_status_code ret = rtems_semaphore_create( + rtems_build_name('L', 'W', 'I', 'P'), + 1, + RTEMS_PRIORITY|RTEMS_BINARY_SEMAPHORE|RTEMS_INHERIT_PRIORITY|RTEMS_LOCAL, + 0, + &mutex->mutex + ); + + if (ret != RTEMS_SUCCESSFUL) { + mutex->mutex = RTEMS_ID_NONE; + return ret; + } + return ERR_OK; +} +/** Lock a mutex + * @param mutex the mutex to lock */ +void +sys_mutex_lock(sys_mutex_t *mutex) +{ + rtems_semaphore_obtain(mutex->mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); +} +/** Unlock a mutex + * @param mutex the mutex to unlock */ +void +sys_mutex_unlock(sys_mutex_t *mutex) +{ + rtems_semaphore_release(mutex->mutex); +} +/** Delete a semaphore + * @param mutex the mutex to delete */ +void +sys_mutex_free(sys_mutex_t *mutex) +{ + rtems_semaphore_delete(mutex->mutex); +} + +void +sys_arch_delay(unsigned int timeout) +{ + rtems_interval tps = rtems_clock_get_ticks_per_second(); + rtems_interval tick_timeout = (timeout * tps + 999) / 1000; + + rtems_task_wake_after(tick_timeout); +} + +/** Ticks/jiffies since power up. */ +uint32_t +sys_jiffies(void) +{ + return rtems_clock_get_ticks_since_boot(); +} + +int +sys_request_irq(unsigned int irqnum, sys_irq_handler_t handler, + unsigned long flags, const char *name, void *context) +{ + rtems_status_code res; + + res = rtems_interrupt_handler_install(irqnum, name, flags, + handler, context); + return (res != RTEMS_SUCCESSFUL) ? -1 : 0; +} + +sys_prot_t +sys_arch_protect() +{ + sys_prot_t pval; + + rtems_interrupt_disable(pval); + return pval; +} + +void +sys_arch_unprotect(sys_prot_t pval) +{ + rtems_interrupt_enable(pval); +} +err_t +sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg) +{ + return sys_mbox_trypost(q, msg); +} + diff --git a/uLan/ports/os/rtems/arch/sys_arch.h b/uLan/ports/os/rtems/arch/sys_arch.h new file mode 100644 index 0000000..c89abd4 --- /dev/null +++ b/uLan/ports/os/rtems/arch/sys_arch.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is system adaptation of the lwIP TCP/IP stack + * by Adam Dunkels <adam@sics.se> for RTEMS system. + * + * Author: Premysl Houdek <houdepre@fel.cvut.cz> + * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz> + * Industrial Informatics Group, FEE, Czech Technical University in Prague + * + */ +/* + * mapping of lwIP system dependencies to RTEMS system services and types. + * DETAILS: ./lwip/doc/sys_arch.txt + */ +#ifndef __ARCH_SYS_ARCH_H__ +#define __ARCH_SYS_ARCH_H__ + +#include <rtems/rtems/sem.h> +#include <rtems/rtems/intr.h> +#include <rtems/score/cpu.h> +#include <bsp/irq-generic.h> +//#include "eth_lwip_default.h" + +/* Typedefs for the various port-specific types. */ +#if defined(NO_SYS) && NO_SYS + #error "RTEMS SYS_ARCH cannot be compiled in NO_SYS variant" +#endif + +#define sys_arch_printk printk + +typedef struct { + rtems_id mailbox; + rtems_id sem; +} port_mailbox_t; + +typedef struct { + rtems_id semaphore; +} port_sem_t; + +typedef struct { + rtems_id mutex; +} port_mutex_t; + +typedef port_mailbox_t sys_mbox_t; +typedef port_sem_t sys_sem_t; +typedef rtems_id sys_thread_t; +typedef port_mutex_t sys_mutex_t; +typedef rtems_interrupt_level sys_prot_t; + +void +sys_arch_delay(unsigned int x); +void +sys_sem_signal_from_ISR(sys_sem_t *sem); + +typedef void sys_irqreturn_t; +#define SYS_IRQ_NONE ((void)0) +#define SYS_IRQ_HANDLED ((void)1) +#define SYS_IRQ_RETVAL(x) (IRQ_HANDLED) +typedef rtems_interrupt_handler sys_irq_handler_t; +#define SYS_IRQ_HANDLER_FNC(M_fnc_name) \ + sys_irqreturn_t M_fnc_name(void *__irq_handler_context) +#define sys_irq_handler_get_context() (__irq_handler_context) + +int +sys_request_irq(unsigned int irqnum, sys_irq_handler_t handler, + unsigned long flags, const char *name, void *context); + +static inline void +sys_arch_mask_interrupt_source(unsigned int x) +{ + bsp_interrupt_vector_disable(x); +} + +static inline void +sys_arch_unmask_interrupt_source(unsigned int x) +{ + bsp_interrupt_vector_enable(x); +} + +sys_prot_t sys_arch_protect(); + +void sys_arch_unprotect(sys_prot_t pval); + +#endif /* __ARCH_SYS_ARCH_H__ */ |