//-----------------------------------------------------------------------------
// \file evmomapl138_emac.c
// \brief implementation of the emac/mdio driver for the OMAP-L138 EVM.
//
//-----------------------------------------------------------------------------
#include "stdio.h"
#include "string.h"
#include "types.h"
#include "evmomapl138.h"
#include "evmomapl138_timer.h"
#include "ethernet_smsc.h"
#include "evmomapl138_emac.h"
#include "evmomapl138_gpio.h"
#include "evmomapl138_i2c_gpio.h"
#include "evmomapl138_cdce913.h"
//-----------------------------------------------------------------------------
// Private Defines and Macros
//-----------------------------------------------------------------------------
// mdio clock divide down value.
#define MDIO_CLK_FREQ_HZ (2000000)
#define MDIO_CLK_DIVISOR ((SYSCLOCK4_HZ / MDIO_CLK_FREQ_HZ) - 1)
// packet defines.
#define MAX_RX_BUFFERS (10)
#define MIN_PACKET_SIZE (46)
#define MAX_PACKET_SIZE (1518)
#define PACKET_ALIGN (18)
// rx / tx desriptor memory offsets.
#define RX_DESC_OFFSET (0)
#define TX_DESC_OFFSET (0x1000)
//MII pinmux
#define PINMUX_MII_REG_0 (2)
#define PINMUX_MII_MASK_0 (0xFFFFFFF0)
#define PINMUX_MII_VAL_0 (0x88888880)
#define PINMUX_MII_REG_1 (3)
#define PINMUX_MII_MASK_1 (0xFFFFFFFF)
#define PINMUX_MII_VAL_1 (0x88888888)
//RMII pinmux
#define PINMUX_RMII_REG_0 (14)
#define PINMUX_RMII_MASK_0 (0xFFFFFF00)
#define PINMUX_RMII_VAL_0 (0x88888800)
#define PINMUX_RMII_REG_1 (15)
#define PINMUX_RMII_MASK_1 (0x000000FF)
#define PINMUX_RMII_VAL_1 (0x00000080)
//MDIO pinmux
#define PINMUX_MDIO_REG (4)
#define PINMUX_MDIO_MASK (0x000000FF)
#define PINMUX_MDIO_VAL (0x00000088)
//GPIO pinmux
#define PINMUX_MII_MDIO_EN_REG (6)
#define PINMUX_MII_MDIO_EN_MASK (0x000000F0)
#define PINMUX_MII_MDIO_EN_VAL (0x00000080)
//
#define EMAC_RMII_SPEED_100 (0x00008000)
//-----------------------------------------------------------------------------
// Private Static Variables
//-----------------------------------------------------------------------------
static uint8_t g_active_phy_id = 0x1;
static volatile emac_descriptor_t *g_rx_desc = (emac_descriptor_t *)(EMAC_RAM_BASE + RX_DESC_OFFSET);
static volatile emac_descriptor_t *g_tx_desc = (emac_descriptor_t *)(EMAC_RAM_BASE + TX_DESC_OFFSET);
static volatile emac_descriptor_t *g_rx_active_head = 0;
static volatile emac_descriptor_t *g_rx_active_tail = 0;
static uint8_t g_rx_queue_active = 0;
static uint8_t g_rx_buffers[MAX_RX_BUFFERS * (MAX_PACKET_SIZE + PACKET_ALIGN)];
//-----------------------------------------------------------------------------
// Private Function Prototypes
//-----------------------------------------------------------------------------
static uint32_t initMdioPhy(void);
static uint8_t isLinkActive(uint8_t in_phy);
static uint16_t phyRegRead(uint8_t in_phy, uint8_t in_reg);
static void phyRegWrite(uint8_t in_phy, uint8_t in_reg, uint16_t in_data);
//-----------------------------------------------------------------------------
// Public Function Definitions
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// \brief initialize the EMAC and MDIO for use.
//
// \param none.
//
// \return uint32_t
// ERR_NO_ERROR - everything is ok...emac ready to use.
// ERR_INIT_FAIL - something happened during initialization.
//-----------------------------------------------------------------------------
uint32_t EMAC_init(emac_interface_e emac_interface)
{
uint32_t rtn = 0;
uint32_t i;
volatile emac_descriptor_t *tmp_rx_desc;
// reset emac module.
EMAC->SOFTRESET = 1;
while (EMAC->SOFTRESET != 0) {}
// init emac module.
//------------------
// make sure emac control interrupts are disabled.
EMAC_CTRL->C0RXTHRESHEN = 0;
EMAC_CTRL->C1RXTHRESHEN = 0;
EMAC_CTRL->C0RXEN = 0;
EMAC_CTRL->C1RXEN = 0;
EMAC_CTRL->C0TXEN = 0;
EMAC_CTRL->C1TXEN = 0;
EMAC_CTRL->C0MISCEN = 0;
EMAC_CTRL->C1MISCEN = 0;
// enable the psc and config pinmux for the desired interface.
EVMOMAPL138_lpscTransition(PSC1, DOMAIN0, LPSC_EMAC, PSC_ENABLE);
EVMOMAPL138_pinmuxConfig(PINMUX_MDIO_REG, PINMUX_MDIO_MASK, PINMUX_MDIO_VAL); //MDIO shared by both RMII and MII
EVMOMAPL138_pinmuxConfig(PINMUX_MII_MDIO_EN_REG, PINMUX_MII_MDIO_EN_MASK, PINMUX_MII_MDIO_EN_VAL); //pinmux to select gpio bank2 pin6
if (EMAC_INTERFACE_MII == emac_interface)
{
//PINMUXING
EVMOMAPL138_pinmuxConfig(PINMUX_MII_REG_0, PINMUX_MII_MASK_0, PINMUX_MII_VAL_0);
EVMOMAPL138_pinmuxConfig(PINMUX_MII_REG_1, PINMUX_MII_MASK_1, PINMUX_MII_VAL_1);
SYSCONFIG->KICKR[0] = KICK0R_UNLOCK;
SYSCONFIG->KICKR[1] = KICK1R_UNLOCK;
CLRBIT(SYSCONFIG->CFGCHIP[3], 0x00000100);
}
else
{
//PINMUXING
EVMOMAPL138_pinmuxConfig(PINMUX_RMII_REG_0, PINMUX_RMII_MASK_0, PINMUX_RMII_VAL_0);
EVMOMAPL138_pinmuxConfig(PINMUX_RMII_REG_1, PINMUX_RMII_MASK_1, PINMUX_RMII_VAL_1);
SYSCONFIG->KICKR[0] = KICK0R_UNLOCK;
SYSCONFIG->KICKR[1] = KICK1R_UNLOCK;
SETBIT(SYSCONFIG->CFGCHIP[3], 0x00000100);
}
// setup local MAC address, only channel 0 is valid.
// program all 8, only need to set MACADDRHI for index = 0.
// use duplicate address for all unused channels.
// TODO: read MAC address from SPI flash.
EMAC->MACINDEX = 0;
EMAC->MACADDRHI = 0x01020304;
EMAC->MACADDRLO = 0x00000506 | MACADDRLO_VALID | MACADDRLO_MATCHFILT;
for (i = 1; i < 8; i++)
{
EMAC->MACINDEX = i;
EMAC->MACADDRLO = 0x00000506;
}
EMAC->MACSRCADDRHI = 0x01020304;
EMAC->MACSRCADDRLO = 0x00000506;
// init header descriptor pointer regs to 0.
for (i = 0; i < 8; i++)
{
EMAC->TXHDP[i] = 0;
EMAC->RXHDP[i] = 0;
}
// clear all network statistics registers.
#ifndef BOOT
memset((uint8_t *)NET_STAT_REG_BASE, 0, NET_STAT_REG_NUM_BYTES);
#endif
// initialize receive channel free buffer count regs, if buffer flow
// control is to be enabled.
// NOTE: this example does not use buffer flow control.
// no multicast addresses, clear MAC address hash registers.
EMAC->MACHASH1 = 0;
EMAC->MACHASH2 = 0;
// enable receive and transmit channel interrupts.
EMAC->RXINTMASKSET = 1;
EMAC->TXINTMASKSET = 1;
// init receive buffer offset and max length.
EMAC->RXBUFFEROFFSET = 0;
EMAC->RXMAXLEN = MAX_PACKET_SIZE;
// enable unicast chan 0 only.
EMAC->RXUNICASTSET = 0x01;
// config receive multicast/broadcast/promiscuous channel enable.
EMAC->RXMBPENABLE = 0;
SETBIT(EMAC->RXMBPENABLE, RXCAFEN);
EMAC->RXMBPENABLE = 0x01E02020; //enable reception of almost all frames inc error
// initialize receive/transmit descriptor list queues.
g_rx_active_head = tmp_rx_desc = g_rx_desc;
for (i = 0; i < MAX_RX_BUFFERS; i++)
{
tmp_rx_desc->buffer = &g_rx_buffers[i * (MAX_PACKET_SIZE + PACKET_ALIGN)];
tmp_rx_desc->buff_offset_length = MAX_PACKET_SIZE;
tmp_rx_desc->flags_pkt_length = EMAC_DSC_FLAG_OWNER;
if (i == (MAX_RX_BUFFERS - 1))
{
tmp_rx_desc->next = 0;
g_rx_active_tail = tmp_rx_desc;
g_rx_queue_active = 1;
}
else
{
tmp_rx_desc->next = (uint32_t)(tmp_rx_desc + 1);
tmp_rx_desc++;
}
}
// clear MAC, receive, and transmit control registers.
EMAC->MACCONTROL |= EMAC_RMII_SPEED_100;
EMAC->RXCONTROL = 0;
EMAC->TXCONTROL = 0;
// prepare for receive by writing pointer to head of rece