#include "lip/ll/lip_ll.h"
#include "lip/lip_log.h"
#include "lip/link/lip_eth.h"
#include "lip/net/ipv4/lip_ipv4.h"
#include "lip/link/mac/lip_mac.h"
#include "lip/link/mac/tx/lip_mac_tx.h"
#include "lip/link/mac/rx/lip_mac_rx.h"
#include "chip.h"
#include "ltimer.h"
#include "lip_config.h"
#include <string.h>


#define PTP_REQ_FREQ        CHIP_MHZ(50)

#define MAC_RESET_TOUT 10




#define LIP_ETH_PIN_MDC     CHIP_PIN_PC1_ETH_MDC
#define LIP_ETH_PIN_MDIO    CHIP_PIN_PA2_ETH_MDIO
#define LIP_ETH_PIN_REF_CLK CHIP_PIN_PA1_ETH_RMII_REF_CLK
#define LIP_ETH_PIN_CRS_DV  CHIP_PIN_PA7_ETH_RMII_CRS_DV
#define LIP_ETH_PIN_RXD0    CHIP_PIN_PC4_ETH_RMII_RXD0
#define LIP_ETH_PIN_RXD1    CHIP_PIN_PC5_ETH_RMII_RXD1
#ifndef LIP_ETH_PIN_TX_EN
    #error LIP_ETH_PIN_TX_EN must be specified as CHIP_PIN_PB11_ETH_RMII_TX_EN or CHIP_PIN_PG11_ETH_RMII_TX_EN
#endif
#ifndef LIP_ETH_PIN_TXD0
    #error LIP_ETH_PIN_TXD0 must be specified as CHIP_PIN_PB12_ETH_RMII_TXD0 or CHIP_PIN_PG13_ETH_RMII_TXD0
#endif
#ifndef LIP_ETH_PIN_TXD1
    #error LIP_ETH_PIN_TXD1 must be specified as CHIP_PIN_PB13_ETH_RMII_TXD1, CHIP_PIN_PG12_ETH_RMII_TXD1 or CHIP_PIN_PG14_ETH_RMII_TXD1
#endif


#if CHIP_CLK_ETH_MAC_FREQ > CHIP_MHZ(300)
    #error MAC clock frequency is out of fange
#elif CHIP_CLK_ETH_MAC_FREQ > CHIP_MHZ(250)
    #define LIP_PORT_RVAL_MDIO_CR   5
#elif CHIP_CLK_ETH_MAC_FREQ > CHIP_MHZ(150)
    #define LIP_PORT_RVAL_MDIO_CR   4
#elif CHIP_CLK_ETH_MAC_FREQ > CHIP_MHZ(100)
    #define LIP_PORT_RVAL_MDIO_CR   1
#elif CHIP_CLK_ETH_MAC_FREQ > CHIP_MHZ(60)
    #define LIP_PORT_RVAL_MDIO_CR   0
#elif CHIP_CLK_ETH_MAC_FREQ > CHIP_MHZ(35)
    #define LIP_PORT_RVAL_MDIO_CR   3
#elif CHIP_CLK_ETH_MAC_FREQ >= CHIP_MHZ(20)
    #define LIP_PORT_RVAL_MDIO_CR   2
#else
    #error MAC clock frequency is out of fange
#endif

/* TDES normal descriptor read format */
#define ETH_TDES0_BUF1AP            (0xFFFFFFFFUL << 0) /* buffer 1 Address */
#define ETH_TDES1_BUF2AP            (0xFFFFFFFFUL << 0) /* buffer 2 Address */
#define ETH_TDES2_B1L               (0x3FFFUL << 0) /* Buffer 1 len */
#define ETH_TDES2_VTIR              (0xCUL << 14) /* VLAN TAG Insertion or Replacement */
#define ETH_TDES2_B2L               (0x3FFFUL << 16) /* buffer 2 len */
#define ETH_TDES2_TTSE              (0x1UL << 30) /* Transmit Timestamp Enable */
#define ETH_TDES2_IOC               (0x1UL << 31) /* Interrupt on completion */
#define ETH_TDES3_OWN               (0x1UL << 31) /* Own bit */
#define ETH_TDES3_CTXT              (0x1UL << 30) /* Context Type */
#define ETH_TDES3_FD                (0x1UL << 29) /* First Descriptor */
#define ETH_TDES3_LD                (0x1UL << 28) /* Last Descriptor */
#define ETH_TDES3_CPC               (0x3UL << 26) /* CRC Pad Control */
#define ETH_TDES3_CPC_CRC_PAD_INS   (0) /* crc and pad insertion */
#define ETH_TDES3_CPC_CRC_INS       (1) /* crc only insertion */
#define ETH_TDES3_CPC_CRC_DIS       (2) /* disable crc insertion */
#define ETH_TDES3_CPC_CRC_REPL      (3) /* crc replacement */
#define ETH_TDES3_SAIC              (0x3UL << 23) /* SA Insertion Control */
#define ETH_TDES3_SAIC_DIS          (0) /* do not include SA */
#define ETH_TDES3_SAIC_INS          (1) /* insert SA */
#define ETH_TDES3_SAIC_REPL         (2) /* replace SA */
#define ETH_TDES3_THL               (0xFUL << 19) /* TCP header length */
#define ETH_TDES3_TSE               (0x1UL << 18) /* TCP segmentation enable */
#define ETH_TDES3_CIC               (0x3UL << 16) /* Checksum Insertion Control (if TSE == 0) */
#define ETH_TDES3_CIC_DIS           (0) /* checksum insertion disabled */
#define ETH_TDES3_CIC_IP            (1) /* ip header checksum */
#define ETH_TDES3_CIC_IP_PL         (2) /* ip header checksum + payload checksum without ip pseudo-header*/
#define ETH_TDES3_CIC_IP_PL_PH      (3) /* ip header checksum + payload checksum with ip pseudo-header */
#define ETH_TDES3_FL                (0x7FFFUL << 0) /* Full packet length (if TSE == 0) */
#define ETH_TDES3_TPL               (0x3FFFUL << 0) /* TCP Payload length (if TSE == 1) */

/* tdes normal descriptor write-back format */
#define ETH_TDES0_WB_TTSL           (0xFFFFFFFFUL << 0) /* Transmit Packet Timestamp Low */
#define ETH_TDES1_WB_TTSH           (0xFFFFFFFFUL << 0) /* Transmit Packet Timestamp High */
#define ETH_TDES3_WB_OWN            (0x1UL << 31)
#define ETH_TDES3_WB_CTXT           (0x1UL << 30)
#define ETH_TDES3_WB_FD             (0x1UL << 29)
#define ETH_TDES3_WB_LD             (0x1UL << 28)
#define ETH_TDES3_WB_TTSS           (0x1UL << 17) /* Tx Timestamp Status */
#define ETH_TDES3_WB_ES             (0x1UL << 15) /* Error Summary */
#define ETH_TDES3_WB_JT             (0x1UL << 14) /* Jabber Timeoit */
#define ETH_TDES3_WB_FF             (0x1UL << 13) /* Packet Flushed */
#define ETH_TDES3_WB_PCE            (0x1UL << 12) /* Payload checksum error */
#define ETH_TDES3_WB_LOC            (0x1UL << 11) /* Loss of Carrier */
#define ETH_TDES3_WB_NC             (0x1UL << 10) /* No Carrier */
#define ETH_TDES3_WB_LC             (0x1UL <<  9) /* Late Collision */
#define ETH_TDES3_WB_EC             (0x1UL <<  8) /* Excessive Collision */
#define ETH_TDES3_WB_CC             (0xFUL <<  4) /* Collision Count */
#define ETH_TDES3_WB_ED             (0x1UL <<  3) /* Excessive Deferral */
#define ETH_TDES3_WB_UF             (0x1UL <<  2) /* Underflow Error */
#define ETH_TDES3_WB_DB             (0x1UL <<  1) /* Deferred Bit */
#define ETH_TDES3_WB_IHE            (0x1UL <<  0) /* IP Header Error */

/* tdes context descriptor */
#define ETH_TDES0_CTX_TTSL          (0xFFFFFFFFUL << 0) /* Transmit Packet Timestamp Low */
#define ETH_TDES1_CTX_TTSH          (0xFFFFFFFFUL << 0) /* Transmit Packet Timestamp High */
#define ETH_TDES2_CTX_IVT           (0xFFFFUL << 16) /* Inner VLAN Tag */
#define ETH_TDES2_CTX_MSS           (0x3FFFUL << 0) /* Maximum Segment Size */
#define ETH_TDES3_CTX_OWN           (0x1UL << 31)
#define ETH_TDES3_CTX_CTXT          (0x1UL << 30)
#define ETH_TDES3_CTX_OSTC          (0x1UL << 27) /* One-Step Timestamp Correction Enable */
#define ETH_TDES3_CTX_TCMSSV        (0x1UL << 26) /* One-Step Timestamp Correction of MSS Valid */
#define ETH_TDES3_CTX_CDE           (0x1UL << 23) /* Context Descriptor Error */
#define ETH_TDES3_CTX_IVTIR         (0x3UL << 18) /* Inner VLAN Tag Insert or Replace */
#define ETH_TDES3_CTX_IVTIR_DIS     (0)
#define ETH_TDES3_CTX_IVTIR_REM     (1)
#define ETH_TDES3_CTX_IVTIR_INS     (2)
#define ETH_TDES3_CTX_IVTIR_REPL    (3)
#define ETH_TDES3_CTX_IVLTV         (0x1UL << 17) /* Inner VLAN Tag Valid */
#define ETH_TDES3_CTX_VLTV          (0x1UL << 16) /* VLAN Tag Valid */
#define ETH_TDES3_CTX_VT            (0xFFFFUL << 0) /* VLAN Tag */


/* rdes normal descriptor read format */
#define ETH_RDES0_BUF1AP            (0xFFFFFFFFUL << 0)
#define ETH_RDES2_BUF2AP            (0xFFFFFFFFUL << 0)
#define ETH_RDES3_OWN               (1UL << 31) /* own bit */
#define ETH_RDES3_IOC               (1UL << 30) /* interrupt on completion */
#define ETH_RDES3_BUF2V             (1UL << 25) /* buffer 2 address valid */
#define ETH_RDES3_BUF1V             (1UL << 24) /* buffer 1 address valid */

/* rdes normal descriptor write-back format */
#define ETH_RDES0_WB_IVT            (0xFFFFUL << 16) /* Inner VLAN Tag */
#define ETH_RDES0_WB_OVT            (0xFFFFUL << 0)  /* Outer VLAN Tag */
#define ETH_RDES1_WB_OPC            (0xFFFFUL << 16) /* OAM Sub-Type Code or MAC Control Packet opcode */
#define ETH_RDES1_WB_TD             (0x1UL << 15) /* Timestamp dropped */
#define ETH_RDES1_WB_TSA            (0x1UL << 14) /* Timestamp aviable */
#define ETH_RDES1_WB_PV             (0x1UL << 13) /* PTP Version (1 - v2, 0 - v1) */
#define ETH_RDES1_WB_PFT            (0x1UL << 12) /* PTP Packet Type */
#define ETH_RDES1_WB_PMT            (0xFUL <<  8) /* PTP Message Type */
#define ETH_RDES1_WB_IPCE           (0x1UL <<  7) /* IP Payload Error */
#define ETH_RDES1_WB_IPCB           (0x1UL <<  6) /* IP Checksum Bypassed */
#define ETH_RDES1_WB_IPV6           (0x1UL <<  5) /* IPv6 header Present */
#define ETH_RDES1_WB_IPV4           (0x1UL <<  4) /* IPv4 header Present */
#define ETH_RDES1_WB_IPHE           (0x1UL <<  3) /* IP Header Error */
#define ETH_RDES1_WB_PT             (0x7UL <<  0) /* Payload Type */
#define ETH_RDES1_WB_PT_UNKNOWN     (0)
#define ETH_RDES1_WB_PT_UDP         (1)
#define ETH_RDES1_WB_PT_TCP         (2)
#define ETH_RDES1_WB_PT_ICMP        (3)

#define ETH_RDES2_WB_L3L4FM         (0x7UL << 29) /* Layer 3 and Layer 4 Filter Number Matched */
#define ETH_RDES2_WB_L4FM           (0x1UL << 28) /* Layer 4 Filter Match */
#define ETH_RDES2_WB_L3FM           (0x1UL << 27) /* Layer 3 Filter Match */
#define ETH_RDES2_WB_MADRM          (0xFFUL << 19) /* MAC Address Match or Hash Value */
#define ETH_RDES2_WB_HF             (0x1UL << 18) /* Hash Filter status */
#define ETH_RDES2_WB_DAF            (0x1UL << 17) /* DA Filter Fail */
#define ETH_RDES2_WB_SAF            (0x1UL << 16) /* SA Filter Fail */
#define ETH_RDES2_WB_VF             (0x1UL << 15) /* VLAN Filter Status */
#define ETH_RDES2_WB_ARPNR          (0x1UL << 10) /* ARP Replay Not Generated */

#define ETH_RDES3_WB_OWN            (0x1UL << 31)
#define ETH_RDES3_WB_CTXT           (0x1UL << 30)
#define ETH_RDES3_WB_FD             (0x1UL << 29) /* First Descriptor */
#define ETH_RDES3_WB_LD             (0x1UL << 28) /* Last Descriptor */
#define ETH_RDES3_WB_RS2V           (0x1UL << 27) /* RDES2 Valid */
#define ETH_RDES3_WB_RS1V           (0x1UL << 26) /* RDES1 Valid */
#define ETH_RDES3_WB_RS0V           (0x1UL << 25) /* RDES0 Valid */
#define ETH_RDES3_WB_CE             (0x1UL << 24) /* CRC Error */
#define ETH_RDES3_WB_GP             (0x1UL << 23) /* Giant Packet */
#define ETH_RDES3_WB_RWT            (0x1UL << 22) /* Receive Watchdog Timeout */
#define ETH_RDES3_WB_OE             (0x1UL << 21) /* Overflow Error */
#define ETH_RDES3_WB_RE             (0x1UL << 20) /* Receive Error */
#define ETH_RDES3_WB_DE             (0x1UL << 19) /* Dribble Error */
#define ETH_RDES3_WB_LT             (0x7UL << 16) /* Length Type Field */
#define ETH_RDES3_WB_LT_LEN         (0) /* Length Packet */
#define ETH_RDES3_WB_LT_TYPE        (1) /* Type Packet */
#define ETH_RDES3_WB_LT_ARP_REQ     (3) /* ARP Request Packet */
#define ETH_RDES3_WB_LT_TYPE_VLAN   (4) /* Type Packet with VLAN Tag */
#define ETH_RDES3_WB_LT_TYPE_DVALN  (5) /* Type Packet with double VLAN Tag */
#define ETH_RDES3_WB_LT_MAC_CTL     (6) /* MAC Control Packet */
#define ETH_RDES3_WB_LT_OAM         (7) /* OAM Packet Type */
#define ETH_RDES3_WB_ES             (0x1UL << 15) /* Error Summary */
#define ETH_RDES3_WB_PL             (0x7FFFUL << 0) /* Packet Len */

/* rdes context descriptor */
#define ETH_RDES0_CTX_RTSL          (0xFFFFFFFFUL << 0) /* Receive Packet Timestamp Low */
#define ETH_RDES1_CTX_RTSH          (0xFFFFFFFFUL << 0) /* Receive Packet Timestamp High */
#define ETH_RDES3_CTX_OWN           (0x1UL << 31)
#define ETH_RDES3_CTX_CTXT          (0x1UL << 30)


typedef struct {
    uint32_t tdes0;
    uint32_t tdes1;
    uint32_t tdes2;
    uint32_t tdes3;
} t_eth_tx_descr;


typedef  struct {
    uint32_t rdes0;
    uint32_t rdes1;
    uint32_t rdes2;
    uint32_t rdes3;
} t_eth_rx_descr;


#define LIP_LL_INTERRUPT_ENABLE  (LIP_LL_PORT_TX_INTERRUPT_ENABLE || LIP_LL_PORT_RX_INTERRUPT_ENABLE)


/* количество блоков на прием (оно же - кол-во дескрипторов) */
#ifndef LIP_PORT_RX_DESCR_CNT
    #define LIP_PORT_RX_DESCR_CNT      8
#endif
/* размер одного блока */
#ifndef LIP_PORT_RX_BUF_SIZE
    #define LIP_PORT_RX_BUF_SIZE        (512)
#endif
/* общий размер всей памяти на прием */
#define LIP_PORT_RX_FULL_BUF_SIZE (LIP_PORT_RX_BUF_SIZE * LIP_PORT_RX_DESCR_CNT)


/* кол-во дескрипторов на передачу */
#ifndef LIP_PORT_TX_DESCR_CNT
    #define LIP_PORT_TX_DESCR_CNT      8
#endif

#define LIP_PORT_RX_NEXT_IND(ind) ((ind)==(LIP_PORT_RX_DESCR_CNT-1) ? 0 : (ind)+1)
#define LIP_PORT_TX_NEXT_IND(ind) ((ind)==(LIP_PORT_TX_DESCR_CNT-1) ? 0 : (ind)+1)


#define ETH_BUF_ALIGN  4

#define LSPEC_ALIGNMENT ETH_BUF_ALIGN

/* Массив дескрипторов DMA на прием */
#include "lcspec_align.h"
LIP_PORT_DESCR_MEM(static volatile t_eth_rx_descr  f_rx_descr[LIP_PORT_RX_DESCR_CNT]);

/* Массив дескрпиторов DMA на передачу */
#include "lcspec_align.h"
LIP_PORT_DESCR_MEM(static volatile t_eth_tx_descr  f_tx_descr[LIP_PORT_TX_DESCR_CNT]);
static t_lip_tx_frame  *f_tx_frames[LIP_PORT_TX_DESCR_CNT];

/* Массив данных в который сохраняются входные пакеты */
#include "lcspec_align.h"
LIP_PORT_BUF_MEM(static volatile uint8_t f_rx_bufs[LIP_PORT_RX_FULL_BUF_SIZE]);


/* номер дескриптора, соответствующий началу принимаемого пакета */
static int f_rx_cur_descr;

/* номер дескриптора, который будет использован для передачи след. пакета */
static int f_tx_put_descr;
/* номер дескриптора, следующий за последним, по которому завершена передача */
static int f_tx_done_descr;
/* кол-во дескрипторов, по которым начата, но не завершена передача */
static int f_tx_descr_progr_cnt;
/* признак, что MAC проинициализрован */
static bool f_mac_init_finish;

#if LIP_PTP_ENABLE
    static bool f_tstmp_en;
    static void f_tstm_start(void);
#endif
static void f_tstm_stop(void);



static void f_update_arp_addr(void) {
    const uint8_t *ipv4_addr = lip_ipv4_cur_addr();
    CHIP_REGS_ETH->MACARPAR = lip_ipv4_cur_addr_is_valid() ?
            (((uint32_t)ipv4_addr[0] << 24) |
            ((uint32_t)ipv4_addr[1] << 16) |
            ((uint32_t)ipv4_addr[2] <<  8) |
            ((uint32_t)ipv4_addr[3] <<  0)) : 0;
}

static LINLINE void *f_rdes_buf_addr(int idx) {
    return  (void*)&f_rx_bufs[idx*LIP_PORT_RX_BUF_SIZE];
}


static LINLINE void f_rdes_init(int idx) {
    volatile t_eth_rx_descr *rdes = &f_rx_descr[idx];
    rdes->rdes0 = LBITFIELD_SET(ETH_RDES0_BUF1AP, (uint32_t)f_rdes_buf_addr(idx));
    rdes->rdes1 = 0;
    rdes->rdes2 = 0;
    rdes->rdes3 = ETH_RDES3_OWN | ETH_RDES3_BUF1V | ETH_RDES3_IOC;
}


/* Функция сдвигает текущий указатель на обрабатываемый дескриптор f_rx_cur_descr
 * на cnt дескрпиторов и инициализирует эти cnt дескрипторов для готовности приема
 * новых данных, после чего обновляет f_rx_cur_descr и tail-pointer для DMA,
 * чтобы DMA мог их использовать для нового приема */
static void f_rx_curpos_update(int cnt) {
    int cur_pos = f_rx_cur_descr;
    for (int i = 0; i < cnt; ++i) {
        f_rdes_init(cur_pos);
        cur_pos = LIP_PORT_RX_NEXT_IND(cur_pos);
    }
    f_rx_cur_descr = cur_pos;
    chip_dmb();
    CHIP_REGS_ETH->DMACRXDTPR = (uint32_t)&f_rx_descr[cur_pos];
}




void f_descr_rx_init(void) {
    int i;
    for (i=0; i < LIP_PORT_RX_DESCR_CNT; i++) {
        f_rdes_init(i);
    }

    f_rx_cur_descr = 0;

    CHIP_REGS_ETH->DMACRXDLAR = (uint32_t)&f_rx_descr[0]; /* rx descriptors list start  */
    CHIP_REGS_ETH->DMACRXRLR = LIP_PORT_RX_DESCR_CNT - 1; /* rx descriptors count - 1 */
    CHIP_REGS_ETH->DMACRXDTPR = (uint32_t)&f_rx_descr[LIP_PORT_RX_DESCR_CNT];
}

void f_descr_tx_init(void) {
    memset((void*)&f_tx_descr[0], 0, sizeof(f_tx_descr));
    /* сам массив дескрипторов реально инициализируется при начале передачи,
       поэтому здесь доп. инициализация не требуется */

    f_tx_put_descr = f_tx_done_descr = 0;
    f_tx_descr_progr_cnt = 0;

    chip_dmb();

    CHIP_REGS_ETH->DMACTXDLAR = (uint32_t)&f_tx_descr[0]; /* tx descriptors list start  */
    CHIP_REGS_ETH->DMACTXDTPR = (uint32_t)&f_tx_descr[0]; /* tx descriptors list tail */
    CHIP_REGS_ETH->DMACTXRLR = LIP_PORT_TX_DESCR_CNT - 1; /* tx descriptors count - 1 */
}


static t_lip_errs f_mac_init(int flags) {
    t_lip_errs err = LIP_ERR_SUCCESS;
    t_ltimer tmr;
    /* Выбор RMII интерфейса. Выполняется через syscfg, поэтому вначале нужно
     * при необходимости нужно разрешить клоки блока */
    int syscfg_en = chip_per_clk_is_en(CHIP_PER_ID_SYSCFG);
    if (!syscfg_en)
        chip_per_clk_en(CHIP_PER_ID_SYSCFG);
    LBITFIELD_UPD(CHIP_REGS_SYSCFG->PMCR, CHIP_REGFLD_SYSCFG_PMCR_EPIS, CHIP_REGFLDVAL_SYSCFG_PMCR_EPIS_RMII);
    chip_dmb();
    /** @todo проверить, можем ли сразу запрещать клоки SYSCFG */
    if (!syscfg_en)
        chip_per_clk_dis(CHIP_PER_ID_SYSCFG);

    CHIP_REGS_ETH->DMAMR |=  CHIP_REGFLD_ETH_DMAMR_SWR;
    /* ожидание завершения сброса MAC */
    ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(MAC_RESET_TOUT));
    while ((CHIP_REGS_ETH->DMAMR & CHIP_REGFLD_ETH_DMAMR_SWR) && !ltimer_expired(&tmr)) {
        continue;
    }

    /* если не удалось выполнить сброс, то это означает как правило,
     * что нет действительного клока от PHY. дальнейшая работа
     * невозможна */
    if (CHIP_REGS_ETH->DMAMR & CHIP_REGFLD_ETH_DMAMR_SWR) {
        err = LIP_ERR_INIT_MAC_RESET;
        lip_printf(LIP_LOG_MODULE_PORT, LIP_LOG_LVL_ERROR_FATAL, err,
                   "lip port: mac reset error. possibly phy clock not present!\n");
    } else {
        CHIP_REGS_ETH->DMAMR = (CHIP_REGS_ETH->DMAMR & CHIP_REGMSK_ETH_DMAMR_RESERVED)
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMAMR_DA, 0) /* Arbitration (0 - round-robin, 1 - fixed) */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMAMR_TXPR, 0) /* Transmit priority */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMAMR_PR, 7) /* Priority ratio */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMAMR_INTM, 0) /* Interrupt mode */
                ;

        /* настройки AHB... не понятно на основании чего выбираются... */
        CHIP_REGS_ETH->DMASBMR = (CHIP_REGS_ETH->DMASBMR & CHIP_REGMSK_ETH_DMASBMR_RESERVED)
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMASBMR_FB, 1)  /* Fixed burst length */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMASBMR_AAL, 1) /* Address-aligned beats */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMASBMR_MB, 0) /* Mixed burst */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMASBMR_RB, 0) /* Rebuild INCRX burst */
                ;

        CHIP_REGS_ETH->DMACCR = (CHIP_REGS_ETH->DMACCR & CHIP_REGMSK_ETH_DMACCR_RESERVED)
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMACCR_MSS, LIP_ETH_MAX_PACKET_SIZE) /* размер сегмента для TCP Segmentation */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMACCR_PBLX8, 0) /* TXPBL умножается в 8 раз */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMACCR_DSL, 0) /* количество слов между дескрипторами */
                ;

        CHIP_REGS_ETH->DMACTXCR =  (CHIP_REGS_ETH->DMACTXCR & CHIP_REGMSK_ETH_DMACTXCR_RESERVED)
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMACTXCR_OSP, 0) /* operate on second packet */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMACTXCR_TSE, 0) /* TCP segmentation enable */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMACTXCR_TPBL, 32) /* transmit progr. burst length */
                ;

        CHIP_REGS_ETH->DMACRXCR = (CHIP_REGS_ETH->DMACRXCR & CHIP_REGMSK_ETH_DMACRXCR_RESERVED)
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMACRXCR_RBSZ, LIP_PORT_RX_BUF_SIZE) /* receive buffer size */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMACRXCR_RPBL, 32) /* receive rogr. burst length */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMACRXCR_RPF, 1) /* rx packet flush on stop */
                ;

        f_descr_rx_init();
        f_descr_tx_init();




        CHIP_REGS_ETH->DMACRXIWTR = (CHIP_REGS_ETH->DMACRXIWTR & CHIP_REGMSK_ETH_DMACRXIWTR_RESERVED)
                | LBITFIELD_SET(CHIP_REGFLD_ETH_DMACRXIWTR_RWT, 0); /* rx interrupt timer */



        /* ---------------- MTL --------------------*/
        CHIP_REGS_ETH->MTLOMR |= CHIP_REGFLD_ETH_MTLOMR_CNTCLR; /* reset counters */
        CHIP_REGS_ETH->MTLTXQOMR = (CHIP_REGS_ETH->MTLTXQOMR & CHIP_REGMSK_ETH_MTLTXQOMR_RESERVED)
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLTXQOMR_TQS, 7) /* tx queue size x * 256 */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLTXQOMR_TTC, 0) /* transmit threshold control */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLTXQOMR_TXQEN, CHIP_REGFLDVAL_ETH_MTLTXQOMR_TXQEN_EN) /* transmit queue enable */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLTXQOMR_TSF, 1) /* transmit store and forward */
                ;
        CHIP_REGS_ETH->MTLRXQOMR = (CHIP_REGS_ETH->MTLRXQOMR & CHIP_REGMSK_ETH_MTLRXQOMR_RESERVED)
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLRXQOMR_RQS, 7) /* rx queue size x * 256 */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLRXQOMR_RFD, 0) /* Threshold for Deactivating Flow Control  */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLRXQOMR_RFA, 0) /* Threshold for Activating Flow Control  */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLRXQOMR_EHFC, 0) /* Enable Hardware Flow Control */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLRXQOMR_DISTCPEF, 0) /* Disable dropping of TCP/IP Checksum Error Packets */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLRXQOMR_RSF, 1) /* Receive Queue Store and Forward */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLRXQOMR_FEP, 0) /* Forward Error Packets */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLRXQOMR_FUP, 0) /* Forward Undersized Good Packets */
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MTLRXQOMR_RTC, 0) /* Receive Queue Threshold Control */
                ;


        /* ----------------- MAC -------------------------*/
         CHIP_REGS_ETH->MACCR = (CHIP_REGS_ETH->MACCR & CHIP_REGMSK_ETH_MACCR_RESERVED)
                | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_ARP, (flags & LIP_INIT_FLAGS_MAC_RX_HWPROC_DIS) ? 0 : 1) /* ARP Offload Enable */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_SARC, 0) /* SA Insertion or Replacement (2 - ins SA1, 3 - repl SA1,
                                                                                                4 - ins SA2, 5 - repl SA2) */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_IPC, (flags & LIP_INIT_FLAGS_MAC_RX_HWPROC_DIS) ? 0 : 1) /* Checksum Offload */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_IPG, 0) /* Inter-Packet Gap. 0 - 96 bit times, 7 - 40 bit */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_GPSLCE, 0) /* Giant Packet Size Limit Control Enable */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_S2KP, 0) /* 802as 2K Packets Support */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_CST, (flags & LIP_INIT_FLAGS_MAC_RX_HWPROC_DIS) ? 0 : 1) /* CRC stripping for Type packets */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_ACS, (flags & LIP_INIT_FLAGS_MAC_RX_HWPROC_DIS) ? 0 : 1) /* Automatic Pad or CRC stripping (len < 1536) */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_WD, 0)  /* watchdog disable */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_JD, 0)  /* jabber disable */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_JE, 0)  /* jumbo packet enable */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_LM, (flags & LIP_INIT_FLAGS_MAC_LOOPBACK) ? 1 : 0) /* loopback mode */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_ECRSFD, 1) /* enable carrier sense before transmission in fd mode */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_DO, 1) /* disable own */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_DCRS, 0) /* disable carrier sense during tx */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_DR, 0) /* disable retry */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_BL, 0) /* backoff limit */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_DC, 1) /* deferral check */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_PRELEN, 0) /* preamble length */
                 ;

         CHIP_REGS_ETH->MACECR = (CHIP_REGS_ETH->MACECR & CHIP_REGMSK_ETH_MACECR_RESERVED)
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACECR_EIPG, 0) /* Extended Inter-Packet Gap */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACECR_EIPGEN, 0) /* EIPG enable */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACECR_USP, 0) /* Unicast Slow Protocol Packet Detect */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACECR_SPEN, 0) /* Slow Protocol Detection Enabled */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACECR_DCRCC, (flags & LIP_INIT_FLAGS_MAC_RX_HWPROC_DIS) ? 1 : 0) /* Disable CRC Checking for rx */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACECR_GPSL, LIP_ETH_MAX_FULL_PACKET_SIZE) /* Giant Packet  Size Limit */
                 ;

         CHIP_REGS_ETH->MACPFR = (CHIP_REGS_ETH->MACPFR & CHIP_REGMSK_ETH_MACPFR_RESERVED)
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_RA, (flags & LIP_INIT_FLAGS_MAC_RX_FILTER_DIS) ? 1 : 0) /* Receive All */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_DNTU, 0) /* Drop Non-TCP/UDP over IP packets */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_IPFE, 0) /* Layer 3 and Layer 4 Filter Enable */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_VTFE, 0) /* VLAN Tag Filter Enable */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_HPF, 0) /* Hash or perfect filter */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_SAF, 0) /* Source Address Filter Enable */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_SAIF, 0) /* SA Inverse Filtering */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_PCF, 0) /* Pass Control Packets (4 modes) */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_DBF, 0) /* Disable Broadcast Packets */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_PM, 1) /* Pass All Multicast (or use HMC bit) */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_DAIF, 0) /* DA Inverse Filtering */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_HMC, 0) /* Hash multicast (or perfect match) */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_HUC, 0) /* Hash unicast (or perfect match) */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACPFR_PR, (flags & LIP_INIT_FLAGS_MAC_RX_HWPROC_DIS) ? 1 : 0) /* Promiscouous Mode (даже без статуса в отличии от RA) */
                 ;

        CHIP_REGS_ETH->MACWTR = (CHIP_REGS_ETH->MACWTR & CHIP_REGMSK_ETH_MACWTR_RESERVED)
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACWTR_PWE, 0) /* Programmable Watchdog Enable (иначе предопределнный размер) */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACWTR_WTO, 0) /* Watchdog Timeout - макс. размер в КБ от 2 */
                 ;

        /* В текущей реализации поддерживаем обработку только одного уровня VLAN */
         CHIP_REGS_ETH->MACVTR = (CHIP_REGS_ETH->MACVTR & CHIP_REGMSK_ETH_MACVTR_RESERVED)
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACVTR_EIVLRXS, 0) /* Inner VLAN in RX status */
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACVTR_EVLRXS, LIP_VLAN_ENABLE)
                 | LBITFIELD_SET(CHIP_REGFLD_ETH_MACVTR_EVLS, CHIP_REGFLDVAL_ETH_MACVTR_EVLS_STRIP_ALL)
            ;

#if LIP_PTP_ENABLE
        if (f_tstmp_en) {
            f_tstm_start();
        }
#else
        f_tstm_stop();
#endif


        /* пропуск настроек hash-таблиц и VLAN, так как не испольузем */

        /* заполняем ARP адрес ответа (т.к. он был сброшен при ресете mac) */
        f_update_arp_addr();


        /* сброс флагов прерываний перед разрешением */
        CHIP_REGS_ETH->DMACSR = CHIP_REGS_ETH->DMACSR;
        CHIP_REGS_ETH->DMACIER = CHIP_REGFLD_ETH_DMACIER_TIE | CHIP_REGFLD_ETH_DMACIER_RIE | CHIP_REGFLD_ETH_DMACIER_NIE;

        f_mac_init_finish = true;
#if LIP_LL_INTERRUPT_ENABLE
        chip_interrupt_enable(ETH_IRQn);
#endif
    }

    return  err;
}

static void f_eth_config(const t_lip_phy_mode *mode) {
    CHIP_REGS_ETH->MACCR = (CHIP_REGS_ETH->MACCR & ~(CHIP_REGFLD_ETH_MACCR_FES | CHIP_REGFLD_ETH_MACCR_DM))
            | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_FES, mode->speed == LIP_PHY_SPEED_100)
            | LBITFIELD_SET(CHIP_REGFLD_ETH_MACCR_DM, mode->flags & LIP_PHY_MODE_FLAG_DUPLEX_FULL)
            ;
}

static void f_eth_start(void) {
    LBITFIELD_UPD(CHIP_REGS_ETH->DMACTXCR, CHIP_REGFLD_ETH_DMACTXCR_ST, 1);
    LBITFIELD_UPD(CHIP_REGS_ETH->DMACRXCR, CHIP_REGFLD_ETH_DMACRXCR_SR, 1);
    CHIP_REGS_ETH->MACCR |= (CHIP_REGFLD_ETH_MACCR_TE | CHIP_REGFLD_ETH_MACCR_RE);
}

static void f_tstm_stop(void) {
    CHIP_REGS_ETH->MACTSCR = CHIP_REGS_ETH->MACTSCR & ~CHIP_REGMSK_ETH_MACTSCR_RESERVED;
}

#if LIP_PTP_ENABLE
static void f_tstm_start(void) {
    /* 1. Mask the Timestamp Trigger interrupt by clearing bit 12 of Interrupt enable register (ETH_MACIER). */

    /* 2. Enable timestamping */
    /* SNAPTYPSEL = 1, TSEVNTENA = 0, TSEVNTENA = 1 => Timestamps for SYNC, Pdelay_Req, Pdelay_Resp.
                В текущей реализации используется всегда Peer-to-Peer delay, как более точный способ,
                SYNC нужен для Slave, но в режиме мастера не мешает и можно не менять во время работы. */
    CHIP_REGS_ETH->MACTSCR = (CHIP_REGS_ETH->MACTSCR & ~CHIP_REGMSK_ETH_MACTSCR_RESERVED)
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TSENA, 1) /* Разрешение timestamp */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TSCTRLSSR, 1) /* Выбор разделения на nonosecond/second (1) или сполошной счетчик */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TSVER2ENA, 1) /* PTP version 2 */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TSIPENA, 1)   /* PTP over Ethernet */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TSIPV6ENA, 0) /* PTP over IPv6-UDP */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TSIPV4ENA, 0) /* PTP over IPv4-UDP */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TSENALL, 0) /* Timestamp for All packet */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TSEVNTENA, 1) /* Timestamp for event packet */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TSMSTRENA, 0) /* Timestamp for master */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_SNAPTYPSEL, 1) /* Select PTP packets for Taking Snapshots */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TSENMACADDR, 0) /* Enable MAC Address for PTP Packet Filtering ??? */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_CSC, 0) /* Enable checksum correction during OST for PTP over UDP/IPv4 packets */
                             | LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TXTSSTSM, 0) /* Transmit Timestamp Status Mode (overwrite (1) or drop (0) on fifo fill) */
        ;
    /* 3. Program Sub-second increment register (ETH_MACSSIR) based on the PTP clock frequency. */
    CHIP_REGS_ETH->MACSSIR = LBITFIELD_SET(CHIP_REGFLD_ETH_MACSSIR_SSINC, (CHIP_REGS_ETH->MACTSCR & CHIP_REGFLD_ETH_MACTSCR_TSCTRLSSR) ? 20 : 0x2B);
    /* 4.  program Timestamp addend register (ETH_MACTSAR) and set bit 5 of Timestamp control Register (ETH_MACTSCR). */
    CHIP_REGS_ETH->MACTSAR =  ((double) PTP_REQ_FREQ / CHIP_CLK_PTP_FREQ) * 2 * 0x80000000UL;
    CHIP_REGS_ETH->MACTSCR |= CHIP_REGFLD_ETH_MACTSCR_TSADDREG;
    /* 5. Poll the Timestamp control Register (ETH_MACTSCR) until bit 5 is cleared. */
    while (CHIP_REGS_ETH->MACTSCR & CHIP_REGFLD_ETH_MACTSCR_TSADDREG) {
         continue;
    }

    /* setting bit 31 to 1 and bits 30:0 containing 10^9 - <ingress_correction_value> represented in binary.
       INGRESS_SYNC_CORR = -(2*PTP_CLK_PER) */
    uint32_t correction_val = (1UL << 31U) | (1000000000 - (uint32_t)(2*1000000000./CHIP_CLK_PTP_FREQ + 0.5));
    CHIP_REGS_ETH->MACTSICNR = correction_val;
    /* 2-step - EGRESS_SYNC_CORR = -(2*PTP_CLK_PER) = INGRESS_SYNC_CORR
     * (если разрешать 1-step - (1*PTP_CLK_PER + 4*TX_CLK_PER) */
    CHIP_REGS_ETH->MACTSECNR = correction_val;


    CHIP_REGS_ETH->MACTSCR |= CHIP_REGFLD_ETH_MACTSCR_TSCFUPDT;

    CHIP_REGS_ETH->MACTSCR |= LBITFIELD_SET(CHIP_REGFLD_ETH_MACTSCR_TSINIT, 1);
}

void lip_ll_tstmp_enable(void) {    
    if (!f_tstmp_en) {
        f_tstmp_en = true;
        if (f_mac_init_finish) {
            f_tstm_start();
        }
    }
}

void lip_ll_tstmp_disable(void) {
    if (f_tstmp_en) {
        f_tstmp_en = false;
        if (f_mac_init_finish) {
            f_tstm_stop();
        }
    }
}

bool lip_ll_tstmp_is_enabled(void) {
    return f_tstmp_en;
}

t_lip_errs lip_ll_tstmp_read(t_lip_ptp_tstmp *tstmp) {
    tstmp->fract_ns = 0;
    tstmp->hsec = 0;
    uint32_t s1 = CHIP_REGS_ETH->MACSTSR;
    tstmp->ns = CHIP_REGS_ETH->MACSTNR;
    uint32_t s2 = CHIP_REGS_ETH->MACSTSR;
    /* для избежания изменения значения секунд между двумя чтениями выполняем
     * три чтения. Если нс меньше половины предела. Считаем, что если количество
     * нс ближе к началу, то переполнение не возможно после, если ближе к концу,
     * то перед */
    tstmp->sec = tstmp->ns < 500000000 ? s2 : s1;
    return LIP_ERR_SUCCESS;
}

#endif

t_lip_errs lip_ll_init(t_lip_init_stage stage, int flags) {
    t_lip_errs err = LIP_ERR_SUCCESS;
    switch (stage) {
        case LIP_INIT_STAGE_PHY_INTF_INIT:
            /* сброс модуля и разрешение необходимых клоков */
            chip_per_rst(CHIP_PER_ID_ETH1_MAC);
            chip_per_clk_en(CHIP_PER_ID_ETH1_MAC);
            chip_per_clk_en(CHIP_PER_ID_ETH1_TX);
            chip_per_clk_en(CHIP_PER_ID_ETH1_RX);

            CHIP_PIN_CONFIG(LIP_ETH_PIN_MDC);
            CHIP_PIN_CONFIG(LIP_ETH_PIN_MDIO);
            CHIP_PIN_CONFIG(LIP_ETH_PIN_REF_CLK);
            CHIP_PIN_CONFIG(LIP_ETH_PIN_CRS_DV);
            CHIP_PIN_CONFIG(LIP_ETH_PIN_RXD0);
            CHIP_PIN_CONFIG(LIP_ETH_PIN_RXD1);
            CHIP_PIN_CONFIG(LIP_ETH_PIN_TX_EN);
            CHIP_PIN_CONFIG(LIP_ETH_PIN_TXD0);
            CHIP_PIN_CONFIG(LIP_ETH_PIN_TXD1);
            break;
        case LIP_INIT_STAGE_MAC_INIT:
            err = f_mac_init(flags);
            break;
        case LIP_INIT_STAGE_MAC_START:
            f_eth_config(lip_mac_phy_mode());
            f_eth_start();
            break;
    }
    return err;
}

void lip_ll_stop(void) {
    chip_interrupt_disable(ETH_IRQn);
    CHIP_REGS_ETH->DMACIER = 0;
    f_tstm_stop();

    /* 1. Disable the Transmit DMA */
    LBITFIELD_UPD(CHIP_REGS_ETH->DMACTXCR, CHIP_REGFLD_ETH_DMACTXCR_ST, 0);
    chip_dmb();

    /* 2. Wait for any previous frame transmission to complete */
    int tx_idle = 0;
    do {
        uint32_t regval = CHIP_REGS_ETH->MTLTXQDR;
        tx_idle = (LBITFIELD_GET(regval, CHIP_REGFLD_ETH_MTLTXQDR_TXQSTS) == 0)
                  && (LBITFIELD_GET(regval, CHIP_REGFLD_ETH_MTLTXQDR_TRCSTS) != 1);
    } while (!tx_idle);

    /* 3. Disable the MAC transmitter and receiver */
    CHIP_REGS_ETH->MACCR &= ~(CHIP_REGFLD_ETH_MACCR_TE | CHIP_REGFLD_ETH_MACCR_RE);

    /* 4a. Make sure that the data in RxFifo is transfered */
    int rx_idle = 0;
    do {
        uint32_t regval = CHIP_REGS_ETH->MTLRXQDR;
        rx_idle = (LBITFIELD_GET(regval, CHIP_REGFLD_ETH_MTLRXQDR_PRXQ) == 0)
                      && (LBITFIELD_GET(regval, CHIP_REGFLD_ETH_MTLRXQDR_RXQSTS) == 0);
    } while (!rx_idle);
    /* 4b. Disable the receive DMA */
    LBITFIELD_UPD(CHIP_REGS_ETH->DMACRXCR, CHIP_REGFLD_ETH_DMACRXCR_SR, 0);

    f_mac_init_finish = false;
}

void lip_ll_close(void) {
    chip_per_clk_dis(CHIP_PER_ID_ETH1_RX);
    chip_per_clk_dis(CHIP_PER_ID_ETH1_TX);
    chip_per_clk_dis(CHIP_PER_ID_ETH1_MAC);
}

void lip_ll_set_mac_addr(const uint8_t *mac_addr) {
    CHIP_REGS_ETH->MACA0LR = ((uint32_t) mac_addr[3] << 24) |
            ((uint32_t) mac_addr[2] << 16) |
            ((uint32_t) mac_addr[1] << 8) |
            ((uint32_t) mac_addr[0]);
    CHIP_REGS_ETH->MACA0HR = (CHIP_REGS_ETH->MACA1HR & 0x7FFF0000) |
            LBITFIELD_SET(CHIP_REGFLD_ETH_MACAHR_AE, 1) |
            ((uint32_t) mac_addr[5] << 8) |
            ((uint32_t) mac_addr[4]);

}

static t_lip_errs f_start_mdio_op(unsigned dev_addr, unsigned reg_addr, uint8_t op) {
    CHIP_REGS_ETH->MACMDIOAR =
            LBITFIELD_SET(CHIP_REGFLD_ETH_MACMDIOAR_CR, LIP_PORT_RVAL_MDIO_CR)
            | LBITFIELD_SET(CHIP_REGFLD_ETH_MACMDIOAR_PA, dev_addr)
            | LBITFIELD_SET(CHIP_REGFLD_ETH_MACMDIOAR_RDA, reg_addr)
            | LBITFIELD_SET(CHIP_REGFLD_ETH_MACMDIOAR_MOC, op);
     CHIP_REGS_ETH->MACMDIOAR |= CHIP_REGFLD_ETH_MACMDIOAR_MB;
     return LIP_ERR_SUCCESS;
}


t_lip_errs lip_ll_mdio_write_start(uint8_t phyaddr, uint8_t regaddr, uint16_t value) {
    CHIP_REGS_ETH->MACMDIODR = LBITFIELD_SET(CHIP_REGFLD_ETH_MACMDIODR_MD, value);
    return f_start_mdio_op(phyaddr, regaddr, CHIP_REGFLDVAL_ETH_MACMDIOAR_MOC_WR);
}


t_lip_errs lip_ll_mdio_read_start(uint8_t phyaddr, uint8_t regaddr) {
    return f_start_mdio_op(phyaddr, regaddr, CHIP_REGFLDVAL_ETH_MACMDIOAR_MOC_RD);
}

bool lip_ll_mdio_rdy(void) {
    return (CHIP_REGS_ETH->MACMDIOAR & CHIP_REGFLD_ETH_MACMDIOAR_MB) == 0;
}

t_lip_errs lip_ll_mdio_data(uint16_t *data) {
    *data = LBITFIELD_GET(CHIP_REGS_ETH->MACMDIODR, CHIP_REGFLD_ETH_MACMDIODR_MD);
    return LIP_ERR_SUCCESS;
}


static void f_tx_check_descr(void) {
    /* проверяем, какие дескрипторы завершились */
    while ((f_tx_descr_progr_cnt != 0) &&
           !(f_tx_descr[f_tx_done_descr].tdes3 & ETH_TDES3_WB_OWN)) {
        int tx_descr_num = f_tx_done_descr;
        volatile t_eth_tx_descr *tx_descr = &f_tx_descr[tx_descr_num];
        t_lip_tx_frame  *frame = f_tx_frames[tx_descr_num];

        if (tx_descr->tdes3 & ETH_TDES3_WB_ES) {
            frame->status.flags |= LIP_FRAME_TXSTATUS_FLAG_ERROR;
            lip_printf(LIP_LOG_MODULE_PORT, LIP_LOG_LVL_DEBUG_HIGH, 0,
                       "lip port: tx buf done with error! status = 0x%08X\n",
                       tx_descr->tdes3);

            if (tx_descr->tdes3  & ETH_TDES3_WB_UF) {
                /* сброс флага underflow */
                CHIP_REGS_ETH->MTLQICSR = CHIP_REGFLD_ETH_MTLQICSR_TXUNFIS;
                /* выводим DMA из suspend путем перезапуска tail.
                 * при этом само значение не меняем */
                chip_dmb();
                CHIP_REGS_ETH->DMACTXDTPR = CHIP_REGS_ETH->DMACTXDTPR;
            }
        }


        if (tx_descr->tdes3 & ETH_TDES3_WB_TTSS) {
#if LIP_PTP_ENABLE
            frame->status.tstmp.ns = tx_descr->tdes0;
            frame->status.tstmp.sec = tx_descr->tdes1;
#endif
            frame->status.flags |= LIP_FRAME_TXSTATUS_FLAG_TSTMP_VALID;
        }

        f_tx_done_descr = LIP_PORT_TX_NEXT_IND(tx_descr_num);
        f_tx_descr_progr_cnt--;
        frame->status.flags |= LIP_FRAME_TXSTATUS_FLAG_FINISH;
        lip_mac_tx_frame_done_cb(frame);
    }
}

static bool f_tx_descr_rdy(void) {
    return f_mac_init_finish && (f_tx_descr_progr_cnt < LIP_PORT_TX_DESCR_CNT);
}



t_lip_errs lip_ll_tx_frame(t_lip_tx_frame *frame) {
    t_lip_errs res = f_tx_descr_rdy() ?  LIP_ERR_SUCCESS : LIP_ERR_BUF_NOT_RDY;
    if (res == LIP_ERR_SUCCESS) {
        int next_descr;
        t_eth_tx_descr *tdes = (t_eth_tx_descr *)&f_tx_descr[f_tx_put_descr];
        uint32_t hdr_size = frame->buf.cur_ptr - frame->buf.start_ptr;
        const uint32_t data_size = frame->exdata_size;
        f_tx_frames[f_tx_put_descr] = frame;
        f_tx_descr[f_tx_put_descr].tdes0 = LBITFIELD_SET(ETH_TDES0_BUF1AP, (uint32_t)frame->buf.start_ptr);
        /* заполняем все поля, кроме начального адреса */
        tdes->tdes1 = LBITFIELD_SET(ETH_TDES1_BUF2AP, (uint32_t)frame->exdata_ptr);
        tdes->tdes2 = 0
                      | LBITFIELD_SET(ETH_TDES2_B1L, hdr_size)
                      | LBITFIELD_SET(ETH_TDES2_B2L, data_size)
#if LIP_PTP_ENABLE
                      | LBITFIELD_SET(ETH_TDES2_TTSE, f_tstmp_en && (frame->info.flags & LIP_FRAME_TXINFO_FLAG_TSTAMP_REQ))
#endif
                      | LBITFIELD_SET(ETH_TDES2_IOC, 1)
                      | LBITFIELD_SET(ETH_TDES2_VTIR, 0)
            ;
        tdes->tdes3 = 0
                      | LBITFIELD_SET(ETH_TDES3_FL, (hdr_size + data_size))
                      | LBITFIELD_SET(ETH_TDES3_OWN, 1)
                      | LBITFIELD_SET(ETH_TDES3_CTXT, 0)
                      | LBITFIELD_SET(ETH_TDES3_FD, 1)
                      | LBITFIELD_SET(ETH_TDES3_LD, 1)
                      | LBITFIELD_SET(ETH_TDES3_CPC, frame->info.flags & LIP_FRAME_TXINFO_FLAG_RAW ?
                                                     ETH_TDES3_CPC_CRC_DIS : ETH_TDES3_CPC_CRC_PAD_INS)
                      | LBITFIELD_SET(ETH_TDES3_SAIC, frame->info.flags & (LIP_FRAME_TXINFO_FLAG_RAW | LIP_FRAME_TXINFO_FLAG_SRC_MAC_BCAST) ?
                                                      ETH_TDES3_SAIC_DIS : ETH_TDES3_SAIC_INS)
                      | LBITFIELD_SET(ETH_TDES3_THL, 0)
                      | LBITFIELD_SET(ETH_TDES3_TSE, 0)
                      | LBITFIELD_SET(ETH_TDES3_CIC, frame->info.flags & LIP_FRAME_TXINFO_FLAG_RAW ?
                                                     ETH_TDES3_CIC_DIS : ETH_TDES3_CIC_IP_PL_PH)
            ;
        chip_dmb();
        /* обновляем tail, чтобы возобновить работу DMA на передачу */
        next_descr = LIP_PORT_TX_NEXT_IND(f_tx_put_descr);
        CHIP_REGS_ETH->DMACTXDTPR = (uint32_t)&f_tx_descr[next_descr];

        /* переходим к следующему дескриптору */
        f_tx_put_descr = next_descr;
        f_tx_descr_progr_cnt++;
    }

    return res;
}



/* Функция проходит по завершенным дескрипторам на прием и ищет завершенные
 * полностью кадры. На каждый найденный кадр вызывается lip_mac_rx_proc_frame
 * для обработки данного кадра */
static void f_rx_check_descr(void) {
    int cur_descr_idx = f_rx_cur_descr;
    int start_idx = -1;
    int frame_descr_cnt = 0;
    int drop_cnt = 0;
    int proc_cnt = 0;

    bool frame_finish = false;
    bool ctx_descr_wt = false;
    t_lip_rx_ll_frame rx_frame;


#define ETH_LL_CUR_RX_FRAME_IN_PROGR() (start_idx >= 0)

#define ETH_LL_CUR_RX_FRAME_MARK_TO_DROP() do { \
    if (ETH_LL_CUR_RX_FRAME_IN_PROGR()) { \
        drop_cnt += frame_descr_cnt; \
        start_idx = -1; \
        frame_descr_cnt = 0; \
    } \
} while(0)

#define ETH_LL_CUR_RX_DROP() do { \
    if (drop_cnt > 0)  { \
        f_rx_curpos_update(drop_cnt); \
        drop_cnt = 0; \
    }\
} while(0)

    /* проход по цепочке дескрипторов до тех пор пока не обнаружим установленный
     * бит OWN, который говорит, что этот дескрпитор еще обрабатывается DMA.
     * текже считаем число дескрпиторов с помощью porc_cnt, чтобы избежать повторного
     * захода на круг */
    while (!(f_rx_descr[cur_descr_idx].rdes3 & ETH_RDES3_OWN) && (proc_cnt < LIP_PORT_RX_DESCR_CNT)) {
        const t_eth_rx_descr *cur_descr = (const t_eth_rx_descr *)&f_rx_descr[cur_descr_idx];

        if (!(cur_descr->rdes3 & ETH_RDES3_WB_CTXT)) {
            if (ctx_descr_wt) {
                ETH_LL_CUR_RX_FRAME_MARK_TO_DROP();
            }

            if (cur_descr->rdes3 & ETH_RDES3_WB_ES) {
                lip_printf(LIP_LOG_MODULE_PORT, LIP_LOG_LVL_DEBUG_HIGH, 0,
                           "lip port: rx buf done with error! rdes3 = 0x%08X\n",
                           cur_descr->rdes3);
                /* отбрасываем весь обрабатываемый пакет по ошибке */
                ETH_LL_CUR_RX_FRAME_MARK_TO_DROP();
                /* отбрасываем также текущий дескриптор */
                drop_cnt++;
            } else if (!ETH_LL_CUR_RX_FRAME_IN_PROGR() && !(cur_descr->rdes3 & ETH_RDES3_WB_FD)) {
                /* если первый завершенный пакет без признака first, то отбрасываем его до нахождения first */
                drop_cnt++;
            } else {
                if (cur_descr->rdes3 & ETH_RDES3_WB_FD) {
                    /* если нашли новое начало кадра без завершения предыдущего,
                     * то считаем кадр от этого дескриптора, а предыдущие отбрасываем.
                     * т.к. еще не увеличили frame_descr_cnt, то отбрасываем только до
                     * текущего */
                    ETH_LL_CUR_RX_FRAME_MARK_TO_DROP();
                    /* сразу освобождаем ошибочные дексприпторы, если есть */
                    ETH_LL_CUR_RX_DROP();
                    start_idx = cur_descr_idx;
                }

                frame_descr_cnt++;

                if (cur_descr->rdes3 & ETH_RDES3_WB_LD) {

                    rx_frame.info.ll_flags = 0;
                    rx_frame.info.flags = 0;
#if LIP_MULTIPORT_ENABLE
                    rx_frame.info.rx_port = 0;
#endif
                    rx_frame.pl_main.data = f_rdes_buf_addr(start_idx);
                    rx_frame.pl_main.size = LBITFIELD_GET(cur_descr->rdes3, ETH_RDES3_WB_PL);




                    /* если данные кадра переходят через границу кольцевого буфера (с последнего
                     * на первый дескриптор), то они оказываются не непрерывны.
                     * В конце остается место, чтобы можно было данные из начала
                     * скопировать в конец буфера для непрерывности */
                    if ((start_idx + frame_descr_cnt) > LIP_PORT_RX_DESCR_CNT) {
                        rx_frame.pl_tail.size = (t_lip_size)(rx_frame.pl_main.size  - (LIP_PORT_RX_DESCR_CNT - start_idx) * LIP_PORT_RX_BUF_SIZE);
                        rx_frame.pl_main.size -= rx_frame.pl_tail.size;
                        rx_frame.pl_tail.data = f_rdes_buf_addr(0);
                    } else {
                        rx_frame.pl_tail.data = NULL;
                        rx_frame.pl_tail.size = 0;
                    }

                    if (ETH_LL_CUR_RX_FRAME_IN_PROGR()) {
                        int type = LBITFIELD_GET(cur_descr->rdes3, ETH_RDES3_WB_LT);


                        if ((type == ETH_RDES3_WB_LT_ARP_REQ) &&
                            (!(cur_descr->rdes3 & ETH_RDES3_WB_RS2V) ||
                               !(cur_descr->rdes2 & ETH_RDES2_WB_ARPNR))) {
                            rx_frame.info.ll_flags |= LIP_LL_RXFLAGS_ARP_RESP_SENT;

                            lip_printf(LIP_LOG_MODULE_PORT, LIP_LOG_LVL_DEBUG_LOW, 0,
                                       "lip port: arp request was processed by hw\n");
                        } else if (type != ETH_RDES3_WB_LT_TYPE) {
                            lip_printf(LIP_LOG_MODULE_PORT, LIP_LOG_LVL_DEBUG_LOW, 0,
                                       "lip port: rx spec packet type: %d\n", type);
                        }
#if LIP_VLAN_ENABLE
                        if (cur_descr->rdes3 & ETH_RDES3_WB_RS0V) {
                            rx_frame.info.vlan_pcp = LBITFIELD_GET(LBITFIELD_GET(cur_descr->rdes0, ETH_RDES0_WB_OVT), LIP_VLAN_TCI_FLD_PCP);
                            rx_frame.info.flags |= LIP_FRAME_RXINFO_FLAG_VLAN_PCP_VALID;
                        }
#endif
                        if (cur_descr->rdes3 & ETH_RDES3_WB_RS1V) {
                            lip_printf(LIP_LOG_MODULE_PORT, LIP_LOG_LVL_DEBUG_LOW, 0,
                                       "lip port: rx rdes1 valid: 0x%08X\n",
                                       cur_descr->rdes1);


                            if (cur_descr->rdes1 & ETH_RDES1_WB_TSA) {
                                /* Если есть метка времени, то для окончания пакета должен быть еще
                                 * context descriptor */
                                ctx_descr_wt = true;
                            }
#if LIP_PTP_ENABLE
                            if (cur_descr->rdes1 & ETH_RDES1_WB_PFT) {
                                rx_frame.info.ll_flags |= LIP_LL_RXFLAGS_PTP_PACKET;
                            }
#endif

                            if (cur_descr->rdes1 & (ETH_RDES1_WB_IPV4 | ETH_RDES1_WB_IPV6)) {

                                /* Флаги ошибок ip заголовка и данных действительны только,
                                 * если IP-заголовок определен. При этом они не влияют на
                                 * флаг ES и их надо проверять отдельно */
                                if (cur_descr->rdes1 & (ETH_RDES1_WB_IPHE | ETH_RDES1_WB_IPCE)) {
                                    lip_printf(LIP_LOG_MODULE_PORT, LIP_LOG_LVL_DEBUG_HIGH, 0,
                                               "lip port: rx ip %s error\n",
                                               cur_descr->rdes1 & ETH_RDES1_WB_IPHE ? "header" : "payload");
                                    ETH_LL_CUR_RX_FRAME_MARK_TO_DROP();
                                } else {
                                    /* если обнаружен IP заголовок без ошибок, значит
                                     * его контрольная сумма проверена */
                                    /** @note не совсем очевидно, признак ETH_RDES1_WB_IPCB
                                     * означает, что не проверена только контрольная сумма
                                     * протокола над IP или и IP тоже. В последнем случае нет
                                     * признака различия, поэтому исходим из того, что
                                     * если IPv4 загловок определен, то и его сумма проверена */
                                    rx_frame.info.ll_flags |= LIP_LL_RXFLAGS_IP_CHECKSUM_CHECKED;

                                    /* если IPCB не установлен и payload поддерживаемого типа
                                     * то соотвествтующее CRC должно быть проверено */
                                    if (!(cur_descr->rdes1 & ETH_RDES1_WB_IPCB)) {
                                        uint8_t pl_type = LBITFIELD_GET(cur_descr->rdes1, ETH_RDES1_WB_PT);
                                        if (pl_type == ETH_RDES1_WB_PT_TCP) {
                                            rx_frame.info.ll_flags |= LIP_LL_RXFLAGS_TRANSP_CHECKSUM_CHECKED;
                                        } else if (pl_type == ETH_RDES1_WB_PT_UDP) {
                                            rx_frame.info.ll_flags |= LIP_LL_RXFLAGS_TRANSP_CHECKSUM_CHECKED;
                                        } else if (pl_type == ETH_RDES1_WB_PT_ICMP) {
                                            rx_frame.info.ll_flags |= LIP_LL_RXFLAGS_TRANSP_CHECKSUM_CHECKED;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    /* если завершили обработку последнего буфера без ошибок,
                     * то устанавливаем признак завершения обрабтки для обработки пакета,
                     * если нет контекстного дескриптора. Если есть, то завершаем
                     * обработку только после обработки контекстного */
                    if (ETH_LL_CUR_RX_FRAME_IN_PROGR() && !ctx_descr_wt) {
                        frame_finish = true;
                    }
                }
            }
        } else {
            if (!ctx_descr_wt) {
                drop_cnt++;
                ETH_LL_CUR_RX_FRAME_MARK_TO_DROP();
                lip_printf(LIP_LOG_MODULE_PORT, LIP_LOG_LVL_DEBUG_HIGH, 0,
                           "lip port: rx unexpected context descriptor\n");
            } else {
                ++frame_descr_cnt;
                frame_finish = true;
                ctx_descr_wt = false;
#if LIP_PTP_ENABLE
                if (f_tstmp_en) {
                    rx_frame.info.tstmp.hsec = 0;
                    rx_frame.info.tstmp.fract_ns = 0;
                    rx_frame.info.tstmp.ns = cur_descr->rdes0;
                    rx_frame.info.tstmp.sec = cur_descr->rdes1;
                    rx_frame.info.flags |= LIP_FRAME_RXINFO_FLAG_TSTAMP_VALID;
                }
#endif
            }

        }

        if (frame_finish) {
            lip_mac_rx_proc_frame(&rx_frame);
            ETH_LL_CUR_RX_FRAME_MARK_TO_DROP();
            ETH_LL_CUR_RX_DROP();
            frame_finish = false;
        }

        cur_descr_idx = LIP_PORT_RX_NEXT_IND(cur_descr_idx);
        proc_cnt++;
    }

    /* если остались помеченные пакеты на освобождение, освобождаем */
    ETH_LL_CUR_RX_DROP();
#undef ETH_LL_CUR_RX_FRAME_IN_PROGR
#undef ETH_LL_CUR_RX_FRAME_MARK_TO_DROP
#undef ETH_LL_CUR_RX_DROP
}




#ifdef LIP_USE_IGMP
    t_lip_errs lip_ll_join(const uint8_t* mac) {

        return LIP_ERR_SUCCESS;
    }

    t_lip_errs lip_ll_leave(const uint8_t* mac) {

        return LIP_ERR_SUCCESS;
    }
#endif


void lip_ll_ip_addr_changed(void) {
    f_update_arp_addr();
}

#if LIP_LL_INTERRUPT_ENABLE
void lip_ll_irq_enable(void) {
    chip_interrupt_enable(ETH_IRQn);
}
void lip_ll_irq_disable(void) {
    chip_interrupt_disable(ETH_IRQn);
}
#endif

static void f_check_isr(void) {
    const uint32_t inst = CHIP_REGS_ETH->DMAISR;
    if (inst & CHIP_REGFLD_ETH_DMAISR_DC0IS) {

        const uint32_t ch_st = CHIP_REGS_ETH->DMACSR;
        CHIP_REGS_ETH->DMACSR = ch_st;
        if (ch_st & CHIP_REGFLD_ETH_DMACSR_RI) {
            f_rx_check_descr();
        }
        if (ch_st & CHIP_REGFLD_ETH_DMACSR_TI) {
            f_tx_check_descr();
        }
    }
}

void lip_ll_pull(void) {
#if !LIP_LL_INTERRUPT_ENABLE
    f_check_isr();
#endif
}
#if LIP_LL_INTERRUPT_ENABLE
void ETH_IRQHandler(void) {
    f_check_isr();
}
#endif
