/**************************************************************************** Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED. This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT be copied by any method or incorporated into another program without the express written consent of Aerospace C.Power. This Information or any portion thereof remains the property of Aerospace C.Power. The Information contained herein is believed to be accurate and Aerospace C.Power assumes no responsibility or liability for its use in any way and conveys no license or title under any patent or copyright and makes no representation or warranty that this Information is free from patent or copyright infringement. ****************************************************************************/ #include "chip_reg_base.h" #include "hw_reg_api.h" #include "plc_fr.h" #include "mac_reset.h" #include "mac_sys_reg.h" #include "ahb.h" #include "hw_desc.h" #include "hw_phy_init.h" #include "mac_raw_reg.h" #include "mac_tmr_reg.h" #include "mac_hwq_reg.h" #include "mac_init_api.h" /* HW WAR for cfg reg not take effect */ #include "mac_txq_hw.h" #include "mac_status.h" #include "mac_rx_buf_ring.h" #include "os_utils_api.h" #include "os_task.h" #include "mac_rf_common_hw.h" #include "phy_phase.h" #include "phy_reg.h" #include "mac_tx_descriptor_reg.h" #include "mac_sched_hw.h" void enable_mac(uint32_t enable) { #if HW_PLATFORM != HW_PLATFORM_SIMU if (enable) { ahb_mac_enable(); } else { ahb_mac_disable(); } #else (void)enable; #endif return; } void warm_rst_mac_hold() { #if HW_PLATFORM != HW_PLATFORM_SIMU ahb_mac_reset_hold(); #endif return; } void warm_rst_mac_release() { #if HW_PLATFORM != HW_PLATFORM_SIMU ahb_mac_reset_release(); #endif return; } void mac_cfg_reg_reset() { #if HW_PLATFORM >= HW_PLATFORM_FPGA ahb_mac_reset(); #endif return; } void mac_reset(MAC_RST_REASON_ID rst_reason) { (void)rst_reason; enable_mac(true); /* reset mac's logic */ warm_rst_mac_hold(); if (rst_reason == MAC_RST_REASON_COLD) { /* reset mac's reg * not reset all reg here, as the cfg reg reset * not only reset mac reg, put it at phy_reset() * kunlun2, we should able to reset mac's reg */ mac_cfg_reg_reset(); } warm_rst_mac_release(); return; } void mac_warm_reset_war(uint32_t flag) { (void)flag; if (flag == CONT_RX_ABORT4) { #if ENA_WAR_244 /* disable MAC RAW DATA MODE */ RGF_RAW_WRITE_REG(CFG_RAW_DATA_MODE_ADDR, 0); /* clear pb size BB */ phy_rawdata_mode_bb_set_ps_tr(0,0,0); #endif } else if (flag == PHY_TX_HANG){ mac_new_phy_cfg_apply(); /* clear mac status cnt */ mac_status_cnt_clr(); } } void mac_set_sw_idle_mode(uint32_t ena, uint32_t is_idle) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t tmp; tmp = RGF_MAC_READ_REG(CFG_PHASE_BAND_SEL_ADDR); REG_FIELD_SET(CFG_SW_IDLE_MODE_EN, tmp, ena); REG_FIELD_SET(CFG_SW_IDLE_MODE, tmp, is_idle); RGF_MAC_WRITE_REG(CFG_PHASE_BAND_SEL_ADDR, tmp); #else (void)ena; (void)is_idle; #endif } uint32_t mac_wait_phy_txrx_idle() { #if HW_PLATFORM >= HW_PLATFORM_FPGA /* return 0 for wait idle successful * 1 for wait failed if timeout */ /* TODO: support timeout */ uint32_t tmp; uint32_t tx_active; uint32_t rx_active; do { tmp = RGF_MAC_READ_REG(CFG_RD_MACPHY_INTF_0_ADDR); rx_active = REG_FIELD_GET(PHY_RX_ENABLE, tmp); tx_active = REG_FIELD_GET(PHY_TX_ENABLE, tmp); } while (tx_active && rx_active); #else #endif return 0; } void mac_force_phy_tx_ready(uint32_t ena, uint32_t is_force_ready) { #if HW_PLATFORM >= HW_PLATFORM_FPGA /* make phy tx ready to 1 before mac disable hwq */ uint32_t tmp; tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_2_ADDR); REG_FIELD_SET(CFG_PHY_TX_READY_FORCE_EN, tmp, ena); REG_FIELD_SET(CFG_PHY_TX_READY, tmp, is_force_ready); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_2_ADDR, tmp); #else (void)ena; (void)is_force_ready; #endif return; } uint32_t mac_dbg_bus_is_in_tx() { #define TX_FSM_IS_TX_MASK (0x2 << 23) uint32_t debug_tmp; mac_set_debug_reg(0xB00); debug_tmp = mac_rx_get_debug_reg(); /* if (bit25:23) = 2, then means tx */ return debug_tmp & TX_FSM_IS_TX_MASK; } void mac_tx_wait_all_queue_idle(uint32_t iscco, uint32_t time_ms) { uint32_t start_ts = os_boot_time32(); volatile uint32_t is_tx_busy = mac_dbg_bus_is_in_tx(); #if DEBUG_HWQ_SHCED_HANG uint32_t try_cnt = 0; #endif uint32_t start_ntb = mac_sched_get_lts(); while (is_tx_busy) { if ((os_boot_time32() - start_ts) > time_ms) { #if DEBUG_HWQ_SHCED_HANG try_cnt++; /* war for stop sched hang */ if (try_cnt < 2) { /* force mac phy interface */ mac_force_mac_phy_interface(1); os_delay(1); mac_force_mac_phy_interface(0); phy_reset(PHY_RST_REASON_WARM); } else #endif { #if WAR_HWQ_SHCED_HANG /* reset chip */ iot_system_restart(IOT_SYS_RST_REASON_MAC_TX_HANG); #endif /* if try_cnt >= 2 then assert */ uint32_t dump_buf[5]; dump_buf[0] = start_ts; dump_buf[1] = os_boot_time32(); dump_buf[2] = start_ntb; dump_buf[3] = mac_sched_get_lts(); while (mac_dbg_bus_is_in_tx()) { if ((os_boot_time32() - dump_buf[1]) > 500) { break; } os_delay(1); } dump_buf[4] = os_boot_time32(); mac_dump_buf(MAC_DUMP_TYPE_4, dump_buf, 5, (uint32_t *)RGF_HWQ_BASEADDR, 108, (uint32_t *)(PHY_BASEADDR + CFG_BB_DBG_BUS_SEL_ADDR), 39, true); } } os_delay(1); is_tx_busy = mac_dbg_bus_is_in_tx(); } return; } void mac_sw_trig_need_en(bool_t ena) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t tmp; tmp = RGF_MAC_READ_REG(CFG_MAC_TRX_START_ADDR); REG_FIELD_SET(CFG_MAC_TRX_START_NEED_TRIG, tmp, ena); RGF_MAC_WRITE_REG(CFG_MAC_TRX_START_ADDR, tmp); #else (void)ena; (void)is_idle; #endif } void mac_sw_trig_start(bool_t ena) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t tmp; tmp = RGF_MAC_READ_REG(CFG_MAC_TRX_START_ADDR); REG_FIELD_SET(CFG_MAC_TRX_START_TRIG, tmp, ena); RGF_MAC_WRITE_REG(CFG_MAC_TRX_START_ADDR, tmp); #else (void)ena; #endif } /* 1'b0: AHB clk and mac clk 1:1; 1'b1: 2:1 */ void mac_dma_ckl_sel(bool_t ena) { /* NOTE: this function is inoperative on kl3 */ return; #if HW_PLATFORM > HW_PLATFORM_FPGA uint32_t tmp = RGF_TMR_READ_REG(CFG_NTB_CFG_ADDR); REG_FIELD_SET(CFG_DMA_CLK_SEL, tmp, ena); RGF_TMR_WRITE_REG(CFG_NTB_CFG_ADDR, tmp); #else (void)ena; #endif } uint32_t mac_get_phy_txrx_sts() { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t tmp; uint32_t tx_active; uint32_t rx_active; tmp = RGF_MAC_READ_REG(CFG_RD_MACPHY_INTF_0_ADDR); rx_active = REG_FIELD_GET(PHY_RX_ENABLE, tmp); tx_active = REG_FIELD_GET(PHY_TX_ENABLE, tmp); if (rx_active == 0 && tx_active == 0) { return MAC_PHY_IDLE_STS; } else if (rx_active == 1 && tx_active == 0) { return MAC_PHY_RX_STS; } else if (rx_active == 0 && tx_active == 1) { return MAC_PHY_TX_STS; } else if (rx_active == 1 && tx_active == 1) { IOT_ASSERT(0); return MAC_PHY_UNKNOW_STS; } #else #endif return 0; } /* NOTE: this function cannot call in interrupt */ uint32_t mac_set_sts_idle() { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t tmp; phy_force_0_access_require(); tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_0_ADDR); REG_FIELD_SET(CFG_PHY_RX_FRAME_FORCE_EN, tmp, 1); REG_FIELD_SET(CFG_PHY_RX_FRAME, tmp, 0); REG_FIELD_SET(CFG_PHY_RX_VLD_FORCE_EN, tmp, 1); REG_FIELD_SET(CFG_PHY_RX_VLD, tmp, 0); REG_FIELD_SET(CFG_PHY_FC_CRC_DONE_FORCE_EN, tmp, 1); REG_FIELD_SET(CFG_PHY_FC_CRC_DONE, tmp, 0); REG_FIELD_SET(CFG_PHY_PB_CRC_DONE_FORCE_EN, tmp, 1); REG_FIELD_SET(CFG_PHY_PB_CRC_DONE, tmp, 0); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_0_ADDR, tmp); phy_force_0_access_release(); tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_1_ADDR); REG_FIELD_SET(CFG_PHY_PB_RCV_DONE_FORCE_EN, tmp, 1); REG_FIELD_SET(CFG_PHY_PB_RCV_DONE, tmp, 0); REG_FIELD_SET(CFG_PHY_FC_RCV_DONE_FORCE_EN, tmp, 1); REG_FIELD_SET(CFG_PHY_FC_RCV_DONE, tmp, 0); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_1_ADDR, tmp); tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_2_ADDR); REG_FIELD_SET(CFG_PHY_TX_READY_FORCE_EN, tmp, 1); REG_FIELD_SET(CFG_PHY_TX_READY, tmp, 1); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_2_ADDR, tmp); #else #endif return 0; } /* NOTE: this function cannot call in interrupt */ uint32_t mac_free_sts_idle() { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t tmp; phy_force_0_access_require(); tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_0_ADDR); REG_FIELD_SET(CFG_PHY_RX_FRAME_FORCE_EN, tmp, 0); REG_FIELD_SET(CFG_PHY_RX_FRAME, tmp, 0); REG_FIELD_SET(CFG_PHY_RX_VLD_FORCE_EN, tmp, 0); REG_FIELD_SET(CFG_PHY_RX_VLD, tmp, 0); REG_FIELD_SET(CFG_PHY_FC_CRC_DONE_FORCE_EN, tmp, 0); REG_FIELD_SET(CFG_PHY_FC_CRC_DONE, tmp, 0); REG_FIELD_SET(CFG_PHY_PB_CRC_DONE_FORCE_EN, tmp, 0); REG_FIELD_SET(CFG_PHY_PB_CRC_DONE, tmp, 0); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_0_ADDR, tmp); phy_force_0_access_release(); tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_1_ADDR); REG_FIELD_SET(CFG_PHY_PB_RCV_DONE_FORCE_EN, tmp, 0); REG_FIELD_SET(CFG_PHY_PB_RCV_DONE, tmp, 0); REG_FIELD_SET(CFG_PHY_FC_RCV_DONE_FORCE_EN, tmp, 0); REG_FIELD_SET(CFG_PHY_FC_RCV_DONE, tmp, 0); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_1_ADDR, tmp); tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_2_ADDR); REG_FIELD_SET(CFG_PHY_TX_READY_FORCE_EN, tmp, 0); REG_FIELD_SET(CFG_PHY_TX_READY, tmp, 0); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_2_ADDR, tmp); #else #endif return 0; } uint32_t mac_dbg_bus_get_mac_sts(uint32_t value, uint32_t mask) { uint32_t debug_tmp; mac_set_debug_reg(value); debug_tmp = mac_rx_get_debug_reg(); /* if 0, then means idle */ return debug_tmp & mask; } /* flag of plc cpu to handle pcs reg */ static void mac_set_hplc_set_pcs_flag(uint32_t set_pcs) { uint32_t tmp = RGF_HWQ_READ_REG(CFG_HWQ8_PTR_ADDR); tmp &= ~(0x1 << 0); tmp |= (!!set_pcs << 0); RGF_HWQ_WRITE_REG(CFG_HWQ8_PTR_ADDR, tmp); } static uint32_t mac_get_hplc_set_pcs_flag() { uint32_t tmp = RGF_HWQ_READ_REG(CFG_HWQ8_PTR_ADDR); return (tmp & (0x1 << 0)); } /* NOTE: this function cannot call in interrupt */ uint32_t mac_set_pcs_busy(uint32_t enable, uint32_t value) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t tmp; phy_force_0_access_require(); /* NOTE: enable and mac_get_hplc_set_pcs_flag() must be opposite values*/ IOT_ASSERT((!!enable) != (!!mac_get_hplc_set_pcs_flag())); if (enable) { mac_set_hplc_set_pcs_flag(1); tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_0_ADDR); REG_FIELD_SET(CFG_PHY_PCS_BUSY_FORCE_EN, tmp, enable); REG_FIELD_SET(CFG_PHY_PCS_BUSY, tmp, value); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_0_ADDR, tmp); } else { mac_set_hplc_set_pcs_flag(0); if (!mac_rf_get_hplc_pcs_reg()) { tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_0_ADDR); REG_FIELD_SET(CFG_PHY_PCS_BUSY_FORCE_EN, tmp, enable); REG_FIELD_SET(CFG_PHY_PCS_BUSY, tmp, value); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_0_ADDR, tmp); } } phy_force_0_access_release(); #else (void)enable; (void)value; #endif return 0; } uint32_t IRAM_ATTR mac_set_pcs_busy_from_isr(uint32_t enable, uint32_t value) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t tmp; phy_force_0_access_require_from_isr(); if (enable) { tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_0_ADDR); REG_FIELD_SET(CFG_PHY_PCS_BUSY_FORCE_EN, tmp, enable); REG_FIELD_SET(CFG_PHY_PCS_BUSY, tmp, value); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_0_ADDR, tmp); } else { if (mac_get_hplc_set_pcs_flag() == 0) { tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_0_ADDR); REG_FIELD_SET(CFG_PHY_PCS_BUSY_FORCE_EN, tmp, enable); REG_FIELD_SET(CFG_PHY_PCS_BUSY, tmp, value); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_0_ADDR, tmp); } } phy_force_0_access_release_from_isr(); #else (void)enable; (void)value; #endif return 0; } /* NOTE: this function cannot call in interrupt */ uint32_t mac_set_fc_crc_done(uint32_t enable, uint32_t value) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t tmp; phy_force_0_access_require(); tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_0_ADDR); REG_FIELD_SET(CFG_PHY_FC_CRC_DONE_FORCE_EN, tmp, enable); REG_FIELD_SET(CFG_PHY_FC_CRC_DONE, tmp, value); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_0_ADDR, tmp); phy_force_0_access_release(); #else (void)enable; (void)value; #endif return 0; } uint32_t mac_set_reg_tx_abort_debug_value() { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t tmp; tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_1_ADDR); REG_FIELD_SET(CFG_PHY_TX_ABORT_FORCE_EN, tmp, 1); REG_FIELD_SET(CFG_PHY_TX_ABORT, tmp, 0); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_1_ADDR, tmp); #endif return 0; } uint32_t mac_force_mac_phy_interface(uint32_t value) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t tmp; tmp = RGF_MAC_READ_REG(CFG_PHY_FORCE_2_ADDR); REG_FIELD_SET(CFG_PHY_TX_READY_FORCE_EN, tmp, value); REG_FIELD_SET(CFG_PHY_TX_READY, tmp, value); REG_FIELD_SET(CFG_PHY_TX_PROCESSING_FORCE_EN, tmp, value); REG_FIELD_SET(CFG_PHY_TX_PROCESSING, tmp, value); RGF_MAC_WRITE_REG(CFG_PHY_FORCE_2_ADDR, tmp); #else (void)value; #endif return 0; }