316 lines
9.8 KiB
C
316 lines
9.8 KiB
C
/****************************************************************************
|
|
|
|
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 */
|