Files
xiuos/Ubiquitous/XiZi_AIoT/services/drivers/imx6q-sabrelite/enet/enet_drv.c
2024-05-15 17:59:38 +08:00

621 lines
20 KiB
C
Executable File

/*
* 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) {
printf("[%s %d], EIR: %08x\n", __func__, __LINE__, enet_reg->EIR.U);
enet_reg->EIR.U = ENET_EVENT_MII;
break;
}
if ((--waiting) == 0)
return -1;
hal_delay_us(0);
}
printf("[%s %d], EIR: %08x\n", __func__, __LINE__, enet_reg->EIR.U);
*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 */
printf("MMFR.U: %08x value: %08x\n", enet_reg->MMFR.U, value);
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) * (ENET_BD_RX_NUM * NUM_OF_ETH_DEVS)), //
*tx_bd_base = (imx_enet_bd_t*)malloc(sizeof(imx_enet_bd_t) * (ENET_BD_TX_NUM * NUM_OF_ETH_DEVS));
#define _SABRELITE_ENET_BUFFER_SIZE 2048
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(_SABRELITE_ENET_BUFFER_SIZE);
// 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(_SABRELITE_ENET_BUFFER_SIZE);
// 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) {
hal_delay_us(ENET_COMMON_TICK);
}
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;
printf("EIR: %08x, ECR: %08x, TDAR.U: %08x, RDAR.U: %08x (%08x)\n", dev->enet_reg->EIR.U, dev->enet_reg->ECR.U, dev->enet_reg->TDAR.U, dev->enet_reg->RDAR.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;
HW_ENET_RDAR_WR(ENET_RX_TX_ACTIVE);
printf("addr1: %x, addr2: %x\n", &dev->enet_reg->RDAR.U, HW_ENET_RDAR_ADDR);
printf("EIR: %08x, ECR: %08x, TDAR.U: %08x, RDAR.U: %08x (%08x)\n", dev->enet_reg->EIR.U, dev->enet_reg->ECR.U, dev->enet_reg->TDAR.U, 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;
}
printf("RCR: %08x, TFWR: %08x\n", enet_reg->RCR.U, enet_reg->TFWR.U);
return 0;
}