/**************************************************************************** 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_init_api.h" /* HW WAR for cfg reg not take effect */ #include "mac_txq_hw.h" #include "mac_status.h" #include "mac_sched_hw.h" #include "tx_mpdu_start.h" #include "os_utils_api.h" #include "phy_reg.h" #include "mac_pdev.h" #include "iot_system_api.h" #include "os_task.h" #include "phy_phase.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(); /* Sadc stop working after phy reset, but dma still working, dma will move * error data to buffer. So, we need reset sadc after phy reset quickly. * See details at bugID:733. * 1:select the sadc data; 0:select adc 16-downsampling data. */ phy_adc_mon_sel_set(true); #endif return; } void mac_reset(MAC_RST_REASON_ID rst_reason) { (void)rst_reason; enable_mac(true); warm_rst_mac_hold(); warm_rst_mac_release(); /* not reset all reg here, as the cfg reg reset * not only reset mac reg, put it at phy_reset() */ } 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 0x38000 uint32_t debug_tmp; mac_set_debug_reg(0x100); debug_tmp = mac_rx_get_debug_reg(); /* if 0, then means idle */ 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(); #if DEBUG_HWQ_SHCED_HANG uint32_t try_cnt = 0; #endif while (mac_dbg_bus_is_in_tx()) { 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); } 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 */ mac_dump_buf(MAC_DUMP_TYPE_4, (uint32_t *)mac_txq_get_curr_desc_ptr(\ !!iscco, \ false), \ sizeof(tx_mpdu_start)/sizeof(uint32_t), \ (uint32_t *)RGF_HWQ_BASEADDR, 108, \ (uint32_t *)(PHY_BASEADDR + CFG_BB_RX_TD_DBG_BUS0_ADDR), 38, true); } } } return; } void mac_sw_trig_need_en(bool_t ena) { /* for kunlun 1 we don't have this define */ (void)ena; return; } void mac_sw_trig_start(bool_t ena) { /* for kunlun 1 we don't have this define */ (void)ena; return; } void mac_dma_ckl_sel(bool_t ena) { /* for kunlun 1 we don't have this define */ (void)ena; return; } 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; } /* 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(); 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; } /* 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; }