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 */
 |