rt-thread-official/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_hw.c

277 lines
9.2 KiB
C

/*
* Copyright (C) 2010 - 2019 Xilinx, Inc.
* 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.
*
*/
#include "netif/xemacpsif.h"
#include "lwipopts.h"
#if XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1 || \
XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1
#define PCM_PMA_CORE_PRESENT
#else
#undef PCM_PMA_CORE_PRESENT
#endif
u32_t link_speed = 100;
extern XEmacPs_Config XEmacPs_ConfigTable[];
extern u32_t phymapemac0[32];
extern u32_t phymapemac1[32];
extern u32_t phyaddrforemac;
extern enum ethernet_link_status eth_link_status;
#ifdef OS_IS_FREERTOS
extern long xInsideISR;
#endif
XEmacPs_Config *xemacps_lookup_config(unsigned mac_base)
{
XEmacPs_Config *cfgptr = NULL;
s32_t i;
for (i = 0; i < XPAR_XEMACPS_NUM_INSTANCES; i++) {
if (XEmacPs_ConfigTable[i].BaseAddress == mac_base) {
cfgptr = &XEmacPs_ConfigTable[i];
break;
}
}
return (cfgptr);
}
void init_emacps(xemacpsif_s *xemacps, struct netif *netif)
{
XEmacPs *xemacpsp;
s32_t status = XST_SUCCESS;
u32_t i;
u32_t phyfoundforemac0 = FALSE;
u32_t phyfoundforemac1 = FALSE;
xemacpsp = &xemacps->emacps;
#ifdef ZYNQMP_USE_JUMBO
XEmacPs_SetOptions(xemacpsp, XEMACPS_JUMBO_ENABLE_OPTION);
#endif
#ifdef LWIP_IGMP
XEmacPs_SetOptions(xemacpsp, XEMACPS_MULTICAST_OPTION);
#endif
/* set mac address */
status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
if (status != XST_SUCCESS) {
xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
}
XEmacPs_SetMdioDivisor(xemacpsp, MDC_DIV_224);
/* Please refer to file header comments for the file xemacpsif_physpeed.c
* to know more about the PHY programming sequence.
* For PCS PMA core, phy_setup_emacps is called with the predefined PHY address
* exposed through xaparemeters.h
* For RGMII case, assuming multiple PHYs can be present on the MDIO bus,
* detect_phy is called to get the addresses of the PHY present on
* a particular MDIO bus (emac0 or emac1). This address map is populated
* in phymapemac0 or phymapemac1.
* phy_setup_emacps is then called for each PHY present on the MDIO bus.
*/
#ifdef PCM_PMA_CORE_PRESENT
#ifdef XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT
link_speed = phy_setup_emacps(xemacpsp, XPAR_PCSPMA_1000BASEX_PHYADDR);
#elif XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT
link_speed = phy_setup_emacps(xemacpsp, XPAR_PCSPMA_SGMII_PHYADDR);
#endif
#else
detect_phy(xemacpsp);
for (i = 31; i > 0; i--) {
if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
if (phymapemac0[i] == TRUE) {
link_speed = phy_setup_emacps(xemacpsp, i);
phyfoundforemac0 = TRUE;
phyaddrforemac = i;
}
} else {
if (phymapemac1[i] == TRUE) {
link_speed = phy_setup_emacps(xemacpsp, i);
phyfoundforemac1 = TRUE;
phyaddrforemac = i;
}
}
}
/* If no PHY was detected, use broadcast PHY address of 0 */
if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
if (phyfoundforemac0 == FALSE)
link_speed = phy_setup_emacps(xemacpsp, 0);
} else {
if (phyfoundforemac1 == FALSE)
link_speed = phy_setup_emacps(xemacpsp, 0);
}
#endif
if (link_speed == XST_FAILURE) {
eth_link_status = ETH_LINK_DOWN;
xil_printf("Phy setup failure %s \n\r",__func__);
return;
} else {
eth_link_status = ETH_LINK_UP;
}
XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
/* Setting the operating speed of the MAC needs a delay. */
{
volatile s32_t wait;
for (wait=0; wait < 20000; wait++);
}
}
void init_emacps_on_error (xemacpsif_s *xemacps, struct netif *netif)
{
XEmacPs *xemacpsp;
s32_t status = XST_SUCCESS;
xemacpsp = &xemacps->emacps;
/* set mac address */
status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
if (status != XST_SUCCESS) {
xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
}
XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
/* Setting the operating speed of the MAC needs a delay. */
{
volatile s32_t wait;
for (wait=0; wait < 20000; wait++);
}
}
void setup_isr (struct xemac_s *xemac)
{
xemacpsif_s *xemacpsif;
xemacpsif = (xemacpsif_s *)(xemac->state);
/*
* Setup callbacks
*/
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMASEND,
(void *) emacps_send_handler,
(void *) xemac);
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMARECV,
(void *) emacps_recv_handler,
(void *) xemac);
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_ERROR,
(void *) emacps_error_handler,
(void *) xemac);
}
void start_emacps (xemacpsif_s *xemacps)
{
/* start the temac */
XEmacPs_Start(&xemacps->emacps);
}
void restart_emacps_transmitter (xemacpsif_s *xemacps) {
u32_t Reg;
Reg = XEmacPs_ReadReg(xemacps->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
Reg = Reg & (~XEMACPS_NWCTRL_TXEN_MASK);
XEmacPs_WriteReg(xemacps->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET, Reg);
Reg = XEmacPs_ReadReg(xemacps->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
Reg = Reg | (XEMACPS_NWCTRL_TXEN_MASK);
XEmacPs_WriteReg(xemacps->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET, Reg);
}
void emacps_error_handler(void *arg,u8 Direction, u32 ErrorWord)
{
struct xemac_s *xemac;
xemacpsif_s *xemacpsif;
XEmacPs_BdRing *rxring;
XEmacPs_BdRing *txring;
#ifdef OS_IS_FREERTOS
xInsideISR++;
#endif
xemac = (struct xemac_s *)(arg);
xemacpsif = (xemacpsif_s *)(xemac->state);
rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps);
txring = &XEmacPs_GetTxRing(&xemacpsif->emacps);
if (ErrorWord != 0) {
switch (Direction) {
case XEMACPS_RECV:
if (ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Receive DMA error\r\n"));
HandleEmacPsError(xemac);
}
if (ErrorWord & XEMACPS_RXSR_RXOVR_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Receive over run\r\n"));
emacps_recv_handler(arg);
setup_rx_bds(xemacpsif, rxring);
}
if (ErrorWord & XEMACPS_RXSR_BUFFNA_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Receive buffer not available\r\n"));
emacps_recv_handler(arg);
setup_rx_bds(xemacpsif, rxring);
}
break;
case XEMACPS_SEND:
if (ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Transmit DMA error\r\n"));
HandleEmacPsError(xemac);
}
if (ErrorWord & XEMACPS_TXSR_URUN_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Transmit under run\r\n"));
HandleTxErrors(xemac);
}
if (ErrorWord & XEMACPS_TXSR_BUFEXH_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Transmit buffer exhausted\r\n"));
HandleTxErrors(xemac);
}
if (ErrorWord & XEMACPS_TXSR_RXOVR_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Transmit retry excessed limits\r\n"));
HandleTxErrors(xemac);
}
if (ErrorWord & XEMACPS_TXSR_FRAMERX_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Transmit collision\r\n"));
// process_sent_bds(xemacpsif, txring);
}
break;
}
}
#ifdef OS_IS_FREERTOS
xInsideISR--;
#endif
}