/**************************************************************************** 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. ****************************************************************************/ /* os shim includes */ #include "os_types.h" #include "os_utils.h" #include "mac_reset.h" #include "os_task.h" /* public api includes */ #include "plc_fr.h" #include "iot_io.h" /* mac module internal includes */ #include "mac_rf_vdev.h" #include "mac_rf_pdev.h" #include "mac_rf_sched_hw.h" #include "mac_sched_hw.h" #include "mac_rf_isr.h" #if HW_PLATFORM >= HW_PLATFORM_FPGA #include "hw_reg_api.h" #include "rfplc_reg_base.h" #include "rf_mac_reg.h" #include "mac_sys_reg.h" #include "mac_rf_common_hw.h" #include "phy_phase.h" /* define the schedule queue depth */ #define RF_HW_SCHED_QUEUE_DEPTH 1 /* rf schedule shadow */ typedef struct _rf_sched_reg_shadow { /* cmdlist start ntb */ uint32_t rf_start_ntb; /* cmdlist period */ uint32_t rf_bp_dur; /* cmdlist pointer */ uint32_t rf_cmd_list_ptr; /* cmd cnt */ uint16_t rf_cmd_cnt; } rf_sched_reg_shadow_t; /* rf schedule shadow */ typedef struct _rf_sched_txt { /* cmdlist is running or not */ uint8_t rf_sched_running; /* reg shadow cnt */ uint8_t queue_cnt; rf_sched_reg_shadow_t reg_shadow[RF_HW_SCHED_QUEUE_DEPTH]; rf_sched_reg_shadow_t reg_shadow_tmp; } rf_sched_txt_t; rf_sched_txt_t rf_sched_txt = { 0 }; rf_sched_txt_t *rf_sched_p = &rf_sched_txt; uint8_t mac_rf_sched_get_cmd_list_cnt(mac_rf_vdev_t *rf_vdev) { // NOTE: rfmac can switch cmdList at any time. so not care current hw cnt (void)rf_vdev; return 0; } /* config start ntb of next beacon period */ void mac_rf_sched_set_bp_start_ntb(mac_rf_vdev_t *rf_vdev, uint32_t start_ntb) { (void)rf_vdev; rf_sched_p->reg_shadow_tmp.rf_start_ntb = start_ntb; #if MAC_SCHED_HW_DEBUG iot_printf("%s start_ntb_tmp: 0x%x\n", __FUNCTION__, start_ntb); #endif } /* config start ntb of next beacon period */ static void IRAM_ATTR mac_rf_sched_set_bp_start_ntb_hw(uint32_t start_ntb) { /* set schedule start ntb */ uint32_t tmp = RF_MAC_READ_REG(CFG_RF_MAC_BCN_START_NTB_ADDR); REG_FIELD_SET(RF_MAC_CMDLIST_START_NTB, tmp, start_ntb); RF_MAC_WRITE_REG(CFG_RF_MAC_BCN_START_NTB_ADDR, tmp); } /* config scheduler of next beacon period */ void mac_rf_sched_set_bp_cmd_list(mac_rf_vdev_t *rf_vdev, hw_sched_cmd_t *cmd, uint16_t cnt) { (void)rf_vdev; rf_sched_p->reg_shadow_tmp.rf_cmd_cnt = cnt; rf_sched_p->reg_shadow_tmp.rf_cmd_list_ptr = (uint32_t)cmd; #if MAC_SCHED_HW_DEBUG iot_printf("%s cmdnumtmp: %lu, startptrtmp:%p\n", __FUNCTION__, cnt, cmd); #endif } /* config scheduler of next beacon period */ static void IRAM_ATTR mac_rf_sched_set_bp_cmd_list_hw(uint32_t cmd, uint16_t cnt) { uint32_t tmp = RF_MAC_READ_REG(CFG_RF_MAC_SCHEDULE_ADDR); REG_FIELD_SET(RF_MAC_CMDLIST_CMD_NUM, tmp, cnt); RF_MAC_WRITE_REG(CFG_RF_MAC_SCHEDULE_ADDR, tmp); tmp = RF_MAC_READ_REG(CFG_RF_MAC_SCHED_PTR_ADDR); REG_FIELD_SET(RF_MAC_CMDLIST_START_PTR, tmp, (uint32_t)cmd); RF_MAC_WRITE_REG(CFG_RF_MAC_SCHED_PTR_ADDR, tmp); } /* config next beacon period duration */ void mac_rf_sched_set_bp_dur(mac_rf_vdev_t *rf_vdev, uint32_t bp) { (void)rf_vdev; rf_sched_p->reg_shadow_tmp.rf_bp_dur = bp; #if MAC_SCHED_HW_DEBUG iot_printf("%s tmp_bp_ms: %lu\n", __FUNCTION__, bp); #endif } /* config next beacon period duration */ static void IRAM_ATTR mac_rf_sched_set_bp_dur_hw(uint32_t bp) { uint32_t tmp = RF_MAC_READ_REG(CFG_RF_MAC_CMDLIST_LENGTH_ADDR); REG_FIELD_SET(RF_MAC_CMDLIST_LENGTH_CPU2, tmp, MAC_MS_TO_NTB(bp)); RF_MAC_WRITE_REG(CFG_RF_MAC_CMDLIST_LENGTH_ADDR, tmp); } void mac_rf_sched_trigger_bp(mac_rf_vdev_t *rf_vdev) { (void)rf_vdev; os_disable_irq(); IOT_ASSERT(rf_sched_p->queue_cnt < RF_HW_SCHED_QUEUE_DEPTH); /* record to reg shadow */ rf_sched_p->reg_shadow[rf_sched_p->queue_cnt].rf_bp_dur = rf_sched_p->reg_shadow_tmp.rf_bp_dur; rf_sched_p->reg_shadow[rf_sched_p->queue_cnt].rf_start_ntb = rf_sched_p->reg_shadow_tmp.rf_start_ntb; rf_sched_p->reg_shadow[rf_sched_p->queue_cnt].rf_cmd_cnt = rf_sched_p->reg_shadow_tmp.rf_cmd_cnt; rf_sched_p->reg_shadow[rf_sched_p->queue_cnt].rf_cmd_list_ptr = rf_sched_p->reg_shadow_tmp.rf_cmd_list_ptr; rf_sched_p->queue_cnt++; os_enable_irq(); } uint32_t mac_rf_sched_get_enable(mac_rf_vdev_t *rf_vdev) { (void)rf_vdev; uint32_t tmp = RF_MAC_READ_REG(CFG_RF_MAC_SCHEDULE_ADDR); return REG_FIELD_GET(RF_MAC_CFG_SCH_EN, tmp); } static void IRAM_ATTR mac_rf_sched_enable_bp_hw(uint8_t enable) { uint32_t tmp; if (enable) { /* schedule enable */ tmp = RF_MAC_READ_REG(CFG_RF_MAC_SCHEDULE_ADDR); REG_FIELD_SET(RF_MAC_CFG_SCH_EN, tmp, enable); RF_MAC_WRITE_REG(CFG_RF_MAC_SCHEDULE_ADDR, tmp); /* schedule start */ tmp = RF_MAC_READ_REG(CFG_RF_MAC_SCHEDULE_ADDR); REG_FIELD_SET(RF_MAC_CFG_SCH_START, tmp, enable); RF_MAC_WRITE_REG(CFG_RF_MAC_SCHEDULE_ADDR, tmp); } else { #define STOP_SCHED_TIMEOUT 50000000 // 2S * 1000 * 25 uint32_t start_ntb, cur_ntb; int64_t time_span; /* mac_rf_set_stop_sched_sts_start and CFG_RF_MAC_TXRX_CTL_ADDR * need atomic process. * spinlock start. */ phy_force_0_access_require_from_isr(); /* stop sched status */ mac_rf_set_stop_sched_sts_start(); /* stop sched start */ tmp = RF_MAC_READ_REG(CFG_RF_MAC_TXRX_CTL_ADDR); /* NOTE: this register cannot be written to do atomic operations, * VCS may be misoperated and vcs always 1. * so need to force vsc = 0 to avoid VCS being 1 all the time. */ REG_FIELD_SET(RF_MAC_VCS_STATUS, tmp, 0); REG_FIELD_SET(RF_MAC_EARLY_STOP_START, tmp, 1); RF_MAC_WRITE_REG(CFG_RF_MAC_TXRX_CTL_ADDR, tmp); /* spinlock end */ phy_force_0_access_release_from_isr(); /* wait early stop complete */ start_ntb = RGF_MAC_READ_REG(CFG_RD_LOCAL_TMR_ADDR); do { cur_ntb = RGF_MAC_READ_REG(CFG_RD_LOCAL_TMR_ADDR); time_span = cur_ntb - start_ntb; if (time_span < 0) { // wrap around time_span = (0x100000000LL) - start_ntb + cur_ntb; } } while (mac_rf_get_stop_sched_sts() && time_span < STOP_SCHED_TIMEOUT); /* judge again */ if (mac_rf_get_stop_sched_sts()) { IOT_ASSERT(0); } tmp = RF_MAC_READ_REG(CFG_RF_MAC_SCHEDULE_ADDR); REG_FIELD_SET(RF_MAC_CFG_SCH_EN, tmp, enable); RF_MAC_WRITE_REG(CFG_RF_MAC_SCHEDULE_ADDR, tmp); } } static void IRAM_ATTR mac_rf_sched_enable_bp_ext(uint8_t enable) { if (enable) { if (rf_sched_p->rf_sched_running) { return; } if (rf_sched_p->queue_cnt == 0) { return; } rf_sched_p->queue_cnt--; rf_sched_p->rf_sched_running = 1; /* config reg shadow to reg */ mac_rf_sched_set_bp_start_ntb_hw( rf_sched_p->reg_shadow[rf_sched_p->queue_cnt].rf_start_ntb); mac_rf_sched_set_bp_cmd_list_hw( rf_sched_p->reg_shadow[rf_sched_p->queue_cnt].rf_cmd_list_ptr, rf_sched_p->reg_shadow[rf_sched_p->queue_cnt].rf_cmd_cnt); mac_rf_sched_set_bp_dur_hw( rf_sched_p->reg_shadow[rf_sched_p->queue_cnt].rf_bp_dur); mac_rf_sched_enable_bp_hw(1); } else { if (rf_sched_p->rf_sched_running == 0) { return; } rf_sched_p->rf_sched_running = 0; rf_sched_p->queue_cnt = 0; mac_rf_sched_enable_bp_hw(0); } } void mac_rf_sched_enable_bp(mac_rf_vdev_t *rf_vdev, uint8_t enable) { (void)rf_vdev; #if ENA_RF_MULTI_CSMA_HWQ_WAR if (enable) { extern void mac_rf_enable_all_csma_hwqid(); mac_rf_enable_all_csma_hwqid(); } #endif os_disable_irq(); mac_rf_sched_enable_bp_ext(enable); os_enable_irq(); } uint32_t IRAM_ATTR mac_rf_handle_cmdlist_done() { /* some exception: * 1.alert interrupt lost, add check rf_sched_p->queue_cnt * 2.alert interrupt delay(for bbai...), * need stop schedule to sync schedule hw and sw flag. */ if (rf_sched_p->rf_sched_running) { if (rf_sched_p->queue_cnt) { rf_sched_p->rf_sched_running = 0; mac_rf_sched_enable_bp_ext(1); } else { /* if schedule not restart, need stop scheduler */ mac_rf_sched_enable_bp_ext(0); } } return 0; } void mac_rf_sched_set_bp_ahead_alert(mac_rf_vdev_t *rf_vdev, uint16_t ahead_ms) { (void)rf_vdev; uint32_t tmp; /* alert time */ tmp = RF_MAC_READ_REG(CFG_RF_MAC_BCN_ALERT_AHEAD_ADDR); REG_FIELD_SET(RF_MAC_CMDLIST_ALERT_TIME, tmp, MAC_MS_TO_NTB(ahead_ms)); RF_MAC_WRITE_REG(CFG_RF_MAC_BCN_ALERT_AHEAD_ADDR, tmp); #if MAC_SCHED_HW_DEBUG iot_printf("%s alert_ms: %lu\n", __FUNCTION__, ahead_ms); #endif } uint32_t mac_rf_sched_get_ntb(void *rf_vdev) { return mac_sched_get_ntb(rf_vdev); } uint64_t mac_rf_sched_get_ntb64(void *rf_vdev) { return mac_sched_get_ntb64(rf_vdev); } #endif /* HW_PLATFORM >= HW_PLATFORM_FPGA */