Merge branch 'refactor/emac_hal' into 'master'

hal/emac_hal: refactor of emac_hal

Closes IDF-3155

See merge request espressif/esp-idf!13500
This commit is contained in:
Michael (XIAO Xufeng)
2021-06-22 15:34:51 +00:00
10 changed files with 1307 additions and 997 deletions

View File

@@ -1,687 +0,0 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "soc/gpio_periph.h"
#include "soc/rtc.h"
#include "hal/emac.h"
#include "hal/gpio_hal.h"
#define ETH_CRC_LENGTH (4)
#if CONFIG_ETH_RMII_CLK_OUTPUT
static void emac_config_apll_clock(void)
{
/* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
rtc_xtal_freq_t rtc_xtal_freq = rtc_clk_xtal_freq_get();
switch (rtc_xtal_freq) {
case RTC_XTAL_FREQ_40M: // Recommended
/* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000 */
/* sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2 */
rtc_clk_apll_enable(true, 0, 0, 6, 2);
break;
case RTC_XTAL_FREQ_26M:
/* 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992 */
/* sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3 */
rtc_clk_apll_enable(true, 39, 118, 15, 3);
break;
case RTC_XTAL_FREQ_24M:
/* 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977 */
/* sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2 */
rtc_clk_apll_enable(true, 255, 255, 12, 2);
break;
default: // Assume we have a 40M xtal
rtc_clk_apll_enable(true, 0, 0, 6, 2);
break;
}
}
#endif
void emac_hal_init(emac_hal_context_t *hal, void *descriptors,
uint8_t **rx_buf, uint8_t **tx_buf)
{
hal->dma_regs = &EMAC_DMA;
hal->mac_regs = &EMAC_MAC;
hal->ext_regs = &EMAC_EXT;
hal->descriptors = descriptors;
hal->rx_buf = rx_buf;
hal->tx_buf = tx_buf;
}
void emac_hal_lowlevel_init(emac_hal_context_t *hal)
{
/* GPIO configuration */
/* TX_EN to GPIO21 */
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_EMAC_TX_EN);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[21]);
/* TXD0 to GPIO19 */
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[19]);
/* TXD1 to GPIO22 */
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO22_U, FUNC_GPIO22_EMAC_TXD1);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[22]);
/* RXD0 to GPIO25 */
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO25_U, FUNC_GPIO25_EMAC_RXD0);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[25]);
/* RXD1 to GPIO26 */
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO26_U, FUNC_GPIO26_EMAC_RXD1);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[26]);
/* CRS_DV to GPIO27 */
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO27_U, FUNC_GPIO27_EMAC_RX_DV);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[27]);
#if CONFIG_ETH_RMII_CLK_INPUT
#if CONFIG_ETH_RMII_CLK_IN_GPIO == 0
/* RMII clock (50MHz) input to GPIO0 */
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_EMAC_TX_CLK);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]);
#else
#error "ESP32 EMAC only support input RMII clock to GPIO0"
#endif
#endif
#if CONFIG_ETH_RMII_CLK_OUTPUT
#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
/* APLL clock output to GPIO0 (must be configured to 50MHz!) */
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[0]);
#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 16
/* RMII CLK (50MHz) output to GPIO16 */
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[16]);
#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 17
/* RMII CLK (50MHz) output to GPIO17 */
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180);
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[17]);
#endif
#endif // CONFIG_ETH_RMII_CLK_OUTPUT
/* Clock configuration */
#if CONFIG_ETH_PHY_INTERFACE_MII
hal->ext_regs->ex_phyinf_conf.phy_intf_sel = 0;
hal->ext_regs->ex_clk_ctrl.mii_clk_rx_en = 1;
hal->ext_regs->ex_clk_ctrl.mii_clk_tx_en = 1;
#elif CONFIG_ETH_PHY_INTERFACE_RMII
hal->ext_regs->ex_phyinf_conf.phy_intf_sel = 4;
#if CONFIG_ETH_RMII_CLK_INPUT
hal->ext_regs->ex_clk_ctrl.ext_en = 1;
hal->ext_regs->ex_clk_ctrl.int_en = 0;
hal->ext_regs->ex_oscclk_conf.clk_sel = 1;
#elif CONFIG_ETH_RMII_CLK_OUTPUT
hal->ext_regs->ex_clk_ctrl.ext_en = 0;
hal->ext_regs->ex_clk_ctrl.int_en = 1;
hal->ext_regs->ex_oscclk_conf.clk_sel = 0;
emac_config_apll_clock();
hal->ext_regs->ex_clkout_conf.div_num = 0;
hal->ext_regs->ex_clkout_conf.h_div_num = 0;
#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
/* Choose the APLL clock to output on GPIO */
REG_WRITE(PIN_CTRL, 6);
#endif // CONFIG_RMII_CLK_OUTPUT_GPIO0
#endif // CONFIG_ETH_RMII_CLK_INPUT
#endif // CONFIG_ETH_PHY_INTERFACE_MII
}
void emac_hal_reset(emac_hal_context_t *hal)
{
hal->dma_regs->dmabusmode.sw_rst = 1;
}
bool emac_hal_is_reset_done(emac_hal_context_t *hal)
{
return hal->dma_regs->dmabusmode.sw_rst ? false : true;
}
void emac_hal_set_csr_clock_range(emac_hal_context_t *hal)
{
/* Tell MAC system clock Frequency, which will determin the frequency range of MDC(1MHz~2.5MHz) */
if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 20 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 35) {
hal->mac_regs->emacgmiiaddr.miicsrclk = 2;
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 35 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 60) {
hal->mac_regs->emacgmiiaddr.miicsrclk = 3;
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 60 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 100) {
hal->mac_regs->emacgmiiaddr.miicsrclk = 0;
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 100 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 150) {
hal->mac_regs->emacgmiiaddr.miicsrclk = 1;
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ > 150 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 250) {
hal->mac_regs->emacgmiiaddr.miicsrclk = 4;
} else {
hal->mac_regs->emacgmiiaddr.miicsrclk = 5;
}
}
void emac_hal_reset_desc_chain(emac_hal_context_t *hal)
{
/* reset DMA descriptors */
hal->rx_desc = (eth_dma_rx_descriptor_t *)(hal->descriptors);
hal->tx_desc = (eth_dma_tx_descriptor_t *)(hal->descriptors +
sizeof(eth_dma_rx_descriptor_t) * CONFIG_ETH_DMA_RX_BUFFER_NUM);
/* init rx chain */
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
/* Set Own bit of the Rx descriptor Status: DMA */
hal->rx_desc[i].RDES0.Own = 1;
/* Set Buffer1 size and Second Address Chained bit */
hal->rx_desc[i].RDES1.SecondAddressChained = 1;
hal->rx_desc[i].RDES1.ReceiveBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
/* Enable Ethernet DMA Rx Descriptor interrupt */
hal->rx_desc[i].RDES1.DisableInterruptOnComplete = 0;
/* point to the buffer */
hal->rx_desc[i].Buffer1Addr = (uint32_t)(hal->rx_buf[i]);
/* point to next descriptor */
hal->rx_desc[i].Buffer2NextDescAddr = (uint32_t)(hal->rx_desc + i + 1);
}
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
hal->rx_desc[CONFIG_ETH_DMA_RX_BUFFER_NUM - 1].Buffer2NextDescAddr = (uint32_t)(hal->rx_desc);
/* init tx chain */
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
/* Set Second Address Chained bit */
hal->tx_desc[i].TDES0.SecondAddressChained = 1;
hal->tx_desc[i].TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
/* Enable Ethernet DMA Tx Descriptor interrupt */
hal->tx_desc[1].TDES0.InterruptOnComplete = 1;
/* Enable Transmit Timestamp */
hal->tx_desc[i].TDES0.TransmitTimestampEnable = 1;
/* point to the buffer */
hal->tx_desc[i].Buffer1Addr = (uint32_t)(hal->tx_buf[i]);
/* point to next descriptor */
hal->tx_desc[i].Buffer2NextDescAddr = (uint32_t)(hal->tx_desc + i + 1);
}
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
hal->tx_desc[CONFIG_ETH_DMA_TX_BUFFER_NUM - 1].Buffer2NextDescAddr = (uint32_t)(hal->tx_desc);
/* set base address of the first descriptor */
hal->dma_regs->dmarxbaseaddr = (uint32_t)hal->rx_desc;
hal->dma_regs->dmatxbaseaddr = (uint32_t)hal->tx_desc;
}
void emac_hal_init_mac_default(emac_hal_context_t *hal)
{
/* MACCR Configuration */
typeof(hal->mac_regs->gmacconfig) maccr = hal->mac_regs->gmacconfig;
/* Enable the watchdog on the receiver, frame longer than 2048 Bytes is not allowed */
maccr.watchdog = EMAC_WATCHDOG_ENABLE;
/* Enable the jabber timer on the transmitter, frame longer than 2048 Bytes is not allowed */
maccr.jabber = EMAC_JABBER_ENABLE;
/* minimum IFG between frames during transmission is 96 bit times */
maccr.interframegap = EMAC_INTERFRAME_GAP_96BIT;
/* Enable Carrier Sense During Transmission */
maccr.disablecrs = EMAC_CARRIERSENSE_ENABLE;
/* Select port: 10/100 Mbps */
maccr.mii = EMAC_PORT_10_100MBPS;
/* Select speed: here set default 100M, afterwards, will reset by auto-negotiation */
maccr.fespeed = EMAC_SPEED_100M;
/* Allow the reception of frames when the TX_EN signal is asserted in Half-Duplex mode */
maccr.rxown = EMAC_RECEIVE_OWN_ENABLE;
/* Disable internal loopback mode */
maccr.loopback = EMAC_LOOPBACK_DISABLE;
/* Select duplex mode: here set default full duplex, afterwards, will reset by auto-negotiation */
maccr.duplex = EMAC_DUPLEX_FULL;
/* Select the checksum mode for received frame payload's TCP/UDP/ICMP headers */
maccr.rxipcoffload = EMAC_CHECKSUM_HW;
/* Enable MAC retry transmission when a colision occurs in half duplex mode */
maccr.retry = EMAC_RETRY_TRANSMISSION_ENABLE;
/* MAC passes all incoming frames to host, without modifying them */
maccr.padcrcstrip = EMAC_AUTO_PAD_CRC_STRIP_DISABLE;
/* Set Back-Off limit time before retry a transmittion after a collision */
maccr.backofflimit = EMAC_BACKOFF_LIMIT_10;
/* Disable deferral check, MAC defers until the CRS signal goes inactive */
maccr.deferralcheck = EMAC_DEFERRAL_CHECK_DISABLE;
/* Set preamble length 7 Bytes */
maccr.pltf = EMAC_PREAMBLE_LENGTH_7;
hal->mac_regs->gmacconfig = maccr;
/* MACFFR Configuration */
typeof(hal->mac_regs->gmacff) macffr = hal->mac_regs->gmacff;
/* Receiver module passes only those frames to the Application that pass the SA or DA address filter */
macffr.receive_all = EMAC_RECEIVE_ALL_DISABLE;
/* Disable source address filter */
macffr.safe = EMAC_SOURCE_ADDR_FILTER_DISABLE;
macffr.saif = 0;
/* MAC blocks all control frames */
macffr.pcf = EMAC_CONTROL_FRAME_BLOCKALL;
/* AFM module passes all received broadcast frames and multicast frames */
macffr.dbf = EMAC_RECEPT_BROADCAST_ENABLE;
macffr.pam = 1;
/* Address Check block operates in normal filtering mode for the DA address */
macffr.daif = EMAC_DEST_ADDR_FILTER_NORMAL;
/* Disable Promiscuous Mode */
macffr.pmode = EMAC_PROMISCUOUS_DISABLE;
hal->mac_regs->gmacff = macffr;
}
void emac_hal_enable_flow_ctrl(emac_hal_context_t *hal, bool enable)
{
/* MACFCR Configuration */
typeof(hal->mac_regs->gmacfc) macfcr = hal->mac_regs->gmacfc;
if (enable) {
/* Pause time */
macfcr.pause_time = EMAC_PAUSE_TIME;
/* Enable generation of Zero-Quanta Pause Control frames */
macfcr.dzpq = EMAC_ZERO_QUANTA_PAUSE_ENABLE;
/* Threshold of the PAUSE to be checked for automatic retransmission of PAUSE Frame */
macfcr.plt = EMAC_PAUSE_LOW_THRESHOLD_MINUS_28;
/* Don't allow MAC detect Pause frames with MAC address0 unicast address and unique multicast address */
macfcr.upfd = EMAC_UNICAST_PAUSE_DETECT_DISABLE;
/* Enable MAC to decode the received Pause frame and disable its transmitter for a specific time */
macfcr.rfce = EMAC_RECEIVE_FLOW_CONTROL_ENABLE;
/* Enable MAC to transmit Pause frames in full duplex mode or the MAC back-pressure operation in half duplex mode */
macfcr.tfce = EMAC_TRANSMIT_FLOW_CONTROL_ENABLE;
} else {
macfcr.val = 0;
}
hal->mac_regs->gmacfc = macfcr;
}
void emac_hal_init_dma_default(emac_hal_context_t *hal)
{
/* DMAOMR Configuration */
typeof(hal->dma_regs->dmaoperation_mode) dmaomr = hal->dma_regs->dmaoperation_mode;
/* Enable Dropping of TCP/IP Checksum Error Frames */
dmaomr.dis_drop_tcpip_err_fram = EMAC_DROP_TCPIP_CHECKSUM_ERROR_ENABLE;
/* Enable Receive Store Forward */
dmaomr.rx_store_forward = EMAC_RECEIVE_STORE_FORWARD_ENABLE;
/* Enable Flushing of Received Frames because of the unavailability of receive descriptors or buffers */
dmaomr.dis_flush_recv_frames = EMAC_FLUSH_RECEIVED_FRAME_ENABLE;
/* Enable Transmit Store Forward */
dmaomr.tx_str_fwd = EMAC_TRANSMIT_STORE_FORWARD_ENABLE;
/* Flush Transmit FIFO */
dmaomr.flush_tx_fifo = 1;
/* Transmit Threshold Control */
dmaomr.tx_thresh_ctrl = EMAC_TRANSMIT_THRESHOLD_CONTROL_64;
/* Disable Forward Error Frame */
dmaomr.fwd_err_frame = EMAC_FORWARD_ERROR_FRAME_DISABLE;
/* Disable forward undersized good frame */
dmaomr.fwd_under_gf = EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_DISABLE;
/* Receive Threshold Control */
dmaomr.rx_thresh_ctrl = EMAC_RECEIVE_THRESHOLD_CONTROL_64;
/* Allow the DMA to process a second frame of Transmit data even before obtaining the status for the first frame */
dmaomr.opt_second_frame = EMAC_OPERATE_SECOND_FRAME_ENABLE;
hal->dma_regs->dmaoperation_mode = dmaomr;
/* DMABMR Configuration */
typeof(hal->dma_regs->dmabusmode) dmabmr = hal->dma_regs->dmabusmode;
/* Enable Mixed Burst */
dmabmr.dmamixedburst = EMAC_MIXED_BURST_ENABLE;
/* Enable Address Aligned Beates */
dmabmr.dmaaddralibea = EMAC_ADDR_ALIGN_BEATS_ENABLE;
/* Use Separate PBL */
dmabmr.use_sep_pbl = EMAC_USE_SEPARATE_PBL;
/* Set Rx/Tx DMA Burst Length */
dmabmr.rx_dma_pbl = EMAC_DMA_BURST_LENGTH_32BEAT;
dmabmr.prog_burst_len = EMAC_DMA_BURST_LENGTH_32BEAT;
/* Enable Enhanced Descriptor,8 Words(32 Bytes) */
dmabmr.alt_desc_size = EMAC_ENHANCED_DESCRIPTOR_ENABLE;
/* Specifies the number of word to skip between two unchained descriptors (Ring mode) */
dmabmr.desc_skip_len = 0;
/* DMA Arbitration Scheme */
dmabmr.dma_arb_sch = EMAC_DMA_ARBITRATION_SCHEME_ROUNDROBIN;
/* Set priority ratio in the weighted round-robin arbitration between Rx DMA and Tx DMA */
dmabmr.pri_ratio = EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1;
hal->dma_regs->dmabusmode = dmabmr;
}
void emac_hal_set_speed(emac_hal_context_t *hal, uint32_t speed)
{
hal->mac_regs->gmacconfig.fespeed = speed;
}
void emac_hal_set_duplex(emac_hal_context_t *hal, uint32_t duplex)
{
hal->mac_regs->gmacconfig.duplex = duplex;
}
void emac_hal_set_promiscuous(emac_hal_context_t *hal, bool enable)
{
if (enable) {
hal->mac_regs->gmacff.pmode = 1;
} else {
hal->mac_regs->gmacff.pmode = 0;
}
}
void emac_hal_send_pause_frame(emac_hal_context_t *hal, bool enable)
{
if (enable) {
hal->ext_regs->ex_phyinf_conf.sbd_flowctrl = 1;
} else {
hal->ext_regs->ex_phyinf_conf.sbd_flowctrl = 0;
}
}
bool emac_hal_is_mii_busy(emac_hal_context_t *hal)
{
return hal->mac_regs->emacgmiiaddr.miibusy ? true : false;
}
void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t phy_reg, bool write)
{
typeof(hal->mac_regs->emacgmiiaddr) macmiiar = hal->mac_regs->emacgmiiaddr;
macmiiar.miidev = phy_addr;
/* Set the PHY register address */
macmiiar.miireg = phy_reg;
if (write) {
/* Set write mode */
macmiiar.miiwrite = 1;
} else {
/* Set read mode */
macmiiar.miiwrite = 0;
}
/* Set MII busy bit */
macmiiar.miibusy = 1;
/* Write the result value into the MII Address register */
hal->mac_regs->emacgmiiaddr = macmiiar;
}
void emac_hal_set_phy_data(emac_hal_context_t *hal, uint32_t reg_value)
{
hal->mac_regs->emacmiidata.mii_data = reg_value;
}
uint32_t emac_hal_get_phy_data(emac_hal_context_t *hal)
{
return hal->mac_regs->emacmiidata.mii_data;
}
void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr)
{
/* Make sure mac address is unicast type */
if (!(mac_addr[0] & 0x01)) {
hal->mac_regs->emacaddr0high.address0_hi = (mac_addr[5] << 8) | mac_addr[4];
hal->mac_regs->emacaddr0low = (mac_addr[3] << 24) | (mac_addr[2] << 16) | (mac_addr[1] << 8) | (mac_addr[0]);
}
}
void emac_hal_start(emac_hal_context_t *hal)
{
typeof(hal->dma_regs->dmaoperation_mode) opm = hal->dma_regs->dmaoperation_mode;
typeof(hal->mac_regs->gmacconfig) cfg = hal->mac_regs->gmacconfig;
/* Enable Ethernet MAC and DMA Interrupt */
hal->dma_regs->dmain_en.val = 0xFFFFFFFF;
/* Flush Transmit FIFO */
opm.flush_tx_fifo = 1;
/* Start DMA transmission */
opm.start_stop_transmission_command = 1;
/* Start DMA reception */
opm.start_stop_rx = 1;
/* Enable transmit state machine of the MAC for transmission on the MII */
cfg.tx = 1;
/* Enable receive state machine of the MAC for reception from the MII */
cfg.rx = 1;
hal->dma_regs->dmaoperation_mode = opm;
hal->mac_regs->gmacconfig = cfg;
/* Clear all pending interrupts */
hal->dma_regs->dmastatus.val = 0xFFFFFFFF;
}
void emac_hal_stop(emac_hal_context_t *hal)
{
typeof(hal->dma_regs->dmaoperation_mode) opm = hal->dma_regs->dmaoperation_mode;
typeof(hal->mac_regs->gmacconfig) cfg = hal->mac_regs->gmacconfig;
/* Flush Transmit FIFO */
opm.flush_tx_fifo = 1;
/* Stop DMA transmission */
opm.start_stop_transmission_command = 0;
/* Stop DMA reception */
opm.start_stop_rx = 0;
/* Disable receive state machine of the MAC for reception from the MII */
cfg.rx = 0;
/* Disable transmit state machine of the MAC for transmission on the MII */
cfg.tx = 0;
hal->dma_regs->dmaoperation_mode = opm;
hal->mac_regs->gmacconfig = cfg;
/* Disable Ethernet MAC and DMA Interrupt */
hal->dma_regs->dmain_en.val = 0x0;
}
uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal)
{
return hal->tx_desc->TDES0.Own;
}
uint32_t emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length)
{
/* Get the number of Tx buffers to use for the frame */
uint32_t bufcount = 0;
uint32_t lastlen = length;
uint32_t sentout = 0;
while (lastlen > CONFIG_ETH_DMA_BUFFER_SIZE) {
lastlen -= CONFIG_ETH_DMA_BUFFER_SIZE;
bufcount++;
}
if (lastlen) {
bufcount++;
}
if (bufcount > CONFIG_ETH_DMA_TX_BUFFER_NUM) {
goto err;
}
eth_dma_tx_descriptor_t *desc_iter = hal->tx_desc;
/* A frame is transmitted in multiple descriptor */
for (size_t i = 0; i < bufcount; i++) {
/* Check if the descriptor is owned by the Ethernet DMA (when 1) or CPU (when 0) */
if (desc_iter->TDES0.Own != EMAC_DMADESC_OWNER_CPU) {
goto err;
}
/* Clear FIRST and LAST segment bits */
desc_iter->TDES0.FirstSegment = 0;
desc_iter->TDES0.LastSegment = 0;
desc_iter->TDES0.InterruptOnComplete = 0;
if (i == 0) {
/* Setting the first segment bit */
desc_iter->TDES0.FirstSegment = 1;
}
if (i == (bufcount - 1)) {
/* Setting the last segment bit */
desc_iter->TDES0.LastSegment = 1;
/* Enable transmit interrupt */
desc_iter->TDES0.InterruptOnComplete = 1;
/* Program size */
desc_iter->TDES1.TransmitBuffer1Size = lastlen;
/* copy data from uplayer stack buffer */
memcpy((void *)(desc_iter->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, lastlen);
sentout += lastlen;
} else {
/* Program size */
desc_iter->TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
/* copy data from uplayer stack buffer */
memcpy((void *)(desc_iter->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, CONFIG_ETH_DMA_BUFFER_SIZE);
sentout += CONFIG_ETH_DMA_BUFFER_SIZE;
}
/* Point to next descriptor */
desc_iter = (eth_dma_tx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
}
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
for (size_t i = 0; i < bufcount; i++) {
hal->tx_desc->TDES0.Own = EMAC_DMADESC_OWNER_DMA;
hal->tx_desc = (eth_dma_tx_descriptor_t *)(hal->tx_desc->Buffer2NextDescAddr);
}
hal->dma_regs->dmatxpolldemand = 0;
return sentout;
err:
return 0;
}
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc)
{
eth_dma_rx_descriptor_t *desc_iter = NULL;
eth_dma_rx_descriptor_t *first_desc = NULL;
uint32_t used_descs = 0;
uint32_t seg_count = 0;
uint32_t ret_len = 0;
uint32_t copy_len = 0;
uint32_t write_len = 0;
uint32_t frame_count = 0;
first_desc = hal->rx_desc;
desc_iter = hal->rx_desc;
/* Traverse descriptors owned by CPU */
while ((desc_iter->RDES0.Own != EMAC_DMADESC_OWNER_DMA) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM) && !frame_count) {
used_descs++;
seg_count++;
/* Last segment in frame */
if (desc_iter->RDES0.LastDescriptor) {
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
ret_len = desc_iter->RDES0.FrameLength - ETH_CRC_LENGTH;
/* packets larger than expected will be truncated */
copy_len = ret_len > size ? size : ret_len;
/* update unhandled frame count */
frame_count++;
}
/* First segment in frame */
if (desc_iter->RDES0.FirstDescriptor) {
first_desc = desc_iter;
}
/* point to next descriptor */
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
}
/* there's at least one frame to process */
if (frame_count) {
/* check how many frames left to handle */
while ((desc_iter->RDES0.Own != EMAC_DMADESC_OWNER_DMA) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM)) {
used_descs++;
if (desc_iter->RDES0.LastDescriptor) {
frame_count++;
}
/* point to next descriptor */
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
}
desc_iter = first_desc;
for (size_t i = 0; i < seg_count - 1; i++) {
used_descs--;
write_len = copy_len < CONFIG_ETH_DMA_BUFFER_SIZE ? copy_len : CONFIG_ETH_DMA_BUFFER_SIZE;
/* copy data to buffer */
memcpy(buf, (void *)(desc_iter->Buffer1Addr), write_len);
buf += write_len;
copy_len -= write_len;
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
desc_iter->RDES0.Own = EMAC_DMADESC_OWNER_DMA;
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
}
memcpy(buf, (void *)(desc_iter->Buffer1Addr), copy_len);
desc_iter->RDES0.Own = EMAC_DMADESC_OWNER_DMA;
/* update rxdesc */
hal->rx_desc = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
/* poll rx demand */
hal->dma_regs->dmarxpolldemand = 0;
frame_count--;
used_descs--;
}
*frames_remain = frame_count;
*free_desc = CONFIG_ETH_DMA_RX_BUFFER_NUM - used_descs;
return ret_len;
}
IRAM_ATTR void emac_hal_isr(void *arg)
{
emac_hal_context_t *hal = (emac_hal_context_t *)arg;
typeof(hal->dma_regs->dmastatus) dma_status = hal->dma_regs->dmastatus;
hal->dma_regs->dmastatus.val = dma_status.val;
/* DMA Normal Interrupt */
if (dma_status.norm_int_summ) {
/* Transmit Interrupt */
if (dma_status.trans_int) {
emac_hal_tx_complete_cb(arg);
}
/* Transmit Buffer Unavailable */
if (dma_status.trans_buf_unavail) {
emac_hal_tx_unavail_cb(arg);
}
/* Receive Interrupt */
if (dma_status.recv_int) {
emac_hal_rx_complete_cb(arg);
}
/* Early Receive Interrupt */
if (dma_status.early_recv_int) {
emac_hal_rx_early_cb(arg);
}
}
/* DMA Abnormal Interrupt */
if (dma_status.abn_int_summ) {
/* Transmit Process Stopped */
if (dma_status.trans_proc_stop) {
}
/* Transmit Jabber Timeout */
if (dma_status.trans_jabber_to) {
}
/* Receive FIFO Overflow */
if (dma_status.recv_ovflow) {
}
/* Transmit Underflow */
if (dma_status.trans_undflow) {
}
/* Receive Buffer Unavailable */
if (dma_status.recv_buf_unavail) {
emac_hal_rx_unavail_cb(arg);
}
/* Receive Process Stopped */
if (dma_status.recv_proc_stop) {
}
/* Receive Watchdog Timeout */
if (dma_status.recv_wdt_to) {
}
/* Early Transmit Interrupt */
if (dma_status.early_trans_int) {
}
/* Fatal Bus Error */
if (dma_status.fatal_bus_err_int) {
}
}
}
IRAM_ATTR __attribute__((weak)) void emac_hal_tx_complete_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
// Note: you're in the interrupt context
return;
}
IRAM_ATTR __attribute__((weak)) void emac_hal_tx_unavail_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
// Note: you're in the interrupt context
return;
}
IRAM_ATTR __attribute__((weak)) void emac_hal_rx_complete_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
// Note: you're in the interrupt context
return;
}
IRAM_ATTR __attribute__((weak)) void emac_hal_rx_early_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
// Note: you're in the interrupt context
return;
}
IRAM_ATTR __attribute__((weak)) void emac_hal_rx_unavail_cb(void *arg)
{
// This is a weak function, do nothing by default
// Upper code can rewrite this function
// Note: you're in the interrupt context
return;
}

View File

@@ -1,410 +0,0 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "soc/emac_dma_struct.h"
#include "soc/emac_mac_struct.h"
#include "soc/emac_ext_struct.h"
#define EMAC_MEDIA_INTERFACE_MII (0)
#define EMAC_MEDIA_INTERFACE_RMII (1)
#define EMAC_WATCHDOG_ENABLE (0)
#define EMAC_WATCHDOG_DISABLE (1)
#define EMAC_JABBER_ENABLE (0)
#define EMAC_JABBER_DISABLE (1)
#define EMAC_INTERFRAME_GAP_96BIT (0)
#define EMAC_INTERFRAME_GAP_88BIT (1)
#define EMAC_INTERFRAME_GAP_80BIT (2)
#define EMAC_INTERFRAME_GAP_72BIT (3)
#define EMAC_INTERFRAME_GAP_64BIT (4)
#define EMAC_INTERFRAME_GAP_56BIT (5)
#define EMAC_INTERFRAME_GAP_48BIT (6)
#define EMAC_INTERFRAME_GAP_40BIT (7)
#define EMAC_CARRIERSENSE_ENABLE (0)
#define EMAC_CARRIERSENSE_DISABLE (1)
#define EMAC_PORT_1000MBPS (0)
#define EMAC_PORT_10_100MBPS (1)
#define EMAC_SPEED_10M (0)
#define EMAC_SPEED_100M (1)
#define EMAC_RECEIVE_OWN_ENABLE (0)
#define EMAC_RECEIVE_OWN_DISABLE (1)
#define EMAC_LOOPBACK_DISABLE (0)
#define EMAC_LOOPBACK_ENABLE (1)
#define EMAC_DUPLEX_HALF (0)
#define EMAC_DUPLEX_FULL (1)
#define EMAC_CHECKSUM_SW (0)
#define EMAC_CHECKSUM_HW (1)
#define EMAC_RETRY_TRANSMISSION_ENABLE (0)
#define EMAC_RETRY_TRANSMISSION_DISABLE (1)
#define EMAC_AUTO_PAD_CRC_STRIP_DISABLE (0)
#define EMAC_AUTO_PAD_CRC_STRIP_ENABLE (1)
#define EMAC_BACKOFF_LIMIT_10 (0)
#define EMAC_BACKOFF_LIMIT_8 (1)
#define EMAC_BACKOFF_LIMIT_4 (2)
#define EMAC_BACKOFF_LIMIT_1 (3)
#define EMAC_DEFERRAL_CHECK_DISABLE (0)
#define EMAC_DEFERRAL_CHECK_ENABLE (1)
#define EMAC_PREAMBLE_LENGTH_7 (0)
#define EMAC_PREAMBLE_LENGTH_5 (1)
#define EMAC_PREAMBLE_LENGTH_3 (2)
#define EMAC_RECEIVE_ALL_DISABLE (0)
#define EMAC_RECEIVE_ALL_ENABLE (1)
#define EMAC_SOURCE_ADDR_FILTER_DISABLE (0)
#define EMAC_SOURCE_ADDR_FILTER_NORMAL (2)
#define EMAC_SOURCE_ADDR_FILTER_INVERSE (3)
#define EMAC_CONTROL_FRAME_BLOCKALL (0)
#define EMAC_CONTROL_FRAME_FORWARDALL_PAUSE (1)
#define EMAC_CONTROL_FRAME_FORWARDALL (2)
#define EMAC_CONTROL_FRAME_FORWARDFILT (3)
#define EMAC_RECEPT_BROADCAST_ENABLE (0)
#define EMAC_RECEPT_BROADCAST_DISABLE (1)
#define EMAC_DEST_ADDR_FILTER_NORMAL (0)
#define EMAC_DEST_ADDR_FILTER_INVERSE (1)
#define EMAC_PROMISCUOUS_DISABLE (0)
#define EMAC_PROMISCUOUS_ENABLE (1)
#define EMAC_PAUSE_TIME 0x1648
#define EMAC_ZERO_QUANTA_PAUSE_ENABLE (0)
#define EMAC_ZERO_QUANTA_PAUSE_DISABLE (1)
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_4 (0)
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_28 (1)
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_144 (2)
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_256
#define EMAC_UNICAST_PAUSE_DETECT_DISABLE (0)
#define EMAC_UNICAST_PAUSE_DETECT_ENABLE (1)
#define EMAC_RECEIVE_FLOW_CONTROL_DISABLE (0)
#define EMAC_RECEIVE_FLOW_CONTROL_ENABLE (1)
#define EMAC_TRANSMIT_FLOW_CONTROL_DISABLE (0)
#define EMAC_TRANSMIT_FLOW_CONTROL_ENABLE (1)
#define EMAC_DROP_TCPIP_CHECKSUM_ERROR_ENABLE (0)
#define EMAC_DROP_TCPIP_CHECKSUM_ERROR_DISABLE (1)
#define EMAC_RECEIVE_STORE_FORWARD_DISABLE (0)
#define EMAC_RECEIVE_STORE_FORWARD_ENABLE (1)
#define EMAC_FLUSH_RECEIVED_FRAME_ENABLE (0)
#define EMAC_FLUSH_RECEIVED_FRAME_DISABLE (1)
#define EMAC_TRANSMIT_STORE_FORWARD_DISABLE (0)
#define EMAC_TRANSMIT_STORE_FORWARD_ENABLE (1)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_64 (0)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_128 (1)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_192 (2)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_256 (3)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_40 (4)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_32 (5)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_24 (6)
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_16 (7)
#define EMAC_FORWARD_ERROR_FRAME_DISABLE (0)
#define EMAC_FORWARD_ERROR_FRAME_ENABLE (1)
#define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_DISABLE (0)
#define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_ENABLE (1)
#define EMAC_RECEIVE_THRESHOLD_CONTROL_64 (0)
#define EMAC_RECEIVE_THRESHOLD_CONTROL_32 (1)
#define EMAC_RECEIVE_THRESHOLD_CONTROL_96 (2)
#define EMAC_RECEIVE_THRESHOLD_CONTROL_128 (3)
#define EMAC_OPERATE_SECOND_FRAME_DISABLE (0)
#define EMAC_OPERATE_SECOND_FRAME_ENABLE (1)
#define EMAC_MIXED_BURST_DISABLE (0)
#define EMAC_MIXED_BURST_ENABLE (1)
#define EMAC_ADDR_ALIGN_BEATS_DISABLE (0)
#define EMAC_ADDR_ALIGN_BEATS_ENABLE (1)
#define EMAC_UNUSE_SEPARATE_PBL (0)
#define EMAC_USE_SEPARATE_PBL (1)
#define EMAC_DMA_BURST_LENGTH_1BEAT (1)
#define EMAC_DMA_BURST_LENGTH_2BEAT (2)
#define EMAC_DMA_BURST_LENGTH_4BEAT (4)
#define EMAC_DMA_BURST_LENGTH_8BEAT (8)
#define EMAC_DMA_BURST_LENGTH_16BEAT (16)
#define EMAC_DMA_BURST_LENGTH_32BEAT (32)
#define EMAC_ENHANCED_DESCRIPTOR_DISABLE (0)
#define EMAC_ENHANCED_DESCRIPTOR_ENABLE (1)
#define EMAC_DMA_ARBITRATION_SCHEME_ROUNDROBIN (0)
#define EMAC_DMA_ARBITRATION_SCHEME_FIXEDPRIO (1)
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1 (0)
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_2_1 (1)
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_3_1 (2)
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_4_1 (3)
/**
* @brief Ethernet DMA TX Descriptor
*
*/
typedef struct {
volatile union {
struct {
uint32_t Deferred : 1; /*!< MAC defers before transmission */
uint32_t UnderflowErr : 1; /*!< DMA encountered an empty transmit buffer */
uint32_t ExcessiveDeferral : 1; /*!< Excessive deferral of over 24,288 bit times */
uint32_t CollisionCount : 4; /*!< Number of collisions occurred before transmitted */
uint32_t VLanFrame : 1; /*!< Transmitted frame is a VLAN-type frame */
uint32_t ExcessiveCollision : 1; /*!< Transmission aborted after 16 successive collisions */
uint32_t LateCollision : 1; /*!< Collision occurred after the collision window */
uint32_t NoCarrier : 1; /*!< Carrier Sense signal from the PHY was not asserted */
uint32_t LossCarrier : 1; /*!< Loss of carrier occurred during transmission */
uint32_t PayloadChecksumErr : 1; /*!< Checksum error in TCP/UDP/ICMP datagram payload */
uint32_t FrameFlushed : 1; /*!< DMA or MTL flushed the frame */
uint32_t JabberTimeout : 1; /*!< MAC transmitter has experienced a jabber timeout */
uint32_t ErrSummary : 1; /*!< Error Summary */
uint32_t IPHeadErr : 1; /*!< IP Header Error */
uint32_t TxTimestampStatus : 1; /*!< Timestamp captured for the transmit frame */
uint32_t VLANInsertControl : 2; /*!< VLAN tagging or untagging before transmitting */
uint32_t SecondAddressChained : 1; /*!< Second address in the descriptor is Next Descriptor address */
uint32_t TransmitEndRing : 1; /*!< Descriptor list reached its final descriptor */
uint32_t ChecksumInsertControl : 2; /*!< Control checksum calculation and insertion */
uint32_t CRCReplacementControl : 1; /*!< Control CRC replace */
uint32_t TransmitTimestampEnable : 1; /*!< Enable IEEE1588 harware timestamping */
uint32_t DisablePad : 1; /*!< Control add padding when frame short than 64 bytes */
uint32_t DisableCRC : 1; /*!< Control append CRC to the end of frame */
uint32_t FirstSegment : 1; /*!< Buffer contains the first segment of a frame */
uint32_t LastSegment : 1; /*!< Buffer contains the last segment of a frame */
uint32_t InterruptOnComplete : 1; /*!< Interrupt after frame transmitted */
uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */
};
uint32_t Value;
} TDES0;
union {
struct {
uint32_t TransmitBuffer1Size : 13; /*!< First data buffer byte size */
uint32_t Reserved : 3; /*!< Reserved */
uint32_t TransmitBuffer2Size : 13; /*!< Second data buffer byte size */
uint32_t SAInsertControl : 3; /*!< Control MAC add or replace Source Address field */
};
uint32_t Value;
} TDES1;
uint32_t Buffer1Addr; /*!< Buffer1 address pointer */
uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */
uint32_t Reserved1; /*!< Reserved */
uint32_t Reserved2; /*!< Reserved */
uint32_t TimeStampLow; /*!< Transmit Frame Timestamp Low */
uint32_t TimeStampHigh; /*!< Transmit Frame Timestamp High */
} eth_dma_tx_descriptor_t;
#define EMAC_DMATXDESC_CHECKSUM_BYPASS 0 /*!< Checksum engine bypass */
#define EMAC_DMATXDESC_CHECKSUM_IPV4HEADER 1 /*!< IPv4 header checksum insertion */
#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPSEGMENT 2 /*!< TCP/UDP/ICMP Checksum Insertion calculated over segment only */
#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPFULL 3 /*!< TCP/UDP/ICMP Checksum Insertion fully calculated */
_Static_assert(sizeof(eth_dma_tx_descriptor_t) == 32, "eth_dma_tx_descriptor_t should occupy 32 bytes in memory");
/**
* @brief Ethernet DMA RX Descriptor
*
*/
typedef struct {
volatile union {
struct {
uint32_t ExtendStatusAvailable : 1; /*!< Extended statsu is available in RDES4 */
uint32_t CRCErr : 1; /*!< CRC error occurred on frame */
uint32_t DribbleBitErr : 1; /*!< frame contains non int multiple of 8 bits */
uint32_t ReceiveErr : 1; /*!< Receive error */
uint32_t ReceiveWatchdogTimeout : 1; /*!< Receive Watchdog timeout */
uint32_t FrameType : 1; /*!< Ethernet type or IEEE802.3 */
uint32_t LateCollision : 1; /*!< Late collision occurred during reception */
uint32_t TSAvailIPChecksumErrGiantFrame : 1; /*!< Timestamp available or IP Checksum error or Giant frame */
uint32_t LastDescriptor : 1; /*!< Last buffer of the frame */
uint32_t FirstDescriptor : 1; /*!< First buffer of the frame */
uint32_t VLANTag : 1; /*!< VLAN Tag: received frame is a VLAN frame */
uint32_t OverflowErr : 1; /*!< Frame was damaged due to buffer overflow */
uint32_t LengthErr : 1; /*!< Frame size not matching with length field */
uint32_t SourceAddrFilterFail : 1; /*!< SA field of frame failed the SA filter */
uint32_t DescriptorErr : 1; /*!< Frame truncated and DMA doesn't own next descriptor */
uint32_t ErrSummary : 1; /*!< Error Summary, OR of all errors in RDES */
uint32_t FrameLength : 14; /*!< Byte length of received frame */
uint32_t DestinationAddrFilterFail : 1; /*!< Frame failed in the DA Filter in the MAC */
uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */
};
uint32_t Value;
} RDES0;
union {
struct {
uint32_t ReceiveBuffer1Size : 13; /*!< First data buffer size in bytes */
uint32_t Reserved1 : 1; /*!< Reserved */
uint32_t SecondAddressChained : 1; /*!< Seconde address is the Next Descriptor address */
uint32_t ReceiveEndOfRing : 1; /*!< Descriptor reached its final descriptor */
uint32_t ReceiveBuffer2Size : 13; /*!< Second data buffer size in bytes */
uint32_t Reserved : 2; /*!< Reserved */
uint32_t DisableInterruptOnComplete : 1; /*!< Disable the assertion of interrupt to host */
};
uint32_t Value;
} RDES1;
uint32_t Buffer1Addr; /*!< Buffer1 address pointer */
uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */
volatile union {
struct {
uint32_t IPPayloadType : 3; /*!< Type of payload in the IP datagram */
uint32_t IPHeadErr : 1; /*!< IP header error */
uint32_t IPPayloadErr : 1; /*!< IP payload error */
uint32_t IPChecksumBypass : 1; /*!< Checksum offload engine is bypassed */
uint32_t IPv4PacketReceived : 1; /*!< Received packet is an IPv4 packet */
uint32_t IPv6PacketReceived : 1; /*!< Received packet is an IPv6 packet */
uint32_t MessageType : 4; /*!< PTP Message Type */
uint32_t PTPFrameType : 1; /*!< PTP message is over Ethernet or IPv4/IPv6 */
uint32_t PTPVersion : 1; /*!< Version of PTP protocol */
uint32_t TimestampDropped : 1; /*!< Timestamp dropped because of overflow */
uint32_t Reserved1 : 1; /*!< Reserved */
uint32_t AVPacketReceived : 1; /*!< AV packet is received */
uint32_t AVTaggedPacketReceived : 1; /*!< AV tagged packet is received */
uint32_t VLANTagPrioVal : 3; /*!< VLAN tag's user value in the received packekt */
uint32_t Reserved2 : 3; /*!< Reserved */
uint32_t Layer3FilterMatch : 1; /*!< Received frame matches one of the enabled Layer3 IP */
uint32_t Layer4FilterMatch : 1; /*!< Received frame matches one of the enabled Layer4 IP */
uint32_t Layer3Layer4FilterNumberMatch : 2; /*!< Number of Layer3 and Layer4 Filter that matches the received frame */
uint32_t Reserved3 : 4; /*!< Reserved */
};
uint32_t Value;
} ExtendedStatus;
uint32_t Reserved; /*!< Reserved */
uint32_t TimeStampLow; /*!< Receive frame timestamp low */
uint32_t TimeStampHigh; /*!< Receive frame timestamp high */
} eth_dma_rx_descriptor_t;
#define EMAC_DMAPTPRXDESC_PTPMT_SYNC 0x00000100U /* SYNC message (all clock types) */
#define EMAC_DMAPTPRXDESC_PTPMT_FOLLOWUP 0x00000200U /* FollowUp message (all clock types) */
#define EMAC_DMAPTPRXDESC_PTPMT_DELAYREQ 0x00000300U /* DelayReq message (all clock types) */
#define EMAC_DMAPTPRXDESC_PTPMT_DELAYRESP 0x00000400U /* DelayResp message (all clock types) */
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYREQ_ANNOUNCE 0x00000500U /* PdelayReq message (peer-to-peer transparent clock) or Announce message (Ordinary or Boundary clock) */
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESP_MANAG 0x00000600U /* PdelayResp message (peer-to-peer transparent clock) or Management message (Ordinary or Boundary clock) */
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESPFOLLOWUP_SIGNAL 0x00000700U /* PdelayRespFollowUp message (peer-to-peer transparent clock) or Signaling message (Ordinary or Boundary clock) */
#define EMAC_DMAPTPRXDESC_IPPT_UDP 0x00000001U /* UDP payload encapsulated in the IP datagram */
#define EMAC_DMAPTPRXDESC_IPPT_TCP 0x00000002U /* TCP payload encapsulated in the IP datagram */
#define EMAC_DMAPTPRXDESC_IPPT_ICMP 0x00000003U /* ICMP payload encapsulated in the IP datagram */
#define EMAC_DMADESC_OWNER_CPU (0)
#define EMAC_DMADESC_OWNER_DMA (1)
_Static_assert(sizeof(eth_dma_rx_descriptor_t) == 32, "eth_dma_rx_descriptor_t should occupy 32 bytes in memory");
typedef struct {
emac_mac_dev_t *mac_regs;
emac_dma_dev_t *dma_regs;
emac_ext_dev_t *ext_regs;
uint8_t **rx_buf;
uint8_t **tx_buf;
void *descriptors;
eth_dma_rx_descriptor_t *rx_desc;
eth_dma_tx_descriptor_t *tx_desc;
} emac_hal_context_t;
void emac_hal_init(emac_hal_context_t *hal, void *descriptors,
uint8_t **rx_buf, uint8_t **tx_buf);
void emac_hal_reset_desc_chain(emac_hal_context_t *hal);
void emac_hal_lowlevel_init(emac_hal_context_t *hal);
void emac_hal_reset(emac_hal_context_t *hal);
bool emac_hal_is_reset_done(emac_hal_context_t *hal);
void emac_hal_set_csr_clock_range(emac_hal_context_t *hal);
void emac_hal_init_mac_default(emac_hal_context_t *hal);
void emac_hal_init_dma_default(emac_hal_context_t *hal);
void emac_hal_set_speed(emac_hal_context_t *hal, uint32_t speed);
void emac_hal_set_duplex(emac_hal_context_t *hal, uint32_t duplex);
void emac_hal_set_promiscuous(emac_hal_context_t *hal, bool enable);
/**
* @brief Send MAC-CTRL frames to peer (EtherType=0x8808, opcode=0x0001, dest_addr=MAC-specific-ctrl-proto-01 (01:80:c2:00:00:01))
*/
void emac_hal_send_pause_frame(emac_hal_context_t *hal, bool enable);
bool emac_hal_is_mii_busy(emac_hal_context_t *hal);
void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t phy_reg, bool write);
void emac_hal_set_phy_data(emac_hal_context_t *hal, uint32_t reg_value);
uint32_t emac_hal_get_phy_data(emac_hal_context_t *hal);
void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr);
void emac_hal_start(emac_hal_context_t *hal);
void emac_hal_stop(emac_hal_context_t *hal);
uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal);
uint32_t emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length);
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc);
void emac_hal_enable_flow_ctrl(emac_hal_context_t *hal, bool enable);
void emac_hal_isr(void *arg);
void emac_hal_tx_complete_cb(void *arg);
void emac_hal_tx_unavail_cb (void *arg);
void emac_hal_rx_complete_cb (void *arg);
void emac_hal_rx_early_cb(void *arg);
void emac_hal_rx_unavail_cb(void *arg);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,596 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32 eMAC register operations
#pragma once
#include <stdint.h>
#include "hal/eth_types.h"
#include "soc/emac_dma_struct.h"
#include "soc/emac_mac_struct.h"
#include "soc/emac_ext_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Register configuration */
#define EMAC_LL_INTERFRAME_GAP_96BIT (0)
#define EMAC_LL_INTERFRAME_GAP_88BIT (1)
#define EMAC_LL_INTERFRAME_GAP_80BIT (2)
#define EMAC_LL_INTERFRAME_GAP_72BIT (3)
#define EMAC_LL_INTERFRAME_GAP_64BIT (4)
#define EMAC_LL_INTERFRAME_GAP_56BIT (5)
#define EMAC_LL_INTERFRAME_GAP_48BIT (6)
#define EMAC_LL_INTERFRAME_GAP_40BIT (7)
#define EMAC_LL_BACKOFF_LIMIT_10 (0)
#define EMAC_LL_BACKOFF_LIMIT_8 (1)
#define EMAC_LL_BACKOFF_LIMIT_4 (2)
#define EMAC_LL_BACKOFF_LIMIT_1 (3)
#define EMAC_LL_PREAMBLE_LENGTH_7 (0)
#define EMAC_LL_PREAMBLE_LENGTH_5 (1)
#define EMAC_LL_PREAMBLE_LENGTH_3 (2)
#define EMAC_LL_SOURCE_ADDR_FILTER_DISABLE (0)
#define EMAC_LL_SOURCE_ADDR_FILTER_NORMAL (2)
#define EMAC_LL_SOURCE_ADDR_FILTER_INVERSE (3)
#define EMAC_LL_CONTROL_FRAME_BLOCKALL (0)
#define EMAC_LL_CONTROL_FRAME_FORWARDALL_PAUSE (1)
#define EMAC_LL_CONTROL_FRAME_FORWARDALL (2)
#define EMAC_LL_CONTROL_FRAME_FORWARDFILT (3)
#define EMAC_LL_PAUSE_TIME 0x1648
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_4 (0)
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_28 (1)
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_144 (2)
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_256 (3)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_64 (0)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_128 (1)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_192 (2)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_256 (3)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_40 (4)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_32 (5)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_24 (6)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_16 (7)
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_64 (0)
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_32 (1)
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_96 (2)
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_128 (3)
#define EMAC_LL_DMA_BURST_LENGTH_1BEAT (1)
#define EMAC_LL_DMA_BURST_LENGTH_2BEAT (2)
#define EMAC_LL_DMA_BURST_LENGTH_4BEAT (4)
#define EMAC_LL_DMA_BURST_LENGTH_8BEAT (8)
#define EMAC_LL_DMA_BURST_LENGTH_16BEAT (16)
#define EMAC_LL_DMA_BURST_LENGTH_32BEAT (32)
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1 (0)
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_2_1 (1)
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_3_1 (2)
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_4_1 (3)
/* PTP register bits */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_SYNC 0x00000100U /* SYNC message (all clock types) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_FOLLOWUP 0x00000200U /* FollowUp message (all clock types) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_DELAYREQ 0x00000300U /* DelayReq message (all clock types) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_DELAYRESP 0x00000400U /* DelayResp message (all clock types) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_PDELAYREQ_ANNOUNCE 0x00000500U /* PdelayReq message (peer-to-peer transparent clock) or Announce message (Ordinary or Boundary clock) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_PDELAYRESP_MANAG 0x00000600U /* PdelayResp message (peer-to-peer transparent clock) or Management message (Ordinary or Boundary clock) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_PDELAYRESPFOLLOWUP_SIGNAL 0x00000700U /* PdelayRespFollowUp message (peer-to-peer transparent clock) or Signaling message (Ordinary or Boundary clock) */
#define EMAC_LL_DMAPTPRXDESC_IPPT_UDP 0x00000001U /* UDP payload encapsulated in the IP datagram */
#define EMAC_LL_DMAPTPRXDESC_IPPT_TCP 0x00000002U /* TCP payload encapsulated in the IP datagram */
#define EMAC_LL_DMAPTPRXDESC_IPPT_ICMP 0x00000003U /* ICMP payload encapsulated in the IP datagram */
#define EMAC_LL_DMADESC_OWNER_CPU (0)
#define EMAC_LL_DMADESC_OWNER_DMA (1)
/* Interrupt flags (referring to dmastatus register in emac_dma_struct.h) */
#define EMAC_LL_DMA_TRANSMIT_FINISH_INTR 0x00000001U
#define EMAC_LL_DMA_TRANSMIT_STOP_INTR 0x00000002U
#define EMAC_LL_DMA_TRANSMIT_BUFF_UNAVAILABLE_INTR 0x00000004U
#define EMAC_LL_DMA_TRANSMIT_TIMEOUT_INTR 0x00000008U
#define EMAC_LL_DMA_RECEIVE_OVERFLOW_INTR 0x00000010U
#define EMAC_LL_DMA_TRANSMIT_UNDERFLOW_INTR 0x00000020U
#define EMAC_LL_DMA_RECEIVE_FINISH_INTR 0x00000040U
#define EMAC_LL_DMA_RECEIVE_BUFF_UNAVAILABLE_INTR 0x00000080U
#define EMAC_LL_DMA_RECEIVE_STOP_INTR 0x00000100U
#define EMAC_LL_DMA_RECEIVE_TIMEOUT_INTR 0x00000200U
#define EMAC_LL_DMA_TRANSMIT_FIRST_BYTE_INTR 0x00000400U
#define EMAC_LL_DMA_FATAL_BUS_ERROR_INRT 0x00001000U
#define EMAC_LL_DMA_RECEIVE_FIRST_BYTE_INTR 0x00002000U
#define EMAC_LL_DMA_ABNORMAL_INTR_SUMMARY 0x00004000U
#define EMAC_LL_DMA_NORMAL_INTR_SUMMARY 0x00008000U
#define EMAC_LL_DMA_POWER_MANAGE_INTR 0x10000000U
#define EMAC_LL_DMA_TIMESTAMP_TRIGGER_INTR 0x20000000U
/* Interrupt enable (referring to dmain_en register in emac_dma_struct.h) */
#define EMAC_LL_INTR_TRANSMIT_ENABLE 0x00000001U
#define EMAC_LL_INTR_TRANSMIT_STOP_ENABLE 0x00000002U
#define EMAC_LL_INTR_TRANSMIT_BUFF_UNAVAILABLE_ENABLE 0x00000004U
#define EMAC_LL_INTR_TRANSMIT_TIMEOUT_ENABLE 0x00000008U
#define EMAC_LL_INTR_OVERFLOW_ENABLE 0x00000010U
#define EMAC_LL_INTR_UNDERFLOW_ENABLE 0x00000020U
#define EMAC_LL_INTR_RECEIVE_ENABLE 0x00000040U
#define EMAC_LL_INTR_REVEIVE_BUFF_UNAVAILABLE_ENABLE 0x00000080U
#define EMAC_LL_INTR_RECEIVE_STOP_ENABLE 0x00000100U
#define EMAC_LL_INTR_RECEIVE_TIMEOUT_ENABLE 0x00000200U
#define EMAC_LL_INTR_TRANSMIT_FIRST_BYTE_ENABLE 0x00000400U
#define EMAC_LL_INTR_FATAL_BUS_ERR_ENABLE 0x00002000U
#define EMAC_LL_INTR_RECEIVE_FIRST_BYTE_ENABLE 0x00004000U
#define EMAC_LL_INTR_ABNORMAL_SUMMARY_ENABLE 0x00008000U
#define EMAC_LL_INTR_NORMAL_SUMMARY_ENABLE 0x00010000U
/* Enable needed interrupts (recv/recv_buf_unavailabal/normal must be enabled to make eth work) */
#define EMAC_LL_CONFIG_ENABLE_INTR_MASK (EMAC_LL_INTR_RECEIVE_ENABLE | EMAC_LL_INTR_NORMAL_SUMMARY_ENABLE)
/************** Start of mac regs operation ********************/
/* emacgmiiaddr */
static inline void emac_ll_set_csr_clock_division(emac_mac_dev_t *mac_regs, uint32_t div_mode)
{
mac_regs->emacgmiiaddr.miicsrclk = div_mode;
}
static inline bool emac_ll_is_mii_busy(emac_mac_dev_t *mac_regs)
{
return mac_regs->emacgmiiaddr.miibusy ? true : false;
}
static inline void emac_ll_set_phy_addr(emac_mac_dev_t *mac_regs, uint32_t addr)
{
mac_regs->emacgmiiaddr.miidev = addr;
}
static inline void emac_ll_set_phy_reg(emac_mac_dev_t *mac_regs, uint32_t reg)
{
mac_regs->emacgmiiaddr.miireg = reg;
}
static inline void emac_ll_write_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->emacgmiiaddr.miiwrite = enable;
}
static inline void emac_ll_set_busy(emac_mac_dev_t *mac_regs, bool busy)
{
mac_regs->emacgmiiaddr.miibusy = busy ? 1 : 0;
}
/* gmacconfig */
static inline void emac_ll_watchdog_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.watchdog = !enable;
}
static inline void emac_ll_jabber_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.jabber = !enable;
}
static inline void emac_ll_set_inter_frame_gap(emac_mac_dev_t *mac_regs, uint32_t gap)
{
mac_regs->gmacconfig.interframegap = gap;
}
static inline void emac_ll_carrier_sense_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.disablecrs = !enable;
}
static inline void emac_ll_set_port_speed(emac_mac_dev_t *mac_regs, eth_speed_t speed)
{
if (speed == ETH_SPEED_10M || speed == ETH_SPEED_100M) {
mac_regs->gmacconfig.mii = 1; // 10_100MBPS
mac_regs->gmacconfig.fespeed = speed;
} else {
mac_regs->gmacconfig.mii = 0; // 1000MBPS
}
}
static inline void emac_ll_recv_own_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.rxown = !enable;
}
static inline void emac_ll_loopback_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.loopback = enable;
}
static inline void emac_ll_set_duplex(emac_mac_dev_t *mac_regs, eth_duplex_t duplex)
{
mac_regs->gmacconfig.duplex = duplex;
}
static inline void emac_ll_checksum_offload_mode(emac_mac_dev_t *mac_regs, eth_checksum_t mode)
{
mac_regs->gmacconfig.rxipcoffload = mode;
}
static inline void emac_ll_retry_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.retry = !enable;
}
static inline void emac_ll_auto_pad_crc_strip_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.padcrcstrip = enable;
}
static inline void emac_ll_set_back_off_limit(emac_mac_dev_t *mac_regs, uint32_t limit)
{
mac_regs->gmacconfig.backofflimit = limit;
}
static inline void emac_ll_deferral_check_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.padcrcstrip = enable;
}
static inline void emac_ll_set_preamble_length(emac_mac_dev_t *mac_regs, uint32_t len)
{
mac_regs->gmacconfig.pltf = len;
}
static inline void emac_ll_transmit_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.tx = enable;
}
static inline void emac_ll_receive_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.rx = enable;
}
/* gmacff */
static inline void emac_ll_receive_all_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.receive_all = enable;
}
static inline void emac_ll_set_src_addr_filter(emac_mac_dev_t *mac_regs, uint32_t filter)
{
mac_regs->gmacff.safe = filter;
}
static inline void emac_ll_sa_inverse_filter_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.saif = enable;
}
static inline void emac_ll_set_pass_ctrl_frame_mode(emac_mac_dev_t *mac_regs, uint32_t mode)
{
mac_regs->gmacff.pcf = mode;
}
static inline void emac_ll_broadcast_frame_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.dbf = !enable;
}
static inline void emac_ll_pass_all_multicast_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.pam = enable;
}
static inline void emac_ll_da_inverse_filter_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.daif = enable;
}
static inline void emac_ll_promiscuous_mode_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.pmode = enable;
}
/* gmacfc */
static inline void emac_ll_set_pause_time(emac_mac_dev_t *mac_regs, uint32_t time)
{
mac_regs->gmacfc.pause_time = time;
}
static inline void emac_ll_zero_quanta_pause_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacfc.dzpq = !enable;
}
static inline void emac_ll_set_pause_low_threshold(emac_mac_dev_t *mac_regs, uint32_t threshold)
{
mac_regs->gmacfc.plt = threshold;
}
static inline void emac_ll_unicast_pause_frame_detect_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacfc.upfd = enable;
}
static inline void emac_ll_receive_flow_ctrl_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacfc.rfce = enable;
}
static inline void emac_ll_transmit_flow_ctrl_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacfc.tfce = enable;
}
static inline void emac_ll_clear(emac_mac_dev_t *mac_regs)
{
mac_regs->gmacfc.val = 0;
}
/* emacmiidata */
static inline void emac_ll_set_phy_data(emac_mac_dev_t *mac_regs, uint32_t data)
{
mac_regs->emacmiidata.mii_data = data;
}
static inline uint32_t emac_ll_get_phy_data(emac_mac_dev_t *mac_regs)
{
return mac_regs->emacmiidata.mii_data;
}
/* emacaddr0 */
static inline void emac_ll_set_addr(emac_mac_dev_t *mac_regs, const uint8_t *addr)
{
mac_regs->emacaddr0high.address0_hi = (addr[5] << 8) | addr[4];
mac_regs->emacaddr0low = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | (addr[0]);
}
/*************** End of mac regs operation *********************/
/************** Start of dma regs operation ********************/
/* dmabusmode */
static inline void emac_ll_reset(emac_dma_dev_t *dma_regs)
{
dma_regs->dmabusmode.sw_rst = 1;
}
static inline bool emac_ll_is_reset_done(emac_dma_dev_t *dma_regs)
{
return dma_regs->dmabusmode.sw_rst ? false : true;
}
/* dmarxbaseaddr / dmatxbaseaddr */
static inline void emac_ll_set_rx_desc_addr(emac_dma_dev_t *dma_regs, uint32_t addr)
{
dma_regs->dmarxbaseaddr = addr;
}
static inline void emac_ll_set_tx_desc_addr(emac_dma_dev_t *dma_regs, uint32_t addr)
{
dma_regs->dmatxbaseaddr = addr;
}
/* dmaoperation_mode */
static inline void emac_ll_drop_tcp_err_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.dis_drop_tcpip_err_fram = !enable;
}
static inline void emac_ll_recv_store_forward_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.rx_store_forward = enable;
}
static inline void emac_ll_flush_recv_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.dis_flush_recv_frames = !enable;
}
static inline void emac_ll_trans_store_forward_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.tx_str_fwd = !enable;
}
static inline void emac_ll_flush_trans_fifo_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.flush_tx_fifo = enable;
}
static inline void emac_ll_set_transmit_threshold(emac_dma_dev_t *dma_regs, uint32_t threshold)
{
dma_regs->dmaoperation_mode.tx_thresh_ctrl = threshold;
}
static inline void emac_ll_start_stop_dma_transmit(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.start_stop_transmission_command = enable;
}
static inline void emac_ll_forward_err_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.fwd_err_frame = enable;
}
static inline void emac_ll_forward_undersized_good_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.fwd_under_gf = enable;
}
static inline void emac_ll_set_recv_threshold(emac_dma_dev_t *dma_regs, uint32_t threshold)
{
dma_regs->dmaoperation_mode.rx_thresh_ctrl = threshold;
}
static inline void emac_ll_opt_second_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.opt_second_frame = enable;
}
static inline void emac_ll_start_stop_dma_receive(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.start_stop_rx = enable;
}
/* dmabusmode */
static inline void emac_ll_mixed_burst_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmabusmode.dmamixedburst = enable;
}
static inline void emac_ll_addr_align_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmabusmode.dmaaddralibea = enable;
}
static inline void emac_ll_use_separate_pbl_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmabusmode.use_sep_pbl = enable;
}
static inline void emac_ll_set_rx_dma_pbl(emac_dma_dev_t *dma_regs, uint32_t pbl)
{
dma_regs->dmabusmode.rx_dma_pbl = pbl;
}
static inline void emac_ll_set_prog_burst_len(emac_dma_dev_t *dma_regs, uint32_t len)
{
dma_regs->dmabusmode.prog_burst_len = len;
}
static inline void emac_ll_enhance_desc_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmabusmode.alt_desc_size = enable;
}
static inline void emac_ll_set_desc_skip_len(emac_dma_dev_t *dma_regs, uint32_t len)
{
dma_regs->dmabusmode.desc_skip_len = len;
}
static inline void emac_ll_fixed_arbitration_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmabusmode.dma_arb_sch = enable;
}
static inline void emac_ll_set_priority_ratio(emac_dma_dev_t *dma_regs, uint32_t ratio)
{
dma_regs->dmabusmode.pri_ratio = ratio;
}
/* dmain_en */
static inline void emac_ll_enable_all_intr(emac_dma_dev_t *dma_regs)
{
dma_regs->dmain_en.val = 0xFFFFFFFF;
}
static inline void emac_ll_disable_all_intr(emac_dma_dev_t *dma_regs)
{
dma_regs->dmain_en.val = 0x00000000;
}
static inline void emac_ll_enable_corresponding_intr(emac_dma_dev_t *dma_regs, uint32_t mask)
{
dma_regs->dmain_en.val |= mask;
}
static inline void emac_ll_disable_corresponding_intr(emac_dma_dev_t *dma_regs, uint32_t mask)
{
dma_regs->dmain_en.val &= ~mask;
}
static inline uint32_t emac_ll_get_intr_enable_status(emac_dma_dev_t *dma_regs)
{
return dma_regs->dmain_en.val;
}
/* dmastatus */
__attribute__((always_inline)) static inline uint32_t emac_ll_get_intr_status(emac_dma_dev_t *dma_regs)
{
return dma_regs->dmastatus.val;
}
__attribute__((always_inline)) static inline void emac_ll_clear_corresponding_intr(emac_dma_dev_t *dma_regs, uint32_t bits)
{
dma_regs->dmastatus.val = bits;
}
__attribute__((always_inline)) static inline void emac_ll_clear_all_pending_intr(emac_dma_dev_t *dma_regs)
{
dma_regs->dmastatus.val = 0xFFFFFFFF;
}
/* dmatxpolldemand / dmarxpolldemand */
static inline void emac_ll_transmit_poll_demand(emac_dma_dev_t *dma_regs, uint32_t val)
{
dma_regs->dmatxpolldemand = val;
}
static inline void emac_ll_receive_poll_demand(emac_dma_dev_t *dma_regs, uint32_t val)
{
dma_regs->dmarxpolldemand = val;
}
/*************** End of dma regs operation *********************/
/************** Start of ext regs operation ********************/
static inline void emac_ll_clock_enable_mii(emac_ext_dev_t *ext_regs)
{
/* 0 for mii mode */
ext_regs->ex_phyinf_conf.phy_intf_sel = 0;
ext_regs->ex_clk_ctrl.mii_clk_rx_en = 1;
ext_regs->ex_clk_ctrl.mii_clk_tx_en = 1;
}
static inline void emac_ll_clock_enable_rmii_input(emac_ext_dev_t *ext_regs)
{
/* 4 for rmii mode */
ext_regs->ex_phyinf_conf.phy_intf_sel = 4;
/* ref clk for phy is input in rmii mode, the clk can be offered by mac layer or external crystal.
config pin as output to generate ref clk by esp32 mac layer or input to obtain the clock from external crystal */
ext_regs->ex_clk_ctrl.ext_en = 1;
ext_regs->ex_clk_ctrl.int_en = 0;
ext_regs->ex_oscclk_conf.clk_sel = 1;
}
static inline void emac_ll_clock_enable_rmii_output(emac_ext_dev_t *ext_regs)
{
/* 4 for rmii mode */
ext_regs->ex_phyinf_conf.phy_intf_sel = 4;
/* ref clk for phy is input in rmii mode, the clk can be offered by mac layer or external crystal.
config pin as output to generate ref clk by esp32 mac layer or input to obtain the clock from external crystal */
ext_regs->ex_clk_ctrl.ext_en = 0;
ext_regs->ex_clk_ctrl.int_en = 1;
ext_regs->ex_oscclk_conf.clk_sel = 0;
ext_regs->ex_clkout_conf.div_num = 0;
ext_regs->ex_clkout_conf.h_div_num = 0;
}
static inline void emac_ll_pause_frame_enable(emac_ext_dev_t *ext_regs, bool enable)
{
ext_regs->ex_phyinf_conf.sbd_flowctrl = enable;
}
/*************** End of ext regs operation *********************/
#ifdef __cplusplus
}
#endif