Skip to content

Instantly share code, notes, and snippets.

@possan
Created December 25, 2020 22:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save possan/7630b411bc3ed2a7d2cd840eb3f4146f to your computer and use it in GitHub Desktop.
Save possan/7630b411bc3ed2a7d2cd840eb3f4146f to your computer and use it in GitHub Desktop.
/******************************************************************************
*
* Copyright (C) 2010 - 2019 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*
*
******************************************************************************/
/****************************************************************************/
/**
*
* @file xemacps_example_intr_dma.c
*
* Implements examples that utilize the EmacPs's interrupt driven DMA
* packet transfer mode to send and receive frames.
*
* These examples demonstrate:
*
* - How to perform simple send and receive.
* - Interrupt
* - Error handling
* - Device reset
*
* Functional guide to example:
*
* - EmacPsDmaSingleFrameIntrExample demonstrates the simplest way to send and
* receive frames in in interrupt driven DMA mode.
*
* - EmacPsErrorHandler() demonstrates how to manage asynchronous errors.
*
* - EmacPsResetDevice() demonstrates how to reset the driver/HW without
* losing all configuration settings.
*
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a wsy 01/10/10 First release
* 1.00a asa 11/25/11 The cache disable routines are removed. So now both
* I-cache and D-cache are enabled. The array RxBuffer is
* removed to avoid an extra copy from RxBuffer to RxFrame.
* Now the address of RxFrame is submitted to the Rx BD
* instead of the address of RxBuffer.
* In function EmacPsDmaSingleFrameIntrExample, BdRxPtr
* is made as a pointer instead of array of pointers. This
* is done since on the Rx path we now submit a single BD
* instead of all 32 BDs. Because of this change, relevant
* changes are made throughout the function
* EmacPsDmaSingleFrameIntrExample.
* Cache invalidation is now being done for the RxFrame
* buffer.
* The unnecessary cache flush (Xil_DCacheFlushRange) is
* removed. This was being done towards the end of the
* example which was unnecessary.
* 1.00a asa 01/24/12 Support for Zynq board is added. The SLCR divisors are
* different for Zynq. Changes are made for the same.
* Presently the SLCR GEM clock divisors are hard-coded
* assuming that IO PLL output frequency is 1000 MHz.
* The BDs are allocated at the address 0xFF00000 and the
* 1 MB address range starting from this address is made
* uncached. This is because, for GEM the BDs need to be
* placed in uncached memory. The RX BDs are allocated at
* address 0xFF00000 and TX BDs are allocated at address
* 0xFF10000.
* The MDIO divisor used of 224 is used for Zynq board.
* 1.01a asa 02/27/12 The hardcoded SLCR divisors for Zynq are removed. The
* divisors are obtained from xparameters.h.c. The sleep
* values are reduced for Zynq. One sleep is added after
* MDIO divisor is set. Some of the prints are removed.
* 1.01a asa 03/14/12 The SLCR divisor support for ENET1 is added.
* 1.01a asa 04/15/12 The funcation calls to Xil_DisableMMU and Xil_EnableMMU
* are removed for setting the translation table
* attributes for the BD memory region.
* 1.05a asa 09/22/13 Cache handling is changed to fix an issue (CR#663885).
* The cache invalidation of the Rx frame is now moved to
* XEmacPsRecvHandler so that invalidation happens after the
* received data is available in the memory. The variable
* TxFrameLength is now made global.
* 2.1 srt 07/11/14 Implemented 64-bit changes and modified as per
* Zynq Ultrascale Mp GEM specification
* 3.0 kpc 01/23/14 Removed PEEP board related code
* 3.0 hk 03/18/15 Added support for jumbo frames.
* Add cache flush after BD terminate entries.
* 3.2 hk 10/15/15 Added clock control using CRL_APB_GEM_REF_CTRL register.
* Enabled 1G speed for ZynqMP GEM.
* Select GEM interrupt based on instance present.
* Manage differences between emulation platform and silicon.
* 3.2 mus 20/02/16.Added support for INTC interrupt controlller.
* Added support to access zynq emacps interrupt from
* microblaze.
* 3.3 kpc 12/09/16 Fixed issue when -O2 is enabled
* 3.4 ms 01/23/17 Modified xil_printf statement in main function to
* ensure that "Successfully ran" and "Failed" strings
* are available in all examples. This is a fix for
* CR-965028.
* 3.5 hk 08/14/17 Don't perform data cache operations when CCI is enabled
* on ZynqMP.
* 3.8 hk 10/01/18 Fix warning for redefinition of interrupt number.
* 3.9 hk 02/12/19 Change MDC divisor for Versal emulation.
* 03/06/19 Fix BD space assignment and its memory attributes.
* 03/20/19 Fix alignment pragmas for IAR compiler.
* 3.10 hk 05/17/19 Use correct platform register for Versal.
* 08/12/19 Add clock setup support for Versal.
* 14/08/19 Move definition of Platform to _util file for common use.
* 08/24/19 Add support for clock configuration in EL1 Non Secure for
* Versal.
*
* </pre>
*
*****************************************************************************/
/***************************** Include Files ********************************/
#include "xemacps_example.h"
#include "xil_exception.h"
#ifndef __MICROBLAZE__
#include "xil_mmu.h"
#endif
#if EL1_NONSECURE
#include "xil_smc.h"
#endif
/*************************** Constant Definitions ***************************/
/*
* The following constants map to the XPAR parameters created in the
* xparameters.h file. They are defined here such that a user can easily
* change all the needed parameters in one place.
*/
#ifdef __MICROBLAZE__
#define XPS_SYS_CTRL_BASEADDR XPAR_PS7_SLCR_0_S_AXI_BASEADDR
#endif
#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC XIntc
#define EMACPS_DEVICE_ID XPAR_XEMACPS_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID
#else
#define INTC XScuGic
#define EMACPS_DEVICE_ID XPAR_XEMACPS_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#endif
#if defined(XPAR_INTC_0_DEVICE_ID)
#define EMACPS_IRPT_INTR XPAR_AXI_INTC_0_PROCESSING_SYSTEM7_0_IRQ_P2F_ENET0_INTR
#elif defined(XPAR_PSV_ETHERNET_0_DEVICE_ID) || \
defined(XPAR_PSU_ETHERNET_0_DEVICE_ID) || \
defined(XPAR_PS7_ETHERNET_0_DEVICE_ID)
#define EMACPS_IRPT_INTR XPS_GEM0_INT_ID
#elif defined(XPAR_PSV_ETHERNET_1_DEVICE_ID) || \
defined(XPAR_PSU_ETHERNET_1_DEVICE_ID) || \
defined(XPAR_PS7_ETHERNET_1_DEVICE_ID)
#define EMACPS_IRPT_INTR XPS_GEM1_INT_ID
#elif defined(XPAR_PSU_ETHERNET_2_DEVICE_ID)
#define EMACPS_IRPT_INTR XPS_GEM2_INT_ID
#elif defined(XPAR_PSU_ETHERNET_3_DEVICE_ID)
#define EMACPS_IRPT_INTR XPS_GEM3_INT_ID
#endif
#define RXBD_CNT 4 /* Number of RxBDs to use */
#define TXBD_CNT 4 /* Number of TxBDs to use */
/*
* SLCR setting
*/
#define SLCR_LOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x4)
#define SLCR_UNLOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x8)
#define SLCR_GEM0_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x140)
#define SLCR_GEM1_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x144)
#define SLCR_LOCK_KEY_VALUE 0x767B
#define SLCR_UNLOCK_KEY_VALUE 0xDF0D
#define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214)
/* CRL APB registers for GEM clock control */
#ifdef XPAR_PSU_CRL_APB_S_AXI_BASEADDR
#define CRL_GEM0_REF_CTRL (XPAR_PSU_CRL_APB_S_AXI_BASEADDR + 0x50)
#define CRL_GEM1_REF_CTRL (XPAR_PSU_CRL_APB_S_AXI_BASEADDR + 0x54)
#define CRL_GEM2_REF_CTRL (XPAR_PSU_CRL_APB_S_AXI_BASEADDR + 0x58)
#define CRL_GEM3_REF_CTRL (XPAR_PSU_CRL_APB_S_AXI_BASEADDR + 0x5C)
#endif
#define CRL_GEM_DIV_MASK 0x003F3F00
#define CRL_GEM_1G_DIV0 0x00000C00
#define CRL_GEM_1G_DIV1 0x00010000
#ifdef XPAR_PSV_CRL_0_S_AXI_BASEADDR
#define CRL_GEM0_REF_CTRL (XPAR_PSV_CRL_0_S_AXI_BASEADDR + 0x118)
#define CRL_GEM1_REF_CTRL (XPAR_PSV_CRL_0_S_AXI_BASEADDR + 0x11C)
#endif
#define CRL_GEM_DIV_VERSAL_MASK 0x0003FF00
#define CRL_GEM_DIV_VERSAL_SHIFT 8
#define JUMBO_FRAME_SIZE 10240
#define FRAME_HDR_SIZE 18
#define GEMVERSION_ZYNQMP 0x7
#define GEMVERSION_VERSAL 0x107
/*************************** Variable Definitions ***************************/
#ifdef __ICCARM__
#pragma data_alignment = 64
EthernetFrame TxFrame; /* Transmit buffer */
#pragma data_alignment = 64
EthernetFrame RxFrame; /* Receive buffer */
#else
EthernetFrame TxFrame; /* Transmit buffer */
EthernetFrame RxFrame; /* Receive buffer */
#endif
/*
* Buffer descriptors are allocated in uncached memory. The memory is made
* uncached by setting the attributes appropriately in the MMU table.
*/
// #define RXBD_SPACE_BYTES XEmacPs_BdRingMemCalc(XEMACPS_BD_ALIGNMENT, RXBD_CNT)
// #define TXBD_SPACE_BYTES XEmacPs_BdRingMemCalc(XEMACPS_BD_ALIGNMENT, TXBD_CNT)
/*
* Buffer descriptors are allocated in uncached memory. The memory is made
* uncached by setting the attributes appropriately in the MMU table.
* The minimum region for which attribute settings take effect is 2MB for
* arm 64 variants(A53) and 1MB for the rest (R5 and A9). Hence the same
* is allocated, even if not used fully by this example, to make sure none
* of the adjacent global memory is affected.
*/
//#ifdef __ICCARM__
//#if defined __aarch64__
//#pragma data_alignment = 0x200000
//u8 bd_space[0x200000];
//#else
//#pragma data_alignment = 0x100000
//u8 bd_space[0x100000];
//#endif
//#else
//#if defined __aarch64__
// u8 bd_space[0x200000] __attribute__ ((aligned (0x200000)));
//#else
u8 rxSpace[0x100000] __attribute__ ((aligned (0x100000)));
u8 txSpace[0x100000] __attribute__ ((aligned (0x100000)));
//#endif
//#endif
// #define RX_BD_START_ADDRESS 0x0FF00000
// #define TX_BD_START_ADDRESS 0x0FF10000
// u8 *RxBdSpacePtr;
// u8 *TxBdSpacePtr;
// #ifdef __ICCARM__
// #pragma data_alignment = XEMACPS_RX_BUF_ALIGNMENT
// u8 RxBuf[RXBD_CNT][1600];
// #else
u8 RxBuf[RXBD_CNT][1600] __attribute__ ((aligned(32)));
u8 FrameBuffer[1600] __attribute__ ((aligned(32)));
// #endif
// #define FIRST_FRAGMENT_SIZE 64
/*
* Counters to be incremented by callbacks
*/
volatile s32 FramesRx; /* Frames have been received */
volatile s32 FramesTx; /* Frames have been sent */
volatile s32 DeviceErrors; /* Number of errors detected in the device */
u32 TxFrameLength;
#ifndef TESTAPP_GEN
static INTC IntcInstance;
#endif
#ifdef __ICCARM__
#pragma data_alignment = 64
XEmacPs_Bd BdTxTerminate;
#pragma data_alignment = 64
XEmacPs_Bd BdRxTerminate;
#else
XEmacPs_Bd BdTxTerminate __attribute__ ((aligned(64)));
XEmacPs_Bd BdRxTerminate __attribute__ ((aligned(64)));
#endif
u32 PayloadSize = 200;
// u32 GemVersion;
/*************************** Function Prototypes ****************************/
/*
* Example
*/
LONG EmacPsDmaIntrExample(INTC *IntcInstancePtr,
XEmacPs *EmacPsInstancePtr,
u16 EmacPsDeviceId, u16 EmacPsIntrId);
LONG EmacPsDmaSingleFrameIntrExample(XEmacPs * EmacPsInstancePtr);
/*
* Interrupt setup and Callbacks for examples
*/
static LONG EmacPsSetupIntrSystem(INTC * IntcInstancePtr,
XEmacPs * EmacPsInstancePtr,
u16 EmacPsIntrId);
static void EmacPsDisableIntrSystem(INTC * IntcInstancePtr,
u16 EmacPsIntrId);
static void XEmacPsSendHandler(void *Callback);
static void XEmacPsRecvHandler(void *Callback);
static void XEmacPsErrorHandler(void *Callback, u8 direction, u32 word);
// void XEmacPs_PHYSetup (XEmacPs *EmacPsInstancePtr);
/*
* Utility routines
*/
static LONG EmacPsResetDevice(XEmacPs * EmacPsInstancePtr);
void XEmacPsClkSetup(XEmacPs *EmacPsInstancePtr, u16 EmacPsIntrId);
void XEmacPs_SetMdioDivisor(XEmacPs *InstancePtr, XEmacPs_MdcDiv Divisor);
/****************************************************************************/
/**
*
* This is the main function for the EmacPs example. This function is not
* included if the example is generated from the TestAppGen test tool.
*
* @param None.
*
* @return XST_SUCCESS to indicate success, otherwise XST_FAILURE.
*
* @note None.
*
****************************************************************************/
#ifndef TESTAPP_GEN
int main(void)
{
LONG Status;
while (1) {
xil_printf("\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"
"\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"
"\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n");
xil_printf("Entering into main() \r\n");
/*
* Call the EmacPs DMA interrupt example , specify the parameters
* generated in xparameters.h
*/
Status = EmacPsDmaIntrExample(&IntcInstance,
&EmacPsInstance,
EMACPS_DEVICE_ID,
EMACPS_IRPT_INTR);
if (Status != XST_SUCCESS) {
xil_printf("Emacps intr dma Example Failed\r\n");
// return XST_FAILURE;
} else {
xil_printf("Successfully ran Emacps intr dma Example\r\n");
}
EmacpsDelay(2);
}
return XST_SUCCESS;
}
#endif
/* Generic MII registers. */
#define MII_BMCR 0x00 /* Basic mode control register */
#define MII_BMSR 0x01 /* Basic mode status register */
#define MII_PHYSID1 0x02 /* PHYS ID 1 */
#define MII_PHYSID2 0x03 /* PHYS ID 2 */
#define MII_ADVERTISE 0x04 /* Advertisement control reg */
#define MII_LPA 0x05 /* Link partner ability reg */
#define MII_EXPANSION 0x06 /* Expansion register */
#define MII_CTRL1000 0x09 /* 1000BASE-T control */
#define MII_STAT1000 0x0a /* 1000BASE-T status */
#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */
#define MII_MMD_DATA 0x0e /* MMD Access Data Register */
#define MII_ESTATUS 0x0f /* Extended Status */
#define MII_DCOUNTER 0x12 /* Disconnect counter */
#define MII_FCSCOUNTER 0x13 /* False carrier counter */
#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
#define MII_RERRCOUNTER 0x15 /* Receive error counter */
#define MII_SREVISION 0x16 /* Silicon revision */
#define MII_RESV1 0x17 /* Reserved... */
#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
#define MII_PHYADDR 0x19 /* PHY address */
#define MII_RESV2 0x1a /* Reserved... */
#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
#define MII_NCONFIG 0x1c /* Network interface config */
#define MII_PHYCR 0x10
/* Basic mode control register. */
#define BMCR_RESV 0x003f /* Unused... */
#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
#define BMCR_CTST 0x0080 /* Collision test */
#define BMCR_FULLDPLX 0x0100 /* Full duplex */
#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
#define BMCR_ISOLATE 0x0400 /* Isolate data paths from MII */
#define BMCR_PDOWN 0x0800 /* Enable low power state */
#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
#define BMCR_RESET 0x8000 /* Reset to default state */
#define BMCR_SPEED10 0x0000 /* Select 10Mbps */
/* Basic mode status register. */
#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
#define BMSR_JCD 0x0002 /* Jabber detected */
#define BMSR_LSTATUS 0x0004 /* Link status */
#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
#define BMSR_RFAULT 0x0010 /* Remote fault detected */
#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
#define BMSR_RESV 0x00c0 /* Unused... */
#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
/* Advertisement control register. */
#define ADVERTISE_SLCT 0x001f /* Selector bits */
#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
#define ADVERTISE_RESV 0x1000 /* Unused... */
#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
ADVERTISE_CSMA)
#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
ADVERTISE_100HALF | ADVERTISE_100FULL)
/* Link partner ability register. */
#define LPA_SLCT 0x001f /* Same as advertise selector */
#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */
#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */
#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */
#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/
#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */
#define LPA_PAUSE_CAP 0x0400 /* Can pause */
#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */
#define LPA_RESV 0x1000 /* Unused... */
#define LPA_RFAULT 0x2000 /* Link partner faulted */
#define LPA_LPACK 0x4000 /* Link partner acked us */
#define LPA_NPAGE 0x8000 /* Next page bit */
#define LPA_DUPLEX (LPA_10FULL | LPA_100FULL)
#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
/* Expansion register for auto-negotiation. */
#define EXPANSION_NWAY 0x0001 /* Can do N-way auto-nego */
#define EXPANSION_LCWP 0x0002 /* Got new RX page code word */
#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */
#define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */
#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */
#define EXPANSION_RESV 0xffe0 /* Unused... */
#define ESTATUS_1000_XFULL 0x8000 /* Can do 1000BaseX Full */
#define ESTATUS_1000_XHALF 0x4000 /* Can do 1000BaseX Half */
#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */
#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */
/* N-way test register. */
#define NWAYTEST_RESV1 0x00ff /* Unused... */
#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */
#define NWAYTEST_RESV2 0xfe00 /* Unused... */
/* MAC and PHY tx_config_Reg[15:0] for SGMII in-band auto-negotiation.*/
#define ADVERTISE_SGMII 0x0001 /* MAC can do SGMII */
#define LPA_SGMII 0x0001 /* PHY can do SGMII */
#define LPA_SGMII_SPD_MASK 0x0c00 /* SGMII speed mask */
#define LPA_SGMII_FULL_DUPLEX 0x1000 /* SGMII full duplex */
#define LPA_SGMII_DPX_SPD_MASK 0x1C00 /* SGMII duplex and speed bits */
#define LPA_SGMII_10 0x0000 /* 10Mbps */
#define LPA_SGMII_10HALF 0x0000 /* Can do 10mbps half-duplex */
#define LPA_SGMII_10FULL 0x1000 /* Can do 10mbps full-duplex */
#define LPA_SGMII_100 0x0400 /* 100Mbps */
#define LPA_SGMII_100HALF 0x0400 /* Can do 100mbps half-duplex */
#define LPA_SGMII_100FULL 0x1400 /* Can do 100mbps full-duplex */
#define LPA_SGMII_1000 0x0800 /* 1000Mbps */
#define LPA_SGMII_1000HALF 0x0800 /* Can do 1000mbps half-duplex */
#define LPA_SGMII_1000FULL 0x1800 /* Can do 1000mbps full-duplex */
#define LPA_SGMII_LINK 0x8000 /* PHY link with copper-side partner */
/* 1000BASE-T Control register */
#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
#define CTL1000_PREFER_MASTER 0x0400 /* prefer to operate as master */
#define CTL1000_AS_MASTER 0x0800
#define CTL1000_ENABLE_MASTER 0x1000
/* 1000BASE-T Status register */
#define LPA_1000MSFAIL 0x8000 /* Master/Slave resolution failure */
#define LPA_1000MSRES 0x4000 /* Master/Slave resolution status */
#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */
#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */
#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */
#define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */
/* Flow control flags */
#define FLOW_CTRL_TX 0x01
#define FLOW_CTRL_RX 0x02
/* MMD Access Control register fields */
#define MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/
#define MII_MMD_CTRL_ADDR 0x0000 /* Address */
#define MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */
#define MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */
#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */
void dumpregs(XEmacPs * EmacPsInstancePtr) {
#define DUMP(k,v,t) \
xil_printf(" %d (%04X) (%s)\r\n", (Temp & k) > 0, k, t );
for( int j=0; j<32; j++) {
u16 Temp;
XEmacPs_PhyRead(EmacPsInstancePtr, 0, j, &Temp);
xil_printf("phy reg %d = %4X => ", j, Temp);
for(int k=0; k<16; k++) {
xil_printf("%d", (Temp & (1 << k)) > 0);
}
xil_printf("\r\n");
if (j == MII_BMCR) {
xil_printf("^ MII_BMCR control register:\r\n");
DUMP(BMCR_RESV, 0x003f, "Unused...");
DUMP(BMCR_SPEED1000, 0x0040, "MSB of Speed (1000)");
DUMP(BMCR_CTST, 0x0080, "Collision test");
DUMP(BMCR_FULLDPLX, 0x0100, "Full duplex");
DUMP(BMCR_ANRESTART, 0x0200, "Auto negotiation restart");
DUMP(BMCR_ISOLATE, 0x0400, "Isolate data paths from");
DUMP(BMCR_PDOWN, 0x0800, "Enable low power state");
DUMP(BMCR_ANENABLE, 0x1000, "Enable auto negotiation");
DUMP(BMCR_SPEED100, 0x2000, "Select 100Mbps");
DUMP(BMCR_LOOPBACK, 0x4000, "TXD loopback bits");
DUMP(BMCR_RESET, 0x8000, "Reset to default state");
// DUMP(BMCR_SPEED10, 0x0000, "Select 10Mbps");
xil_printf("\r\n");
}
if (j == MII_BMSR) {
xil_printf("^ MII_BMCR status register:\r\n");
DUMP(BMSR_ERCAP, 0x0001, "Ext-reg capability");
DUMP(BMSR_JCD, 0x0002, "Jabber detected");
DUMP(BMSR_LSTATUS, 0x0004, "Link status");
DUMP(BMSR_ANEGCAPABLE, 0x0008, "Able to do auto-negotiation");
DUMP(BMSR_RFAULT, 0x0010, "Remote fault detected");
DUMP(BMSR_ANEGCOMPLETE, 0x0020, "Auto-negotiation complete");
DUMP(BMSR_RESV, 0x00c0, "Unused...");
DUMP(BMSR_ESTATEN, 0x0100, "Extended Status in R15");
DUMP(BMSR_100HALF2, 0x0200, "Can do 100BASE-T2 HDX");
DUMP(BMSR_100FULL2, 0x0400, "Can do 100BASE-T2 FDX");
DUMP(BMSR_10HALF, 0x0800, "Can do 10mbps, half-duplex");
DUMP(BMSR_10FULL, 0x1000, "Can do 10mbps, full-duplex");
DUMP(BMSR_100HALF, 0x2000, "Can do 100mbps, half-duplex");
DUMP(BMSR_100FULL, 0x4000, "Can do 100mbps, full-duplex");
DUMP(BMSR_100BASE4, 0x8000, "Can do 100mbps, 4k packets");
xil_printf("\r\n");
}
if (j == MII_ADVERTISE) {
xil_printf("^ MII_ADVERTISE advertisement control register:\r\n");
DUMP(ADVERTISE_SLCT, 0x001f, "Selector bits");
DUMP(ADVERTISE_CSMA, 0x0001, "Only selector supported");
DUMP(ADVERTISE_10HALF, 0x0020, "Try for 10mbps half-duplex");
DUMP(ADVERTISE_1000XFULL, 0x0020, "Try for 1000BASE-X full-duplex");
DUMP(ADVERTISE_10FULL, 0x0040, "Try for 10mbps full-duplex");
DUMP(ADVERTISE_1000XHALF, 0x0040, "Try for 1000BASE-X half-duplex");
DUMP(ADVERTISE_100HALF, 0x0080, "Try for 100mbps half-duplex");
DUMP(ADVERTISE_1000XPAUSE, 0x0080, "Try for 1000BASE-X pause");
DUMP(ADVERTISE_100FULL, 0x0100, "Try for 100mbps full-duplex");
DUMP(ADVERTISE_1000XPSE_ASYM, 0x0100, "Try for 1000BASE-X asym pause");
DUMP(ADVERTISE_100BASE4, 0x0200, "Try for 100mbps 4k packets");
DUMP(ADVERTISE_PAUSE_CAP, 0x0400, "Try for pause");
DUMP(ADVERTISE_PAUSE_ASYM, 0x0800, "Try for asymetric pause");
DUMP(ADVERTISE_RESV, 0x1000, "Unused...");
DUMP(ADVERTISE_RFAULT, 0x2000, "Say we can detect faults");
DUMP(ADVERTISE_LPACK, 0x4000, "Ack link partners response");
DUMP(ADVERTISE_NPAGE, 0x8000, "Next page bit");
xil_printf("\r\n");
}
if (j == MII_LPA) {
xil_printf("^ MII_LPA link partner ability register:\r\n");
DUMP(LPA_SLCT, 0x001f, "Same as advertise selector");
DUMP(LPA_10HALF, 0x0020, "Can do 10mbps half-duplex");
DUMP(LPA_1000XFULL, 0x0020, "Can do 1000BASE-X full-duplex");
DUMP(LPA_10FULL, 0x0040, "Can do 10mbps full-duplex");
DUMP(LPA_1000XHALF, 0x0040, "Can do 1000BASE-X half-duplex");
DUMP(LPA_100HALF, 0x0080, "Can do 100mbps half-duplex");
DUMP(LPA_1000XPAUSE, 0x0080, "Can do 1000BASE-X pause");
DUMP(LPA_100FULL, 0x0100, "Can do 100mbps full-duplex");
DUMP(LPA_1000XPAUSE_ASYM, 0x0100, "Can do 1000BASE-X pause ");
DUMP(LPA_100BASE4, 0x0200, "Can do 100mbps 4k packets");
DUMP(LPA_PAUSE_CAP, 0x0400, "Can pause");
DUMP(LPA_PAUSE_ASYM, 0x0800, "Can pause asymetrically");
DUMP(LPA_RESV, 0x1000, "Unused...");
DUMP(LPA_RFAULT, 0x2000, "Link partner faulted");
DUMP(LPA_LPACK, 0x4000, "Link partner acked us");
DUMP(LPA_NPAGE, 0x8000, "Next page bit");
xil_printf("\r\n");
}
}
}
int XEmacPs_PtpTxPacket(XEmacPs *EmacPsInstance, u8 *PacketBuf,
int PacketLen)
{
int Status;
XEmacPs_Bd *BdPtr;
XEmacPs_BdRing *TxRingPtr;
Xil_ExceptionDisable();
// while((XEmacPs_ReadReg(EmacPsInstance->Config.BaseAddress, XEMACPS_TXSR_OFFSET)) & 0x08) {
// };
TxRingPtr = &(XEmacPs_GetTxRing(EmacPsInstance));
Status = XEmacPs_BdRingAlloc(TxRingPtr, 1, &BdPtr);
xil_printf("Got Bdptr %X\r\n", (u32)BdPtr);
if (Status != XST_SUCCESS) {
Xil_ExceptionEnable();
EmacPsUtilErrorTrap("Failed to send: XEmacPs_BdRingAlloc");
return XST_FAILURE;
}
Xil_DCacheFlushRange((u32)PacketBuf, 128);
XEmacPs_BdSetAddressTx (BdPtr, PacketBuf);
XEmacPs_BdSetLength(BdPtr, PacketLen);
XEmacPs_BdClearTxUsed(BdPtr);
XEmacPs_BdSetLast(BdPtr);
dmb();
dsb();
Status = XEmacPs_BdRingToHw(TxRingPtr, 1, BdPtr);
if (Status != XST_SUCCESS) {
Xil_ExceptionEnable();
EmacPsUtilErrorTrap("Failed to send: XEmacPs_BdRingToHw");
return XST_FAILURE;
}
dmb();
dsb();
/*
* Start the Tx
*/
XEmacPs_Transmit(EmacPsInstance);
xil_printf("Transmitted\r\n");
Xil_ExceptionEnable();
return XST_SUCCESS;
}
LONG SendPacket(XEmacPs * EmacPsInstancePtr)
{
xil_printf("Preparing frame\r\n");
/*
EmacPsUtilFrameMemClear(&TxFrame);
EmacPsUtilFrameHdrFormatMAC(&TxFrame, EmacPsMAC);
EmacPsUtilFrameHdrFormatType(&TxFrame, 3);
EmacPsUtilFrameSetPayloadData(&TxFrame, PayloadSize);
*/
u8 *Frame = (u8*) &TxFrame;
Frame[0] = 0xff;
Frame[1] = 0xff;
Frame[2] = 0xff;
Frame[3] = 0xff;
Frame[4] = 0xff;
Frame[5] = 0xff;
Frame[6] = 0x01;
Frame[7] = 0x02;
Frame[8] = 0x03;
Frame[9] = 0x04;
Frame[10] = 0x05;
Frame[11] = 0x06;
Frame[12] = 0x88; // XEMACPS_PTP_ETHERTYPE
Frame[13] = 0xF7;
XEmacPs_PtpTxPacket(EmacPsInstancePtr, Frame, XEMACPS_HDR_SIZE + PayloadSize);
}
LONG RunCommLoop(INTC * IntcInstancePtr,
XEmacPs * EmacPsInstancePtr,
u16 EmacPsDeviceId,
u16 EmacPsIntrId)
{
LONG Status, Index;
XEmacPs_Bd BdTemplate;
u16 Temp;
u32 Reg;
XEmacPs_BdRing *TxRingPtr;
XEmacPs_BdRing *RxRingPtr;
XEmacPs_Bd *RxBdPtr;
XEmacPs_Bd *CurrBdPtr;
/* Allocate Rx and Tx BD space each */
u32 RxBdSpacePtr = (u32)&rxSpace;
u32 TxBdSpacePtr = (u32)&txSpace;
TxRingPtr = &XEmacPs_GetTxRing(EmacPsInstancePtr);
RxRingPtr = &XEmacPs_GetRxRing(EmacPsInstancePtr);
// RX BDs
XEmacPs_BdClear(&BdTemplate);
Status = XEmacPs_BdRingCreate(RxRingPtr,
RxBdSpacePtr,
RxBdSpacePtr,
XEMACPS_BD_ALIGNMENT,
RXBD_CNT);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error setting up RxBD space, BdRingCreate");
return XST_FAILURE;
}
Status = XEmacPs_BdRingClone(RxRingPtr, &BdTemplate, XEMACPS_RECV);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error setting up RxBD space, BdRingClone");
return XST_FAILURE;
}
xil_printf("RX BDs setup\r\n");
// TX BDs
XEmacPs_BdClear(&BdTemplate);
XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);
Status = XEmacPs_BdRingCreate(TxRingPtr,
TxBdSpacePtr,
TxBdSpacePtr,
XEMACPS_BD_ALIGNMENT,
TXBD_CNT);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error setting up TxBD space, BdRingCreate");
return XST_FAILURE;
}
Status = XEmacPs_BdRingClone(TxRingPtr, &BdTemplate, XEMACPS_SEND);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error setting up TxBD space, BdRingClone");
return XST_FAILURE;
}
xil_printf("TX BDs setup\r\n");
Status = XEmacPs_BdRingAlloc(RxRingPtr, RXBD_CNT, &RxBdPtr);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error allocating RxBD");
return XST_FAILURE;
}
CurrBdPtr = RxBdPtr;
for (Index = 0; Index < RXBD_CNT; Index++) {
XEmacPs_BdSetAddressRx (CurrBdPtr, &(RxBuf[Index][0]));
XEmacPs_BdSetLast(CurrBdPtr);
CurrBdPtr = XEmacPs_BdRingNext (RxRingPtr, CurrBdPtr);
}
Status = XEmacPs_BdRingToHw(RxRingPtr, RXBD_CNT, RxBdPtr);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error committing RxBD to HW");
return XST_FAILURE;
}
xil_printf("RX Ring setup\r\n");
XEmacPs_Start(EmacPsInstancePtr);
xil_printf("XEmacPs started\r\n");
// Ex https://github.com/Xilinx/embeddedsw/blob/xilinx-v2020.1/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588_example.c
/*
* Wait for transmission to complete
*/
u16 counter = 0;
while (1) {
if (counter % 5 == 0) {
SendPacket(EmacPsInstancePtr);
}
sleep(1);
xil_printf("waiting.. %d\r\n", counter);
xil_printf(" %d frames received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXCNT_OFFSET));
xil_printf(" %d frames sent\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_TXCNT_OFFSET));
xil_printf(" %d undersize frames received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXUNDRCNT_OFFSET));
xil_printf(" %d oversize frames received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXOVRCNT_OFFSET));
xil_printf(" %d jabbers received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXJABCNT_OFFSET));
xil_printf(" %d fcs errors received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXFCSCNT_OFFSET));
xil_printf(" %d length errors received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXLENGTHCNT_OFFSET));
xil_printf(" %d receive overrun errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXORCNT_OFFSET));
xil_printf(" %d receive resource errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXRESERRCNT_OFFSET));
xil_printf(" %d counter\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXALIGNCNT_OFFSET));
xil_printf(" %d ip checksum errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXIPCCNT_OFFSET));
xil_printf(" %d tcp checksum errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXTCPCCNT_OFFSET));
xil_printf(" %d udp checksum errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXUDPCCNT_OFFSET));
xil_printf(" %d ip checksum errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXIPCCNT_OFFSET));
counter += 1;
}
// xil_printf("x7\r\n");
/* Gem IP version on Zynq-7000 */
// Xil_SetTlbAttributes((INTPTR)bd_space, DEVICE_MEMORY);
// xil_printf("x8\r\n");
// xil_printf("x13\r\n");
Status = XEmacPs_BdRingClone(&(XEmacPs_GetTxRing(EmacPsInstancePtr)),
&BdTemplate, XEMACPS_SEND);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap
("Error setting up TxBD space, BdRingClone");
return XST_FAILURE;
}
// xil_printf("x14\r\n");
XEmacPs_SetOperatingSpeed(EmacPsInstancePtr, 100);
XEmacPs_SetOptions(EmacPsInstancePtr, XEMACPS_PROMISC_OPTION);
// XEmacPs_ClearOptions(EmacPsInstancePtr, XEMACPS_FCS_INSERT_OPTION);
XEmacPs_SetOptions(EmacPsInstancePtr, XEMACPS_FCS_INSERT_OPTION);
Reg = XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET);
Reg &= ~XEMACPS_NWCFG_FDEN_MASK;
// Reg |= XEMACPS_NWCFG_FDEN_MASK;
// Reg |= XEMACPS_NWCFG_BADPREAMBEN_MASK;
// Reg |= XEMACPS_NWCFG_FCSIGNORE_MASK;
XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET, Reg);
// XEmacPs_ClearOptions(EmacPsInstancePtr, XEMACPS_FLOW_CONTROL_OPTION);
// XEmacPs_ClearOptions(EmacPsInstancePtr, XEMACPS_TRANSMITTER_ENABLE_OPTION);
// XEmacPs_ClearOptions(EmacPsInstancePtr, XEMACPS_TX_CHKSUM_ENABLE_OPTION);
// XEmacPs_ClearOptions(EmacPsInstancePtr, XEMACPS_RX_CHKSUM_ENABLE_OPTION);
// dumpregs(EmacPsInstancePtr);
// Disable crossover otherwise autoneg is always on (1gbit)
// https://datasheet.lcsc.com/szlcsc/Realtek-Semicon-RTL8211EG-VB-CG_C69264.pdf
xil_printf("disable crossover\r\n");
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_PHYCR, &Temp);
Temp &= ~(1 << 6); // Disable Crossover
Temp &= ~(1 << 5); // MDI
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, MII_PHYCR, Temp);
// From https://github.com/torvalds/linux/blob/master/drivers/net/phy/realtek.c#L260
/*
XEmacPs_PhyRead(EmacPsInstancePtr, 0, 0x17, &Temp);
Temp = 0x2138;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, 0x17, Temp);
XEmacPs_PhyRead(EmacPsInstancePtr, 0, 0x0e, &Temp);
Temp = 0x0260;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, 0x0e, Temp);
*/
xil_printf("resetting...\r\n");
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_BMCR, &Temp);
Temp |= BMCR_RESET;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, MII_BMCR, Temp);
do {
EmacpsDelay(1);
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_BMCR, &Temp);
} while (Temp & BMCR_RESET);
xil_printf("resetted\r\n");
/*
xil_printf("change advertising\r\n");
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_ADVERTISE, &Temp);
Temp &= ~ADVERTISE_10HALF;
Temp &= ~ADVERTISE_10FULL;
// Temp &= ~ADVERTISE_100FULL;
Temp |= ADVERTISE_100FULL;
Temp |= ADVERTISE_100HALF;
// Temp &= ~ADVERTISE_PAUSE_CAP;
// Temp &= ~ADVERTISE_PAUSE_ASYM;
// Temp &= ~ADVERTISE_1000XPAUSE;
// Temp &= ~ADVERTISE_RFAULT;
// Temp |= ADVERTISE_LPACK;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, MII_ADVERTISE, Temp);
*/
xil_printf("change speed\r\n");
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_BMCR, &Temp);
// Temp |= BMCR_FULLDPLX;
Temp &= ~BMCR_FULLDPLX;
Temp &= ~BMCR_SPEED1000;
Temp &= ~BMCR_SPEED10;
Temp |= BMCR_SPEED100;
Temp &= ~BMCR_ANENABLE;
Temp |= BMCR_ANRESTART;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, MII_BMCR, Temp);
/*
xil_printf("resetting...\r\n");
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_BMCR, &Temp);
Temp |= BMCR_RESET;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, MII_BMCR, Temp);
do {
EmacpsDelay(1);
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_BMCR, &Temp);
} while (Temp & BMCR_RESET);
xil_printf("resetted\r\n");
*/
// dumpregs(EmacPsInstancePtr);
// xil_printf("x15.2\r\n");
// xil_printf("x15.3\r\n");
EmacpsDelay(1);
dumpregs(EmacPsInstancePtr);
xil_printf("x15.41\r\n");
// xil_printf("x15.42\r\n");
for(int k=0; k<50; k++) {
/*
* Setup the interrupt controller and enable interrupts
*/
/*
* Run the EmacPs DMA Single Frame Interrupt example
*/
xil_printf("\r\n\r\nattempt #%d\r\n\r\n\r\n", k);
Status = EmacPsDmaSingleFrameIntrExample(EmacPsInstancePtr);
xil_printf("attempt result %d\r\n", Status);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
xil_printf("\r\n\r\n\r\n");
}
/*
* Disable the interrupts for the EmacPs device
*/
// EmacPsDisableIntrSystem(IntcInstancePtr, EmacPsIntrId);
/*
* Stop the device
*/
XEmacPs_Stop(EmacPsInstancePtr);
return XST_SUCCESS;
}
void XEmacPs_PHYSetup (INTC * IntcInstancePtr, XEmacPs * EmacPsInstancePtr, u16 EmacPsDeviceId, u16 EmacPsIntrId)
{
/*
u16 Control = 0;
u16 Status;
u32 SlcrTxClkCntrl;
#ifdef PHY_AUTONEGOTIATION
u16 Temp;
u16 Partner_capabilities;
#ifdef DEBUG_XEMACPS_LEVEL1
xil_printf("In %s: Start PHY autonegotiation \r\n",__func__);
#endif
PhyAddress = XEmacPs_DetectPHY(EmacPsInstancePtr);
XEmacPs_PhyWrite(EmacPsInstancePtr,PhyAddress, 22, 2);
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 21, &Control);
Control |= 0x30;
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 21, Control);
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 22, 0);
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
IEEE_AUTONEGO_ADVERTISE_REG, &Control);
Control |= 0xd80;
Control |= 0x60;
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress,
IEEE_AUTONEGO_ADVERTISE_REG, Control);
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
IEEE_1000_ADVERTISE_REG_OFFSET, &Control);
Control |= ADVERTISE_1000;
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress,
IEEE_1000_ADVERTISE_REG_OFFSET, Control);
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 22, 0);
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 16, &Control);
Control |= (7 << 12);
Control |= (1 << 11);
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 16, Control);
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
IEEE_CONTROL_REG_OFFSET, &Control);
Control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
Control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress,
IEEE_CONTROL_REG_OFFSET, Control);
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
IEEE_CONTROL_REG_OFFSET, &Control);
Control |= IEEE_CTRL_RESET_MASK;
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress,
IEEE_CONTROL_REG_OFFSET, Control);
while (1) {
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
IEEE_CONTROL_REG_OFFSET, &Control);
if (Control & IEEE_CTRL_RESET_MASK)
continue;
else
break;
}
#ifdef DEBUG_XEMACPS_LEVEL1
xil_printf("In %s: Waiting for PHY to complete autonegotiation.\r\n",
__func__);
#endif
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
IEEE_STATUS_REG_OFFSET, &Status);
while ( !(Status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
sleep(1);
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 19, &Temp);
if (Temp & 0x8000) {
#ifdef DEBUG_XEMACPS_LEVEL1
xil_printf("In %s: Auto negotiation error \r\n",
__func__);
#endif
}
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
IEEE_STATUS_REG_OFFSET,
&Status);
}
#ifdef DEBUG_XEMACPS_LEVEL1
xil_printf("In %s: Autonegotiation complete \r\n", __func__);
#endif
XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress,
IEEE_SPECIFIC_STATUS_REG,
&Partner_capabilities);
if ( ((Partner_capabilities >> 14) & 3) == 2) {
Link_Speed = 1000;
xil_printf("Partner_capabilities are %x\r\n",
Partner_capabilities);
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) =
SLCR_UNLOCK_KEY_VALUE;
SlcrTxClkCntrl =
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR);
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
SlcrTxClkCntrl |=
(XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1 << 20);
SlcrTxClkCntrl
|= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 << 8);
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) =
SlcrTxClkCntrl;
*(volatile unsigned int *)(SLCR_LOCK_ADDR) =
SLCR_LOCK_KEY_VALUE;
sleep(1);
}
else if ( ((Partner_capabilities >> 14) & 3) == 1) {
Link_Speed = 100;
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) =
SLCR_UNLOCK_KEY_VALUE;
SlcrTxClkCntrl =
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR);
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
SlcrTxClkCntrl
|= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1 << 20);
SlcrTxClkCntrl
|= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 << 8);
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) =
SlcrTxClkCntrl;
*(volatile unsigned int *)(SLCR_LOCK_ADDR) =
SLCR_LOCK_KEY_VALUE;
sleep(1);
}
else {
Link_Speed = 10;
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) =
SLCR_UNLOCK_KEY_VALUE;
SlcrTxClkCntrl =
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR);
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
SlcrTxClkCntrl |=
(XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1 << 20);
SlcrTxClkCntrl |=
(XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0 << 8);
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) =
SlcrTxClkCntrl;
*(volatile unsigned int *)(SLCR_LOCK_ADDR) =
SLCR_LOCK_KEY_VALUE;
sleep(1);
}
xil_printf("In %s: Autonegotiated link speed is %d\r\n",
__func__, Link_Speed);
return;
#else
u16 PhyReg0 = 0;
PhyAddress = XEmacPs_DetectPHY(EmacPsInstancePtr);
Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0);
PhyReg0 &= (~IEEE_CTRL_AUTONEGOTIATE_ENABLE);
Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0, PhyReg0);
Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0);
Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0,
(PhyReg0 |PHY_R0_RESET));
sleep(1);
XEmacPs_PhyWrite(EmacPsInstancePtr,PhyAddress, 22, 2);
Control |= PHY_REG21_100;
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 21, Control);
XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 22, 0);
Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0);
PhyReg0 = PHY_REG0_100;
Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0, PhyReg0);
Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0);
Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0,
(PhyReg0 |PHY_R0_RESET));
sleep(1);
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE;
SlcrTxClkCntrl = *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR);
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1 << 20);
SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 << 8);
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) = SlcrTxClkCntrl;
*(volatile unsigned int *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE;
sleep(1);
#endif
*/
u16 Temp;
u32 Reg;
xil_printf("Setting up phy\r\n");
XEmacPs_SetMdioDivisor(EmacPsInstancePtr, MDC_DIV_224);
XEmacPs_SetOperatingSpeed(EmacPsInstancePtr, 100);
XEmacPs_SetOptions(EmacPsInstancePtr, XEMACPS_PROMISC_OPTION);
// XEmacPs_ClearOptions(EmacPsInstancePtr, XEMACPS_FCS_INSERT_OPTION);
XEmacPs_SetOptions(EmacPsInstancePtr, XEMACPS_FCS_INSERT_OPTION);
Reg = XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET);
Reg &= ~XEMACPS_NWCFG_FDEN_MASK;
// Reg |= XEMACPS_NWCFG_FDEN_MASK;
// Reg |= XEMACPS_NWCFG_BADPREAMBEN_MASK;
// Reg |= XEMACPS_NWCFG_FCSIGNORE_MASK;
XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET, Reg);
// XEmacPs_ClearOptions(EmacPsInstancePtr, XEMACPS_FLOW_CONTROL_OPTION);
// XEmacPs_ClearOptions(EmacPsInstancePtr, XEMACPS_TRANSMITTER_ENABLE_OPTION);
// XEmacPs_ClearOptions(EmacPsInstancePtr, XEMACPS_TX_CHKSUM_ENABLE_OPTION);
// XEmacPs_ClearOptions(EmacPsInstancePtr, XEMACPS_RX_CHKSUM_ENABLE_OPTION);
// dumpregs(EmacPsInstancePtr);
// Disable crossover otherwise autoneg is always on (1gbit)
// https://datasheet.lcsc.com/szlcsc/Realtek-Semicon-RTL8211EG-VB-CG_C69264.pdf
xil_printf("disable crossover\r\n");
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_PHYCR, &Temp);
Temp &= ~(1 << 6); // Disable Crossover
Temp &= ~(1 << 5); // MDI
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, MII_PHYCR, Temp);
// From https://github.com/torvalds/linux/blob/master/drivers/net/phy/realtek.c#L260
/*
XEmacPs_PhyRead(EmacPsInstancePtr, 0, 0x17, &Temp);
Temp = 0x2138;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, 0x17, Temp);
XEmacPs_PhyRead(EmacPsInstancePtr, 0, 0x0e, &Temp);
Temp = 0x0260;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, 0x0e, Temp);
*/
xil_printf("resetting...\r\n");
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_BMCR, &Temp);
Temp |= BMCR_RESET;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, MII_BMCR, Temp);
do {
EmacpsDelay(1);
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_BMCR, &Temp);
} while (Temp & BMCR_RESET);
xil_printf("resetted\r\n");
xil_printf("change advertising\r\n");
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_ADVERTISE, &Temp);
Temp &= ~ADVERTISE_10HALF;
Temp &= ~ADVERTISE_10FULL;
Temp &= ~ADVERTISE_100FULL;
// Temp |= ADVERTISE_100FULL;
Temp |= ADVERTISE_100HALF;
// Temp &= ~ADVERTISE_PAUSE_CAP;
// Temp &= ~ADVERTISE_PAUSE_ASYM;
Temp &= ~ADVERTISE_1000XPAUSE;
// Temp &= ~ADVERTISE_RFAULT;
// Temp |= ADVERTISE_LPACK;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, MII_ADVERTISE, Temp);
xil_printf("change speed\r\n");
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_BMCR, &Temp);
// Temp |= BMCR_FULLDPLX;
Temp &= ~BMCR_FULLDPLX;
Temp &= ~BMCR_SPEED1000;
Temp &= ~BMCR_SPEED10;
Temp |= BMCR_SPEED100;
Temp &= ~BMCR_ANENABLE;
Temp |= BMCR_ANRESTART;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, MII_BMCR, Temp);
/*
xil_printf("resetting...\r\n");
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_BMCR, &Temp);
Temp |= BMCR_RESET;
XEmacPs_PhyWrite(EmacPsInstancePtr, 0, MII_BMCR, Temp);
do {
EmacpsDelay(1);
XEmacPs_PhyRead(EmacPsInstancePtr, 0, MII_BMCR, &Temp);
} while (Temp & BMCR_RESET);
xil_printf("resetted\r\n");
*/
// dumpregs(EmacPsInstancePtr);
// xil_printf("x15.2\r\n");
// xil_printf("x15.3\r\n");
EmacpsDelay(1);
dumpregs(EmacPsInstancePtr);
xil_printf("phy setup done\r\n");
XEmacPsClkSetup(EmacPsInstancePtr, EmacPsIntrId);
}
LONG EmacPsDmaIntrExample(INTC * IntcInstancePtr,
XEmacPs * EmacPsInstancePtr,
u16 EmacPsDeviceId,
u16 EmacPsIntrId)
{
LONG Status;
XEmacPs_Config *Config;
XEmacPs_Bd BdTemplate;
u16 Temp;
u32 Reg;
/*************************************/
/* Setup device for first-time usage */
/*************************************/
/*
* Initialize instance. Should be configured for DMA
* This example calls _CfgInitialize instead of _Initialize due to
* retiring _Initialize. So in _CfgInitialize we use
* XPAR_(IP)_BASEADDRESS to make sure it is not virtual address.
*/
Config = XEmacPs_LookupConfig(EmacPsDeviceId);
Status = XEmacPs_CfgInitialize(EmacPsInstancePtr, Config, Config->BaseAddress);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error in XEmacPs_CfgInitialize");
return XST_FAILURE;
}
Status = XEmacPs_SetMacAddress(EmacPsInstancePtr, EmacPsMAC, 1);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error setting MAC address");
return XST_FAILURE;
}
XEmacPs_PHYSetup(IntcInstancePtr, EmacPsInstancePtr, EmacPsDeviceId, EmacPsIntrId);
sleep(1);
// XEmacPs_SetOptions(EmacPsInstancePtr, XEMACPS_PROMISC_OPTION);
Status = XEmacPs_SetHandler(EmacPsInstancePtr, XEMACPS_HANDLER_DMASEND, (void *) XEmacPsSendHandler, EmacPsInstancePtr);
Status |= XEmacPs_SetHandler(EmacPsInstancePtr, XEMACPS_HANDLER_DMARECV, (void *) XEmacPsRecvHandler, EmacPsInstancePtr);
Status |= XEmacPs_SetHandler(EmacPsInstancePtr, XEMACPS_HANDLER_ERROR, (void *) XEmacPsErrorHandler, EmacPsInstancePtr);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error assigning handlers");
return XST_FAILURE;
}
Status = EmacPsSetupIntrSystem(IntcInstancePtr, EmacPsInstancePtr, EmacPsIntrId);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error setting up interrupts");
return XST_FAILURE;
}
RunCommLoop(IntcInstancePtr, EmacPsInstancePtr, EmacPsDeviceId, EmacPsIntrId);
XEmacPs_Stop(EmacPsInstancePtr);
return XST_SUCCESS;
}
/****************************************************************************/
/**
*
* This function demonstrates the usage of the EMACPS by sending and
* receiving a single frame in DMA interrupt mode.
* The source packet will be described by two descriptors. It will be
* received into a buffer described by a single descriptor.
*
* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs
* driver.
*
* @return XST_SUCCESS to indicate success, otherwise XST_FAILURE.
*
* @note None.
*
*****************************************************************************/
LONG EmacPsDmaSingleFrameIntrExample(XEmacPs *EmacPsInstancePtr)
{
LONG Status;
u32 NumRxBuf = 0;
// u32 RxFrLen;
XEmacPs_Bd *Bd1Ptr;
XEmacPs_Bd *BdRxPtr;
/*
* Clear variables shared with callbacks
*/
FramesRx = 0;
FramesTx = 0;
DeviceErrors = 0;
/*
if (GemVersion > 2) {
PayloadSize = (JUMBO_FRAME_SIZE - FRAME_HDR_SIZE);
}*/
/*
* Calculate the frame length (not including FCS)
*/
TxFrameLength = XEMACPS_HDR_SIZE + PayloadSize;
/*
* Setup packet to be transmitted
*/
EmacPsUtilFrameMemClear(&TxFrame);
EmacPsUtilFrameHdrFormatMAC(&TxFrame, EmacPsMAC);
EmacPsUtilFrameHdrFormatType(&TxFrame, 3);
EmacPsUtilFrameSetPayloadData(&TxFrame, PayloadSize);
u8 *Frame = (u8*) &TxFrame;
Frame[0] = 0x00;
Frame[1] = 0x10;
Frame[2] = 0x20;
Frame[3] = 0x30;
Frame[4] = 0x40;
Frame[5] = 0x50;
Frame[6] = 0x00;
Frame[7] = 0x01;
Frame[8] = 0x02;
Frame[9] = 0x03;
Frame[10] = 0x04;
Frame[11] = 0x05;
Frame[12] = 0x12;
Frame[13] = 0x34;
// xil_printf("x3.1\r\n");
if (EmacPsInstancePtr->Config.IsCacheCoherent == 0) {
Xil_DCacheFlushRange((UINTPTR)&TxFrame, sizeof(EthernetFrame));
}
/*
* Clear out receive packet memory area
*/
EmacPsUtilFrameMemClear(&RxFrame);
if (EmacPsInstancePtr->Config.IsCacheCoherent == 0) {
Xil_DCacheFlushRange((UINTPTR)&RxFrame, sizeof(EthernetFrame));
}
// xil_printf("x3.2\r\n");
/*
* Allocate RxBDs since we do not know how many BDs will be used
* in advance, use RXBD_CNT here.
*/
Status = XEmacPs_BdRingAlloc(&(XEmacPs_GetRxRing(EmacPsInstancePtr)),
1, &BdRxPtr);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error allocating RxBD");
return XST_FAILURE;
}
XEmacPs_BdSetAddressRx(BdRxPtr, (UINTPTR)&RxFrame);
/*
* Enqueue to HW
*/
Status = XEmacPs_BdRingToHw(&(XEmacPs_GetRxRing(EmacPsInstancePtr)),
1, BdRxPtr);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error committing RxBD to HW");
return XST_FAILURE;
}
Status = XEmacPs_BdRingAlloc(&(XEmacPs_GetTxRing(EmacPsInstancePtr)),
1, &Bd1Ptr);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error allocating TxBD");
return XST_FAILURE;
}
/*
* Setup first TxBD
*/
XEmacPs_BdSetAddressTx(Bd1Ptr, (UINTPTR)&TxFrame);
XEmacPs_BdSetLength(Bd1Ptr, TxFrameLength);
XEmacPs_BdClearTxUsed(Bd1Ptr);
XEmacPs_BdSetLast(Bd1Ptr);
/*
* Enqueue to HW
*/
Status = XEmacPs_BdRingToHw(&(XEmacPs_GetTxRing(EmacPsInstancePtr)),
1, Bd1Ptr);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error committing TxBD to HW");
return XST_FAILURE;
}
if (EmacPsInstancePtr->Config.IsCacheCoherent == 0) {
Xil_DCacheFlushRange((UINTPTR)Bd1Ptr, 64);
}
/*
* Set the Queue pointers
*/
XEmacPs_SetQueuePtr(EmacPsInstancePtr, EmacPsInstancePtr->RxBdRing.BaseBdAddr, 0, XEMACPS_RECV);
XEmacPs_SetQueuePtr(EmacPsInstancePtr, EmacPsInstancePtr->TxBdRing.BaseBdAddr, 0, XEMACPS_SEND);
/* if (GemVersion > 2) {
XEmacPs_SetQueuePtr(EmacPsInstancePtr, EmacPsInstancePtr->TxBdRing.BaseBdAddr, 1, XEMACPS_SEND);
} else {
} */
// xil_printf("x3.5\r\n");
// dumpregs(EmacPsInstancePtr);
/*
* Start the device
*/
xil_printf("Waiting to send\r\n");
sleep(1);
xil_printf("Sending\r\n");
XEmacPs_Start(EmacPsInstancePtr);
/* Start transmit */
XEmacPs_Transmit(EmacPsInstancePtr);
/*
* Wait for transmission to complete
*/
u16 waiting = 0;
while (!FramesTx && waiting < 10) {
sleep(2);
xil_printf("waiting for transmit.. %d\r\n", FramesTx);
xil_printf(" %d frames received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXCNT_OFFSET));
xil_printf(" %d frames sent\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_TXCNT_OFFSET));
xil_printf(" %d undersize frames received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXUNDRCNT_OFFSET));
xil_printf(" %d oversize frames received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXOVRCNT_OFFSET));
xil_printf(" %d jabbers received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXJABCNT_OFFSET));
xil_printf(" %d fcs errors received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXFCSCNT_OFFSET));
xil_printf(" %d length errors received\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXLENGTHCNT_OFFSET));
xil_printf(" %d receive overrun errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXORCNT_OFFSET));
xil_printf(" %d receive resource errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXRESERRCNT_OFFSET));
xil_printf(" %d counter\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXALIGNCNT_OFFSET));
xil_printf(" %d ip checksum errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXIPCCNT_OFFSET));
xil_printf(" %d tcp checksum errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXTCPCCNT_OFFSET));
xil_printf(" %d udp checksum errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXUDPCCNT_OFFSET));
xil_printf(" %d ip checksum errors\r\n", XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, XEMACPS_RXIPCCNT_OFFSET));
waiting += 1;
}
xil_printf("Sent?!\r\n");
sleep(1);
/*
* Now that the frame has been sent, post process our TxBDs.
* Since we have only submitted 1 to hardware, then there should
* be only 1 ready for post processing.
*/
if (XEmacPs_BdRingFromHwTx(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), 1, &Bd1Ptr) == 0) {
EmacPsUtilErrorTrap("TxBDs were not ready for post processing");
return XST_FAILURE;
}
/*
* Examine the TxBDs.
*
* There isn't much to do. The only thing to check would be DMA
* exception bits. But this would also be caught in the error
* handler. So we just return these BDs to the free list.
*/
Status = XEmacPs_BdRingFree(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), 1, Bd1Ptr);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error freeing up TxBDs");
return XST_FAILURE;
}
/*
* Wait for Rx indication
*/
/*
xil_printf("x3.86 receiving %d\r\n", FramesRx);
u16 waiting = 0;
while (!FramesRx && waiting < 5) {
*/
/* waiting ++;
}
xil_printf("x3.9 received\r\n");
*/
/*
* Now that the frame has been received, post process our RxBD.
* Since we have submitted to hardware, then there should be only 1
* ready for post processing.
*/
NumRxBuf = XEmacPs_BdRingFromHwRx(&(XEmacPs_GetRxRing
(EmacPsInstancePtr)), 1,
&BdRxPtr);
xil_printf("x3.10 %d\r\n", NumRxBuf);
// if (0 == NumRxBuf) {
// EmacPsUtilErrorTrap("RxBD was not ready for post processing");
// return XST_FAILURE;
// }
/*
*/
/*
* There is no device status to check. If there was a DMA error,
* it should have been reported to the error handler. Check the
* receive length against the transmitted length, then verify
* the data.
*/
/*
if (GemVersion > 2) {
RxFrLen = XEmacPs_GetRxFrameSize(EmacPsInstancePtr, BdRxPtr);
} else {
RxFrLen = XEmacPs_BdGetLength(BdRxPtr);
}
xil_printf("received %d bytes, expecting %d bytes\r\n", RxFrLen, TxFrameLength);
for(int k=0; k<RxFrLen; k++) {
xil_printf("%02X ", RxFrame[k]);
}
xil_printf("\r\n");
if (RxFrLen != TxFrameLength) {
EmacPsUtilErrorTrap("Length mismatch");
return XST_FAILURE;
}
if (EmacPsUtilFrameVerify(&TxFrame, &RxFrame) != 0) {
EmacPsUtilErrorTrap("Data mismatch");
return XST_FAILURE;
}
*/
/*
* Return the RxBD back to the channel for later allocation. Free
* the exact number we just post processed.
*/
Status = XEmacPs_BdRingFree(&(XEmacPs_GetRxRing(EmacPsInstancePtr)),
NumRxBuf, BdRxPtr);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error freeing up RxBDs");
return XST_FAILURE;
}
/*
* Finished this example. If everything worked correctly, all TxBDs
* and RxBDs should be free for allocation. Stop the device.
*/
XEmacPs_Stop(EmacPsInstancePtr);
return XST_SUCCESS;
}
/****************************************************************************/
/**
* This function resets the device but preserves the options set by the user.
*
* The descriptor list could be reinitialized with the same calls to
* XEmacPs_BdRingClone() as used in main(). Doing this is a matter of
* preference.
* In many cases, an OS may have resources tied up in the descriptors.
* Reinitializing in this case may bad for the OS since its resources may be
* permamently lost.
*
* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs
* driver.
*
* @return XST_SUCCESS if successful, else XST_FAILURE.
*
* @note None.
*
*****************************************************************************/
static LONG EmacPsResetDevice(XEmacPs * EmacPsInstancePtr)
{
/*
LONG Status = 0;
u8 MacSave[6];
u32 Options;
XEmacPs_Bd BdTemplate;
XEmacPs_Stop(EmacPsInstancePtr);
XEmacPs_GetMacAddress(EmacPsInstancePtr, &MacSave, 1);
Options = XEmacPs_GetOptions(EmacPsInstancePtr);
XEmacPs_Reset(EmacPsInstancePtr);
XEmacPs_SetMacAddress(EmacPsInstancePtr, &MacSave, 1);
Status |= XEmacPs_SetOptions(EmacPsInstancePtr, Options);
// XEMACPS_RECEIVER_ENABLE_OPTION
Status |= XEmacPs_ClearOptions(EmacPsInstancePtr, ~Options);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error restoring state after reset");
return XST_FAILURE;
}
Status = XEmacPs_SetHandler(EmacPsInstancePtr,
XEMACPS_HANDLER_DMASEND,
(void *) XEmacPsSendHandler,
EmacPsInstancePtr);
Status |= XEmacPs_SetHandler(EmacPsInstancePtr,
XEMACPS_HANDLER_DMARECV,
(void *) XEmacPsRecvHandler,
EmacPsInstancePtr);
Status |= XEmacPs_SetHandler(EmacPsInstancePtr, XEMACPS_HANDLER_ERROR,
(void *) XEmacPsErrorHandler,
EmacPsInstancePtr);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap("Error assigning handlers");
return XST_FAILURE;
}
XEmacPs_BdClear(&BdTemplate);
Status = XEmacPs_BdRingCreate(&(XEmacPs_GetRxRing
(EmacPsInstancePtr)),
(UINTPTR) RxBdSpacePtr,
(UINTPTR) RxBdSpacePtr,
XEMACPS_BD_ALIGNMENT,
RXBD_CNT);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap
("Error setting up RxBD space, BdRingCreate");
return XST_FAILURE;
}
Status = XEmacPs_BdRingClone(&
(XEmacPs_GetRxRing(EmacPsInstancePtr)),
&BdTemplate, XEMACPS_RECV);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap
("Error setting up RxBD space, BdRingClone");
return XST_FAILURE;
}
XEmacPs_BdClear(&BdTemplate);
XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);
Status = XEmacPs_BdRingCreate(&(XEmacPs_GetTxRing
(EmacPsInstancePtr)),
(UINTPTR) TxBdSpacePtr,
(UINTPTR) TxBdSpacePtr,
XEMACPS_BD_ALIGNMENT,
TXBD_CNT);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap
("Error setting up TxBD space, BdRingCreate");
return XST_FAILURE;
}
Status = XEmacPs_BdRingClone(&
(XEmacPs_GetTxRing(EmacPsInstancePtr)),
&BdTemplate, XEMACPS_SEND);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap
("Error setting up TxBD space, BdRingClone");
return XST_FAILURE;
}
XEmacPs_Start(EmacPsInstancePtr);
*/
return XST_SUCCESS;
}
/****************************************************************************/
/**
*
* This function setups the interrupt system so interrupts can occur for the
* EMACPS.
* @param IntcInstancePtr is a pointer to the instance of the Intc driver.
* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs
* driver.
* @param EmacPsIntrId is the Interrupt ID and is typically
* XPAR_<EMACPS_instance>_INTR value from xparameters.h.
*
* @return XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note None.
*
*****************************************************************************/
static LONG EmacPsSetupIntrSystem(INTC *IntcInstancePtr,
XEmacPs *EmacPsInstancePtr,
u16 EmacPsIntrId)
{
LONG Status;
// #ifndef TESTAPP_GEN
XScuGic_Config *GicConfig;
Xil_ExceptionInit();
/*
* Initialize the interrupt controller driver so that it is ready to
* use.
*/
GicConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == GicConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(IntcInstancePtr, GicConfig,
GicConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
IntcInstancePtr);
// #endif
/*
* Connect a device driver handler that will be called when an
* interrupt for the device occurs, the device driver handler performs
* the specific interrupt processing for the device.
*/
Status = XScuGic_Connect(IntcInstancePtr, EmacPsIntrId,
(Xil_InterruptHandler) XEmacPs_IntrHandler,
(void *) EmacPsInstancePtr);
if (Status != XST_SUCCESS) {
EmacPsUtilErrorTrap
("Unable to connect ISR to interrupt controller");
return XST_FAILURE;
}
/*
* Enable interrupts from the hardware
*/
XScuGic_Enable(IntcInstancePtr, EmacPsIntrId);
// #ifndef TESTAPP_GEN
/*
* Enable interrupts in the processor
*/
// Xil_ExceptionEnable();
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
// #endif
return XST_SUCCESS;
}
/****************************************************************************/
/**
*
* This function disables the interrupts that occur for EmacPs.
*
* @param IntcInstancePtr is the pointer to the instance of the ScuGic
* driver.
* @param EmacPsIntrId is interrupt ID and is typically
* XPAR_<EMACPS_instance>_INTR value from xparameters.h.
*
* @return None.
*
* @note None.
*
*****************************************************************************/
static void EmacPsDisableIntrSystem(INTC * IntcInstancePtr,
u16 EmacPsIntrId)
{
/*
* Disconnect and disable the interrupt for the EmacPs device
*/
XScuGic_Disconnect(IntcInstancePtr, EmacPsIntrId);
}
/****************************************************************************/
/**
*
* This the Transmit handler callback function and will increment a shared
* counter that can be shared by the main thread of operation.
*
* @param Callback is the pointer to the instance of the EmacPs device.
*
* @return None.
*
* @note None.
*
*****************************************************************************/
static void XEmacPsSendHandler(void *Callback)
{
unsigned int NumBds;
unsigned int NumBdsToProcess;
XEmacPs_Bd *BdPtr, *CurBdPtr;
void *BufAddr;
int BufLen;
int Status;
XEmacPs_BdRing *TxRingPtr;
unsigned int *Temp;
XEmacPs *EmacPsInstancePtr = (XEmacPs *) Callback;
xil_printf("in send handler()\r\n");
FramesTx++;
/*
* Disable the transmit related interrupts
*/
// XEmacPs_IntDisable(EmacPsInstancePtr, (XEMACPS_IXR_TXCOMPL_MASK |
// XEMACPS_IXR_TX_ERR_MASK));
/*
* Increment the counter so that main thread knows something
* happened.
*/
TxRingPtr = &XEmacPs_GetTxRing(EmacPsInstancePtr);
NumBds = XEmacPs_BdRingFromHwTx( TxRingPtr,
TXBD_CNT, &BdPtr);
xil_printf("numbds=%d\n", NumBds);
if (NumBds == 0) {
return;
}
NumBdsToProcess = NumBds;
CurBdPtr = BdPtr;
while (NumBdsToProcess > 0) {
BufAddr = (void*)(INTPTR)(XEmacPs_BdGetBufAddr(CurBdPtr));
BufLen = XEmacPs_BdGetLength(CurBdPtr);
// XEmacPs_PtpTxDoFurtherProcessing (EmacPsInstancePtr, (u8 *)BufAddr);
Temp = (unsigned int *)CurBdPtr;
Temp++;
*Temp &= XEMACPS_TXBUF_WRAP_MASK;
*Temp |= XEMACPS_TXBUF_USED_MASK;
CurBdPtr = XEmacPs_BdRingNext(TxRingPtr, CurBdPtr);
NumBdsToProcess--;
dmb();
dsb();
}
Status = XEmacPs_BdRingFree( TxRingPtr, NumBds, BdPtr);
if (Status != XST_SUCCESS) {
return;
}
return;
}
/****************************************************************************/
/**
*
* This is the Receive handler callback function and will increment a shared
* counter that can be shared by the main thread of operation.
*
* @param Callback is a pointer to the instance of the EmacPs device.
*
* @return None.
*
* @note None.
*
*****************************************************************************/
static void XEmacPsRecvHandler(void *Callback)
{
XEmacPs *EmacPsInstancePtr = (XEmacPs *) Callback;
/*
* Disable the transmit related interrupts
*/
// XEmacPs_IntDisable(EmacPsInstancePtr, (XEMACPS_IXR_FRAMERX_MASK |
// XEMACPS_IXR_RX_ERR_MASK));
xil_printf("in recv handler()\r\n");
/*
* Increment the counter so that main thread knows something
* happened.
*/
FramesRx++;
// if (EmacPsInstancePtr->Config.IsCacheCoherent == 0) {
// Xil_DCacheInvalidateRange((UINTPTR)&RxFrame, sizeof(EthernetFrame));
// }
}
/****************************************************************************/
/**
*
* This is the Error handler callback function and this function increments
* the error counter so that the main thread knows the number of errors.
*
* @param Callback is the callback function for the driver. This
* parameter is not used in this example.
* @param Direction is passed in from the driver specifying which
* direction error has occurred.
* @param ErrorWord is the status register value passed in.
*
* @return None.
*
* @note None.
*
*****************************************************************************/
static void XEmacPsErrorHandler(void *Callback, u8 Direction, u32 ErrorWord)
{
XEmacPs *EmacPsInstancePtr = (XEmacPs *) Callback;
/*
* Increment the counter so that main thread knows something
* happened. Reset the device and reallocate resources ...
*/
DeviceErrors++;
xil_printf("in error callback.\r\n");
switch (Direction) {
case XEMACPS_RECV:
if (ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK) {
EmacPsUtilErrorTrap("Receive DMA error");
}
if (ErrorWord & XEMACPS_RXSR_RXOVR_MASK) {
EmacPsUtilErrorTrap("Receive over run");
}
if (ErrorWord & XEMACPS_RXSR_BUFFNA_MASK) {
EmacPsUtilErrorTrap("Receive buffer not available");
}
break;
case XEMACPS_SEND:
if (ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK) {
EmacPsUtilErrorTrap("Transmit DMA error");
}
if (ErrorWord & XEMACPS_TXSR_URUN_MASK) {
EmacPsUtilErrorTrap("Transmit under run");
}
if (ErrorWord & XEMACPS_TXSR_BUFEXH_MASK) {
EmacPsUtilErrorTrap("Transmit buffer exhausted");
}
if (ErrorWord & XEMACPS_TXSR_RXOVR_MASK) {
EmacPsUtilErrorTrap("Transmit retry excessed limits");
}
if (ErrorWord & XEMACPS_TXSR_FRAMERX_MASK) {
EmacPsUtilErrorTrap("Transmit collision");
}
if (ErrorWord & XEMACPS_TXSR_USEDREAD_MASK) {
EmacPsUtilErrorTrap("Transmit buffer not available");
}
break;
}
/*
* Bypassing the reset functionality as the default tx status for q0 is
* USED BIT READ. so, the first interrupt will be tx used bit and it resets
* the core always.
*/
// if (GemVersion == 2) {
// EmacPsResetDevice(EmacPsInstancePtr);
// }
}
/****************************************************************************/
/**
*
* This function sets up the clock divisors for 1000Mbps.
*
* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs
* driver.
* @param EmacPsIntrId is the Interrupt ID and is typically
* XPAR_<EMACPS_instance>_INTR value from xparameters.h.
* @return None.
*
* @note None.
*
*****************************************************************************/
void XEmacPsClkSetup(XEmacPs *EmacPsInstancePtr, u16 EmacPsIntrId)
{
u32 ClkCntrl;
// if (GemVersion == 2)
// {
/*************************************/
/* Setup device for first-time usage */
/*************************************/
/* SLCR unlock */
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE;
// if (EmacPsIntrId == XPS_GEM0_INT_ID) {
// #ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
ClkCntrl =
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR);
ClkCntrl &= EMACPS_SLCR_DIV_MASK;
// ClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1 << 20);
// ClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 << 8);
ClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1 << 20);
ClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 << 8);
*(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) = ClkCntrl;
// #endif
// } else if (EmacPsIntrId == XPS_GEM1_INT_ID) {
// }
/* SLCR lock */
*(unsigned int *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE;
sleep(1);
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment