Support imx6q-sabrelite userland timer driver.

This commit is contained in:
TXuian
2024-05-11 17:12:23 +08:00
parent 79d741e015
commit 48abec8a00
53 changed files with 139310 additions and 181 deletions
@@ -0,0 +1,30 @@
ifeq ($(BOARD), imx6q-sabrelite)
toolchain ?= arm-none-eabi-
endif
ifeq ($(BOARD), zynq7000-zc702)
toolchain ?= arm-xilinx-eabi-
endif
cc = ${toolchain}gcc
ld = ${toolchain}g++
objdump = ${toolchain}objdump
user_ldflags = -N -Ttext 0
cflags = -std=c11 -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie
c_useropts = -O0
INC_DIR = -I$(KERNEL_ROOT)/services/app \
-I$(KERNEL_ROOT)/services/boards/$(BOARD) \
-I$(KERNEL_ROOT)/services/lib/serial \
-I$(KERNEL_ROOT)/services/drivers/$(BOARD)/include \
-I$(KERNEL_ROOT)/services/drivers/$(BOARD)/enet \
-I$(KERNEL_ROOT)/services/drivers/$(BOARD)/lib \
-I$(KERNEL_ROOT)/services/lib/usyscall \
-I$(KERNEL_ROOT)/services/lib/ipc \
-I$(KERNEL_ROOT)/services/lib/memory
all: enet_drv.o enet_test.o board_network.o enet_iomux_config.o
@mv $^ $(KERNEL_ROOT)/services/app
%.o: %.c
@echo "cc $^"
@${cc} ${cflags} ${c_useropts} ${INC_DIR} -o $@ -c $^
@@ -0,0 +1,142 @@
/*
* Copyright (c) 2012, Freescale Semiconductor, 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:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o 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.
*
* o Neither the name of Freescale Semiconductor, Inc. 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 HOLDER 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 "enet.h"
#include "gpio.h"
#include "iomux_config.h"
#include "regsiomuxc.h"
#include "soc_memory_map.h"
////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////
/* ENET iomux config */
void imx_ar8031_iomux()
{
enet_iomux_config(); // iomux tool output
}
/*CPU_PER_RST_B low to high*/
void imx_KSZ9021RN_reset(void)
{
// max7310_set_gpio_output(0, 2, GPIO_LOW_LEVEL);
// hal_delay_us(1000000);
// max7310_set_gpio_output(0, 2, GPIO_HIGH_LEVEL);
#ifdef BOARD_SABRE_LITE
gpio_set_level(GPIO_PORT3, 23, GPIO_LOW_LEVEL);
hal_delay_us(100000); // hold in reset for a delay
gpio_set_level(GPIO_PORT3, 23, GPIO_HIGH_LEVEL);
hal_delay_us(10000);
#endif
}
/*CPU_PER_RST_B low to high*/
void imx_ar8031_reset(void)
{
#if defined(BOARD_SMART_DEVICE)
/* Select ALT5 mode of ENET_CRS-DV for GPIO1_25 - PGMII_NRST */
/* active low output */
gpio_set_direction(GPIO_PORT1, 25, GPIO_GDIR_OUTPUT);
gpio_set_level(GPIO_PORT1, 25, GPIO_LOW_LEVEL);
hal_delay_us(500);
gpio_set_level(GPIO_PORT1, 25, GPIO_HIGH_LEVEL);
#elif defined(BOARD_SABRE_AI) && !defined(BOARD_REV_A)
/* CPU_PER_RST_B low to high */
// max7310_set_gpio_output(0, 2, GPIO_LOW_LEVEL);
// hal_delay_us(1000);
// max7310_set_gpio_output(0, 2, GPIO_HIGH_LEVEL);
#endif
}
/*! From obds
* ENET iomux config
*/
void imx_enet_iomux(void)
{
enet_iomux_config(); // iomux tool output
#ifdef BOARD_SABRE_LITE
gpio_set_gpio(GPIO_PORT6, 30);
gpio_set_gpio(GPIO_PORT6, 25);
gpio_set_gpio(GPIO_PORT6, 27);
gpio_set_gpio(GPIO_PORT6, 28);
gpio_set_gpio(GPIO_PORT6, 29);
gpio_set_gpio(GPIO_PORT6, 24);
gpio_set_gpio(GPIO_PORT3, 23);
gpio_set_direction(GPIO_PORT3, 23, GPIO_GDIR_OUTPUT);
gpio_set_direction(GPIO_PORT6, 30, GPIO_GDIR_OUTPUT);
gpio_set_direction(GPIO_PORT6, 25, GPIO_GDIR_OUTPUT);
gpio_set_direction(GPIO_PORT6, 27, GPIO_GDIR_OUTPUT);
gpio_set_direction(GPIO_PORT6, 28, GPIO_GDIR_OUTPUT);
gpio_set_direction(GPIO_PORT6, 29, GPIO_GDIR_OUTPUT);
// set correct phy address and operation mode in KSZ9021RN
gpio_set_level(GPIO_PORT3, 23, GPIO_LOW_LEVEL);
gpio_set_level(GPIO_PORT6, 30, GPIO_HIGH_LEVEL);
gpio_set_level(GPIO_PORT6, 25, GPIO_HIGH_LEVEL);
gpio_set_level(GPIO_PORT6, 27, GPIO_HIGH_LEVEL);
gpio_set_level(GPIO_PORT6, 28, GPIO_HIGH_LEVEL);
gpio_set_level(GPIO_PORT6, 29, GPIO_HIGH_LEVEL);
gpio_set_direction(GPIO_PORT6, 24, GPIO_GDIR_OUTPUT);
gpio_set_level(GPIO_PORT6, 24, GPIO_HIGH_LEVEL);
#endif
#ifdef BOARD_SABRE_AI
/* Select ENET, ENET_CAN1_STEER(PORT_EXP_B3) */
max7310_set_gpio_output(1, 2, GPIO_LOW_LEVEL);
/* Select ALT5 mode of GPIO_19 for GPIO4_5 - PGMIT_INT_B */
/* active low input */
gpio_set_gpio(GPIO_PORT4, 5);
gpio_set_direction(GPIO_PORT4, 5, GPIO_GDIR_INPUT);
#endif
}
#ifdef BOARD_SABRE_LITE
void imx_enet_iomux_reconfig(void)
{
// reconfigure RGMII_RD0-3, RGMII_RXC and RGMII_RX_CTL pads initially configured as GPIOs
enet_iomux_reconfig();
}
#endif
void imx_enet_phy_reset(void)
{
#ifdef BOARD_SABRE_LITE
imx_KSZ9021RN_reset();
#else
imx_ar8031_reset();
#endif
}
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,206 @@
/*
* Copyright (c) 2011-2012, Freescale Semiconductor, 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:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o 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.
*
* o Neither the name of Freescale Semiconductor, Inc. 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 HOLDER 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 __ENET_H__
#define __ENET_H__
#include <stddef.h>
#include <stdint.h>
#include "regsenet.h"
#include "sabrelite_timer.h"
////////////////////////////////////////////////////////////////////////////////
// Definitions
////////////////////////////////////////////////////////////////////////////////
//! @brief Definitions of the event bits.
enum {
ENET_EVENT_HBERR = 0x80000000,
ENET_EVENT_BABR = BM_ENET_EIR_BABR,
ENET_EVENT_BABT = BM_ENET_EIR_BABT,
ENET_EVENT_GRA = BM_ENET_EIR_GRA,
ENET_EVENT_TXF = BM_ENET_EIR_TXF,
ENET_EVENT_TXB = BM_ENET_EIR_TXB,
ENET_EVENT_RXF = BM_ENET_EIR_RXF,
ENET_EVENT_RXB = BM_ENET_EIR_RXB,
ENET_EVENT_MII = BM_ENET_EIR_MII,
ENET_EVENT_EBERR = BM_ENET_EIR_EBERR,
ENET_EVENT_LC = BM_ENET_EIR_LC,
ENET_EVENT_RL = BM_ENET_EIR_RL,
ENET_EVENT_UN = BM_ENET_EIR_UN,
ENET_EVENT_TX = ENET_EVENT_TXF,
ENET_EVENT_TX_ERR = (ENET_EVENT_BABT | ENET_EVENT_LC | ENET_EVENT_RL | ENET_EVENT_UN),
ENET_EVENT_RX = ENET_EVENT_RXF,
ENET_EVENT_ERR = (ENET_EVENT_HBERR | ENET_EVENT_EBERR)
};
//! @brief MII type
enum imx_mii_type {
MII,
RMII,
RGMII,
};
// Forward declaration.
typedef struct imx_enet_bd imx_enet_bd_t;
//! @brief Data structure for ENET device
typedef struct imx_enet_priv_s {
hw_enet_t* enet_reg; //!< the reister base address of ENET
uint8_t phy_addr; //!< the address of PHY which associated with ENET controller
uint32_t phy_id; //!< ID of the PHY
uint8_t tx_busy; //!< 0:free, 1:transmitting frame
uint8_t res[2];
uint32_t status; //!< the status of ENET device:link-status etc.
uint32_t tx_key; //!< save the key delivered from send function
imx_enet_bd_t* rx_bd; //!< the receive buffer description ring
imx_enet_bd_t* rx_cur; //!< the next recveive buffer description
imx_enet_bd_t* tx_bd; //!< the transmit buffer description rign
imx_enet_bd_t* tx_cur; //!< the next transmit buffer description
// TODO: Add interrupt about fields
// TODO: Add timer about fields
} imx_enet_priv_t;
//! @brief Definitions of the status field of imx_enet_priv_t.
enum {
ENET_STATUS_LINK_ON = 0x80000000,
ENET_STATUS_FULL_DPLX = 0x40000000,
ENET_STATUS_AUTO_NEG = 0x20000000,
ENET_STATUS_10M = 0x8000000,
ENET_STATUS_100M = 0x10000000,
ENET_STATUS_1000M = 0x20000000
};
////////////////////////////////////////////////////////////////////////////////
// API
////////////////////////////////////////////////////////////////////////////////
#if defined(__cplusplus)
extern "C" {
#endif
#include "usyscall.h"
extern char enet_server_name[];
extern char timer_server_name[];
extern struct Session timer_session;
static inline void hal_delay_us(int tick)
{
delay_us(&timer_session, tick);
}
/*!
* @brief Enable ENET and start transfer.
* @param dev a pointer of ENET interface(imx_enet_priv_t)
* @param enaddr a pointer of MAC address
*
* @return none
*/
void imx_enet_start(imx_enet_priv_t* dev, unsigned char* enaddr);
/*!
* @brief Disable ENET
* @param dev a pointer of ENET interface(imx_enet_priv_t)
*
* @return none
*/
void imx_enet_stop(imx_enet_priv_t* dev);
/*!
* @brief Initialize ENET PHY, like LAN8700, 8720, AR8031, etc
* @param dev a pointer of ENET interface(imx_enet_priv_t)
*
* @return none
*/
void imx_enet_phy_init(imx_enet_priv_t* dev);
/*!
* @brief Reads the current status from the PHY.
* @param dev Pointer to the enet interface struct.
* @return Current status of the PHY. This is a bitmask composed of the ENET_STATUS_x enums,
* such as #ENET_STATUS_LINK_ON and #ENET_STATUS_100M.
*/
uint32_t imx_enet_get_phy_status(imx_enet_priv_t* dev);
/*!
* @brief Initialize ENET interface, including buffer descriptor and MAC
* @param dev a pointer of ENET interface(imx_enet_priv_t)
* @param reg_base base address of ethernet registers
* @param phy_addr phy address, 0 or 1
*
* @return zero
*/
int imx_enet_init(imx_enet_priv_t* dev, unsigned long reg_base, int phy_addr);
/*!
* @brief Poll ENET events
* @param dev a pointer of ENET interface(imx_enet_priv_t)
*
* @return event value
*/
unsigned long imx_enet_poll(imx_enet_priv_t* dev);
/*!
* @brief Recieve ENET packet
* @param dev a pointer of ENET interface(imx_enet_priv_t)
* @param buf a pointer of buffer for received packet
* @param length the length of received packet
*
* @return 0 if succeeded,
* -1 if failed
*
*/
int imx_enet_recv(imx_enet_priv_t* dev, unsigned char* buf, int* length);
/*!
* @brief Transmit ENET packet
* @param dev a pointer of ENET interface(imx_enet_priv_t)
* @param buf a pointer of buffer for packet to be sent
* @param length the length of packet to be sent
* @param key key
*
* @return zero
*/
int imx_enet_send(imx_enet_priv_t* dev, unsigned char* buf, int length, unsigned long key);
/*!
* @brief Switch the PHY to external loopback mode for testing.
*/
void imx_enet_phy_enable_external_loopback(imx_enet_priv_t* dev);
#if defined(__cplusplus)
}
#endif
#endif //__ENET_H__
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,613 @@
/*
* Copyright (c) 2011-2012, Freescale Semiconductor, 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:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o 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.
*
* o Neither the name of Freescale Semiconductor, Inc. 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 HOLDER 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.
*/
/*!
* @file enet_drv.c
* @brief Driver of the i.MX ENET controller.
*
* @ingroup diag_enet
*/
#include <string.h>
#include "ccm_pll.h"
#include "enet.h"
#include "enet_private.h"
#include "libmem.h"
#include "libserial.h"
#include "usyscall.h"
extern uint32_t get_main_clock(main_clocks_t clock);
/*!
* This function gets the value of the PHY registers through the MII interface.
*/
int imx_enet_mii_read(volatile hw_enet_t* enet_reg, unsigned char phy_addr,
unsigned char reg_addr, unsigned short int* value)
{
unsigned long waiting = ENET_MII_TIMEOUT;
if (enet_reg->EIR.U & ENET_EVENT_MII) {
enet_reg->EIR.U = ENET_EVENT_MII;
}
enet_reg->MMFR.U = ENET_MII_READ(phy_addr, reg_addr); /*Write CMD */
while (1) {
if (enet_reg->EIR.U & ENET_EVENT_MII) {
enet_reg->EIR.U = ENET_EVENT_MII;
break;
}
if ((--waiting) == 0)
return -1;
hal_delay_us(ENET_MII_TICK);
}
*value = ENET_MII_GET_DATA(enet_reg->MMFR.U);
return 0;
}
/*!
* This function sets the value of the PHY registers through the MII interface.
*/
int imx_enet_mii_write(volatile hw_enet_t* enet_reg, unsigned char phy_addr,
unsigned char reg_addr, unsigned short int value)
{
unsigned long waiting = ENET_MII_TIMEOUT;
if (enet_reg->EIR.U & ENET_EVENT_MII) {
enet_reg->EIR.U = ENET_EVENT_MII;
}
enet_reg->MMFR.U = ENET_MII_WRITE(phy_addr, reg_addr, value); /* Write CMD */
while (1) {
if (enet_reg->EIR.U & ENET_EVENT_MII) {
enet_reg->EIR.U = ENET_EVENT_MII;
break;
}
if ((--waiting) == 0)
return -1;
hal_delay_us(ENET_MII_TICK);
}
return 0;
}
/*!
* The function initializes the description buffer for receiving or transmitting.
*/
static void imx_enet_bd_init(imx_enet_priv_t* dev, int dev_idx)
{
int i;
imx_enet_bd_t* p;
imx_enet_bd_t *rx_bd_base = (imx_enet_bd_t*)malloc(sizeof(imx_enet_bd_t)), //
*tx_bd_base = (imx_enet_bd_t*)malloc(sizeof(imx_enet_bd_t));
rx_bd_base += (dev_idx * ENET_BD_RX_NUM);
tx_bd_base += (dev_idx * ENET_BD_TX_NUM);
p = dev->rx_bd = (imx_enet_bd_t*)rx_bd_base;
for (i = 0; i < ENET_BD_RX_NUM; i++, p++) {
p->status = BD_RX_ST_EMPTY;
p->length = 0;
p->data = (unsigned char*)malloc(2048);
// printf("rx bd %x, buffer is %x\n", (unsigned int)p, (unsigned int)p->data);
}
dev->rx_bd[i - 1].status |= BD_RX_ST_WRAP;
dev->rx_cur = dev->rx_bd;
p = dev->tx_bd = (imx_enet_bd_t*)tx_bd_base;
for (i = 0; i < ENET_BD_TX_NUM; i++, p++) {
p->status = 0;
p->length = 0;
p->data = (unsigned char*)malloc(2048);
// printf("tx bd %x, buffer is %x\n", (unsigned int)p, (unsigned int)p->data);
}
dev->tx_bd[i - 1].status |= BD_TX_ST_WRAP;
dev->tx_cur = dev->tx_bd;
/*TODO:: add the sync function for items */
}
/*!
* This function initializes the ENET controller.
*/
static void imx_enet_chip_init(imx_enet_priv_t* dev)
{
volatile hw_enet_t* enet_reg = (hw_enet_t*)dev->enet_reg;
unsigned int ipg_clk;
enet_reg->ECR.U = ENET_RESET;
while (enet_reg->ECR.U & ENET_RESET) {
yield(SYS_TASK_YIELD_NO_REASON);
}
enet_reg->EIMR.U = 0x00000000;
enet_reg->EIR.U = 0xFFFFFFFF;
/*
* setup the MII gasket for RMII mode
*/
enet_reg->RCR.U = (enet_reg->RCR.U & ~(0x0000003F)) | ENET_RCR_RGMII_EN | ENET_RCR_FCE | ENET_RCR_PROM;
enet_reg->TCR.U |= ENET_TCR_FDEN;
enet_reg->MIBC.U |= ENET_MIB_DISABLE;
enet_reg->IAUR.U = 0;
enet_reg->IALR.U = 0;
enet_reg->GAUR.U = 0;
enet_reg->GALR.U = 0;
/*TODO:: Use MII_SPEED(IPG_CLK) to get the value */
ipg_clk = get_main_clock(IPG_CLK);
enet_reg->MSCR.U = (enet_reg->MSCR.U & (~0x7e)) | (((ipg_clk + 499999) / 5000000) << 1);
/*Enable ETHER_EN */
enet_reg->MRBR.U = 2048 - 16;
enet_reg->RDSR.U = (unsigned long)dev->rx_bd;
enet_reg->TDSR.U = (unsigned long)dev->tx_bd;
}
void enet_phy_rework_ar8031(imx_enet_priv_t* dev)
{
unsigned short val = 0;
#if 0
int i;
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1d, 0x1F); // ?? unknown debug reg
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0x1e, &val);
//printf("debug before 0x1F val = 0x%x\n", val);
val |= 0x4;
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1e, val);
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0x1e, &val);
//printf("debug after 0x1F val = 0x%x\n", val);
// Set CLK_25M Clock Select MDIO register
// select_clk25m = 3'b110 = 125 MHz from local PLL source
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0xd, 0x7); // MMD Access Control; device addr=7
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0xe, 0x8016); // MMD Access Address Data; reg=0x8016 (CLK_25M Clock Select)
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0xd, 0x4007); // MMD Access Control; func=data, device addr=7
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0xe, &val);
//printf("debug read from 0x8016 val = 0x%x\n", val);
val &= 0xffe3;
val |= 0x18;
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0xe, val);
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0xe, &val);
//printf("debug after read from 0x8016 val = 0x%x\n", val);
for (i = 0; i < 100000; i++) ;
//debug register 0x5[8]=1'b1 - suggest add 2ns GTX_CLK delay
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1d, 0x5); // debug reg 0x05 = SerDes Test and System Mode Control
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0x1e, &val);
val |= 0x0100; // bit 8 = RGMII_tx_clk_dly
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1e, val);
// Disable hibernate
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1d, 0xb); // Hib Control and Auto-negotiation Test
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0x1e, &val);
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1e, 0x3c40); // disable hibernate
// Config to external loopback
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1d, 0x11); // External Loopback selection
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0x1e, &val);
val |= 0x0001; // enable ext loopback
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1e, val);
// PHY AR8031 Integrated 10/100/1000 Gigabit
// Reset & full duplex
// Use default speed - after Pwer on reset - 1000Mbs
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0, 0x8140);
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0, &val);
while (val == 0x8140)
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0, &val);
#else
/* To enable AR8031 ouput a 125MHz clk from CLK_25M */
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0xd, 0x7);
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0xe, 0x8016);
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0xd, 0x4007);
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0xe, &val);
val &= 0xffe3;
val |= 0x18;
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0xe, val);
/* introduce tx clock delay */
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1d, 0x5);
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0x1e, &val);
val |= 0x0100;
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1e, val);
#endif
}
void enet_phy_rework_ksz9021(imx_enet_priv_t* dev)
{
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x9, 0x1c00);
/* min rx data delay */
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x0b, 0x8105);
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x0c, 0x0000);
/* max rx/tx clock delay, min rx/tx control delay */
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x0b, 0x8104);
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x0c, 0xf0f0);
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x0b, 0x104);
}
/*!
* This function initializes the PHY connected to the ENET controller.
*/
void imx_enet_phy_init(imx_enet_priv_t* dev)
{
unsigned short value = 0;
unsigned long id = 0;
// Read PHY ID registers.
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_IDENTIFY_1, &value);
id = (value & PHY_ID1_MASK) << PHY_ID1_SHIFT;
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_IDENTIFY_2, &value);
id |= (value & PHY_ID2_MASK) << PHY_ID2_SHIFT;
id &= 0xfffffff0; // mask off lower 4 bits
switch (id) {
case 0x00540088: // ?? PHY
break;
case PHY_LAN8700_ID:
printf("ENET LAN8700 PHY: ID=%lx\n", id);
break;
case PHY_LAN8720_ID:
printf("ENET LAN8720 PHY: ID=%lx\n", id);
break;
case PHY_AR8031_ID:
printf("ENET AR8031 PHY: ID=%lx\n", id);
enet_phy_rework_ar8031(dev);
break;
case PHY_KSZ9021RN_ID:
printf("ENET KSZ9021RN PHY: ID=%lx\n", id);
enet_phy_rework_ksz9021(dev);
break;
default:
printf("[Warning] ENET not connect right PHY: ID=%lx\n", id);
}
dev->phy_id = id;
// Reset PHY
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value);
value |= PHY_CTRL_RESET;
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, value);
// Wait for reset to complete.
do {
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value);
} while (value & PHY_CTRL_RESET);
/* restart auto-negotiation */
#if 1
#if 1
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value);
value |= 0x1200;
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, value);
#else
value = 0x8100;
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1f, value);
#endif
#endif
// Read current PHY status.
imx_enet_get_phy_status(dev);
}
uint32_t imx_enet_get_phy_status(imx_enet_priv_t* dev)
{
uint16_t value;
// Reset saved status.
dev->status = 0;
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_STATUS_REG, &value);
printf("enet phy status %0d: %04x\n", dev->phy_addr, value); // 0x7809 or 0x782d
if (value & PHY_STATUS_LINK_ST) {
dev->status |= ENET_STATUS_LINK_ON;
} else {
dev->status &= ~ENET_STATUS_LINK_ON;
}
if (dev->phy_id == PHY_AR8031_ID) {
#if 0
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0x1b, &value); // Cable Diagnostic Tester (CDT)
if (value & (1 << 2))
dev->status |= ENET_STATUS_FULL_DPLX;
else
dev->status &= ~ENET_STATUS_FULL_DPLX;
if (value & 0x2)
dev->status |= ENET_STATUS_1000M;
else if (value & 0x1)
dev->status |= ENET_STATUS_100M;
else
dev->status |= ENET_STATUS_10M;
#else
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0x11, &value); // PHY-Specific status reg
printf("AR8031 reg 0x11 = %04x\n", value);
if (value & (1 << 13))
dev->status |= ENET_STATUS_FULL_DPLX;
else
dev->status &= ~ENET_STATUS_FULL_DPLX;
if (((value >> 14) & 0x3) == 0x2)
dev->status |= ENET_STATUS_1000M;
else if (((value >> 14) & 0x3) == 0x2)
dev->status |= ENET_STATUS_100M;
else
dev->status |= ENET_STATUS_10M;
#endif
} else if (dev->phy_id == PHY_KSZ9021RN_ID) {
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0x1f, &value);
printf("KSZ9021 reg 0x1f = %04x\n", value);
if (value & (1 << 3))
dev->status |= ENET_STATUS_FULL_DPLX;
else
dev->status &= ~ENET_STATUS_FULL_DPLX;
if (value & (1 << 6))
dev->status |= ENET_STATUS_1000M;
else if (value & (1 << 5))
dev->status |= ENET_STATUS_100M;
else
dev->status |= ENET_STATUS_10M;
} else {
if (value & 0xe000)
dev->status |= ENET_STATUS_100M;
else
dev->status |= ENET_STATUS_10M;
if (value & 0x5000)
dev->status |= ENET_STATUS_FULL_DPLX;
else
dev->status &= ~ENET_STATUS_FULL_DPLX;
}
// printf("ENET %0d: [ %s ] [ %s ] [ %s ]:\n", dev->phy_addr,
// (dev->status & ENET_STATUS_FULL_DPLX) ? "FULL_DUPLEX" : "HALF_DUPLEX",
// (dev->status & ENET_STATUS_LINK_ON) ? "connected" : "disconnected",
// (dev->status & ENET_STATUS_1000M) ? "1000M bps" : (dev->status & ENET_STATUS_100M) ?
// "100M bps" : "10M bps");
return dev->status;
}
void imx_enet_phy_enable_external_loopback(imx_enet_priv_t* dev)
{
uint16_t val;
if (dev->phy_id == PHY_AR8031_ID) {
// Disable hibernate
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1d, 0xb); // Hib Control and Auto-negotiation Test
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0x1e, &val);
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1e, 0x3c40); // disable hibernate
// Config to external loopback
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1d, 0x11); // External Loopback selection
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, 0x1e, &val);
val |= 0x0001; // enable ext loopback
imx_enet_mii_write(dev->enet_reg, dev->phy_addr, 0x1e, val);
}
}
unsigned long imx_enet_poll(imx_enet_priv_t* dev)
{
volatile hw_enet_t* enet_reg = dev->enet_reg;
unsigned int value = 0;
value = enet_reg->EIR.U;
enet_reg->EIR.U = value & (~ENET_EVENT_MII);
if (value & ENET_EVENT_TX_ERR) {
printf("WARNING[POLL]: There are error(%x) for transmit\n", value & ENET_EVENT_TX_ERR);
dev->tx_busy = 0;
} else {
if (value & ENET_EVENT_TX) {
dev->tx_busy = 0;
}
}
if (value & ENET_EVENT_RX) {
// imx_enet_check_rx_bd(sc);
}
if (value & ENET_EVENT_HBERR) {
printf("WARNGING[POLL]: Hearbeat error!\n");
}
if (value & ENET_EVENT_EBERR) {
printf("WARNING[POLL]: Ethernet Bus Error!\n");
}
return value;
}
int imx_enet_send(imx_enet_priv_t* dev, unsigned char* buf, int length, unsigned long key)
{
volatile hw_enet_t* enet_reg = dev->enet_reg;
imx_enet_bd_t* p = dev->tx_cur;
memcpy(p->data, buf, length);
p->length = length;
p->status &= ~(BD_TX_ST_LAST | BD_TX_ST_RDY | BD_TX_ST_TC | BD_TX_ST_ABC);
p->status |= BD_TX_ST_LAST | BD_TX_ST_RDY | BD_TX_ST_TC;
if (p->status & BD_TX_ST_WRAP) {
p = dev->tx_bd;
} else
p++;
dev->tx_cur = p;
dev->tx_busy = 1;
dev->tx_key = key;
enet_reg->TDAR.U = ENET_RX_TX_ACTIVE;
return 0;
}
int imx_enet_recv(imx_enet_priv_t* dev, unsigned char* buf, int* length)
{
imx_enet_bd_t* p = dev->rx_cur;
volatile hw_enet_t* enet_reg = dev->enet_reg;
if (p->status & BD_RX_ST_EMPTY) {
return -1;
}
if (!(p->status & BD_RX_ST_LAST)) {
printf("BUG[RX]: status=%x, length=%x\n", p->status, p->length);
return -1;
}
if ((p->status & BD_RX_ST_ERRS) || (p->length > ENET_FRAME_LEN)) {
printf("BUG1[RX]: status=%x, length=%x\n", p->status, p->length);
} else {
memcpy(buf, p->data, p->length - 4);
*length = p->length - 4;
}
p->status = (p->status & BD_RX_ST_WRAP) | BD_RX_ST_EMPTY;
if (p->status & BD_RX_ST_WRAP) {
p = dev->rx_bd;
} else {
p++;
}
dev->rx_cur = p;
enet_reg->ECR.U |= ENET_ETHER_EN;
enet_reg->RDAR.U |= ENET_RX_TX_ACTIVE;
return 0;
}
int imx_enet_init(imx_enet_priv_t* dev, unsigned long reg_base, int phy_addr)
{
dev->enet_reg = (hw_enet_t*)reg_base;
dev->tx_busy = 0;
dev->status = 0;
dev->phy_addr = phy_addr; /* 0 or 1 */
imx_enet_bd_init(dev, phy_addr);
imx_enet_chip_init(dev);
return 0;
}
static void imx_enet_set_mac_address(volatile hw_enet_t* enet_reg, unsigned char* enaddr)
{
unsigned long value;
value = enaddr[0];
value = (value << 8) + enaddr[1];
value = (value << 8) + enaddr[2];
value = (value << 8) + enaddr[3];
enet_reg->PALR.U = value;
value = enaddr[4];
value = (value << 8) + enaddr[5];
enet_reg->PAUR.U = (value << 16);
}
void imx_enet_start(imx_enet_priv_t* dev, unsigned char* enaddr)
{
imx_enet_set_mac_address(dev->enet_reg, enaddr);
dev->tx_busy = 0;
dev->enet_reg->ECR.U |= ENET_ETHER_EN | ENET_ETHER_SPEED_1000M | ENET_ETHER_LITTLE_ENDIAN;
dev->enet_reg->RDAR.U |= ENET_RX_TX_ACTIVE;
}
void imx_enet_stop(imx_enet_priv_t* dev)
{
dev->enet_reg->ECR.U &= ~ENET_ETHER_EN;
}
int imx_enet_isolate_phy(imx_enet_priv_t* dev)
{
unsigned short value = 0;
if (!imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value)) {
value |= (0x01 << 10);
if (!imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, value)) {
return 0;
}
}
return -1;
}
int imx_enet_unisolate_phy(imx_enet_priv_t* dev)
{
unsigned short value = 0;
if (!imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value)) {
value &= ~(0x01 << 10);
if (!imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, value)) {
imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value);
return 0;
}
}
return -1;
}
int imx_enet_mii_type(imx_enet_priv_t* dev, enum imx_mii_type mii_type)
{
volatile hw_enet_t* enet_reg = dev->enet_reg;
switch (mii_type) {
case MII:
/*clear RMII and RGMII */
enet_reg->RCR.U &= ~(ENET_RCR_RMII_MODE | ENET_RCR_RGMII_EN);
enet_reg->RCR.U |= ENET_RCR_MII_MODE;
break;
case RMII:
enet_reg->RCR.U &= ~(ENET_RCR_RGMII_EN);
enet_reg->RCR.U |= (ENET_RCR_MII_MODE | ENET_RCR_RMII_MODE);
break;
case RGMII:
enet_reg->RCR.U &= ~(ENET_RCR_RMII_MODE | ENET_RCR_MII_MODE);
enet_reg->RCR.U |= ENET_RCR_RGMII_EN;
enet_reg->TFWR.U = 0x3f; // for mx6dq
break;
default:
printf("BUG:unknow MII type=%x\n", mii_type);
break;
}
return 0;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,245 @@
/*
* Copyright (c) 2011-2012, Freescale Semiconductor, 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:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o 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.
*
* o Neither the name of Freescale Semiconductor, Inc. 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 HOLDER 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 __ENET_PRIVATE_H__
#define __ENET_PRIVATE_H__
#include "enet.h"
////////////////////////////////////////////////////////////////////////////////
// Definitions
////////////////////////////////////////////////////////////////////////////////
// clang-format off
#define NUM_OF_ETH_DEVS 1
#define ENET_RX_FRAMES 8
#define ENET_FRAME_LEN (1540+4)
/* the defines to active transmit or receive frame */
#define ENET_RX_TX_ACTIVE BM_ENET_TDAR_TDAR //BM_ENET_RDAR_RDAR
/* the defines of Ethernet Control register */
#define ENET_RESET BM_ENET_ECR_RESET
#define ENET_ETHER_EN BM_ENET_ECR_ETHEREN
#define ENET_ETHER_SPEED_1000M (1<<5)
#define ENET_ETHER_LITTLE_ENDIAN (1<<8)
/* the defins of MII operation */
#define ENET_MII_ST 0x40000000
#define ENET_MII_OP_OFF BP_ENET_MMFR_OP
#define ENET_MII_OP_MASK 0x03
#define ENET_MII_OP_RD 0x02
#define ENET_MII_OP_WR 0x01
#define ENET_MII_PA_OFF BP_ENET_MMFR_PA
#define ENET_MII_PA_MASK 0xFF
#define ENET_MII_RA_OFF 18
#define ENET_MII_RA_MASK 0xFF
#define ENET_MII_TA 0x00020000
#define ENET_MII_DATA_OFF BP_ENET_MMFR_DATA
#define ENET_MII_DATA_MASK 0x0000FFFF
#define ENET_MII_FRAME ( ENET_MII_ST | ENET_MII_TA )
#define ENET_MII_OP(x) ( ((x) & ENET_MII_OP_MASK) << ENET_MII_OP_OFF )
#define ENET_MII_PA(pa) (((pa)& ENET_MII_PA_MASK) << ENET_MII_PA_OFF)
#define ENET_MII_RA(ra) (((ra)& ENET_MII_RA_MASK) << ENET_MII_RA_OFF)
#define ENET_MII_SET_DATA(v) (((v) & ENET_MII_DATA_MASK) << ENET_MII_DATA_OFF)
#define ENET_MII_GET_DATA(v) (((v) >> ENET_MII_DATA_OFF) & ENET_MII_DATA_MASK )
#define ENET_MII_READ(pa, ra) ( ( ENET_MII_FRAME | ENET_MII_OP(ENET_MII_OP_RD) )|\
ENET_MII_PA(pa) | ENET_MII_RA(ra) )
#define ENET_MII_WRITE(pa, ra, v) ( ENET_MII_FRAME | ENET_MII_OP(ENET_MII_OP_WR)|\
ENET_MII_PA(pa) | ENET_MII_RA(ra) |ENET_MII_SET_DATA(v) )
#define MII_SPEED_SHIFT 1
#define MII_SPEED_MASK 0x0000003F
#define MII_SPEED(x) ( (((((x)+499999)/2500000)&(MII_SPEED_MASK))>>1)<<(MII_SPEED_SHIFT) )
/*the defines of MIB control */
#define ENET_MIB_DISABLE BM_ENET_MIBC_MIB_DIS
/*the defines of Receive Control*/
#define ENET_RCR_FCE BM_ENET_RCR_FCE
#define ENET_RCR_BC_REJ BM_ENET_RCR_BC_REJ
#define ENET_RCR_PROM BM_ENET_RCR_PROM
#define ENET_RCR_MII_MODE (BM_ENET_RCR_MII_MODE)
#define ENET_RCR_RGMII_EN (1<<6) /*RGMII enable/disable */
#define ENET_RCR_RMII_MODE (BM_ENET_RCR_RMII_MODE) /*RMII mode:1->10M, 0->100M */
/*the defines of Transmit Control*/
#define ENET_TCR_RFC_PAUSE BM_ENET_TCR_RFC_PAUSE
#define ENET_TCR_FDEN BM_ENET_TCR_FDEN
/*the defines of buffer description*/
#define ENET_BD_RX_NUM 8
#define ENET_BD_TX_NUM 2
#define BD_RX_ST_EMPTY 0x8000
#define BD_RX_ST_WRAP 0x2000
#define BD_RX_ST_LAST 0x0800
#define BD_RX_ST_ERRS 0x0037
#define BD_TX_ST_RDY 0x8000
#define BD_TX_ST_WRAP 0x2000
#define BD_TX_ST_LAST 0x0800
#define BD_TX_ST_TC 0x0400
#define BD_TX_ST_ABC 0x0200
//! @brief Data structure for Tx/Rx buffer descriptor
typedef struct imx_enet_bd {
unsigned short int length; /*packet size */
unsigned short int status; /*control & statue of this buffer description */
unsigned char *data; /*frame buffer address */
} imx_enet_bd_t;
#define MXC_ENET_PRIVATE(x) ((imx_enet_priv_t *)(x)->driver_private)
/*The defines of the status field of imx_enet_priv_t */
#define ENET_STATUS_LINK_ON 0x80000000
#define ENET_STATUS_FULL_DPLX 0x40000000
#define ENET_STATUS_AUTO_NEG 0x20000000
#define ENET_STATUS_10M 0x8000000
#define ENET_STATUS_100M 0x10000000
#define ENET_STATUS_1000M 0x20000000
enum
{
PHY_LAN8700_ID = 0x0007c0c0,
PHY_LAN8720_ID = 0x0007c0f0,
PHY_AR8031_ID = 0x004dd070,
PHY_KSZ9021RN_ID = 0x00221610
};
#define PHY_CTRL_REG 0x00
#define PHY_CTRL_RESET 0x8000
#define PHY_CTRL_AUTO_NEG 0x1000
#define PHY_CTRL_FULL_DPLX 0x0100
#define PHY_STATUS_REG 0x01
#define PHY_STATUS_LINK_ST 0x0004
#define PHY_IDENTIFY_1 0x02
#define PHY_IDENTIFY_2 0x03
#define PHY_ID1_SHIFT 16
#define PHY_ID1_MASK 0xFFFF
#define PHY_ID2_SHIFT 0
#define PHY_ID2_MASK 0xFFFF
#define PHY_MODE_NUM 0x03F0
#define PHY_REV_NUM 0x000F
#define PHY_DIAG_REG 0x12
#define PHY_DIAG_DPLX 0x0800
#define PHY_DIAG_RATE 0x0400
#define PHY_MODE_REG 0x15
#define PHY_LED_SEL 0x200
#define PHY_AUTO_NEG_REG 0x5
#define PHY_AUTO_10BASET 0x20
#define PHY_AUTO_10BASET_DPLX 0x40
#define PHY_AUTO_100BASET 0x80
#define PHY_AUTO_100BASET_DPLX 0x100
#define PHY_AUTO_NEG_EXP_REG 0x6
#define PHY_AUTO_NEG_NEW_PAGE 0x2
#define PHY_AUTO_NEG_CAP 0x1
#define PHY_INT_SRC_REG 29
#define PHY_INT_AUTO_NEG 0x40
#define ENET_COMMON_TICK 2
#define ENET_COMMON_TIMEOUT (1000*1000)
#define ENET_MII_TICK 2
#define ENET_MII_TIMEOUT (1000*1000)
// clang-format on
#endif //__ENET_PRIVATE_H__
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,235 @@
/*
* Copyright (c) 2011-2012, Freescale Semiconductor, 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:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o 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.
*
* o Neither the name of Freescale Semiconductor, Inc. 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 HOLDER 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.
*/
/*!
* @file enet_test.c
* @brief Test for the ethernet interface through the ENET + PHY.
*
* @ingroup diag_enet
*/
#include <stddef.h>
#include <string.h>
#include "enet.h"
#include "soc_memory_map.h"
#include "libserial.h"
#include "usyscall.h"
typedef enum _test_return {
TEST_NOT_STARTED = -3, // present in the menu, but not run
TEST_NOT_IMPLEMENTED = -2, // present in the menu, but not functional
TEST_FAILED = -1,
TEST_PASSED = 0,
TEST_BYPASSED = 2, // user elected to exit the test before it was run
TEST_NOT_PRESENT = 3, // not present in the menu.
TEST_CONTINUE = 4 // proceed with the test. opposite of TEST_BYPASSED
} test_return_t;
#define ENET_PHY_ADDR 6
static imx_enet_priv_t enet0;
static unsigned char pkt_send[2048], pkt_recv[2048];
static unsigned char mac_addr0[6] = { 0x00, 0x04, 0x9f, 0x00, 0x00, 0x01 };
extern int imx_enet_mii_type(imx_enet_priv_t* dev, enum imx_mii_type mii_type);
extern void imx_enet_iomux(void);
#ifdef BOARD_SABRE_LITE
extern void imx_enet_iomux_reconfig(void);
#endif
extern void imx_enet_phy_reset(void);
static void pkt_fill(unsigned char* packet, unsigned char* eth_addr, unsigned char seed, int length)
{
unsigned char* pkt = packet;
unsigned char eth_type[2] = { 0x08, 0x00 };
int i;
memset(pkt, 0xff, 6);
pkt += 6;
memcpy(pkt, eth_addr, 6);
pkt += 6;
memcpy(pkt, eth_type, 2);
pkt += 2;
for (i = 0; i < (length - 14); i++)
*pkt++ = (seed + i) & 0xff;
return;
}
static int pkt_compare(unsigned char* packet1, unsigned char* packet2, int length)
{
int i = 0;
unsigned char *pkt1 = packet1, *pkt2 = packet2;
for (i = 0; i < length; i++) {
if (*(pkt1 + i) != *(pkt2 + i))
break;
}
if (i < length)
return TEST_FAILED;
else
return 0;
}
/*!
* This test performs a loopback transfer on the RGMII interface through
* an external AR8031 giga ethernet PHY.
*
* @return TEST_PASSED or TEST_FAILED
*/
int enet_test()
{
imx_enet_priv_t* dev0 = &enet0;
int pkt_len_send = 0, pkt_len_recv = 0, ret = 0, i;
unsigned int enet_events = 0;
unsigned char try = 100;
// Enet loopback test
printf("\nWould you like to run the Ethernet loopback test?\n \
(Please note that in order to run the test, you need to\n \
first plug in a loopback cable to the Ethernet port) \n");
// setup iomux for ENET
imx_enet_iomux();
imx_enet_phy_reset();
#ifdef BOARD_SABRE_LITE
imx_enet_iomux_reconfig();
#endif
// init enet0
imx_enet_init(dev0, ENET_BASE_ADDR, ENET_PHY_ADDR);
imx_enet_mii_type(dev0, RGMII);
// init phy0.
imx_enet_phy_init(dev0);
while (try--) {
uint32_t status = imx_enet_get_phy_status(dev0);
if (status & ENET_STATUS_LINK_ON) {
printf("Ethernet link is up!\n");
break;
}
yield(SYS_TASK_YIELD_NO_REASON);
}
imx_enet_phy_enable_external_loopback(dev0);
printf("ENET %0d: [ %s ] [ %s ] [ %s ]:\n", dev0->phy_addr,
(dev0->status & ENET_STATUS_FULL_DPLX) ? "FULL_DUPLEX" : "HALF_DUPLEX",
(dev0->status & ENET_STATUS_LINK_ON) ? "connected" : "disconnected",
(dev0->status & ENET_STATUS_1000M) ? "1000M bps" : (dev0->status & ENET_STATUS_100M) ? "100M bps"
: "10M bps");
// check phy status
if (!(dev0->status & ENET_STATUS_LINK_ON)) {
printf("ENET link status check fail\n");
return TEST_FAILED;
}
imx_enet_start(dev0, mac_addr0);
// send packet
printf("send packet\n");
pkt_len_send = 1500;
pkt_fill(pkt_send, mac_addr0, 0x23, pkt_len_send);
imx_enet_send(dev0, pkt_send, pkt_len_send, 1);
enet_events = 0;
for (i = 0; i < 100; i++) {
enet_events = imx_enet_poll(dev0);
if (ENET_EVENT_TX & enet_events) {
printf("enet_events = %08x\n", enet_events);
break;
}
hal_delay_us(100);
}
if (!(ENET_EVENT_TX & enet_events)) {
printf("ENET tx fail\n");
return TEST_FAILED;
}
if (!(ENET_EVENT_RX & enet_events)) {
printf("ENET rx fail\n");
return TEST_FAILED;
}
pkt_len_recv = 0;
imx_enet_recv(dev0, pkt_recv, &pkt_len_recv);
if (pkt_len_recv != pkt_len_send) {
printf("ENET rx length check fail \n");
return TEST_FAILED;
}
ret = pkt_compare(pkt_send, pkt_recv, pkt_len_send);
if (ret != 0) {
printf("ENET rx packet check fail \n");
return TEST_FAILED;
}
#ifdef DEBUG_PRINT
printf("ENET rx ok\n");
#endif
printf(" ENET loopback test pass\n");
imx_enet_stop(dev0);
return TEST_PASSED;
}
char enet_server_name[] = "EnetServer";
char timer_server_name[] = "TimerServer";
struct Session timer_session;
int main(int argc, char** argv)
{
if (connect_session(&timer_session, timer_server_name, 4096) < 0) {
printf("%s connect server: %s failed\n", enet_server_name, timer_server_name);
exit();
}
printf("%s: Mapping %x(size: %x) to %x\n", enet_server_name, AIPS1_ARB_PHY_BASE_ADDR, AIPS1_ARB_END_ADDR - AIPS1_ARB_BASE_ADDR, AIPS1_ARB_BASE_ADDR);
if (!mmap(AIPS1_ARB_BASE_ADDR, AIPS1_ARB_PHY_BASE_ADDR, AIPS1_ARB_END_ADDR - AIPS1_ARB_BASE_ADDR, true)) {
printf("%s: mmap AIPS1 ARB(%x) failed\n", enet_server_name, AIPS1_ARB_PHY_BASE_ADDR);
exit();
}
printf("%s: Mapping %x(size: %x) to %x\n", enet_server_name, AIPS2_ARB_PHY_BASE_ADDR, AIPS2_ARB_END_ADDR - AIPS2_ARB_BASE_ADDR, AIPS2_ARB_BASE_ADDR);
if (!mmap(AIPS2_ARB_BASE_ADDR, AIPS2_ARB_PHY_BASE_ADDR, AIPS2_ARB_END_ADDR - AIPS2_ARB_BASE_ADDR, true)) {
printf("%s: mmap AIPS1 ARB(%x) failed\n", enet_server_name, AIPS2_ARB_PHY_BASE_ADDR);
exit();
}
enet_test();
exit();
}
File diff suppressed because it is too large Load Diff