3334 lines
115 KiB
C
3334 lines
115 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.
|
|
|
|
****************************************************************************/
|
|
#include "os_types.h"
|
|
#include "os_mem.h"
|
|
#include "os_utils.h"
|
|
#include "os_timer.h"
|
|
#include "iot_errno_api.h"
|
|
#include "iot_io_api.h"
|
|
#include "iot_system.h"
|
|
#include "iot_oem.h"
|
|
|
|
#include "plc_protocol.h"
|
|
#include "mac_pdev.h"
|
|
#include "mac_vdev.h"
|
|
#include "mac_msg.h"
|
|
#include "mac.h"
|
|
#include "mac_sched_hw.h"
|
|
#include "mac_isr.h"
|
|
#include "mac_tx_power.h"
|
|
#include "mac_cfg.h"
|
|
#include "mac_status.h"
|
|
#include "mac_cmn_hw.h"
|
|
#include "hw_zc_cmn.h"
|
|
#include "mac_zc_hw.h"
|
|
#include "mac_zc.h"
|
|
#include "iot_bitops_api.h"
|
|
#include "iot_board_api.h"
|
|
#include "gpio_mtx.h"
|
|
|
|
/* mac zc system debug log level, 0 - disable, others: enable */
|
|
#define MAC_ZC_DBG_LOG_LEVEL 0
|
|
|
|
/* mac zc feature start { */
|
|
|
|
/* 1 - check whether the phase difference of the collected values among
|
|
* different phase lines meets the rules.
|
|
* 0 - only check current collect phase's period meets the rules.
|
|
* Note: default set to 0.
|
|
*/
|
|
#define MAC_ZC_PHASE_DIFF_CHECK_ENA 0
|
|
|
|
/* TODO: will disable this debug macro*/
|
|
/* only for mac zc debug issue */
|
|
#define MAC_ZC_COLLECT_DEBUG_ENA 0
|
|
|
|
/* mac zc system daemon, when the system abnormal, reset zc system */
|
|
#define MAC_ZC_SYS_DAEMON_RESET_ENA 0
|
|
|
|
/* only for mac zc check update info debug */
|
|
#define MAC_ZC_CHECK_INFO_DBG_ENA 1
|
|
|
|
/* update all delayed info when zc update function excute */
|
|
#define MAC_ZC_UPDATE_DLY_INFO_ENA 0
|
|
|
|
/* mac zc feature end } */
|
|
|
|
/* TODO: 150cnt * 20ms = 3000ms. when bbai move to share task, revert */
|
|
/* error accumulation cnt max for collect, when collect stage, the err counter
|
|
* exceeds this value, then this phase has powerdown.
|
|
*/
|
|
#define MAC_ZC_COLLECT_LOSS_CNT 150
|
|
|
|
/* all phase loss check cnt. */
|
|
/* when any phase error cnt > MAC_ZC_COLLECT_LOSS_CNT,
|
|
* then check all phase error cnt.
|
|
* if the phase error cnt > (MAC_ZC_COLLECT_LOSS_CNT -
|
|
* MAC_ZC_COLLECT_LOSS_MARGIN_CNT),
|
|
* means this phase is also a collect loss(power down).
|
|
*/
|
|
#define MAC_ZC_COLLECT_LOSS_MARGIN_CNT 6
|
|
|
|
/* when inactive stage, the err counter exceeds this value, then this phase
|
|
* has power on.
|
|
*/
|
|
#define MAC_ZC_COLLECT_RESTORE_CNT 32
|
|
|
|
/* all phase restore check cnt */
|
|
/* when any phase error cnt > MAC_ZC_COLLECT_RESTORE_CNT,
|
|
* then check all phase error cnt.
|
|
* if the phase error cnt > (MAC_ZC_COLLECT_RESTORE_CNT -
|
|
* MAC_ZC_COLLECT_LOSS_MARGIN_CNT),
|
|
* means this phase is also a collect restore(power on).
|
|
*/
|
|
#define MAC_ZC_COLLECT_RESTORE_MARGIN_CNT 6
|
|
|
|
/* the max gap between two period allowed, unit ntb */
|
|
#define MAC_ZC_PERIOD_JITTER_GAP_NTB 12500
|
|
|
|
/* all phase goldon gap ntb = 20ms */
|
|
#define MAC_ZC_ALL_PHASE_GOLDON_GAP_NTB 500000
|
|
|
|
/* when the train fail, the delay time to retrain, unit: ms */
|
|
#define MAC_ZC_TRAIN_RESTART_DELAY_MS 30000
|
|
|
|
/* TODO: check protocol need support max count */
|
|
/* sg protocol ntb copy count equal 1 Byte 255 */
|
|
#define MAC_ZC_RPT_NTB_CNT_MAX 255
|
|
|
|
/**
|
|
* The part below is zc check_bitmap assert trace code
|
|
*/
|
|
/* check bitmap trace data buffer size */
|
|
#define MAC_ZC_BITMAP_TRACE_BUF_SIZE 6
|
|
/* assign mac_zc_sm_train_bound_intr_wait_exec() call id 1 */
|
|
#define MAC_ZC_CALL_BOUND 1
|
|
/* assign mac_zc_systic_trig() call id 2 */
|
|
#define MAC_ZC_CALL_SYSTIC 2
|
|
/* assign mac_zc_cal_collect_phase_bitmap call id 3 */
|
|
#define MAC_ZC_CALL_CAL 3
|
|
|
|
/* macro define function */
|
|
/**
|
|
* @brief get mac zc ctxt ptr by pdev_id(mac_zc_id)
|
|
* @param id: mac pdev id or mac zc id
|
|
* @retval: mac zc ctxt ptr
|
|
*/
|
|
#define mac_zc_ctxt_get(id) (((id) >= MAC_ZC_NUM_MAX) ? NULL : \
|
|
&g_mac_zc_ctxt[id])
|
|
|
|
/**
|
|
* @brief get mac ctxt collecting status
|
|
* @param id: mac zc ctxt ptr
|
|
* @retval: 1 - collecting, 0 - not collecting
|
|
*/
|
|
#define mac_zc_is_collecting(zc_ctxt) \
|
|
(((mac_zc_ctxt_t *)(zc_ctxt))->sm_info.cur_sm == MAC_ZC_SM_COLLECT)
|
|
|
|
/**
|
|
* @brief get mac ctxt is stoped status
|
|
* @param id: mac zc ctxt ptr
|
|
* @retval: 1 - stoped, 0 - running
|
|
*/
|
|
#define mac_zc_is_stoped(zc_ctxt) \
|
|
(((mac_zc_ctxt_t *)(zc_ctxt))->sm_info.cur_sm == MAC_ZC_SM_IDLE)
|
|
|
|
/**
|
|
* @brief get current reference phase d
|
|
* @param id: mac zc ctxt ptr
|
|
* @retval: MAC_ZC_PHASE_XXX
|
|
*/
|
|
#define mac_zc_get_ref_phase_id(zc_ctxt) \
|
|
(((mac_zc_ctxt_t *)(zc_ctxt))->ref_phase_id)
|
|
|
|
/**
|
|
* @brief get mac zc ctxt phase collect status is active
|
|
* @param phase_info: mac zc phase info ctxt ptr
|
|
* @retval: 0 - inactive, 1 - active.
|
|
*/
|
|
#define mac_zc_phase_is_active(phase_info) \
|
|
(((mac_zc_phase_info_t *)(phase_info))->collect_sts)
|
|
|
|
#define mac_zc_phase_is_repeat(phase_info, phase_id) \
|
|
((((mac_zc_phase_info_t *)(phase_info))->repeat_phase) != (phase_id))
|
|
|
|
/**
|
|
* @brief get mac zc phase is support to collect
|
|
* @param phase_info: mac zc phase info ctxt ptr
|
|
* @param phase_info: mac zc phase id
|
|
* @retval: 0 - nonsupport, 1 - support.
|
|
*/
|
|
#define mac_zc_phase_is_support(zc_ctxt, phase_id) \
|
|
(!!(((mac_zc_ctxt_t *)(zc_ctxt))->nv_info.support_phase_bitmap \
|
|
& (1 << (phase_id))))
|
|
|
|
/**
|
|
* @brief get ring buffer last valid data index
|
|
* @param phase_info: mac zc phase info ctxt ptr
|
|
* @retval: last valid data index
|
|
*/
|
|
#define mac_zc_ring_get_last_idx(phase_info) \
|
|
((uint32_t)(((mac_zc_phase_info_t *)(phase_info))->write_idx ? \
|
|
(((mac_zc_phase_info_t *)(phase_info))->write_idx - 1) : \
|
|
(((mac_zc_phase_info_t *)(phase_info))->ntb_ring_size - 1)))
|
|
|
|
/**
|
|
* @brief get ring buffer first valid data index
|
|
* @param phase_info: mac zc phase info ctxt ptr
|
|
* @retval: first valid data index
|
|
*/
|
|
#define mac_zc_ring_get_first_idx(phase_info) \
|
|
(((mac_zc_phase_info_t *)(phase_info))->is_ring_full ? \
|
|
((mac_zc_phase_info_t *)(phase_info))->write_idx : 0)
|
|
|
|
/**
|
|
* @brief calibration input ring index value
|
|
* @param phase_info: mac zc phase info ctxt ptr
|
|
* @param idx: input ring index
|
|
* @retval: legal ring index
|
|
*/
|
|
#define mac_zc_ring_get_legal_idx(phase_info, idx) \
|
|
(((idx) < ((mac_zc_phase_info_t *)(phase_info))->ntb_ring_size) ? \
|
|
(idx) : ((idx) - ((mac_zc_phase_info_t *)(phase_info))->ntb_ring_size))
|
|
|
|
/**
|
|
* @brief get real index from mapped index
|
|
* @param mapped_idx: mapped index
|
|
* @param start_idx : start index
|
|
* @param data_sz : mapped ring data size
|
|
*/
|
|
#define mac_zc_ring_get_real_idx(mapped_idx, start_idx, data_sz) \
|
|
((mapped_idx) + (start_idx) < (data_sz)) ? ((mapped_idx) + (start_idx)) \
|
|
: ((mapped_idx) + (start_idx) - (data_sz))
|
|
|
|
/**
|
|
* @brief get ring buffer valid data size
|
|
* @param phase_info: mac zc phase info ctxt ptr
|
|
* @retval: valid data size
|
|
*/
|
|
#define mac_zc_ring_get_valid_size(phase_info) \
|
|
((((mac_zc_phase_info_t *)(phase_info))->is_ring_full) ? \
|
|
(((mac_zc_phase_info_t *)(phase_info))->ntb_ring_size) : \
|
|
(((mac_zc_phase_info_t *)(phase_info))->write_idx))
|
|
|
|
/**
|
|
* @brief get cap id base on mac zc phase id
|
|
* @param zc_ctxt: mac zc ctxt ptr
|
|
* @param phase_id: mac zc phase id, see MAC_ZC_PHASE_A/B/C
|
|
* @retval: cap id
|
|
*/
|
|
#define mac_zc_map_info_phase2cap(zc_ctxt, phase_id) \
|
|
(((mac_zc_ctxt_t *)(zc_ctxt))->nv_info.phase_map[phase_id].cap_id)
|
|
|
|
/**
|
|
* @brief get signal id base on mac zc phase id
|
|
* @param zc_ctxt: mac zc ctxt ptr
|
|
* @param phase_id: mac zc phase id, see MAC_ZC_PHASE_A/B/C
|
|
* @retval: signal id
|
|
*/
|
|
#define mac_zc_map_info_phase2sig(zc_ctxt, phase_id) \
|
|
(((mac_zc_ctxt_t *)(zc_ctxt))->nv_info.phase_map[phase_id].signal)
|
|
|
|
/**
|
|
* @brief stop train timer
|
|
* @param zc_ctxt: mac zc ctxt ptr
|
|
* @retval: none
|
|
*/
|
|
#define mac_zc_train_timer_stop(zc_ctxt) \
|
|
os_stop_timer(((mac_zc_ctxt_t *)(zc_ctxt))->timer_train)
|
|
|
|
/**
|
|
* @brief start train timer and update train timeout ctxt
|
|
* @param zc_ctxt: mac zc ctxt ptr
|
|
* @param timeout_ms: timer timeout, unit:ms
|
|
* @retval: none
|
|
*/
|
|
#define mac_zc_train_timer_start(zc_ctxt, timeout_ms) \
|
|
do {\
|
|
os_start_timer(((mac_zc_ctxt_t *)(zc_ctxt))->timer_train, \
|
|
(timeout_ms)); \
|
|
((mac_zc_ctxt_t *)(zc_ctxt))->train_elapsed_time += (timeout_ms); \
|
|
} while(0)
|
|
|
|
/**
|
|
* @brief clear all phase info ctxt abnormal_cnt
|
|
* @param zc_ctxt: mac zc ctxt ptr
|
|
* @retval: none
|
|
*/
|
|
#define mac_zc_all_phase_abnormal_cnt_clr(zc_ctxt) \
|
|
do {\
|
|
uint8_t __id; \
|
|
for (__id = MAC_ZC_PHASE_A; __id < MAC_ZC_PHASE_CNT; __id++) { \
|
|
((mac_zc_ctxt_t *)(zc_ctxt))->phase_info[__id].abnormal_cnt = 0; \
|
|
} \
|
|
} while(0)
|
|
|
|
#define mac_zc_all_phase_init_active_sts(zc_ctxt) \
|
|
do {\
|
|
uint8_t __id; \
|
|
for (__id = MAC_ZC_PHASE_A; __id < MAC_ZC_PHASE_CNT; __id++) { \
|
|
((mac_zc_ctxt_t *)(zc_ctxt))->phase_info[__id].collect_sts = \
|
|
mac_zc_phase_is_support(zc_ctxt, __id); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define mac_zc_all_phase_set_collet_default_sts(zc_ctxt) \
|
|
do {\
|
|
uint8_t __id; \
|
|
for (__id = MAC_ZC_PHASE_A; __id < MAC_ZC_PHASE_CNT; __id++) { \
|
|
((mac_zc_ctxt_t *)(zc_ctxt))->phase_info[__id].collect_sts = 0; \
|
|
} \
|
|
} while(0)
|
|
|
|
/**
|
|
* @brief load default hw phase map info to zc ctxt
|
|
* @param zc_ctxt: mac zc ctxt ptr
|
|
* @retval: none
|
|
*/
|
|
#define mac_zc_def_phase_map_load(zc_ctxt) \
|
|
do { \
|
|
uint8_t __id; \
|
|
for (__id = MAC_ZC_PHASE_A; __id < MAC_ZC_PHASE_CNT; __id++) { \
|
|
mac_zc_hw_load_phase_map_def(\
|
|
&((mac_zc_ctxt_t *)(zc_ctxt))->nv_info.phase_map[__id], \
|
|
__id);\
|
|
} \
|
|
} while(0)
|
|
|
|
/* one period ntb equal 500000, min jitter = 10000, 500000/10000 = 50
|
|
* in extreme bad condition 50 jitters equal one period.
|
|
* So cvg copy 250 ntb data , we must support worst case 250/50 + 1 = 6
|
|
* Then set the search window to 12, so two sides can avoid the worst case
|
|
*/
|
|
/**
|
|
* @brief get search window half count
|
|
* @param period: search ring buffer period ntb
|
|
* @retval: window half count
|
|
*/
|
|
#define mac_zc_get_ntb_search_window_half(period) \
|
|
(MAC_ZC_RPT_NTB_CNT_MAX * MAC_ZC_PERIOD_JITTER_GAP_NTB / (period) + 1)
|
|
|
|
/**
|
|
* @brief set mac_zc bitmap and record the caller and timestamp
|
|
* @param bitmap_trace: bitmap_trace context
|
|
* @param bitmap : set bitmap value
|
|
* @param pos_call: caller position
|
|
* @retval: none
|
|
*/
|
|
#define mac_zc_set_phase_bitmap(bitmap_trace,bitmap,pos_call) \
|
|
{ \
|
|
uint32_t idx; \
|
|
bitmap_trace_ctxt_t *bm_trace = (bitmap_trace_ctxt_t *)(bitmap_trace); \
|
|
idx = bm_trace->wr_idx; \
|
|
bm_trace->trace_buf[idx].func_traced_ra = (pos_call); \
|
|
bm_trace->trace_buf[idx].set_bitmap_ts = mac_sched_get_ntb(NULL); \
|
|
bm_trace->trace_buf[idx++].set_bitmap_val = (bitmap); \
|
|
if (idx >= MAC_ZC_BITMAP_TRACE_BUF_SIZE) { \
|
|
idx = 0; \
|
|
} \
|
|
bm_trace->wr_idx = idx; \
|
|
} \
|
|
|
|
/**
|
|
* @brief get the postion edge type
|
|
* @pos the offset refer to ring start
|
|
* @retval edge type
|
|
*/
|
|
#define mac_zc_get_ring_position_edge(pos) \
|
|
(((pos) & 0x01) ? (MAC_ZC_PLC_EDGE_FALL) : \
|
|
(MAC_ZC_PLC_EDGE_RISE))
|
|
/**
|
|
* @brief get zc is in half collect state
|
|
* @zc_ctxt zc context
|
|
* @phase which phase you want get
|
|
* @retval is half collect state
|
|
* @TODO: retval base on active and is_switch_gpio
|
|
*/
|
|
#define mac_zc_is_half_clct_state(zc_ctxt, phs) \
|
|
((uint8_t)((((phs) < MAC_ZC_PHASE_ALL) && mac_zc_phase_is_active( \
|
|
&((mac_zc_ctxt_t *)(zc_ctxt))->phase_info[phs])) \
|
|
? (((mac_zc_ctxt_t *)(zc_ctxt))->nv_info.is_switch_gpio_clct) : 0))
|
|
|
|
/**
|
|
*@brief is this phase buffer is empty
|
|
*@phase_info the phase to query
|
|
*retval buffer is empty return true else return false
|
|
*/
|
|
#define mac_zc_is_ring_empty(phase_info) \
|
|
((((mac_zc_phase_info_t *)(phase_info))->write_idx == 0) && \
|
|
(((mac_zc_phase_info_t *)(phase_info))->is_ring_full == 0))
|
|
|
|
/* indicate mac zc train status */
|
|
typedef enum _mac_zc_train_status {
|
|
MAC_ZC_TRAIN_ONGOING = 0,
|
|
MAC_ZC_TRAIN_SUCCESS,
|
|
MAC_ZC_TRAIN_FAIL,
|
|
MAC_ZC_TRAIN_MAX,
|
|
} mac_zc_train_status_t;
|
|
|
|
typedef enum _mac_zc_phase_degree_id {
|
|
MAC_ZC_PHASE_DEGREE_INVALID = 0,
|
|
MAC_ZC_PHASE_DEGREE_0,
|
|
MAC_ZC_PHASE_DEGREE_30,
|
|
MAC_ZC_PHASE_DEGREE_60,
|
|
MAC_ZC_PHASE_DEGREE_120,
|
|
MAC_ZC_PHASE_DEGREE_240,
|
|
MAC_ZC_PHASE_DEGREE_300,
|
|
MAC_ZC_PHASE_DEGREE_330,
|
|
MAC_ZC_PHASE_DEGREE_OTHERS,
|
|
} mac_zc_phase_degree_id_t;
|
|
|
|
/* indicate power line status */
|
|
typedef enum _mac_zc_collect_status {
|
|
/* phase inactive. this phase is cold line, or phase loss(power down) */
|
|
MAC_ZC_COLLECT_INACTIVE = 0,
|
|
/* phase active. this phase is trained success or power restore */
|
|
MAC_ZC_COLLECT_ACTIVE,
|
|
} mac_zc_collect_status_t;
|
|
|
|
/* mac zc system state machine running tirger event id */
|
|
typedef enum _mac_zc_triger_id {
|
|
/* triger id for start zc system request */
|
|
MAC_ZC_TRIG_SYS_START_REQ = 0,
|
|
/* triger id for stop zc system request */
|
|
MAC_ZC_TRIG_SYS_STOP_REQ, //1
|
|
/* triger id for hw zc cap0/1/2 interrupt */
|
|
/* Note: not used */
|
|
MAC_ZC_TRIG_HW_CAP_INT, //2
|
|
/* triger id for hw zc bound low interrupt */
|
|
/* Note: not used */
|
|
MAC_ZC_TRIG_HW_LOWER_BOUND_INT, //3
|
|
/* triger id for hw zc bound upper interrupt */
|
|
MAC_ZC_TRIG_HW_UPPER_BOUND_INT, //4
|
|
/* triger id for zc system train timer timeout callback */
|
|
MAC_ZC_TRIG_TRAIN_TIMER, //5
|
|
/* triger id for os systic timer callback */
|
|
MAC_ZC_TRIG_SYSTIC_TIMER, //6
|
|
/* triger id max */
|
|
MAC_ZC_TRIG_MAX,
|
|
} mac_zc_triger_id_t;
|
|
|
|
/* mac zc train state id */
|
|
typedef enum _mac_zc_train_state_id {
|
|
/* state for wait hw zc gen to be ready */
|
|
MAC_ZC_TRAIN_STATE_GEN_WAIT = 0,
|
|
/* state for config hw zc gen capture, generate low/upper bound interrupt */
|
|
MAC_ZC_TRAIN_STATE_BOUND_INTR_WAIT,
|
|
/* state for train and colloct by system kick timer */
|
|
MAC_ZC_TRAIN_STATE_SYSTICK_WAIT,
|
|
} mac_zc_train_state_id_t;
|
|
|
|
/* mac zc system state machine id */
|
|
typedef enum _mac_zc_sm_id {
|
|
/* state for system idle state */
|
|
MAC_ZC_SM_IDLE = 0,
|
|
/* state for zc system ininted and stoped */
|
|
MAC_ZC_SM_INITED, //1
|
|
/* state for wait hw zc gen to be ready */
|
|
MAC_ZC_SM_TRAIN_INIT, //2
|
|
/* state for config hw zc gen capture, generate low/upper bound interrupt */
|
|
MAC_ZC_SM_TRAIN_BOUND_INTR_WAIT, //3
|
|
/* state for train and colloct by system kick timer */
|
|
MAC_ZC_SM_TRAIN_SYSTICK_WAIT, //4
|
|
/* state for collecting */
|
|
MAC_ZC_SM_COLLECT, //5
|
|
/* state id max */
|
|
MAC_ZC_SM_MAX,
|
|
} mac_zc_sm_id_t;
|
|
|
|
/* save info for not clear when reset */
|
|
typedef struct _mac_zc_nv_info {
|
|
/* save mac zc hw capture edge */
|
|
uint32_t cap_edge : 1,
|
|
/* save mac zc hw collect period: full or half period */
|
|
is_half_collect : 1,
|
|
/* indicate support phase bitmap.
|
|
* bit0: MAC_ZC_PHASE_A, bit1: MAC_ZC_PHASE_B, bit2: MAC_ZC_PHASE_C...
|
|
*/
|
|
support_phase_bitmap : 3,
|
|
/* is new board using switch gpio collect zc ntb */
|
|
is_switch_gpio_clct : 1,
|
|
rsvd0 : 26;
|
|
/* save mac zc system run on os task handle */
|
|
os_task_h *hdl;
|
|
/* save mac zc dsr table address */
|
|
void *dsr_tbl;
|
|
/* save dsr set entry function address */
|
|
mac_zc_dsr_set_entry_fn_t dsr_set_entry;
|
|
/* save dsr event clear function address */
|
|
mac_zc_dsr_clr_fn_t dsr_clr;
|
|
/* HW phase map info */
|
|
mac_zc_hw_map_info_t phase_map[MAC_ZC_PHASE_CNT];
|
|
/* save zc calibration info */
|
|
/* TODO: will add */
|
|
int32_t phase_cali[MAC_ZC_PHASE_CNT];
|
|
} mac_zc_nv_info_t;
|
|
|
|
/* mac zc state machine info */
|
|
typedef struct _mac_zc_sm_info {
|
|
/* mac zc prev state id, see mac_zc_sm_id_t */
|
|
uint32_t prev_sm : 8,
|
|
/* mac zc current state id */
|
|
cur_sm : 8,
|
|
/* last exec sm */
|
|
exec_sm : 8,
|
|
rsvd : 8;
|
|
} mac_zc_sm_info_t;
|
|
|
|
typedef struct _mac_zc_phase_info {
|
|
/* indicate the phase collect status */
|
|
uint32_t collect_sts : 1,
|
|
/* indicate the ntb ring buffer full wrap */
|
|
is_ring_full : 1,
|
|
/* reuse for this phase abnormal count */
|
|
abnormal_cnt : 8,
|
|
/* reuse for this phase collect count */
|
|
collect_cnt : 6,
|
|
/* repeat phase id, refer MAC_ZC_PHASE_XXX */
|
|
repeat_phase : 2,
|
|
/* reserved */
|
|
resv : 14;
|
|
/* save this phase last collected zc timestamp */
|
|
/* TODO: maybe save the mac local timer ntb */
|
|
uint32_t last_ts;
|
|
/* last switch gpio local ts */
|
|
uint32_t last_switch_lts;
|
|
/* record start ntb */
|
|
uint32_t start_ntb;
|
|
/* power line real period */
|
|
uint32_t period;
|
|
/* ntb ring write index, max support 65535 */
|
|
uint32_t write_idx : 16,
|
|
/* indicate ntb ring DW size, max support 65535 */
|
|
ntb_ring_size : 16;
|
|
/* ntb ring buffer header address */
|
|
uint32_t *ntb_ring;
|
|
} mac_zc_phase_info_t;
|
|
|
|
typedef struct _bitmap_trace_bug {
|
|
/* record the function who set bitmap */
|
|
uint32_t func_traced_ra;
|
|
/* record the bitmap set val */
|
|
uint32_t set_bitmap_val;
|
|
/* record when set bitmap */
|
|
uint32_t set_bitmap_ts;
|
|
} bitmap_trace_bug_t;
|
|
|
|
typedef struct _bitmap_trace_ctxt {
|
|
bitmap_trace_bug_t trace_buf[MAC_ZC_BITMAP_TRACE_BUF_SIZE];
|
|
uint32_t wr_idx;
|
|
} bitmap_trace_ctxt_t;
|
|
|
|
typedef struct _mac_zc_ctxt {
|
|
/* indicate os systic triger valid */
|
|
uint32_t systic_trig_en : 1,
|
|
/* indicate need collecet phase bitmap.
|
|
* bit0 - zc phase A, bit1 - zc phase B, bit2 - zc phase C ...
|
|
*/
|
|
check_phase_bitmap : 3,
|
|
/* indicate check phase collect zc valid reference phase id */
|
|
ref_phase_id : 2,
|
|
/* indicate pdev id */
|
|
ref_pdev_id : 2,
|
|
/* indicate reset system */
|
|
is_need_reset : 1,
|
|
/* reserved */
|
|
rsvd0 : 3,
|
|
/* train elapsed time, unit:ms. */
|
|
train_elapsed_time : 20;
|
|
/* current ctxt state info */
|
|
mac_zc_sm_info_t sm_info;
|
|
/* save the alloc ntb ring header address */
|
|
uint32_t *ring;
|
|
/* ring buffer size, unit: 4byte */
|
|
uint32_t ring_sz : 16,
|
|
/* reserved */
|
|
rsvd1 : 16;
|
|
/* timer for trainning, each sm_state multi use */
|
|
timer_id_t timer_train;
|
|
/* current mac zc all phase info */
|
|
mac_zc_phase_info_t phase_info[MAC_ZC_PHASE_CNT];
|
|
/* do not clean this info when reset system */
|
|
mac_zc_nv_info_t nv_info;
|
|
#if MAC_ZC_COLLECT_DEBUG_ENA
|
|
bitmap_trace_ctxt_t bitmap_trace;
|
|
#endif
|
|
} mac_zc_ctxt_t;
|
|
|
|
#if MAC_ZC_ENABLE
|
|
|
|
mac_zc_ctxt_t g_mac_zc_ctxt[MAC_ZC_NUM_MAX] = {0};
|
|
|
|
static void mac_dsr_zc_upper_bound(void);
|
|
|
|
/* base on map info, convert MAC_ZC_HW_CAPx to MAC_ZC_PHASE_XXX */
|
|
static uint8_t mac_zc_map_info_cap2phase(mac_zc_ctxt_t *zc_ctxt,
|
|
uint8_t cap_id)
|
|
{
|
|
uint8_t i;
|
|
IOT_ASSERT(zc_ctxt);
|
|
for (i = MAC_ZC_PHASE_A; i < MAC_ZC_PHASE_CNT; i++) {
|
|
if (zc_ctxt->nv_info.phase_map[i].cap_id == cap_id) {
|
|
return i;
|
|
}
|
|
}
|
|
return MAC_ZC_PHASE_CNT;
|
|
}
|
|
|
|
/* base on map info, convert MAC_ZC_HW_CAPx to chip signal id */
|
|
static uint8_t mac_zc_map_info_cap2sig(mac_zc_ctxt_t *zc_ctxt,
|
|
uint8_t cap_id)
|
|
{
|
|
uint8_t i;
|
|
IOT_ASSERT(zc_ctxt);
|
|
for (i = MAC_ZC_PHASE_A; i < MAC_ZC_PHASE_CNT; i++) {
|
|
if (zc_ctxt->nv_info.phase_map[i].cap_id == cap_id) {
|
|
return zc_ctxt->nv_info.phase_map[i].signal;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief get mac zc ctxt active phase count
|
|
* @retval: total active count
|
|
*/
|
|
static uint8_t IRAM_ATTR mac_zc_get_active_phase_cnt(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t count = 0, phase_id;
|
|
if (zc_ctxt) {
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
|
|
phase_id++) {
|
|
if (mac_zc_phase_is_support(zc_ctxt, phase_id)) {
|
|
count += (uint8_t)mac_zc_phase_is_active(
|
|
&zc_ctxt->phase_info[phase_id]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* @brief : compare one phase ntb with other phase ntb
|
|
* @param ntb : to compare phase ntb
|
|
* @param ref_ntb : refered phase ntb
|
|
* @retval : ntb larger than ref_ntb return 1, else return 0
|
|
*/
|
|
static uint8_t mac_zc_ntb_is_larger_ref(uint32_t ntb, uint32_t ref_ntb)
|
|
{
|
|
uint32_t delta_ntb;
|
|
uint8_t res;
|
|
if (ntb > ref_ntb) {
|
|
delta_ntb = ntb - ref_ntb;
|
|
res = 1;
|
|
} else {
|
|
delta_ntb = ref_ntb - ntb;
|
|
res = 0;
|
|
}
|
|
/* ntb wrapped invert result */
|
|
if (delta_ntb > 0x7fffffff) {
|
|
res = !res;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* @brief update current reference phase id
|
|
* @param zc_ctxt: mac zc ctxt ptr
|
|
* @param phase_id: indicate set the reference phase id.
|
|
* when phase_id != MAC_ZC_PHASE_ALL, means set
|
|
* ref_phase_id = phase_id.
|
|
* others, set ref_phase id to the max last_ts phase.
|
|
* @retval: current reference phase id
|
|
*/
|
|
static uint8_t mac_zc_update_ref_phase_id(mac_zc_ctxt_t *zc_ctxt,
|
|
uint8_t phase_id)
|
|
{
|
|
uint8_t ref_phase_id = MAC_ZC_PHASE_ALL;
|
|
mac_zc_phase_info_t *phs_info;
|
|
uint8_t active_cnt = mac_zc_get_active_phase_cnt(zc_ctxt);
|
|
|
|
IOT_ASSERT(zc_ctxt);
|
|
if (MAC_ZC_PHASE_ALL != phase_id) {
|
|
ref_phase_id = phase_id;
|
|
} else {
|
|
/* find the active phase which has max start ntb */
|
|
for (uint8_t i = (active_cnt > 1) ? MAC_ZC_PHASE_B : MAC_ZC_PHASE_A;
|
|
i < MAC_ZC_PHASE_CNT; i++) {
|
|
phs_info = &zc_ctxt->phase_info[i];
|
|
if (mac_zc_phase_is_active(phs_info)) {
|
|
#if MAC_ZC_DBG_LOG_LEVEL >= 2
|
|
iot_printf("[zc]unsorted: phase=%d, ntb=%u\n", i,
|
|
phs_info->start_ntb);
|
|
#endif
|
|
if (ref_phase_id == MAC_ZC_PHASE_ALL) {
|
|
ref_phase_id = i;
|
|
continue;
|
|
}
|
|
if (mac_zc_ntb_is_larger_ref(phs_info->start_ntb,
|
|
zc_ctxt->phase_info[ref_phase_id].start_ntb)) {
|
|
ref_phase_id = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (MAC_ZC_PHASE_ALL != ref_phase_id) {
|
|
zc_ctxt->ref_phase_id = ref_phase_id;
|
|
iot_printf("zc:ref_phase=%d\n", ref_phase_id);
|
|
}
|
|
ref_phase_id = (uint8_t)(zc_ctxt->ref_phase_id);
|
|
|
|
return ref_phase_id;
|
|
}
|
|
|
|
/**
|
|
* @brief clear all phase info ctxt collect_cnt
|
|
* @param zc_ctxt: mac zc ctxt ptr
|
|
* @param phase_bitmap: clear phase bitmap.
|
|
* bit0 - MAC_ZC_PHASE_A
|
|
* bit0 - MAC_ZC_PHASE_B
|
|
* bit0 - MAC_ZC_PHASE_C...
|
|
* @retval: none
|
|
*/
|
|
static void mac_zc_phase_collect_cnt_clr(mac_zc_ctxt_t *zc_ctxt,
|
|
uint8_t phase_bitmap)
|
|
{
|
|
uint8_t phase_id;
|
|
phase_bitmap &= (uint8_t)((1 << MAC_ZC_PHASE_CNT) - 1);
|
|
if (zc_ctxt) {
|
|
while (phase_bitmap) {
|
|
phase_id = iot_bitops_ffs(phase_bitmap) - 1;
|
|
zc_ctxt->phase_info[phase_id].collect_cnt = 0;
|
|
phase_bitmap &= ~(1 << phase_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
static uint32_t mac_zc_get_phase_collect_cnt(mac_zc_ctxt_t *zc_ctxt,
|
|
uint8_t phase_bitmap)
|
|
{
|
|
uint8_t phase_id;
|
|
uint32_t count = 0;
|
|
phase_bitmap &= (uint8_t)((1 << MAC_ZC_PHASE_CNT) - 1);
|
|
if (zc_ctxt) {
|
|
while (phase_bitmap) {
|
|
phase_id = iot_bitops_ffs(phase_bitmap) - 1;
|
|
if (mac_zc_phase_is_support(zc_ctxt, phase_id)) {
|
|
count += zc_ctxt->phase_info[phase_id].collect_cnt;
|
|
}
|
|
phase_bitmap &= ~(1 << phase_id);
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static inline uint8_t mac_zc_get_average_weight_power(uint32_t rule)
|
|
{
|
|
uint8_t shift_cnt = 0;
|
|
|
|
if (rule >= 1 && rule <= 2) {
|
|
shift_cnt = 1;
|
|
} else if (rule > 2 && rule <= 4) {
|
|
shift_cnt = 2;
|
|
} else if (rule > 4 && rule <= 8) {
|
|
shift_cnt = 3;
|
|
} else if (rule > 8 && rule <= 16) {
|
|
shift_cnt = 4;
|
|
} else if (rule > 16 && rule <= 32) {
|
|
shift_cnt = 5;
|
|
} else {
|
|
shift_cnt = 6;
|
|
}
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 3)
|
|
iot_printf("[zc]get_weight_power:rule=%d, shift=%d\n", rule, shift_cnt);
|
|
#endif
|
|
|
|
return shift_cnt;
|
|
}
|
|
|
|
/* weight_power means 2 ^ weight_power. */
|
|
static inline int64_t mac_zc_updata_average_accum(int64_t src,
|
|
int64_t update, uint8_t weight_power)
|
|
{
|
|
return (uint32_t)((src - (src >> weight_power)) + (update >> weight_power));
|
|
}
|
|
|
|
/* enable/disable mac zc upper bound interrupt */
|
|
static void mac_zc_upper_bound_intr_ena(mac_zc_ctxt_t *zc_ctxt, uint8_t enable)
|
|
{
|
|
#if (HW_PLATFORM >= HW_PLATFORM_FPGA)
|
|
if (zc_ctxt && zc_ctxt->nv_info.dsr_set_entry && \
|
|
zc_ctxt->nv_info.dsr_tbl) {
|
|
if (enable) {
|
|
/* enable upper bound interrupt */
|
|
mac_isr_enable(MAC_ISR_ZC_UPPER_BOUND_ID);
|
|
zc_ctxt->nv_info.dsr_set_entry(zc_ctxt->nv_info.dsr_tbl, \
|
|
(uint8_t)MAC_DSR_ZC_UPPER_BOUND_ID, mac_dsr_zc_upper_bound);
|
|
} else {
|
|
/* disable upper bound interrupt */
|
|
mac_isr_disable(MAC_ISR_ZC_UPPER_BOUND_ID);
|
|
zc_ctxt->nv_info.dsr_set_entry(zc_ctxt->nv_info.dsr_tbl, \
|
|
(uint8_t)MAC_DSR_ZC_UPPER_BOUND_ID, NULL);
|
|
}
|
|
}
|
|
#else //HW_PLATFORM >= HW_PLATFORM_FPGA
|
|
(void)zc_ctxt;
|
|
(void)enable;
|
|
#endif
|
|
}
|
|
|
|
/* get last valid zc timestamp */ //TODO: move to hw.c
|
|
static uint32_t mac_zc_get_cur_zc(mac_zc_ctxt_t *zc_ctxt, uint8_t cap_id)
|
|
{
|
|
uint32_t cur_zc = mac_zc_hw_get_last_zc_ts(cap_id);
|
|
/* for WAR, trigger capx reset */
|
|
mac_zc_hw_capx_reset_trig(mac_zc_map_info_cap2sig(zc_ctxt, cap_id), \
|
|
(uint8_t)zc_ctxt->nv_info.cap_edge);
|
|
/* WAR for trigger capture hw */
|
|
mac_zc_hw_capx_trig(1 << cap_id);
|
|
#if ((HW_PLATFORM >= HW_PLATFORM_FPGA) && (MAC_ZC_DBG_LOG_LEVEL >= 2))
|
|
uint8_t sig = mac_zc_map_info_cap2sig(zc_ctxt, cap_id);
|
|
iot_printf("[zc]phase=%d, hw_period=%u, sig=%d <==> gpio=%d\n",
|
|
mac_zc_map_info_cap2phase(zc_ctxt, cap_id),
|
|
mac_zc_hw_get_zc_period(cap_id), sig, gpio_mtx_sig_in_get_gpio(sig));
|
|
#endif
|
|
return cur_zc;
|
|
}
|
|
|
|
/* print current systme collect status */
|
|
static void mac_zc_system_status_print(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
#define STATUS_PRINT_STR_LEN 40
|
|
char str_buf[STATUS_PRINT_STR_LEN] = {0};
|
|
uint8_t idx = 0, phase_id;
|
|
|
|
idx += (uint8_t)iot_snprintf(str_buf, sizeof(str_buf), "zc:chk-%d-", \
|
|
(char)zc_ctxt->sm_info.cur_sm);
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
|
|
idx += (uint8_t)iot_snprintf(str_buf + idx, sizeof(str_buf),
|
|
"[%d:%d-%d]",
|
|
(char)mac_zc_phase_is_support(zc_ctxt,phase_id),
|
|
(char)mac_zc_phase_is_active(&zc_ctxt->phase_info[phase_id]),
|
|
#if (HW_PLATFORM >= HW_PLATFORM_FPGA)
|
|
(char)gpio_mtx_sig_in_get_gpio(
|
|
zc_ctxt->nv_info.phase_map[phase_id].signal)
|
|
#else
|
|
(char)0
|
|
#endif
|
|
);
|
|
}
|
|
idx += (uint8_t)iot_snprintf(str_buf + idx, sizeof(str_buf), "-%d",
|
|
(char)mac_zc_is_power_collapsed((uint8_t)zc_ctxt->ref_pdev_id));
|
|
IOT_ASSERT(idx <= STATUS_PRINT_STR_LEN);
|
|
iot_printf("%s\n", str_buf);
|
|
}
|
|
|
|
static void mac_zc_set_event(mac_zc_ctxt_t *zc_ctxt, uint32_t event)
|
|
{
|
|
uint8_t phase_id;
|
|
uint32_t phase_status;
|
|
mac_vdev_t *vdev;
|
|
|
|
iot_printf("zc:event-0x%x\n", event);
|
|
IOT_ASSERT(zc_ctxt && event);
|
|
|
|
vdev = get_vdev_ptr(zc_ctxt->ref_pdev_id, PLC_DEFAULT_VDEV);
|
|
if (vdev && vdev->start_cfg.mac_zc_status_rpt_func) {
|
|
for (phase_id = MAC_ZC_PHASE_A, phase_status = 0; \
|
|
phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
|
|
phase_status |= mac_zc_phase_is_active(\
|
|
&zc_ctxt->phase_info[phase_id]) << phase_id;
|
|
}
|
|
vdev->start_cfg.mac_zc_status_rpt_func(
|
|
vdev->start_cfg.mac_callback_arg, phase_status);
|
|
}
|
|
mac_status_add_zc_event_cnt();
|
|
}
|
|
|
|
static void mac_zc_hw_map_def_gpio(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
IOT_ASSERT(zc_ctxt);
|
|
mac_zc_nv_info_t *nv_info = &zc_ctxt->nv_info;
|
|
for (uint8_t phase = MAC_ZC_PHASE_A; phase < MAC_ZC_PHASE_CNT; phase++) {
|
|
if (mac_zc_phase_is_support(zc_ctxt, phase)) {
|
|
mac_zc_hw_fix_map_gpio2sig(nv_info->phase_map[phase].gpio,
|
|
nv_info->phase_map[phase].signal);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void mac_zc_load_oem_info(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t phase_id;
|
|
if (!zc_ctxt) {
|
|
IOT_ASSERT(0);
|
|
return;
|
|
}
|
|
|
|
/* update phase map info */
|
|
mac_zc_def_phase_map_load(zc_ctxt);
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
|
|
if (zc_ctxt->nv_info.phase_map[phase_id].gpio != GPIO_NO_VALID) {
|
|
zc_ctxt->nv_info.support_phase_bitmap |= 1 << phase_id;
|
|
}
|
|
}
|
|
|
|
/* NOTE: for kl1, if set to half period, chip cap edge must be rise. */
|
|
/* early version board hw only support to collect the rise edge input to
|
|
* the hw board. and the hw board design reverses input the zero crossing
|
|
* signal of board into the chip. then for early version hw board:
|
|
* i. for PLC rise edge, input the chip signal is fall
|
|
* ii. for PLC fall edge, input the chip signal is rise.
|
|
*/
|
|
if (GPIO_NO_VALID != zc_ctxt->nv_info.phase_map[MAC_ZC_PHASE_A].gpio_ext) {
|
|
/* board hw support double edge collect for one phase */
|
|
zc_ctxt->nv_info.cap_edge = MAC_ZC_HW_CAP_EDGE_RISE;
|
|
zc_ctxt->nv_info.is_switch_gpio_clct = 1;
|
|
} else {
|
|
zc_ctxt->nv_info.cap_edge = iot_board_support_zc_pulse()
|
|
? MAC_ZC_HW_CAP_EDGE_RISE : MAC_ZC_HW_CAP_EDGE_FALL;
|
|
zc_ctxt->nv_info.is_switch_gpio_clct = 0;
|
|
}
|
|
|
|
/* init mac zc hw full period collect */
|
|
zc_ctxt->nv_info.is_half_collect = 0;
|
|
|
|
//TODO: will add load zc calibration info
|
|
|
|
/* update oem info to flash */
|
|
mac_status_zc_nv_para_update(
|
|
(uint8_t)zc_ctxt->nv_info.is_half_collect,
|
|
(uint8_t)zc_ctxt->nv_info.cap_edge,
|
|
(uint8_t)zc_ctxt->nv_info.support_phase_bitmap,
|
|
(uint8_t)zc_ctxt->nv_info.is_switch_gpio_clct);
|
|
|
|
iot_printf("zc:support_phase_bitmap=0x%x, edge:%d, is_half=%d, "
|
|
"is_swt_gpio=%d\n",
|
|
zc_ctxt->nv_info.support_phase_bitmap,
|
|
zc_ctxt->nv_info.cap_edge,
|
|
zc_ctxt->nv_info.is_half_collect,
|
|
zc_ctxt->nv_info.is_switch_gpio_clct);
|
|
}
|
|
|
|
static void mac_zc_phase_ring_reset(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t id;
|
|
mac_zc_phase_info_t *phase_info;
|
|
IOT_ASSERT(zc_ctxt);
|
|
|
|
for (id = MAC_ZC_PHASE_A; id < MAC_ZC_PHASE_CNT; id++) {
|
|
phase_info = &zc_ctxt->phase_info[id];
|
|
phase_info->is_ring_full = 0;
|
|
phase_info->abnormal_cnt = 0;
|
|
phase_info->write_idx = 0;
|
|
}
|
|
}
|
|
|
|
/* init all phase ring buffer base ctxt->ring. */
|
|
static void mac_zc_phase_info_init(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t phase_cnt, id;
|
|
mac_zc_phase_info_t *phase_info;
|
|
|
|
IOT_ASSERT(zc_ctxt && zc_ctxt->ring);
|
|
//TODO: load module type from iot_oem_get_module_type(), then set bitmap.
|
|
phase_cnt = iot_bitops_cbs(\
|
|
(uint8_t)zc_ctxt->nv_info.support_phase_bitmap);
|
|
|
|
/* Note:
|
|
* 1. for support 1 phase, then only MAC_ZC_PHASE_A is valid.
|
|
* zc_ctxt->ring is all mounted to the MAC_ZC_PHASE_A's ntb_ring.
|
|
* 2. for support 2 phase, then MAC_ZC_PHASE_A & B is valid.
|
|
* zc_ctxt->ring is evenly divided mounted to the 2phase's ntb_ring.
|
|
* 2. for support 3 phase, then MAC_ZC_PHASE_A & B & C is valid.
|
|
* zc_ctxt->ring is evenly divided mounted to the 3phase's ntb_ring.
|
|
*/
|
|
mac_zc_phase_ring_reset(zc_ctxt);
|
|
for (id = MAC_ZC_PHASE_A; id < MAC_ZC_PHASE_CNT; id++) {
|
|
phase_info = &zc_ctxt->phase_info[id];
|
|
if (mac_zc_phase_is_support(zc_ctxt, id)) {
|
|
/* init this phase ring buffer size */
|
|
phase_info->ntb_ring_size = zc_ctxt->ring_sz / phase_cnt;
|
|
/* init this phase ring buffer ptr */
|
|
phase_info->ntb_ring = (uint32_t *)(zc_ctxt->ring \
|
|
+ (phase_info->ntb_ring_size * id));
|
|
} else {
|
|
/* clear phase info ctxt */
|
|
os_mem_set(phase_info, 0, sizeof(*phase_info));
|
|
}
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]%s:%d,support=%d,ring=0x%x,"
|
|
"phase_ring=0x%x,size=%d\n",
|
|
__FUNCTION__, id, zc_ctxt->nv_info.support_phase_bitmap,
|
|
(uint32_t)zc_ctxt->ring, (uint32_t)phase_info->ntb_ring,
|
|
phase_info->ntb_ring_size);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* normal full period collect */
|
|
static uint32_t mac_zc_system_start(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
iot_printf("zc:sys_start-0x%x\n", (uint32_t)zc_ctxt);
|
|
IOT_ASSERT(zc_ctxt);
|
|
|
|
/* check ctxt valid */
|
|
if (NULL == zc_ctxt->ring) {
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)zc_ctxt, \
|
|
sizeof(*zc_ctxt)/sizeof(uint32_t));
|
|
return ERR_NOMEM;
|
|
}
|
|
|
|
/* clear dsr event */
|
|
if (zc_ctxt->nv_info.dsr_clr) {
|
|
zc_ctxt->nv_info.dsr_clr(MAC_DSR_ZC_SYSTIC_TRIG_CB_ID);
|
|
zc_ctxt->nv_info.dsr_clr(MAC_DSR_ZC_UPPER_BOUND_ID);
|
|
}
|
|
|
|
/* clean zc ctxt for training */
|
|
zc_ctxt->systic_trig_en = 0;
|
|
|
|
/* map default gpio to signal, maybe sig and cap have been swaped.
|
|
* so mac_zc_hw_load_phase_map_def() isn't fit here.
|
|
*/
|
|
if (zc_ctxt->nv_info.is_switch_gpio_clct) {
|
|
mac_zc_hw_map_def_gpio(zc_ctxt);
|
|
}
|
|
/* re-config zc hw */
|
|
mac_zc_hw_init((uint8_t)zc_ctxt->nv_info.is_half_collect, \
|
|
(uint8_t)zc_ctxt->nv_info.cap_edge);
|
|
/* enable mac zc hw */
|
|
mac_zc_hw_capx_enable(((uint8_t)(1 << MAC_ZC_HW_CAP0) \
|
|
| (1 << MAC_ZC_HW_CAP1) | (1 << MAC_ZC_HW_CAP2)), 1);
|
|
|
|
/* disable gen bound isr/dsr */
|
|
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
|
|
mac_zc_hw_set_vibrate_protect_dur(MAC_ZC_HW_DEBOUNCE_NTB);
|
|
/* trigger ac track hw run */
|
|
mac_zc_hw_ac_track_trig();
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/* stop mac zc system */
|
|
static uint32_t mac_zc_system_stop(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
iot_printf("zc:sys_stop-0x%x\n", (uint32_t)zc_ctxt);
|
|
IOT_ASSERT(zc_ctxt);
|
|
|
|
/* stop training timer */
|
|
if (zc_ctxt->timer_train) {
|
|
mac_zc_train_timer_stop(zc_ctxt);
|
|
}
|
|
|
|
/* disable zc hw */
|
|
mac_zc_hw_capx_enable(((uint8_t)(1 << MAC_ZC_HW_CAP0) \
|
|
| (1 << MAC_ZC_HW_CAP1) | (1 << MAC_ZC_HW_CAP2)), 0);
|
|
|
|
/* disable systic trig en */
|
|
zc_ctxt->systic_trig_en = 0;
|
|
|
|
/* disable gen bound isr/dsr */
|
|
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
|
|
|
|
/* clear dsr event */
|
|
if (zc_ctxt->nv_info.dsr_clr) {
|
|
zc_ctxt->nv_info.dsr_clr(MAC_DSR_ZC_SYSTIC_TRIG_CB_ID);
|
|
zc_ctxt->nv_info.dsr_clr(MAC_DSR_ZC_UPPER_BOUND_ID);
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
static uint32_t mac_zc_system_status_check(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t id;
|
|
|
|
if (NULL == zc_ctxt) {
|
|
IOT_ASSERT(0);
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
if (!mac_zc_is_collecting(zc_ctxt)) {
|
|
return ERR_OK;
|
|
}
|
|
|
|
for (id = MAC_ZC_PHASE_A; id < MAC_ZC_PHASE_CNT; id++) {
|
|
if (mac_zc_phase_is_support(zc_ctxt, id)
|
|
^ mac_zc_phase_is_active(&zc_ctxt->phase_info[id])) {
|
|
/* if the phase support collect, but it is not active */
|
|
mac_zc_system_status_print(zc_ctxt);
|
|
iot_printf("zc:[WARN].ntb=%u,lts=%u\n",
|
|
mac_sched_get_ntb(NULL), mac_sched_get_lts());
|
|
mem_dump((uint32_t *)zc_ctxt, sizeof(*zc_ctxt)/sizeof(uint32_t));
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
static mac_zc_phase_degree_id_t mac_zc_get_phase_degree(uint32_t base,
|
|
uint32_t target, uint32_t period)
|
|
{
|
|
int32_t diff_check;
|
|
mac_zc_phase_degree_id_t deg_id;
|
|
|
|
diff_check = IOT_ABS((int32_t)(target - base));
|
|
|
|
#if MAC_ZC_PHASE_DIFF_CHECK_ENA
|
|
int32_t std_min, std_max;
|
|
for (deg_id = MAC_ZC_PHASE_DEGREE_0;
|
|
deg_id < MAC_ZC_PHASE_DEGREE_OTHERS; deg_id++) {
|
|
switch (deg_id) {
|
|
case MAC_ZC_PHASE_DEGREE_0:
|
|
std_min = (int32_t)(-MAC_ZC_PERIOD_JITTER_GAP_NTB);
|
|
std_max = (int32_t)MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
break;
|
|
case MAC_ZC_PHASE_DEGREE_30: // 30/360 = 1/12
|
|
std_min = (int32_t)(period / 12) - MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
std_max = (int32_t)(period / 12) + MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
break;
|
|
case MAC_ZC_PHASE_DEGREE_60: // 60/360 = 1/6
|
|
std_min = (int32_t)(period / 6) - MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
std_max = (int32_t)(period / 6) + MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
break;
|
|
case MAC_ZC_PHASE_DEGREE_120: // 120/360 = 1/3
|
|
std_min = (int32_t)(period / 3) - MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
std_max = (int32_t)(period / 3) + MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
break;
|
|
case MAC_ZC_PHASE_DEGREE_240: // 240/360 = 2/3
|
|
std_min = (int32_t)((period << 1) / 3) \
|
|
- MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
std_max = (int32_t)((period << 1) / 3) \
|
|
+ MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
break;
|
|
case MAC_ZC_PHASE_DEGREE_300: // 300/360 = 5/6
|
|
std_min = (int32_t)(period - (period / 6)) \
|
|
- MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
std_max = (int32_t)(period - (period / 6)) \
|
|
+ MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
break;
|
|
case MAC_ZC_PHASE_DEGREE_330: // 330/360 = 11/12
|
|
std_min = (int32_t)(period - (period / 12)) \
|
|
- MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
std_max = (int32_t)(period - (period / 12)) \
|
|
+ MAC_ZC_PERIOD_JITTER_GAP_NTB;
|
|
break;
|
|
default:
|
|
return MAC_ZC_PHASE_DEGREE_INVALID;
|
|
}
|
|
|
|
if ((diff_check >= std_min) && (diff_check <= std_max)) {
|
|
break;
|
|
}
|
|
}
|
|
#else //MAC_ZC_PHASE_DIFF_CHECK_ENA
|
|
/* for not check phase diff. if the diff between target and the base value
|
|
* is within one period, it is considered a valid data.
|
|
*/
|
|
if (diff_check < (int32_t)MAC_ZC_PERIOD_JITTER_GAP_NTB) {
|
|
deg_id = MAC_ZC_PHASE_DEGREE_0;
|
|
} else if (diff_check < (int32_t)(period - MAC_ZC_PERIOD_JITTER_GAP_NTB)) {
|
|
deg_id = MAC_ZC_PHASE_DEGREE_OTHERS;
|
|
} else {
|
|
deg_id = MAC_ZC_PHASE_DEGREE_INVALID;
|
|
}
|
|
#endif
|
|
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
|
|
iot_printf("[zc]degree:%d,base:%u,target:%u,period:%u,diff=%u\n", \
|
|
deg_id, base, target, period, diff_check);
|
|
#endif
|
|
|
|
return deg_id;
|
|
}
|
|
|
|
#if MAC_ZC_CHECK_INFO_DBG_ENA
|
|
|
|
static void mac_zc_update_info_check(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
mac_zc_phase_info_t *phase_info;
|
|
uint32_t err_code = 0;
|
|
uint32_t ref_wr_idx ;
|
|
uint32_t ntb[MAC_ZC_PHASE_CNT] = {0};
|
|
uint32_t idx[MAC_ZC_PHASE_CNT] = {0};
|
|
uint32_t phase_ring_size;
|
|
uint8_t cnt;
|
|
uint8_t phase;
|
|
|
|
IOT_ASSERT(zc_ctxt);
|
|
/* find refer phase id and refer phase write index */
|
|
phase = (uint8_t)mac_zc_get_ref_phase_id(zc_ctxt);
|
|
if (phase >= MAC_ZC_PHASE_ALL) {
|
|
err_code = __LINE__;
|
|
goto out;
|
|
}
|
|
phase_info = &zc_ctxt->phase_info[phase];
|
|
if (mac_zc_phase_is_active(phase_info) &&
|
|
!mac_zc_is_ring_empty(phase_info)) {
|
|
ref_wr_idx = mac_zc_ring_get_last_idx(phase_info);
|
|
} else {
|
|
goto out;
|
|
}
|
|
|
|
/* 1, record ring buffer ntb in same write index, to check delta ntb
|
|
* 2, record phase's latest write index, to check delta write index
|
|
* 3, check every active phase ring size
|
|
*/
|
|
cnt = iot_bitops_cbs((uint8_t)zc_ctxt->nv_info.support_phase_bitmap);
|
|
if ((cnt != 1) && (cnt != 3)) {
|
|
err_code = __LINE__;
|
|
goto out;
|
|
}
|
|
phase_ring_size = (uint32_t)(zc_ctxt->ring_sz / cnt);
|
|
for (phase = MAC_ZC_PHASE_A, cnt = 0; phase < MAC_ZC_PHASE_CNT; phase++) {
|
|
phase_info = &zc_ctxt->phase_info[phase];
|
|
if (mac_zc_phase_is_support(zc_ctxt, phase) &&
|
|
(phase_info->ntb_ring_size != phase_ring_size)) {
|
|
err_code = __LINE__;
|
|
goto out;
|
|
}
|
|
if (mac_zc_phase_is_active(phase_info) &&
|
|
!mac_zc_is_ring_empty(phase_info)) {
|
|
ntb[cnt] = phase_info->ntb_ring[ref_wr_idx];
|
|
idx[cnt++] = mac_zc_ring_get_last_idx(phase_info);
|
|
} else if (phase_info->write_idx) {
|
|
err_code = __LINE__;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/* active phases less than 2, no need to check */
|
|
if (cnt < 2) {
|
|
goto out;
|
|
}
|
|
|
|
/* check delta ntb and delta write index between every active phase */
|
|
for (uint8_t i = 0; i < (cnt - 1); i++) {
|
|
for (uint8_t j = i + 1; j < cnt; j++) {
|
|
uint32_t abs_diff_ntb = IOT_ABS((int32_t)(ntb[i] - ntb[j]));
|
|
if (abs_diff_ntb >= MAC_ZC_ALL_PHASE_GOLDON_GAP_NTB) {
|
|
err_code = __LINE__;
|
|
goto out;
|
|
}
|
|
|
|
uint32_t abs_diff_idx = IOT_ABS((int32_t)(idx[i] - idx[j]));
|
|
if (abs_diff_idx > (phase_ring_size >> 1)) {
|
|
abs_diff_idx = phase_ring_size - abs_diff_idx;
|
|
}
|
|
if (abs_diff_idx > MAC_ZC_PHASE_CNT) {
|
|
err_code = __LINE__;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
out:
|
|
if (err_code) {
|
|
iot_printf("zc:chk_info errno=%u, cur_ntb=%u, cur_lts=%u\n",
|
|
err_code, mac_sched_get_ntb(NULL), mac_sched_get_lts());
|
|
mem_dump((uint32_t *)zc_ctxt, sizeof(*zc_ctxt) / sizeof(uint32_t));
|
|
mac_zc_set_func_cmd((uint8_t)zc_ctxt->ref_pdev_id,
|
|
MAC_ZC_FUNC_CMD_DELAY_RESET_HW, NULL);
|
|
}
|
|
}
|
|
#else
|
|
|
|
#define mac_zc_update_info_check(zc_ctxt) ((void)zc_ctxt)
|
|
|
|
#endif
|
|
|
|
static void mac_zc_phase_ring_write(mac_zc_ctxt_t *zc_ctxt, uint8_t phase_id,
|
|
uint32_t wdata)
|
|
{
|
|
uint32_t widx;
|
|
mac_zc_phase_info_t *phase;
|
|
|
|
phase = &zc_ctxt->phase_info[phase_id];
|
|
widx = phase->write_idx;
|
|
/* update current zc ntb to phase ring buffer */
|
|
phase->ntb_ring[widx] = wdata;
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]phase-%d,update_ring[%u]=%u\n",
|
|
phase_id, widx, phase->ntb_ring[widx]);
|
|
#endif
|
|
widx++;
|
|
if (widx >= phase->ntb_ring_size) {
|
|
IOT_ASSERT(widx == phase->ntb_ring_size);
|
|
/* update the ntb ring buffer full wrap */
|
|
phase->is_ring_full = 1;
|
|
widx = 0;
|
|
}
|
|
phase->write_idx = widx;
|
|
}
|
|
|
|
static uint8_t mac_zc_phase_id_zc2plc(uint8_t zc_phase_id)
|
|
{
|
|
if (zc_phase_id >= MAC_ZC_PHASE_A && zc_phase_id < MAC_ZC_PHASE_ALL) {
|
|
return zc_phase_id - MAC_ZC_PHASE_A + PLC_PHASE_A;
|
|
} else {
|
|
IOT_ASSERT(0);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void mac_zc_repeat_phase_init(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
IOT_ASSERT(zc_ctxt);
|
|
for (uint8_t phase = MAC_ZC_PHASE_A; phase < MAC_ZC_PHASE_CNT; phase++) {
|
|
zc_ctxt->phase_info[phase].repeat_phase = phase;
|
|
}
|
|
}
|
|
|
|
static void mac_zc_repeat_connect_check(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t chk_pid, base_pid;
|
|
IOT_ASSERT(zc_ctxt);
|
|
|
|
#if MAC_ZC_DBG_LOG_LEVEL >= 1
|
|
iot_printf("zc:repeat0.%d:%d:%d-%d:%d:%d\n",
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_A].collect_sts,
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_B].collect_sts,
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_C].collect_sts,
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_A].repeat_phase,
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_B].repeat_phase,
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_C].repeat_phase);
|
|
#endif
|
|
|
|
mac_zc_repeat_phase_init(zc_ctxt);
|
|
for (chk_pid = (MAC_ZC_PHASE_CNT - 1); chk_pid > MAC_ZC_PHASE_A; chk_pid--)
|
|
{
|
|
if ((0 == mac_zc_phase_is_support(zc_ctxt, chk_pid)) ||
|
|
(0 == zc_ctxt->phase_info[chk_pid].last_ts)) {
|
|
continue;
|
|
}
|
|
for (base_pid = MAC_ZC_PHASE_A; base_pid < chk_pid; base_pid++) {
|
|
if ((0 == mac_zc_phase_is_support(zc_ctxt, base_pid)) ||
|
|
(0 == zc_ctxt->phase_info[base_pid].last_ts)) {
|
|
continue;
|
|
}
|
|
|
|
if (MAC_ZC_PHASE_DEGREE_0 == mac_zc_get_phase_degree(
|
|
zc_ctxt->phase_info[base_pid].last_ts,
|
|
zc_ctxt->phase_info[chk_pid].last_ts,
|
|
zc_ctxt->phase_info[base_pid].period)) {
|
|
if (!mac_zc_phase_is_repeat(&zc_ctxt->phase_info[chk_pid],
|
|
chk_pid)) {
|
|
zc_ctxt->phase_info[chk_pid].repeat_phase = base_pid;
|
|
}
|
|
/* set this phase inactive */
|
|
zc_ctxt->phase_info[chk_pid].collect_sts = 0;
|
|
iot_printf("zc:repeat.%d-%d\n", chk_pid, base_pid);
|
|
}
|
|
}
|
|
}
|
|
iot_printf("zc:repeat1.%d:%d:%d-%d:%d:%d\n",
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_A].collect_sts,
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_B].collect_sts,
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_C].collect_sts,
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_A].repeat_phase,
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_B].repeat_phase,
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_C].repeat_phase);
|
|
}
|
|
|
|
static uint8_t mac_zc_is_repeat_connect(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t is_repeat = 0;
|
|
uint8_t pid;
|
|
|
|
if (zc_ctxt) {
|
|
for (pid = MAC_ZC_PHASE_A; pid < MAC_ZC_PHASE_CNT; pid++) {
|
|
if (mac_zc_phase_is_support(zc_ctxt, pid)
|
|
&& mac_zc_phase_is_repeat(&zc_ctxt->phase_info[pid], pid)) {
|
|
is_repeat = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return is_repeat;
|
|
}
|
|
|
|
/*
|
|
* @brief update collect data to phase_id's phase_info.
|
|
* @param zc_id: which pdev to reset
|
|
* @param reason reset reason, see MAC_ZC_RST_REASON_ID
|
|
* @retval: indicate this phase collect status.
|
|
* 1 - this phase is abnormal.
|
|
* 0 - this phase is ok.
|
|
*/
|
|
static uint8_t mac_zc_update_collect_info(mac_zc_ctxt_t *zc_ctxt,
|
|
uint8_t phase_id, uint8_t is_update_ring, uint32_t zc_ntb,
|
|
uint8_t is_half_clct)
|
|
{
|
|
uint8_t is_abnormal, ref_phase_id;
|
|
int32_t delta = 0;
|
|
uint32_t save_zc, cur_ntb;
|
|
mac_zc_phase_info_t *phase_info;
|
|
mac_zc_phase_degree_id_t phase_degree = MAC_ZC_PHASE_DEGREE_INVALID;
|
|
|
|
cur_ntb = mac_sched_get_ntb(NULL);
|
|
is_half_clct = !!is_half_clct;
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
ref_phase_id = (uint8_t)mac_zc_get_ref_phase_id(zc_ctxt);
|
|
/* this parameter save the data is expected flag.
|
|
* 0 - is ok, it is expected. 1 - abnormal.
|
|
*/
|
|
is_abnormal = 0;
|
|
save_zc = zc_ntb;
|
|
/* this phae last_zc and period both valid, base on this info to check
|
|
* current collect valid, and then update: last_zc, period, phase_diff_ntb
|
|
*/
|
|
if (phase_info->last_ts && phase_info->period) {
|
|
/* check valid base on current phase ctxt */
|
|
phase_degree = mac_zc_get_phase_degree((uint32_t)(phase_info->last_ts
|
|
+ (phase_info->period >> is_half_clct)), zc_ntb,
|
|
phase_info->period);
|
|
if (MAC_ZC_PHASE_DEGREE_0 != phase_degree) {
|
|
is_abnormal = 1; //phase diff must be 0 degree
|
|
}
|
|
|
|
/* for non-reference phase, check phase diff base on reference phase */
|
|
if (!is_abnormal && (phase_id != ref_phase_id)
|
|
&& (ref_phase_id != MAC_ZC_PHASE_ALL)) {
|
|
phase_degree = mac_zc_get_phase_degree(
|
|
zc_ctxt->phase_info[ref_phase_id].last_ts,
|
|
zc_ntb, phase_info->period);
|
|
if ((MAC_ZC_PHASE_DEGREE_INVALID == phase_degree)
|
|
#if MAC_ZC_PHASE_DIFF_CHECK_ENA
|
|
|| (MAC_ZC_PHASE_DEGREE_OTHERS == phase_degree)
|
|
#endif
|
|
)
|
|
{
|
|
is_abnormal = 1;
|
|
}
|
|
}
|
|
|
|
/* check repeat phase */
|
|
if (!is_abnormal && mac_zc_phase_is_repeat(phase_info, phase_id) &&
|
|
MAC_ZC_PHASE_DEGREE_0 == mac_zc_get_phase_degree(zc_ntb,
|
|
zc_ctxt->phase_info[phase_info->repeat_phase].last_ts,
|
|
phase_info->period)) {
|
|
is_abnormal = 1;
|
|
}
|
|
|
|
if (is_abnormal) {
|
|
if (mac_zc_phase_is_active(phase_info) || !zc_ntb) {
|
|
/* make sure save_zc is a valid data. */
|
|
save_zc = phase_info->last_ts +
|
|
(phase_info->period >> is_half_clct);
|
|
if (mac_zc_ntb_is_larger_ref(save_zc, cur_ntb)) {
|
|
iot_printf("zc:calc_err-%d.last:%u,sw:%u,hw:%u,cur:%u\n",
|
|
phase_id, phase_info->last_ts, save_zc, zc_ntb,
|
|
cur_ntb);
|
|
save_zc = phase_info->last_ts;
|
|
is_update_ring = 0;
|
|
if (zc_ctxt->sm_info.cur_sm
|
|
>= MAC_ZC_SM_TRAIN_SYSTICK_WAIT) {
|
|
zc_ctxt->is_need_reset = 1;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
/* update this phase period */
|
|
delta = (zc_ntb - phase_info->last_ts) << is_half_clct;
|
|
phase_info->period = (uint32_t)mac_zc_updata_average_accum(\
|
|
(int64_t)phase_info->period, (int64_t)delta, \
|
|
mac_zc_get_average_weight_power(phase_info->collect_cnt));
|
|
}
|
|
/* note: if a normal last_ts equal to 0, we will make it 1 in order to
|
|
* avoid next time update zc information go into 'else' branch.
|
|
*/
|
|
if (save_zc == 0) {
|
|
save_zc++;
|
|
}
|
|
phase_info->last_ts = save_zc;
|
|
} else {
|
|
/* for history last_zc or peiod invalid, but current collect is valid,
|
|
* then update last_zc and period ctxt
|
|
*/
|
|
phase_info->period = zc_ctxt->phase_info[ref_phase_id].period;
|
|
if (zc_ntb) {
|
|
phase_info->last_ts = zc_ntb;
|
|
}
|
|
is_abnormal = 1;
|
|
}
|
|
|
|
/* update this phase abnormal counter */
|
|
if (mac_zc_phase_is_active(phase_info) == is_abnormal) {
|
|
/* if not corresponding to the phase's collect status */
|
|
if (phase_info->abnormal_cnt < 255) {
|
|
phase_info->abnormal_cnt++;
|
|
}
|
|
} else {
|
|
if (phase_info->abnormal_cnt) {
|
|
phase_info->abnormal_cnt--;
|
|
}
|
|
}
|
|
|
|
/* update collect counter */
|
|
if (!is_abnormal && (phase_info->collect_cnt < 63)) {
|
|
phase_info->collect_cnt++;
|
|
}
|
|
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]phase-%d,active:%d,degree:%d,zc=[%u][%u],last=%u,diff=%d,"
|
|
"is_abnor=%d,abnor_cnt=%d,sw_period=%u,collect_cnt=%d, is_half=%d, "
|
|
"is_power_collapse=%d, cur_ntb=%u\n",
|
|
phase_id, mac_zc_phase_is_active(phase_info), phase_degree, \
|
|
zc_ntb, save_zc, phase_info->last_ts, delta, \
|
|
is_abnormal, phase_info->abnormal_cnt,\
|
|
phase_info->period, phase_info->collect_cnt, is_half_clct,
|
|
mac_zc_is_power_collapsed((uint8_t)zc_ctxt->ref_pdev_id),
|
|
mac_sched_get_ntb(NULL));
|
|
#endif
|
|
|
|
/* update phase ring buffer */
|
|
if (is_update_ring && mac_zc_phase_is_support(zc_ctxt, phase_id) \
|
|
&& mac_zc_phase_is_active(phase_info)) {
|
|
IOT_ASSERT_DUMP(phase_info->ntb_ring, (uint32_t *)phase_info, \
|
|
sizeof(*phase_info)/sizeof(uint32_t));
|
|
mac_zc_phase_ring_write(zc_ctxt, phase_id, save_zc);
|
|
}
|
|
|
|
/* Notifies the caller that the phase data needs to be checked */
|
|
return !(is_abnormal ^ mac_zc_phase_is_active(phase_info));
|
|
}
|
|
|
|
/* swap two phase_map infomation */
|
|
static void mac_zc_exec_swap_phase_map(mac_zc_hw_map_info_t *swap0,
|
|
mac_zc_hw_map_info_t *swap1)
|
|
{
|
|
mac_zc_hw_map_info_t tmp_map_info;
|
|
|
|
if (!swap0 || !swap1 || (swap0->gpio == GPIO_NO_VALID) ||
|
|
(swap1->gpio == GPIO_NO_VALID)) {
|
|
return;
|
|
}
|
|
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]swap_befor:[%d:%d:%d:%d]-[%d:%d:%d:%d]\n", \
|
|
swap0->phase_id, swap0->gpio, swap0->signal, swap0->cap_id, \
|
|
swap1->phase_id, swap1->gpio, swap1->signal, swap1->cap_id);
|
|
#endif
|
|
/* save map0 info to tmp */
|
|
os_mem_cpy(&tmp_map_info, swap0, sizeof(tmp_map_info));
|
|
/* copy map1's cap&signal to map0. but not exchange gpio, gpio&zc_phase_id
|
|
* must be match.
|
|
*/
|
|
swap0->cap_id = swap1->cap_id;
|
|
swap0->signal = swap1->signal;
|
|
/* copy map0's cap&signal to map1 */
|
|
swap1->cap_id = tmp_map_info.cap_id;
|
|
swap1->signal = tmp_map_info.signal;
|
|
|
|
/* updata hw gpio->signal setting */
|
|
mac_zc_hw_fix_map_gpio2sig(swap0->gpio, swap0->signal);
|
|
mac_zc_hw_fix_map_gpio2sig(swap1->gpio, swap1->signal);
|
|
|
|
iot_printf("zc:swap_phase:[%d:%d:%d:%d]-[%d:%d:%d:%d]\n", \
|
|
swap0->phase_id, swap0->gpio, swap0->signal, swap0->cap_id, \
|
|
swap1->phase_id, swap1->gpio, swap1->signal, swap1->cap_id);
|
|
}
|
|
|
|
/* make sure if cap0's zc is max, phaseA not map to cap0.
|
|
* return: low_4bit and high_4bit represent the need swap phase_id
|
|
* if not need swap, then return 0
|
|
*/
|
|
static uint8_t mac_zc_get_swap_phase_id(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t phase_id, max_phase, support_bitmap;
|
|
IOT_ASSERT(zc_ctxt);
|
|
|
|
support_bitmap = (uint8_t)zc_ctxt->nv_info.support_phase_bitmap;
|
|
max_phase = MAC_ZC_PHASE_CNT;
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
|
|
phase_id++) {
|
|
if (0 == zc_ctxt->phase_info[phase_id].last_ts) {
|
|
continue;
|
|
}
|
|
|
|
if ((MAC_ZC_PHASE_CNT == max_phase) \
|
|
|| (zc_ctxt->phase_info[phase_id].last_ts \
|
|
> zc_ctxt->phase_info[max_phase].last_ts)) {
|
|
/* get first valid phase id */
|
|
max_phase = phase_id;
|
|
}
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]max_phase=%d\n", max_phase);
|
|
#endif
|
|
}
|
|
|
|
phase_id = mac_zc_map_info_cap2phase(zc_ctxt, MAC_ZC_HW_CAP0);
|
|
if (MAC_ZC_PHASE_CNT == max_phase) {
|
|
/* all phase is inactive, force max_phase = cap0's phase for search */
|
|
max_phase = phase_id;
|
|
} else if (mac_zc_phase_is_active(&zc_ctxt->phase_info[phase_id]) \
|
|
&& (1 == mac_zc_get_active_phase_cnt(zc_ctxt))) {
|
|
/* only cap0's phase active, no need swap */
|
|
return 0;
|
|
} else {
|
|
/* if cap0 connect to first support phase(e.g. PhaseA), and the last_ts
|
|
* of this phase is the max(max_phase), then need swap this phase to
|
|
* other cap. otherwise not need swap phase map info with return 0.
|
|
*/
|
|
phase_id = iot_bitops_ffs(support_bitmap) - 1;
|
|
if ((mac_zc_map_info_cap2phase(zc_ctxt, MAC_ZC_HW_CAP0) != phase_id) \
|
|
|| (max_phase != phase_id)) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint8_t cnt;
|
|
phase_id = max_phase;
|
|
for (cnt = 0; cnt < MAC_ZC_PHASE_CNT; cnt++) {
|
|
phase_id = (phase_id + MAC_ZC_PHASE_CNT - 1) % MAC_ZC_PHASE_CNT;
|
|
if ((1 << phase_id) & support_bitmap) {
|
|
return (max_phase & 0x0F) | ((phase_id << 4) & 0xF0);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static mac_zc_train_status_t mac_zc_train_gen_bound_intr_process(
|
|
mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t cap_id, phase_id, is_abnormal;
|
|
uint8_t is_need_chk = 0;
|
|
uint32_t cur_zc;
|
|
mac_zc_phase_info_t *phase_info;
|
|
|
|
IOT_ASSERT(zc_ctxt);
|
|
|
|
/* update train collect value */
|
|
for (cap_id = MAC_ZC_HW_CAP0; cap_id < MAC_ZC_HW_CAP_CNT; cap_id++) {
|
|
phase_id = mac_zc_map_info_cap2phase(zc_ctxt, cap_id);
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
if (!mac_zc_phase_is_support(zc_ctxt, phase_id)) {
|
|
continue;
|
|
}
|
|
cur_zc = mac_zc_get_cur_zc(zc_ctxt, cap_id);
|
|
if (0 == mac_zc_get_phase_collect_cnt(zc_ctxt, \
|
|
(uint8_t)((1 << MAC_ZC_PHASE_CNT) - 1))) {
|
|
phase_info->last_ts = cur_zc;
|
|
phase_info->period = mac_zc_hw_get_zc_period(cap_id);
|
|
if (phase_info->period) {
|
|
phase_info->collect_cnt = 1;
|
|
} else {
|
|
phase_info->collect_cnt = 0;
|
|
}
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
|
|
iot_printf("[zc]train_bound:init-phase:%d,cap:%d,cur=%u,"
|
|
"period:%u\n", \
|
|
phase_id, cap_id, cur_zc, phase_info->period);
|
|
#endif
|
|
continue;
|
|
}
|
|
/* in state train_bound_wait always full period collect,
|
|
* so set function parameter is_half_clct = 0
|
|
*/
|
|
is_abnormal = mac_zc_update_collect_info(zc_ctxt, phase_id, 0,
|
|
cur_zc, 0);
|
|
/* update phase train cnt. reuse abnormal_cnt to save the phase
|
|
* train collect cnt
|
|
*/
|
|
if (is_abnormal) {
|
|
/* if this phase collect error, re-training */
|
|
mac_zc_phase_collect_cnt_clr(zc_ctxt, (uint8_t)(1 << phase_id));
|
|
} else if (mac_zc_get_phase_collect_cnt(zc_ctxt, \
|
|
(uint8_t)(1 << phase_id)) > MAC_ZC_TRAIN_BOUND_CONS_CNT) {
|
|
is_need_chk = 1;
|
|
}
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
|
|
iot_printf("[zc]train_bound:cap:%d,phase_chk=%d,is_aborn=%d,"
|
|
"zc=%u,avg=%u,collect_cnt=%d\n",
|
|
cap_id, phase_id, is_abnormal, cur_zc,
|
|
phase_info->period,
|
|
phase_info->collect_cnt);
|
|
#endif
|
|
}
|
|
|
|
if (is_need_chk) {
|
|
/* update phase status */
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
|
|
phase_id++) {
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
phase_info->collect_sts = (phase_info->collect_cnt > \
|
|
(MAC_ZC_TRAIN_BOUND_CONS_CNT - MAC_ZC_TRAIN_BOUND_MARGIN_CNT))\
|
|
? MAC_ZC_COLLECT_ACTIVE : MAC_ZC_COLLECT_INACTIVE;
|
|
/* clean inactive phase's last_zc and period for not trigger
|
|
* by system tick timer
|
|
*/
|
|
if (MAC_ZC_COLLECT_INACTIVE == phase_info->collect_sts) {
|
|
phase_info->last_ts = 0;
|
|
phase_info->period = 0;
|
|
} else {
|
|
phase_info->start_ntb = phase_info->last_ts;
|
|
|
|
iot_printf("zc:phase:%d, start_ts=%u\n",
|
|
phase_id, phase_info->start_ntb);
|
|
}
|
|
mac_status_zc_status_para_update(
|
|
(uint8_t)mac_zc_phase_is_active(phase_info), phase_id);
|
|
}
|
|
|
|
mac_zc_repeat_connect_check(zc_ctxt);
|
|
mac_zc_update_ref_phase_id(zc_ctxt, MAC_ZC_PHASE_ALL);
|
|
mac_zc_system_status_print(zc_ctxt);
|
|
return MAC_ZC_TRAIN_SUCCESS;
|
|
}
|
|
|
|
return MAC_ZC_TRAIN_ONGOING;
|
|
}
|
|
|
|
static uint8_t mac_zc_cal_collect_phase_bitmap(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t phase_id, phase_bitmap;
|
|
mac_zc_phase_info_t *phase_info;
|
|
|
|
//support_phase_bitmap same as phase_info->enable
|
|
phase_bitmap = (uint8_t)(zc_ctxt->check_phase_bitmap \
|
|
& zc_ctxt->nv_info.support_phase_bitmap);
|
|
|
|
#if MAC_ZC_COLLECT_DEBUG_ENA
|
|
mac_zc_set_phase_bitmap(&zc_ctxt->bitmap_trace ,
|
|
(zc_ctxt->check_phase_bitmap & (~phase_bitmap)), MAC_ZC_CALL_CAL);
|
|
#endif
|
|
|
|
if (!phase_bitmap) {
|
|
#if MAC_ZC_COLLECT_DEBUG_ENA
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)zc_ctxt,
|
|
sizeof(*zc_ctxt)/sizeof(uint32_t));
|
|
#endif
|
|
return 0;
|
|
}
|
|
zc_ctxt->check_phase_bitmap &= ~phase_bitmap;
|
|
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]systick_collect_phase_bitmap=0x%x\n", phase_bitmap);
|
|
#endif
|
|
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
|
|
if (!mac_zc_phase_is_support(zc_ctxt, phase_id)
|
|
|| mac_zc_phase_is_repeat(phase_info, phase_id)
|
|
|| mac_zc_phase_is_active(phase_info)) {
|
|
continue;
|
|
}
|
|
|
|
/* for some phase not collect, maybe this phase restore,
|
|
* force trigger collect the phase.
|
|
*/
|
|
if (!phase_info->last_ts
|
|
|| ((uint32_t)IOT_ABS((int32_t)(mac_sched_get_ntb(NULL)
|
|
- phase_info->last_ts)) > phase_info->period)) {
|
|
phase_bitmap |= 1 << phase_id;
|
|
}
|
|
}
|
|
|
|
return phase_bitmap;
|
|
}
|
|
|
|
#if MAC_ZC_UPDATE_DLY_INFO_ENA
|
|
|
|
/* calculate the delayed periods since last update phase info */
|
|
static uint32_t mac_zc_calc_dly_periods(mac_zc_ctxt_t *zc_ctxt, uint8_t phase)
|
|
{
|
|
|
|
mac_zc_phase_info_t *phase_info;
|
|
uint32_t abs_diff_ntb, period;
|
|
uint32_t dly_periods = 0;
|
|
|
|
IOT_ASSERT(zc_ctxt && (phase < MAC_ZC_PHASE_CNT));
|
|
if (!mac_zc_is_collecting(zc_ctxt)) {
|
|
return dly_periods;
|
|
}
|
|
|
|
phase_info = &zc_ctxt->phase_info[phase];
|
|
abs_diff_ntb = IOT_ABS((int32_t)(mac_sched_get_ntb(NULL) -
|
|
phase_info->last_ts));
|
|
period = phase_info->period >> (zc_ctxt->nv_info.is_switch_gpio_clct);
|
|
|
|
/* calc active phase real delayed periods, inactive phase return 0 */
|
|
if (mac_zc_phase_is_active(phase_info) && period &&
|
|
(abs_diff_ntb > (period + MAC_ZC_HW_CAP_INT_PROTECT_NTB))) {
|
|
dly_periods = (abs_diff_ntb - MAC_ZC_HW_CAP_INT_PROTECT_NTB) / period;
|
|
iot_printf("zc:dly_chk. phase=%d, cur_ntb=%u, last_ts=%u, widx=%d"
|
|
"dly_periods=%u\n", phase, mac_sched_get_ntb(NULL),
|
|
phase_info->last_ts, phase_info->write_idx, dly_periods);
|
|
}
|
|
|
|
return dly_periods;
|
|
}
|
|
|
|
/* update zc delayed info when task is delayed */
|
|
static void mac_zc_update_dly_info(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint32_t dly_periods, wr_idx;
|
|
uint8_t phase_id, is_half_clct;
|
|
mac_zc_phase_info_t *phase_info;
|
|
|
|
IOT_ASSERT(zc_ctxt);
|
|
if (!mac_zc_is_collecting(zc_ctxt)) {
|
|
return;
|
|
}
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
if ((!mac_zc_phase_is_support(zc_ctxt, phase_id)) ||
|
|
(!mac_zc_phase_is_active(phase_info))) {
|
|
continue;
|
|
}
|
|
dly_periods = mac_zc_calc_dly_periods(zc_ctxt, phase_id);
|
|
|
|
/* only when dly_periods >= 2 update dly_info, to avoid three phase
|
|
* LN reverse, reversed phase always be updated by this function.
|
|
* for long time running, deviation will be larger than one period.
|
|
*/
|
|
if (dly_periods < 2) {
|
|
continue;
|
|
}
|
|
is_half_clct = mac_zc_is_half_clct_state(zc_ctxt, phase_id);
|
|
wr_idx = phase_info->write_idx;
|
|
/* update zc phase info */
|
|
for (uint32_t i = 0; i < dly_periods; i++) {
|
|
phase_info->last_ts += (phase_info->period >> is_half_clct);
|
|
phase_info->ntb_ring[wr_idx] = phase_info->last_ts;
|
|
if (++wr_idx >= phase_info->ntb_ring_size) {
|
|
IOT_ASSERT(wr_idx == phase_info->ntb_ring_size);
|
|
/* update the ntb ring buffer full wrap */
|
|
phase_info->is_ring_full = 1;
|
|
wr_idx = 0;
|
|
}
|
|
}
|
|
phase_info->write_idx = wr_idx;
|
|
iot_printf("zc:dly_update. phase-%d,ring[%u]=%u\n", phase_id,
|
|
mac_zc_ring_get_last_idx(phase_info), phase_info->last_ts);
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
#define mac_zc_update_dly_info(zc_ctxt) ((void)(zc_ctxt))
|
|
|
|
#endif
|
|
|
|
/* update collected ntb of corresponding phase and return abnormal phase bitmap */
|
|
static uint8_t mac_zc_phase_collect(mac_zc_ctxt_t *zc_ctxt,
|
|
uint8_t is_update_ring, uint8_t collect_phase_bitmap)
|
|
{
|
|
uint8_t phase_id, is_abnormal, abnormal_phase_bitmap = 0;
|
|
uint8_t is_half_clct;
|
|
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]%s:0x%x\n", __FUNCTION__, collect_phase_bitmap);
|
|
#endif
|
|
|
|
while (collect_phase_bitmap) {
|
|
phase_id = iot_bitops_ffs(collect_phase_bitmap) - 1;
|
|
IOT_ASSERT(phase_id < MAC_ZC_PHASE_CNT);
|
|
collect_phase_bitmap &= ~(1 << phase_id);
|
|
is_half_clct = mac_zc_is_half_clct_state(zc_ctxt, phase_id);
|
|
is_abnormal = mac_zc_update_collect_info(zc_ctxt, phase_id, \
|
|
is_update_ring, mac_zc_get_cur_zc(zc_ctxt, \
|
|
mac_zc_map_info_phase2cap(zc_ctxt, phase_id)), is_half_clct);
|
|
abnormal_phase_bitmap |= is_abnormal << phase_id;
|
|
}
|
|
mac_zc_update_info_check(zc_ctxt);
|
|
|
|
return abnormal_phase_bitmap;
|
|
}
|
|
|
|
static void mac_zc_phase_collect_start_ts_update(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t phase_id;
|
|
uint32_t last_idx;
|
|
mac_zc_phase_info_t *phase_info;
|
|
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
if (!phase_info->collect_sts) {
|
|
continue;
|
|
}
|
|
|
|
if (mac_zc_is_ring_empty(phase_info)) {
|
|
phase_info->start_ntb = phase_info->last_ts;
|
|
} else {
|
|
last_idx = mac_zc_ring_get_last_idx(phase_info);
|
|
if (zc_ctxt->nv_info.is_switch_gpio_clct) {
|
|
last_idx &= ~((uint32_t)1);
|
|
}
|
|
phase_info->start_ntb = phase_info->ntb_ring[last_idx];
|
|
}
|
|
|
|
iot_printf("zc:%d collect start_ts=%u\n",
|
|
phase_id, phase_info->start_ntb);
|
|
}
|
|
}
|
|
|
|
static void mac_zc_phase_collect_start(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t phase_id, max_ts_id, is_first_phase;
|
|
mac_zc_phase_info_t *phase_info;
|
|
uint32_t w_ntb;
|
|
|
|
mac_zc_phase_ring_reset(zc_ctxt);
|
|
|
|
max_ts_id = MAC_ZC_PHASE_CNT;
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
|
|
if (!phase_info->collect_sts
|
|
|| !mac_zc_phase_is_support(zc_ctxt, phase_id)) {
|
|
continue;
|
|
}
|
|
|
|
if (MAC_ZC_PHASE_CNT == max_ts_id) {
|
|
max_ts_id = phase_id;
|
|
continue;
|
|
}
|
|
|
|
if (mac_zc_ntb_is_larger_ref(phase_info->start_ntb,
|
|
zc_ctxt->phase_info[max_ts_id].start_ntb)) {
|
|
max_ts_id = phase_id;
|
|
}
|
|
}
|
|
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]collect_start. max ts id %d\n", max_ts_id);
|
|
#endif
|
|
|
|
is_first_phase = 1;
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT; phase_id++) {
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
|
|
if (!phase_info->collect_sts
|
|
|| !mac_zc_phase_is_support(zc_ctxt, phase_id)) {
|
|
continue;
|
|
}
|
|
|
|
if (is_first_phase && (phase_id == max_ts_id)) {
|
|
phase_info->start_ntb -= phase_info->period;
|
|
}
|
|
|
|
w_ntb = phase_info->start_ntb;
|
|
is_first_phase = 0;
|
|
|
|
do {
|
|
mac_zc_phase_ring_write(zc_ctxt, phase_id, w_ntb);
|
|
|
|
w_ntb += phase_info->period >> zc_ctxt->nv_info.is_switch_gpio_clct;
|
|
int32_t delta = (int32_t)(phase_info->last_ts - w_ntb);
|
|
if ((IOT_ABS(delta) > MAC_ZC_PERIOD_JITTER_GAP_NTB)
|
|
&& mac_zc_ntb_is_larger_ref(w_ntb, phase_info->last_ts)) {
|
|
break;
|
|
}
|
|
} while (1);
|
|
}
|
|
|
|
mac_zc_update_ref_phase_id(zc_ctxt, MAC_ZC_PHASE_ALL);
|
|
}
|
|
|
|
/* mac_zc collect zc ntb in train state in systick dsr */
|
|
static mac_zc_train_status_t mac_zc_train_systick_intr(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t phase_id, phase_bitmap, is_need_chk = 0, is_abnormal;
|
|
mac_zc_phase_info_t *phase_info;
|
|
|
|
phase_bitmap = mac_zc_cal_collect_phase_bitmap(zc_ctxt);
|
|
mac_zc_phase_collect(zc_ctxt, 1, phase_bitmap);
|
|
while (phase_bitmap) {
|
|
phase_id = iot_bitops_ffs(phase_bitmap) - 1;
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
if (mac_zc_phase_is_support(zc_ctxt, phase_id) \
|
|
&& mac_zc_phase_is_active(phase_info) \
|
|
&& (mac_zc_get_phase_collect_cnt(zc_ctxt, \
|
|
(uint8_t)(1 << phase_id)) > MAC_ZC_TRAIN_SYSTIC_CNT)) {
|
|
is_need_chk = 1;
|
|
break;
|
|
}
|
|
phase_bitmap &= ~(1 << phase_id);
|
|
}
|
|
|
|
if (zc_ctxt->is_need_reset) {
|
|
zc_ctxt->is_need_reset = 0;
|
|
mac_zc_set_func_cmd((uint8_t)zc_ctxt->ref_pdev_id,
|
|
MAC_ZC_FUNC_CMD_DELAY_RESET_HW, NULL);
|
|
return MAC_ZC_TRAIN_FAIL;
|
|
}
|
|
|
|
if (is_need_chk) {
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
|
|
phase_id++) {
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
if (mac_zc_phase_is_support(zc_ctxt, phase_id) \
|
|
&& phase_info->abnormal_cnt > (MAC_ZC_TRAIN_SYSTIC_CNT \
|
|
- MAC_ZC_TRAIN_SYSTIC_MARGIN_CNT) \
|
|
) {
|
|
is_abnormal = !mac_zc_phase_is_active(phase_info);
|
|
phase_info->collect_sts = is_abnormal;
|
|
if (!phase_info->collect_sts) {
|
|
mac_zc_hw_fix_map_gpio2sig(
|
|
zc_ctxt->nv_info.phase_map[phase_id].gpio,
|
|
zc_ctxt->nv_info.phase_map[phase_id].signal);
|
|
}
|
|
}
|
|
mac_status_zc_status_para_update(
|
|
(uint8_t)mac_zc_phase_is_active(phase_info), phase_id);
|
|
}
|
|
mac_zc_phase_collect_start_ts_update(zc_ctxt);
|
|
mac_zc_system_status_print(zc_ctxt);
|
|
return MAC_ZC_TRAIN_SUCCESS;
|
|
} else {
|
|
return MAC_ZC_TRAIN_ONGOING;
|
|
}
|
|
}
|
|
|
|
/* mac_zc collect zc ntb and update power status in systick dsr */
|
|
static uint32_t mac_zc_systick_collect(mac_zc_ctxt_t *zc_ctxt)
|
|
{
|
|
uint8_t phase_id, phase_bitmap, is_abnormal;
|
|
uint8_t ref_abnormal_cnt;
|
|
uint8_t is_power_change = 0;
|
|
mac_zc_phase_info_t *phase_info;
|
|
|
|
phase_id = mac_zc_cal_collect_phase_bitmap(zc_ctxt);
|
|
/* phase_bitmap save the phase is abnormal. 0 - normal, 1 - abnormal.
|
|
* bit0 - Phase A, bit1 - Phase B. bit2 - Phase C.
|
|
*/
|
|
phase_bitmap = mac_zc_phase_collect(zc_ctxt, 1, phase_id);
|
|
|
|
/* check power change status */
|
|
while (phase_bitmap) {
|
|
phase_id = iot_bitops_ffs(phase_bitmap) - 1;
|
|
ref_abnormal_cnt = mac_zc_phase_is_active(
|
|
&zc_ctxt->phase_info[phase_id])
|
|
? MAC_ZC_COLLECT_LOSS_CNT : MAC_ZC_COLLECT_RESTORE_CNT;
|
|
if (zc_ctxt->phase_info[phase_id].abnormal_cnt > ref_abnormal_cnt) {
|
|
is_power_change = 1;
|
|
break;
|
|
}
|
|
phase_bitmap &= ~(1 << phase_id);
|
|
}
|
|
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1 && MAC_ZC_COLLECT_DEBUG_ENA)
|
|
iot_printf("cur_wr_idx=%d\n", zc_ctxt->bitmap_trace.wr_idx);
|
|
for(uint16_t i = 0 ; i < MAC_ZC_BITMAP_TRACE_BUF_SIZE; i++) {
|
|
iot_printf("caller_id:%x, bitmap_val:%d, ts:%u, idx:%d\n",
|
|
zc_ctxt->bitmap_trace.trace_buf[i].func_traced_ra,
|
|
zc_ctxt->bitmap_trace.trace_buf[i].set_bitmap_val,
|
|
zc_ctxt->bitmap_trace.trace_buf[i].set_bitmap_ts, i);
|
|
}
|
|
#endif
|
|
|
|
if (zc_ctxt->is_need_reset) {
|
|
zc_ctxt->is_need_reset = 0;
|
|
mac_zc_set_func_cmd((uint8_t)zc_ctxt->ref_pdev_id,
|
|
MAC_ZC_FUNC_CMD_DELAY_RESET_HW, NULL);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* update phase status */
|
|
if (is_power_change) {
|
|
phase_bitmap = 0;
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
|
|
phase_id++) {
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
ref_abnormal_cnt = mac_zc_phase_is_active(phase_info)
|
|
? (MAC_ZC_COLLECT_LOSS_CNT - MAC_ZC_COLLECT_LOSS_MARGIN_CNT)
|
|
: (MAC_ZC_COLLECT_RESTORE_CNT
|
|
- MAC_ZC_COLLECT_RESTORE_MARGIN_CNT);
|
|
if (phase_info->abnormal_cnt > ref_abnormal_cnt) {
|
|
os_disable_irq();
|
|
/* reuse is_abnormal to save phase collect status */
|
|
is_abnormal = !(uint8_t)phase_info->collect_sts;
|
|
/* update phase status ctxt */
|
|
phase_info->collect_sts = is_abnormal;
|
|
os_enable_irq();
|
|
/* phase inactive map default gpio to signal */
|
|
if (!is_abnormal && mac_zc_phase_is_support(zc_ctxt, phase_id))
|
|
{
|
|
mac_zc_hw_fix_map_gpio2sig(
|
|
zc_ctxt->nv_info.phase_map[phase_id].gpio,
|
|
zc_ctxt->nv_info.phase_map[phase_id].signal);
|
|
}
|
|
/* reuse phase_bitmap save the phase event.
|
|
* bit1:0 - Phase A, bit3:2 - Phase B. bit5:4- Phase C.
|
|
*/
|
|
phase_bitmap |= (uint8_t)((is_abnormal ?
|
|
MAC_ZC_EVENT_PHASE_RESTORE : MAC_ZC_EVENT_PHASE_LOSS)
|
|
<< (iot_bitops_fls(MAC_ZC_EVENT_MAX) * phase_id));
|
|
/* do clean this phase ctxt */
|
|
/* clean this phase abnormal cnt */
|
|
phase_info->abnormal_cnt = 0;
|
|
mac_status_add_zc_phase_chg_cnt(phase_id);
|
|
mac_status_zc_status_para_update(
|
|
(uint8_t)mac_zc_phase_is_active(phase_info), phase_id);
|
|
}
|
|
}
|
|
|
|
mac_zc_phase_collect_start_ts_update(zc_ctxt);
|
|
mac_zc_repeat_connect_check(zc_ctxt);
|
|
mac_zc_set_event(zc_ctxt, (uint32_t)phase_bitmap);
|
|
/* for power collapsed, not update reference phase id */
|
|
if (!mac_zc_is_power_collapsed((uint8_t)zc_ctxt->ref_pdev_id)) {
|
|
mac_zc_update_ref_phase_id(zc_ctxt, MAC_ZC_PHASE_ALL);
|
|
}
|
|
mac_zc_system_status_print(zc_ctxt);
|
|
mac_zc_phase_collect_start(zc_ctxt);
|
|
}
|
|
return ERR_OK;
|
|
}
|
|
|
|
static mac_zc_sm_id_t mac_zc_sm_idle_exec(mac_zc_ctxt_t *zc_ctxt,
|
|
mac_zc_triger_id_t trigger_id)
|
|
{
|
|
mac_zc_sm_id_t next_sm = MAC_ZC_SM_IDLE;
|
|
|
|
IOT_ASSERT(zc_ctxt);
|
|
switch (trigger_id) {
|
|
case MAC_ZC_TRIG_SYS_START_REQ:
|
|
case MAC_ZC_TRIG_TRAIN_TIMER:
|
|
if (ERR_OK != mac_zc_system_start(zc_ctxt)) {
|
|
//TODO: replace assert with abnormal flash log
|
|
//next_sm = MAC_ZC_SM_IDLE;
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)zc_ctxt, \
|
|
sizeof(*zc_ctxt) / sizeof(uint32_t));
|
|
break;
|
|
}
|
|
/* clean train elapsed time ctxt */
|
|
zc_ctxt->train_elapsed_time = 0;
|
|
/* WAR: delay for wait mac zc ac track hw ready
|
|
* if timeout, will entry this sm MAC_ZC_TRIG_TRAIN_TIMER
|
|
*/
|
|
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_AC_TRACK_TIME_MS);
|
|
next_sm = MAC_ZC_SM_INITED;
|
|
break;
|
|
|
|
case MAC_ZC_TRIG_SYS_STOP_REQ:
|
|
mac_zc_system_stop(zc_ctxt);
|
|
next_sm = MAC_ZC_SM_IDLE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return next_sm;
|
|
}
|
|
|
|
static mac_zc_sm_id_t mac_zc_sm_inited_exec(mac_zc_ctxt_t *zc_ctxt,
|
|
mac_zc_triger_id_t trigger_id)
|
|
{
|
|
mac_zc_sm_id_t next_sm = MAC_ZC_SM_INITED;
|
|
|
|
IOT_ASSERT(zc_ctxt);
|
|
switch (trigger_id) {
|
|
case MAC_ZC_TRIG_TRAIN_TIMER:
|
|
/* zc hw ready. ac track running. then trigger gen hw */
|
|
/* re-cfg hw collect interval after collect edge is seleceted */
|
|
mac_zc_hw_set_vibrate_protect_dur(MAC_ZC_HW_VIBRATE_PROTECT_NTB);
|
|
/* disable square wave upper bound interrupt */
|
|
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
|
|
/* cfg sw produce square wave by zc sw */
|
|
mac_zc_hw_gen_set_gen_sel_mtx(MAC_ZC_HW_GEN_SELIN_INTERNAL);
|
|
/* delay 4s for hw traning, then cfg hw produce square wave*/
|
|
/* if timeout, will entry MAC_ZC_SM_TRAIN_GEN_READY's
|
|
* MAC_ZC_TRIG_TRAIN_TIMER
|
|
*/
|
|
/* map default gpio to signal */
|
|
if (zc_ctxt->nv_info.is_switch_gpio_clct) {
|
|
mac_zc_hw_map_def_gpio(zc_ctxt);
|
|
}
|
|
next_sm = MAC_ZC_SM_TRAIN_INIT;
|
|
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_GEN_SW_MTX_TIME_MS);
|
|
break;
|
|
|
|
case MAC_ZC_TRIG_SYS_STOP_REQ:
|
|
mac_zc_system_stop(zc_ctxt);
|
|
next_sm = MAC_ZC_SM_IDLE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return next_sm;
|
|
}
|
|
|
|
/* mac_zc train hw init or do gpio and signal mapping swap */
|
|
static mac_zc_sm_id_t mac_zc_sm_train_init_exec(mac_zc_ctxt_t *zc_ctxt,
|
|
mac_zc_triger_id_t trigger_id)
|
|
{
|
|
uint8_t phase_id;
|
|
mac_zc_sm_id_t next_sm = MAC_ZC_SM_TRAIN_INIT;
|
|
|
|
IOT_ASSERT(zc_ctxt);
|
|
switch (trigger_id) {
|
|
/* training timer timeout */
|
|
case MAC_ZC_TRIG_TRAIN_TIMER:
|
|
/* this timeout case come from MAC_ZC_SM_INITED's
|
|
* MAC_ZC_TRAIN_GEN_SW_MTX_MS
|
|
*/
|
|
if (MAC_ZC_SM_INITED == zc_ctxt->sm_info.exec_sm) {
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
|
|
phase_id++) {
|
|
zc_ctxt->phase_info[phase_id].last_ts = 0;
|
|
zc_ctxt->phase_info[phase_id].last_switch_lts = 0;
|
|
}
|
|
mac_zc_repeat_phase_init(zc_ctxt);
|
|
|
|
/* config produce square wave base zc hw cap */
|
|
mac_zc_hw_gen_set_gen_sel_mtx(MAC_ZC_HW_GEN_SELIN_CAP0);
|
|
/* enable square wave upper bound interrupt. start collect */
|
|
mac_zc_upper_bound_intr_ena(zc_ctxt, 1);
|
|
/* for switch zc gen select to hw input, wait upper/low bound
|
|
* interrupt, if timeout, means cap0 map phase not zc,
|
|
* then need swich phase map(the next else_if case).
|
|
*/
|
|
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_BOUND_INT_WAIT_MS);
|
|
} else if (MAC_ZC_SM_TRAIN_INIT == zc_ctxt->sm_info.exec_sm) {
|
|
/* collect timeout, switch phase map info */
|
|
/* disable square wave upper bound interrupt */
|
|
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
|
|
phase_id = mac_zc_get_swap_phase_id(zc_ctxt);
|
|
if (phase_id) {
|
|
mac_zc_exec_swap_phase_map(\
|
|
&zc_ctxt->nv_info.phase_map[phase_id & 0x0F], \
|
|
&zc_ctxt->nv_info.phase_map[phase_id >> 4]);
|
|
}
|
|
|
|
/* re-train */
|
|
next_sm = MAC_ZC_SM_INITED;
|
|
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_FORCE_TIME_MS);
|
|
mac_zc_hw_capx_trig(MAC_ZC_HW_BITMAP_CAP_ALL);
|
|
}
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
else {
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)zc_ctxt,
|
|
sizeof(*zc_ctxt)/sizeof(uint32_t));
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case MAC_ZC_TRIG_HW_UPPER_BOUND_INT:
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
/* check cap edge config matched current real cap edge. */
|
|
if (mac_zc_hw_get_curr_cap_edge() != mac_zc_hw_cap_get_edge()) {
|
|
/* TODO: only support phaseA */
|
|
iot_printf("[zc]get_cap_edge_not_match:%d:%d\n",
|
|
mac_zc_hw_get_curr_cap_edge(), mac_zc_hw_cap_get_edge());
|
|
}
|
|
#endif
|
|
/* stop this sm training timer when cap0 captured data */
|
|
mac_zc_train_timer_stop(zc_ctxt);
|
|
/* for all phase train fail or not train, set the all enable's
|
|
* phase is active to start training.
|
|
*/
|
|
mac_zc_all_phase_init_active_sts(zc_ctxt);
|
|
/* clear all phase collect counter */
|
|
mac_zc_phase_collect_cnt_clr(zc_ctxt, \
|
|
(uint8_t)((1 << MAC_ZC_PHASE_CNT) - 1));
|
|
|
|
/* force ref phase id set to cap0's phase.
|
|
* at this state, all the zc data is collected based on cap0.
|
|
*/
|
|
mac_zc_update_ref_phase_id(zc_ctxt, \
|
|
mac_zc_map_info_cap2phase(zc_ctxt, MAC_ZC_HW_CAP0));
|
|
|
|
/* if timeout, will entry this sm MAC_ZC_TRIG_TRAIN_TIMER */
|
|
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_GEN_INTR_TIME_MS);
|
|
/* set next state */
|
|
next_sm = MAC_ZC_SM_TRAIN_BOUND_INTR_WAIT;
|
|
mac_zc_hw_capx_trig(MAC_ZC_HW_BITMAP_CAP_ALL);
|
|
break;
|
|
|
|
case MAC_ZC_TRIG_SYS_STOP_REQ:
|
|
mac_zc_system_stop(zc_ctxt);
|
|
next_sm = MAC_ZC_SM_IDLE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return next_sm;
|
|
}
|
|
|
|
/* mac_zc train zc collect in upper bound interrupt dsr */
|
|
static mac_zc_sm_id_t mac_zc_sm_train_bound_intr_wait_exec(
|
|
mac_zc_ctxt_t *zc_ctxt, mac_zc_triger_id_t trigger_id)
|
|
{
|
|
mac_zc_sm_id_t next_sm = MAC_ZC_SM_TRAIN_BOUND_INTR_WAIT;
|
|
uint8_t phase_id;
|
|
|
|
IOT_ASSERT(zc_ctxt);
|
|
switch (trigger_id) {
|
|
case MAC_ZC_TRIG_HW_UPPER_BOUND_INT:
|
|
if (MAC_ZC_TRAIN_SUCCESS == \
|
|
mac_zc_train_gen_bound_intr_process(zc_ctxt)) {
|
|
mac_zc_train_timer_stop(zc_ctxt);
|
|
phase_id = mac_zc_get_swap_phase_id(zc_ctxt);
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]get_swap_phase:%d-%d\n", \
|
|
phase_id & 0x0F, phase_id >> 4);
|
|
#endif
|
|
if (phase_id) {
|
|
/* TODO: maybe not need set next sm to MAC_ZC_SM_INITED.
|
|
* 1. not disable mac_zc_upper_bound_int_ena()
|
|
* 2. set zc_ctxt->train_collect_cnt, prev/ave_period....
|
|
* 3. retrain use current sm.
|
|
*/
|
|
mac_zc_exec_swap_phase_map(\
|
|
&zc_ctxt->nv_info.phase_map[phase_id & 0x0F],
|
|
&zc_ctxt->nv_info.phase_map[(phase_id >> 4) & 0x0F]);
|
|
/* re-train */
|
|
next_sm = MAC_ZC_SM_INITED;
|
|
mac_zc_train_timer_start(zc_ctxt, \
|
|
MAC_ZC_TRAIN_FORCE_TIME_MS);
|
|
} else {
|
|
/* not phase exchange, then goto next state */
|
|
/* disable upper bound interrupt, use systick tigger collect */
|
|
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
|
|
zc_ctxt->check_phase_bitmap = 0;
|
|
#if MAC_ZC_COLLECT_DEBUG_ENA
|
|
mac_zc_set_phase_bitmap(&zc_ctxt->bitmap_trace,
|
|
zc_ctxt->check_phase_bitmap, MAC_ZC_CALL_BOUND);
|
|
#endif
|
|
/* verify that all supported/enable phase have successfully
|
|
* trained. if all the phase are trained successfully, then the
|
|
* state go to MAC_ZC_SM_COLLECT, otherwise the state go to
|
|
* MAC_ZC_SM_TRAIN_SYSTICK_WAIT.
|
|
*/
|
|
for (phase_id = MAC_ZC_PHASE_A; phase_id < MAC_ZC_PHASE_CNT;
|
|
phase_id++) {
|
|
if (!mac_zc_phase_is_active(&zc_ctxt->phase_info[phase_id])
|
|
&& mac_zc_phase_is_support(zc_ctxt, phase_id)) {
|
|
/* support this phase, but inactive */
|
|
break;
|
|
}
|
|
}
|
|
/* update next state mechine */
|
|
if (zc_ctxt->nv_info.is_switch_gpio_clct) {
|
|
/* start switch gpio mapping to signal */
|
|
next_sm = MAC_ZC_SM_TRAIN_SYSTICK_WAIT;
|
|
} else if (phase_id < MAC_ZC_PHASE_CNT) {
|
|
/* some support phase train failed. systick wait sm train */
|
|
next_sm = MAC_ZC_SM_TRAIN_SYSTICK_WAIT;
|
|
} else {
|
|
/* all support phase train success, also need systick wait
|
|
* sm train, to avoid sw_period result influenced by a bad
|
|
* hw_period in MAC_ZC_SM_COLLECT state
|
|
*/
|
|
next_sm = MAC_ZC_SM_TRAIN_SYSTICK_WAIT;
|
|
}
|
|
|
|
/* clear all phase collect counter */
|
|
mac_zc_phase_collect_cnt_clr(zc_ctxt, \
|
|
(uint8_t)((1 << MAC_ZC_PHASE_CNT) - 1));
|
|
mac_zc_phase_collect_start(zc_ctxt);
|
|
/* enable systic trigger */
|
|
zc_ctxt->systic_trig_en = 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* train upper bound int timeout */
|
|
case MAC_ZC_TRIG_TRAIN_TIMER:
|
|
/* disable upper bound interrupt */
|
|
mac_zc_upper_bound_intr_ena(zc_ctxt, 0);
|
|
/* disable systic trigger */
|
|
zc_ctxt->systic_trig_en = 0;
|
|
/* re-train */
|
|
next_sm = MAC_ZC_SM_INITED;
|
|
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_FORCE_TIME_MS);
|
|
break;
|
|
|
|
case MAC_ZC_TRIG_SYS_STOP_REQ:
|
|
mac_zc_system_stop(zc_ctxt);
|
|
next_sm = MAC_ZC_SM_IDLE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return next_sm;
|
|
}
|
|
|
|
/* mac_zc train zc collect function in systick interrupt dsr */
|
|
static mac_zc_sm_id_t mac_zc_sm_train_systick_wait_exec(mac_zc_ctxt_t *zc_ctxt,
|
|
mac_zc_triger_id_t trigger_id)
|
|
{
|
|
mac_zc_sm_id_t next_sm = MAC_ZC_SM_TRAIN_SYSTICK_WAIT;
|
|
|
|
IOT_ASSERT(zc_ctxt);
|
|
switch (trigger_id) {
|
|
case MAC_ZC_TRIG_SYSTIC_TIMER:
|
|
switch (mac_zc_train_systick_intr(zc_ctxt)) {
|
|
case MAC_ZC_TRAIN_SUCCESS:
|
|
/* init ctxt */
|
|
mac_zc_all_phase_abnormal_cnt_clr(zc_ctxt);
|
|
mac_zc_repeat_connect_check(zc_ctxt);
|
|
mac_zc_update_ref_phase_id(zc_ctxt, MAC_ZC_PHASE_ALL);
|
|
mac_zc_phase_collect_start(zc_ctxt);
|
|
/* set next state */
|
|
next_sm = MAC_ZC_SM_COLLECT;
|
|
break;
|
|
|
|
case MAC_ZC_TRAIN_ONGOING:
|
|
case MAC_ZC_TRAIN_FAIL:
|
|
default:
|
|
break;
|
|
}
|
|
/* enable systic trigger */
|
|
zc_ctxt->systic_trig_en = 1;
|
|
break;
|
|
case MAC_ZC_TRIG_SYS_STOP_REQ:
|
|
mac_zc_system_stop(zc_ctxt);
|
|
next_sm = MAC_ZC_SM_IDLE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return next_sm;
|
|
}
|
|
|
|
/* mac_zc collect execute function in state machine */
|
|
static mac_zc_sm_id_t mac_zc_sm_collect_exec(mac_zc_ctxt_t *zc_ctxt,
|
|
mac_zc_triger_id_t trigger_id)
|
|
{
|
|
mac_zc_sm_id_t next_sm = MAC_ZC_SM_COLLECT;
|
|
|
|
switch (trigger_id) {
|
|
case MAC_ZC_TRIG_SYSTIC_TIMER:
|
|
mac_zc_systick_collect(zc_ctxt);
|
|
mac_zc_update_dly_info(zc_ctxt);
|
|
/* enable systic trigger */
|
|
zc_ctxt->systic_trig_en = 1;
|
|
break;
|
|
case MAC_ZC_TRIG_SYS_STOP_REQ:
|
|
mac_zc_system_stop(zc_ctxt);
|
|
next_sm = MAC_ZC_SM_IDLE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return next_sm;
|
|
}
|
|
|
|
/* mac_zc collect state machine */
|
|
static void mac_zc_state_machine(mac_zc_ctxt_t *zc_ctxt,
|
|
mac_zc_triger_id_t trigger_id)
|
|
{
|
|
mac_zc_sm_id_t cur_sm, next_sm;
|
|
|
|
IOT_ASSERT(zc_ctxt);
|
|
|
|
cur_sm = (mac_zc_sm_id_t)zc_ctxt->sm_info.cur_sm;
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]sm:%d,trig:%d\n", cur_sm, trigger_id);
|
|
#endif
|
|
switch (cur_sm) {
|
|
case MAC_ZC_SM_IDLE:
|
|
next_sm = mac_zc_sm_idle_exec(zc_ctxt, trigger_id);
|
|
break;
|
|
case MAC_ZC_SM_INITED:
|
|
next_sm = mac_zc_sm_inited_exec(zc_ctxt, trigger_id);
|
|
break;
|
|
case MAC_ZC_SM_TRAIN_INIT:
|
|
next_sm = mac_zc_sm_train_init_exec(zc_ctxt, trigger_id);
|
|
break;
|
|
case MAC_ZC_SM_TRAIN_BOUND_INTR_WAIT:
|
|
next_sm = mac_zc_sm_train_bound_intr_wait_exec(zc_ctxt, trigger_id);
|
|
break;
|
|
case MAC_ZC_SM_TRAIN_SYSTICK_WAIT:
|
|
next_sm = mac_zc_sm_train_systick_wait_exec(zc_ctxt, trigger_id);
|
|
break;
|
|
case MAC_ZC_SM_COLLECT:
|
|
next_sm = mac_zc_sm_collect_exec(zc_ctxt, trigger_id);
|
|
break;
|
|
default:
|
|
IOT_ASSERT_DUMP(0, (uint32_t *)zc_ctxt, sizeof(*zc_ctxt));
|
|
next_sm = MAC_ZC_SM_IDLE;
|
|
break;
|
|
}
|
|
if (next_sm != cur_sm)
|
|
{
|
|
iot_printf("zc:state %d to %d.trig:%d, is_power_collapsed=%d\n",
|
|
(uint8_t)cur_sm, (uint8_t)next_sm, trigger_id,
|
|
mac_zc_is_power_collapsed((uint8_t)zc_ctxt->ref_pdev_id));
|
|
zc_ctxt->sm_info.prev_sm = (uint32_t)cur_sm;
|
|
zc_ctxt->sm_info.cur_sm = (uint32_t)next_sm;
|
|
|
|
/* trigger start system daemon function */
|
|
if (MAC_ZC_SM_COLLECT == next_sm) {
|
|
mac_zc_train_timer_stop(zc_ctxt);
|
|
zc_ctxt->train_elapsed_time = 0;
|
|
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_SYS_DAEMON_PERIOD_MS);
|
|
}
|
|
}
|
|
zc_ctxt->sm_info.exec_sm = cur_sm;
|
|
}
|
|
|
|
/* mac_zc find target ntb position in phase ring and return valid ntb count */
|
|
static uint32_t mac_zc_get_ring_positon_by_ntb(mac_zc_ctxt_t *zc_ctxt,
|
|
uint8_t phase_id, uint32_t tgt_ntb, uint32_t *find_pos,
|
|
uint8_t is_half_clct, uint8_t edge_tp)
|
|
{
|
|
mac_zc_phase_info_t *phase_info = &zc_ctxt->phase_info[phase_id];
|
|
uint32_t find_cnt = 0;
|
|
uint32_t start_pos;
|
|
uint32_t end_pos;
|
|
uint32_t data_sz;
|
|
uint32_t wnd_st;
|
|
uint32_t wnd_end;
|
|
uint32_t mapped_idx;
|
|
uint32_t real_idx;
|
|
int32_t tmp_delta;
|
|
uint32_t search_wnd_half;
|
|
uint32_t period;
|
|
uint64_t start_ntb;
|
|
uint64_t end_ntb;
|
|
uint64_t mapped_tgt_ntb;
|
|
|
|
/* sanity check */
|
|
if (!phase_info || !find_pos || !phase_info->ntb_ring ||
|
|
(phase_info->ntb_ring_size > (((uint32_t)-1) / phase_info->period))) {
|
|
iot_printf("zc:find_ntb_dump: %p, %p, %p, %d\n", phase_info,
|
|
find_pos, phase_info->ntb_ring, phase_info->ntb_ring_size);
|
|
IOT_ASSERT(0);
|
|
return find_cnt;
|
|
}
|
|
if (!mac_zc_phase_is_support(zc_ctxt, phase_id) ||
|
|
(!phase_info->is_ring_full && !phase_info->write_idx)) {
|
|
return find_cnt;
|
|
}
|
|
/* calc period according to hw zc collect method */
|
|
period = (is_half_clct) ? (phase_info->period >> 1) : (phase_info->period);
|
|
search_wnd_half = mac_zc_get_ntb_search_window_half(period);
|
|
|
|
/* calc start position end position and valid data size */
|
|
start_pos = mac_zc_ring_get_first_idx(phase_info);
|
|
end_pos = mac_zc_ring_get_last_idx(phase_info);
|
|
data_sz = mac_zc_ring_get_valid_size(phase_info);
|
|
|
|
/* check if ntb wrap out , if so conpensate it */
|
|
start_ntb = phase_info->ntb_ring[start_pos];
|
|
end_ntb = phase_info->ntb_ring[end_pos];
|
|
mapped_tgt_ntb = tgt_ntb;
|
|
|
|
if (start_ntb > end_ntb) {
|
|
if (!(end_ntb & (1 << 31))) {
|
|
end_ntb |= ((uint64_t)0x1 << 32);
|
|
}
|
|
if (!(mapped_tgt_ntb & (1 << 31))) {
|
|
mapped_tgt_ntb |= ((uint64_t)0x1 << 32);
|
|
}
|
|
}
|
|
if ((mapped_tgt_ntb < start_ntb) || (mapped_tgt_ntb > end_ntb)) {
|
|
return find_cnt;
|
|
}
|
|
|
|
/* calc target ntb mapped index */
|
|
mapped_idx = (uint32_t)iot_ceil(((mapped_tgt_ntb -
|
|
phase_info->ntb_ring[start_pos]) * (data_sz - 1)),
|
|
(end_ntb - phase_info->ntb_ring[start_pos]));
|
|
|
|
#if MAC_ZC_DBG_LOG_LEVEL >= PLC_MAC_LOG_LEVEL_1
|
|
iot_printf("[zc]ring[%d]=%u, is_ring_full=%d\n", start_pos,
|
|
phase_info->ntb_ring[start_pos], phase_info->is_ring_full);
|
|
#endif
|
|
|
|
/* calc the seach window start position */
|
|
wnd_st = max(((int32_t)(mapped_idx - search_wnd_half)), 0);
|
|
wnd_end = min((mapped_idx + search_wnd_half), (data_sz - 1));
|
|
|
|
/* TODO: the size of the dump buffer needs to calculated based
|
|
* on the period
|
|
*/
|
|
/* buffer size = mac_zc_get_ntb_search_window_half(period) * 2 + 1 */
|
|
uint32_t dump_buf[13] = {0};
|
|
|
|
/* find target ntb in the seach window */
|
|
for (mapped_idx = wnd_st; mapped_idx < wnd_end; mapped_idx++) {
|
|
real_idx = mac_zc_ring_get_real_idx(mapped_idx, start_pos, data_sz);
|
|
if (is_half_clct && (mac_zc_get_ring_position_edge(real_idx)
|
|
!= edge_tp)) {
|
|
continue;
|
|
}
|
|
tmp_delta = (int32_t)(tgt_ntb - phase_info->ntb_ring[real_idx]);
|
|
dump_buf[((mapped_idx - wnd_st) >> is_half_clct)] =
|
|
phase_info->ntb_ring[real_idx];
|
|
if ((uint32_t)IOT_ABS(tmp_delta) < phase_info->period) {
|
|
*find_pos = real_idx;
|
|
find_cnt = data_sz - mapped_idx;
|
|
break;
|
|
}
|
|
}
|
|
dump_buf[sizeof(dump_buf)/sizeof(dump_buf[0]) - 1] = tgt_ntb;
|
|
IOT_ASSERT_DUMP(find_cnt, dump_buf, sizeof(dump_buf)/sizeof(uint32_t));
|
|
|
|
return find_cnt;
|
|
}
|
|
|
|
/* mac_zc get position from latest zc_ntb ring foreward by count */
|
|
static uint32_t mac_zc_get_position_by_count(mac_zc_phase_info_t *phase_info,
|
|
uint32_t tar_cnt, uint32_t *find_pos, uint8_t is_half_clct, uint8_t edge_tp)
|
|
{
|
|
uint32_t valid_cnt;
|
|
uint32_t tmp_tar_cnt;
|
|
valid_cnt = phase_info->is_ring_full ? phase_info->ntb_ring_size \
|
|
: phase_info->write_idx;
|
|
tmp_tar_cnt = is_half_clct ? (tar_cnt + 1) : tar_cnt;
|
|
if (tmp_tar_cnt > valid_cnt) {
|
|
*find_pos = mac_zc_ring_get_first_idx(phase_info);
|
|
} else {
|
|
*find_pos = (phase_info->ntb_ring_size + phase_info->write_idx \
|
|
- tmp_tar_cnt) % phase_info->ntb_ring_size;
|
|
}
|
|
if (is_half_clct && (mac_zc_get_ring_position_edge(*find_pos)
|
|
!= edge_tp)) {
|
|
*find_pos = mac_zc_ring_get_legal_idx(phase_info, (*find_pos) + 1);
|
|
if (valid_cnt) {
|
|
valid_cnt--;
|
|
}
|
|
}
|
|
if (valid_cnt > tar_cnt) {
|
|
valid_cnt = tar_cnt;
|
|
}
|
|
return valid_cnt;
|
|
}
|
|
|
|
/* copy ntb from assigned start position of ring buffer to rpt buffer */
|
|
static uint32_t mac_zc_get_ntb_from_phase_ring(mac_zc_ctxt_t *zc_ctxt,
|
|
uint32_t *rpt_buf, uint8_t get_phase_id, uint8_t is_full_period,
|
|
uint32_t count, uint32_t start_pos, uint8_t edge_type)
|
|
{
|
|
uint8_t phase_id, ref_phase, is_half_clct;
|
|
uint32_t tmp;
|
|
uint8_t phase_cnt;
|
|
uint32_t rpt_pos, ring_pos, find_cnt;
|
|
mac_zc_phase_info_t *phase_info[MAC_ZC_PHASE_CNT] = {0};
|
|
|
|
IOT_ASSERT(zc_ctxt);
|
|
if (0 == count) {
|
|
return 0;
|
|
}
|
|
/* get target phase, and save phase_info ptr to phase_info[].
|
|
* phase_id range: MAC_ZC_PHASE_A ~ MAC_ZC_PHASE_C
|
|
*/
|
|
phase_id = (uint8_t)((get_phase_id == MAC_ZC_PHASE_ALL) ? \
|
|
MAC_ZC_PHASE_A : get_phase_id);
|
|
phase_cnt = 0;
|
|
do {
|
|
if (mac_zc_phase_is_active(&zc_ctxt->phase_info[phase_id])) {
|
|
phase_info[phase_cnt++] = &zc_ctxt->phase_info[phase_id];
|
|
}
|
|
} while (++phase_id < get_phase_id);
|
|
|
|
if (!phase_cnt) {
|
|
/* valid phase count = 0, then return find 0 count zc ntb */
|
|
return 0;
|
|
}
|
|
|
|
ring_pos = start_pos;
|
|
ref_phase = (uint8_t)mac_zc_get_ref_phase_id(zc_ctxt);
|
|
is_half_clct = mac_zc_is_half_clct_state(zc_ctxt, ref_phase);
|
|
/* check the same edge offset base on ref phase */
|
|
if (is_half_clct && (mac_zc_get_ring_position_edge(ring_pos)
|
|
!= edge_type)) {
|
|
IOT_ASSERT(0);
|
|
}
|
|
|
|
rpt_pos = 0;
|
|
find_cnt = 0;
|
|
do {
|
|
/* phase_id range: 0 ~ (phase_cnt - 1) */
|
|
for (phase_id = 0; (phase_id < phase_cnt) && (find_cnt < count); \
|
|
phase_id++) {
|
|
rpt_buf[rpt_pos] = phase_info[phase_id]->ntb_ring[ring_pos];
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
|
|
iot_printf("[zc]cp_ring:phase=%d,rpt_buf[%u]<-ring[%u]=%u\n", \
|
|
phase_id, rpt_pos, ring_pos, rpt_buf[rpt_pos]);
|
|
#endif
|
|
find_cnt++;
|
|
/* get half collect value */
|
|
if (!is_full_period && !is_half_clct) {
|
|
if (find_cnt >= count) {
|
|
break;
|
|
}
|
|
tmp = mac_zc_ring_get_legal_idx(phase_info[phase_id], \
|
|
ring_pos + 1);
|
|
if ((rpt_pos + phase_cnt) < count) {
|
|
rpt_buf[rpt_pos + phase_cnt] = mac_zc_get_ntb_mid(\
|
|
phase_info[phase_id]->ntb_ring[ring_pos], \
|
|
phase_info[phase_id]->ntb_ring[tmp]);
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
|
|
iot_printf("[zc]cp_ring-half:phase=%d,"
|
|
"rpt_buf[%u]<-ring[%u]-ring[%u]=%u\n", \
|
|
phase_id, rpt_pos + phase_cnt, tmp, ring_pos, \
|
|
rpt_buf[rpt_pos + phase_cnt]);
|
|
#endif
|
|
find_cnt++;
|
|
}
|
|
}
|
|
/* update rpt_pos in the collect period */
|
|
rpt_pos++;
|
|
}
|
|
if (find_cnt >= count) {
|
|
break;
|
|
}
|
|
/* update rpt_pos for next collect period */
|
|
if (!is_full_period && !is_half_clct) {
|
|
rpt_pos += phase_cnt;
|
|
}
|
|
/* update ntb ring buffer position */
|
|
if (is_full_period && is_half_clct) {
|
|
ring_pos = mac_zc_ring_get_legal_idx(phase_info[0], ring_pos + 2);
|
|
} else {
|
|
ring_pos = mac_zc_ring_get_legal_idx(phase_info[0], ring_pos + 1);
|
|
}
|
|
} while (1);
|
|
|
|
/* rpt data dump and check phase diff */
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 2)
|
|
iot_printf("zc_rpt_dump:\n");
|
|
for (uint32_t i = 0; i < find_cnt; i++) {
|
|
if (i && !(i % 3)) {
|
|
iot_printf("%u %u %u\n",
|
|
IOT_ABS((int32_t)(rpt_buf[i-2] - rpt_buf[i-3])),
|
|
IOT_ABS((int32_t)(rpt_buf[i-1] - rpt_buf[i-2])),
|
|
IOT_ABS((int32_t)(rpt_buf[i-1] - rpt_buf[i-3])));
|
|
}
|
|
iot_printf("%u ", rpt_buf[i]);
|
|
}
|
|
iot_printf("\n");
|
|
#endif
|
|
|
|
return find_cnt;
|
|
}
|
|
|
|
/* mac_zc copy real time ntb or history ntb to upper layer rpt buffer */
|
|
uint32_t mac_zc_get_ntb(uint8_t id, mac_zc_ntb_rpt_t *rpt,
|
|
uint16_t count, uint8_t is_full_period, uint8_t is_history_ntb,
|
|
uint32_t nid, uint32_t ntb)
|
|
{
|
|
#if (HW_PLATFORM >= HW_PLATFORM_FPGA)
|
|
uint32_t ret = ERR_OK;
|
|
uint32_t err_code = 0;
|
|
uint32_t find_cnt, find_pos;
|
|
uint8_t ref_phase_id, is_half_clct;
|
|
uint8_t edge_type = MAC_ZC_PLC_EDGE_DFT;
|
|
mac_zc_ctxt_t *zc_ctxt = mac_zc_ctxt_get(id);
|
|
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]get_para-cnt:%d,is_full:%d,is_his:%d,tar_nid:0x%x,"
|
|
"tar_ntb:%u,cur_ntb:%u\n",
|
|
count, is_full_period, is_history_ntb, nid, ntb,
|
|
mac_sched_get_ntb(NULL));
|
|
#endif
|
|
|
|
IOT_ASSERT(zc_ctxt && rpt);
|
|
if (!mac_zc_is_collecting(zc_ctxt)) {
|
|
ret = ERR_NOT_READY;
|
|
err_code = __LINE__;
|
|
goto out;
|
|
}
|
|
|
|
if (PLC_NID_INVALID != nid) {
|
|
if (is_history_ntb) {
|
|
/* convert neighbor nid history ntb to current nid ntb.
|
|
* neighbor nid -> my nid ntb */
|
|
if (ERR_OK != mac_other_ntb_to_myntb(id, (nid_t)nid, &ntb, 1)) {
|
|
ret = ERR_NOT_EXIST;
|
|
err_code = __LINE__;
|
|
goto out;
|
|
}
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]near_nid convert rst:ntb=%u\n", ntb);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* get first valid phase id */
|
|
ref_phase_id = mac_zc_get_ref_phase_id(zc_ctxt);
|
|
/* get ref phase is half collect state */
|
|
is_half_clct = mac_zc_is_half_clct_state(zc_ctxt, ref_phase_id);
|
|
if (count && (MAC_ZC_PHASE_ALL != ref_phase_id)) {
|
|
/* get find count and find position base MAC_ZC_PHASE_A */
|
|
if (is_history_ntb) {
|
|
find_cnt = mac_zc_get_ring_positon_by_ntb(zc_ctxt, ref_phase_id,
|
|
ntb, &find_pos, is_half_clct, edge_type);
|
|
} else {
|
|
/* calculate ref phase find count */
|
|
/* zc full period collect but upper layer fetch half period data */
|
|
uint32_t collect_cnt;
|
|
if (!is_full_period && !is_half_clct) {
|
|
collect_cnt = (count >> 1) + 1;
|
|
/* zc half period collect but upper layer fetch full period data */
|
|
} else if (is_full_period && is_half_clct) {
|
|
collect_cnt = (count << 1);
|
|
}else {
|
|
collect_cnt = count;
|
|
}
|
|
/* base phase rpt count */
|
|
collect_cnt = iot_ceil(collect_cnt,
|
|
mac_zc_get_active_phase_cnt(zc_ctxt));
|
|
find_cnt = mac_zc_get_position_by_count(\
|
|
&zc_ctxt->phase_info[ref_phase_id], collect_cnt, &find_pos,
|
|
is_half_clct, edge_type);
|
|
}
|
|
} else {
|
|
/* for only get zc phase info(count == 0), or all the support phase
|
|
* inactive(MAC_ZC_PHASE_ALL = ref_phase_id), not search
|
|
*/
|
|
find_cnt = 0;
|
|
}
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
if (find_cnt) {
|
|
/* find success */
|
|
iot_printf("[zc]get_ntb.ok-find_cnt:%d,ntb[%d]=%u\n", \
|
|
find_cnt, find_pos, \
|
|
zc_ctxt->phase_info[ref_phase_id].ntb_ring[find_pos]);
|
|
} else {
|
|
/* find fail */
|
|
iot_printf("[zc]get_ntb.fail-");
|
|
if (mac_zc_phase_is_active(&zc_ctxt->phase_info[ref_phase_id])) {
|
|
iot_printf("nid:0x%x,widx=%d,last_ntb:%u,cur_ntb:%u\n", \
|
|
nid, zc_ctxt->phase_info[ref_phase_id].write_idx, \
|
|
zc_ctxt->phase_info[ref_phase_id].ntb_ring[\
|
|
mac_zc_ring_get_last_idx(\
|
|
&zc_ctxt->phase_info[ref_phase_id])],
|
|
mac_sched_get_ntb(NULL));
|
|
} else {
|
|
iot_printf("ref_phase inactive\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* fill rpt info */
|
|
if (find_cnt) {
|
|
/* find cnt save base phase(single phase) find cnt */
|
|
/* calculate max rpt ntb count, save to tmp */
|
|
uint32_t max_rpt_cnt = find_cnt * mac_zc_get_active_phase_cnt(zc_ctxt);
|
|
if (!is_full_period && !is_half_clct) {
|
|
max_rpt_cnt <<= 1;
|
|
} else if (is_full_period && is_half_clct) {
|
|
max_rpt_cnt >>= 1;
|
|
}
|
|
/* calculate actual rpt count */
|
|
if (max_rpt_cnt > count) {
|
|
max_rpt_cnt = count;
|
|
}
|
|
/* copy ntb from ring buffer to rpt */
|
|
find_cnt = mac_zc_get_ntb_from_phase_ring(zc_ctxt, rpt->ntb, \
|
|
MAC_ZC_PHASE_ALL, is_full_period, max_rpt_cnt, find_pos, edge_type);
|
|
if (PLC_NID_INVALID != nid) {
|
|
if (ERR_OK != mac_myntb_to_other_ntb(id, nid, rpt->ntb, find_cnt)) {
|
|
ret = ERR_NOT_EXIST;
|
|
err_code = __LINE__;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
rpt->phase_a_valid = mac_zc_phase_is_active(
|
|
&zc_ctxt->phase_info[MAC_ZC_PHASE_A]);
|
|
rpt->phase_b_valid = mac_zc_phase_is_active(
|
|
&zc_ctxt->phase_info[MAC_ZC_PHASE_B]);
|
|
rpt->phase_c_valid = mac_zc_phase_is_active(
|
|
&zc_ctxt->phase_info[MAC_ZC_PHASE_C]);
|
|
rpt->phase_cnt = mac_zc_get_active_phase_cnt(zc_ctxt);
|
|
rpt->is_full_period = !!is_full_period;
|
|
rpt->ntb_cnt = find_cnt;
|
|
rpt->is_repeat_phase = mac_zc_is_repeat_connect(zc_ctxt);
|
|
rpt->phase_a_repeat = mac_zc_phase_id_zc2plc(
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_A].repeat_phase);
|
|
rpt->phase_b_repeat = mac_zc_phase_id_zc2plc(
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_B].repeat_phase);
|
|
rpt->phase_c_repeat = mac_zc_phase_id_zc2plc(
|
|
zc_ctxt->phase_info[MAC_ZC_PHASE_C].repeat_phase);
|
|
for (uint8_t i = MAC_ZC_PHASE_A;
|
|
i < min(MAC_ZC_PHASE_CNT, sizeof(rpt->avg_period) /
|
|
sizeof(rpt->avg_period[0]));
|
|
i++) {
|
|
rpt->avg_period[i] = zc_ctxt->phase_info[i].period;
|
|
}
|
|
|
|
out:
|
|
iot_printf("zc:rpt-%d:%u.cnt-%d:%d,v-%d:%d:%d,full=%d,repeat:%d,cur:%u\n",
|
|
ret, err_code, rpt->phase_cnt, rpt->ntb_cnt,
|
|
rpt->phase_a_valid, rpt->phase_b_valid, rpt->phase_c_valid,
|
|
rpt->is_full_period, rpt->is_repeat_phase, mac_sched_get_ntb(NULL));
|
|
if (rpt->ntb_cnt) {
|
|
iot_printf("ntb=%u:%u\n",
|
|
rpt->ntb[0], rpt->ntb[rpt->ntb_cnt - 1]);
|
|
}
|
|
|
|
return ret;
|
|
|
|
#else //HW_PLATFORM >= HW_PLATFORM_FPGA
|
|
uint32_t size, ntb_cnt, phase_id;
|
|
|
|
(void)id;
|
|
(void)nid; //TODO: maybe need support in simulator
|
|
mac_zc_ctxt_t *zc_ctxt = mac_zc_ctxt_get(id);
|
|
|
|
if (NULL == rpt) {
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
//for simulator, cvg alloc pkt must be phase aligment
|
|
if (count) {
|
|
ntb_cnt = count % (is_full_period ? 3 : 6);
|
|
if (ntb_cnt) {
|
|
ntb_cnt = count + ((is_full_period ? 3 : 6) - ntb_cnt);
|
|
} else {
|
|
ntb_cnt = count;
|
|
}
|
|
|
|
/* get start position zc ntb */
|
|
if (is_history_ntb) {
|
|
/* get history ntb */
|
|
rpt->ntb[0] = ntb;
|
|
} else {
|
|
/* get current ntb */
|
|
size = (is_full_period ? count : ((count - (count % 3)) >> 1)) / 3;
|
|
rpt->ntb[0] = (uint32_t)(mac_sched_get_ntb(NULL) \
|
|
- (MAC_ZC_ALL_PHASE_GOLDON_GAP_NTB * size));
|
|
}
|
|
|
|
if (is_full_period) {
|
|
for (size = 1; size < ntb_cnt; size++) {
|
|
rpt->ntb[size] = rpt->ntb[size - 1] + 166666;
|
|
}
|
|
} else {
|
|
if (ntb_cnt > 3) {
|
|
rpt->ntb[3] = rpt->ntb[0] + 83333;
|
|
}
|
|
for (size = 1; size < ntb_cnt;) {
|
|
rpt->ntb[size] = rpt->ntb[size - 1] + 166666;
|
|
if ((size + 3) < ntb_cnt) {
|
|
rpt->ntb[size + 3] = rpt->ntb[size] + 83333;
|
|
}
|
|
size++;
|
|
if (0 == (size % 3)) {
|
|
size += 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
rpt->ntb_cnt = count;
|
|
rpt->phase_cnt = 3;
|
|
rpt->phase_a_valid = true;
|
|
rpt->phase_b_valid = true;
|
|
rpt->phase_c_valid = true;
|
|
rpt->is_full_period = !!is_full_period;
|
|
rpt->is_repeat_phase = mac_zc_is_repeat_connect(zc_ctxt);
|
|
for (phase_id = MAC_ZC_PHASE_A;
|
|
phase_id < min(MAC_ZC_PHASE_CNT, sizeof(rpt->avg_period) /
|
|
sizeof(rpt->avg_period[0]));
|
|
phase_id++) {
|
|
rpt->avg_period[phase_id] = zc_ctxt->phase_info[phase_id].period;
|
|
}
|
|
|
|
return ERR_OK;
|
|
#endif
|
|
}
|
|
|
|
static void IRAM_ATTR mac_zc_switch_map_gpio(mac_zc_phase_info_t *phs_info,
|
|
mac_zc_hw_map_info_t *hw_map)
|
|
{
|
|
uint32_t current_lts, current_ts;
|
|
uint32_t abs_lts, min_period, periods, ahead_ts;
|
|
|
|
IOT_ASSERT(phs_info && hw_map);
|
|
current_lts = mac_sched_get_lts();
|
|
current_ts = mac_sched_get_ntb(NULL);
|
|
min_period = phs_info->period >> 1;
|
|
|
|
/* phase inactive dont't switch gpio */
|
|
if (!mac_zc_phase_is_active(phs_info)) {
|
|
phs_info->last_switch_lts = 0;
|
|
return;
|
|
}
|
|
if (!phs_info->last_switch_lts) {
|
|
phs_info->last_switch_lts = phs_info->last_ts +
|
|
(current_lts - current_ts) - MAC_ZC_SW_GPIO_AHEAD_NTB;
|
|
}
|
|
abs_lts = (uint32_t)(current_lts - phs_info->last_switch_lts);
|
|
if (abs_lts >= min_period) {
|
|
periods = abs_lts / min_period;
|
|
ahead_ts = abs_lts % min_period;
|
|
if ((periods & 0x01) && (ahead_ts <= MAC_ZC_SW_GPIO_AHEAD_NTB)) {
|
|
if ((uint32_t)(current_ts - phs_info->last_ts) < min_period) {
|
|
phs_info->last_switch_lts = phs_info->last_ts +
|
|
(current_lts - current_ts) + min_period
|
|
- MAC_ZC_SW_GPIO_AHEAD_NTB;
|
|
} else {
|
|
phs_info->last_switch_lts += (periods * min_period);
|
|
}
|
|
#if HW_PLATFORM >= HW_PLATFORM_FPGA
|
|
/* switch gpio mapping to sig */
|
|
uint8_t current_gpio = gpio_mtx_sig_in_get_gpio(hw_map->signal);
|
|
if (current_gpio == hw_map->gpio) {
|
|
mac_zc_hw_fix_map_gpio2sig(hw_map->gpio_ext, hw_map->signal);
|
|
} else if (current_gpio == hw_map->gpio_ext) {
|
|
mac_zc_hw_fix_map_gpio2sig(hw_map->gpio, hw_map->signal);
|
|
} else {
|
|
IOT_ASSERT(0);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
static void mac_dsr_zc_upper_bound(void)
|
|
{
|
|
uint8_t i;
|
|
mac_zc_ctxt_t *zc_ctxt;
|
|
for(i = 0; i < MAC_ZC_NUM_MAX; i++) {
|
|
zc_ctxt = mac_zc_ctxt_get(i);
|
|
if (zc_ctxt) {
|
|
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_HW_UPPER_BOUND_INT);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* mac_zc update need check phase bitmap and set systick dsr */
|
|
void IRAM_ATTR mac_zc_systic_trig(void)
|
|
{
|
|
uint8_t i, phase_id, phase_bitmap, is_half_clct, is_power_collapse;
|
|
mac_zc_ctxt_t *zc_ctxt;
|
|
mac_zc_phase_info_t *phase_info;
|
|
|
|
for(i = 0; i < MAC_ZC_NUM_MAX; i++) {
|
|
zc_ctxt = mac_zc_ctxt_get(i);
|
|
if (!zc_ctxt) {
|
|
continue;
|
|
}
|
|
phase_bitmap = 0;
|
|
is_power_collapse = mac_zc_is_power_collapsed(i);
|
|
/* power collapsed status, only check reference phase */
|
|
for (phase_id = is_power_collapse ? \
|
|
(uint8_t)mac_zc_get_ref_phase_id(zc_ctxt) : MAC_ZC_PHASE_A;
|
|
phase_id < MAC_ZC_PHASE_CNT; \
|
|
phase_id++) {
|
|
phase_info = &zc_ctxt->phase_info[phase_id];
|
|
/* switch gpio mapping */
|
|
if (zc_ctxt->nv_info.is_switch_gpio_clct &&
|
|
zc_ctxt->sm_info.cur_sm >= MAC_ZC_SM_TRAIN_SYSTICK_WAIT &&
|
|
mac_zc_phase_is_support(zc_ctxt, phase_id)) {
|
|
mac_zc_switch_map_gpio(phase_info,
|
|
&zc_ctxt->nv_info.phase_map[phase_id]);
|
|
}
|
|
if ((!is_power_collapse) && (!mac_zc_phase_is_active(phase_info) \
|
|
|| (!mac_zc_phase_is_support(zc_ctxt, phase_id)))) {
|
|
continue;
|
|
}
|
|
|
|
is_half_clct = mac_zc_is_half_clct_state(zc_ctxt, phase_id);
|
|
if (zc_ctxt->systic_trig_en && phase_info->last_ts &&
|
|
phase_info->period && ((uint32_t)(mac_sched_get_ntb(NULL) -
|
|
phase_info->last_ts) > ((phase_info->period >> is_half_clct)
|
|
+ MAC_ZC_HW_CAP_INT_PROTECT_NTB))) {
|
|
phase_bitmap |= (uint8_t)(1 << phase_id);
|
|
}
|
|
if (is_power_collapse) {
|
|
break;
|
|
}
|
|
}
|
|
if (phase_bitmap && zc_ctxt->nv_info.hdl) {
|
|
zc_ctxt->systic_trig_en = 0;
|
|
zc_ctxt->check_phase_bitmap |= (uint32_t)phase_bitmap;
|
|
#if MAC_ZC_COLLECT_DEBUG_ENA
|
|
mac_zc_set_phase_bitmap(&zc_ctxt->bitmap_trace,
|
|
zc_ctxt->check_phase_bitmap, MAC_ZC_CALL_SYSTIC);
|
|
#endif
|
|
os_set_task_event_with_v_from_isr( \
|
|
zc_ctxt->nv_info.hdl, \
|
|
(uint32_t)(0x1 << MAC_DSR_ZC_SYSTIC_TRIG_CB_ID));
|
|
}
|
|
}
|
|
}
|
|
|
|
void mac_zc_train_hw_timeout_internal(uint32_t id, void *arg)
|
|
{
|
|
mac_zc_ctxt_t *zc_ctxt = (mac_zc_ctxt_t *)arg;
|
|
|
|
(void)id;
|
|
#if (MAC_ZC_DBG_LOG_LEVEL >= 1)
|
|
iot_printf("[zc]train_elapsed:%d\n", zc_ctxt->train_elapsed_time);
|
|
#endif
|
|
|
|
if (mac_zc_is_collecting(zc_ctxt)) {
|
|
/* system collecting, background check system running satus. */
|
|
if (ERR_OK == mac_zc_system_status_check(zc_ctxt)) {
|
|
zc_ctxt->train_elapsed_time = 0;
|
|
}
|
|
|
|
#if MAC_ZC_SYS_DAEMON_RESET_ENA
|
|
if (zc_ctxt->train_elapsed_time > MAC_ZC_SYS_DAEMON_TIMEOUT_MS) {
|
|
iot_printf("zc:daemon timeout.%d\n", zc_ctxt->train_elapsed_time);
|
|
zc_ctxt->train_elapsed_time = 0;
|
|
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
|
|
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_FORCE_TIME_MS);
|
|
} else
|
|
#endif
|
|
{
|
|
/* continue to trigger the timer */
|
|
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_SYS_DAEMON_PERIOD_MS);
|
|
}
|
|
} else {
|
|
/* system training */
|
|
if (zc_ctxt->train_elapsed_time > MAC_ZC_TRAIN_TIMEOUT_MS) {
|
|
iot_printf("zc:train timeout.%d\n", zc_ctxt->train_elapsed_time);
|
|
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
|
|
mac_zc_all_phase_set_collet_default_sts(zc_ctxt);
|
|
mac_zc_train_timer_start(zc_ctxt, MAC_ZC_TRAIN_RESTART_DELAY_MS);
|
|
/* Note: must be clear train_elapsed_time after start train timer.*/
|
|
zc_ctxt->train_elapsed_time = 0;
|
|
} else {
|
|
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_TRAIN_TIMER);
|
|
}
|
|
}
|
|
}
|
|
|
|
void mac_zc_train_hw_timeout(timer_id_t timer_id, void *arg)
|
|
{
|
|
(void)timer_id;
|
|
mac_msg_t *msg = mac_alloc_msg();
|
|
|
|
if (msg == NULL) {
|
|
IOT_ASSERT(0);
|
|
return;
|
|
}
|
|
msg->type = MAC_MSG_TYPE_TIMER;
|
|
msg->id = MAC_MSG_ID_ZC_TRAIN_HW_TIMER;
|
|
msg->data1 = (uint32_t)timer_id;
|
|
msg->data2 = arg;
|
|
mac_queue_msg(msg, MAC_MSG_QUEUE_HP);
|
|
}
|
|
|
|
void mac_zc_set_func_cmd_internal(uint8_t zc_id, uint8_t cmd, void *arg)
|
|
{
|
|
(void)arg;
|
|
mac_zc_ctxt_t *zc_ctxt;
|
|
zc_ctxt = mac_zc_ctxt_get(zc_id);
|
|
IOT_ASSERT(zc_ctxt);
|
|
switch((mac_zc_func_cmd_id_t)cmd) {
|
|
case MAC_ZC_FUNC_CMD_DELAY_RESET_HW:
|
|
/* stop mac zc system */
|
|
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
|
|
/* start mac zc system */
|
|
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_START_REQ);
|
|
mac_status_add_zc_reset_hw_cnt();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void mac_zc_set_func_cmd(uint8_t zc_id, mac_zc_func_cmd_id_t cmd, void *arg)
|
|
{
|
|
#if (HW_PLATFORM >= HW_PLATFORM_FPGA)
|
|
mac_zc_ctxt_t *zc_ctxt;
|
|
mac_msg_t *msg = NULL;
|
|
|
|
(void)arg;
|
|
zc_ctxt = mac_zc_ctxt_get(zc_id);
|
|
IOT_ASSERT(zc_ctxt);
|
|
|
|
iot_printf("zc:set_cmd-%u\n", cmd);
|
|
|
|
switch ((mac_zc_func_cmd_id_t)cmd) {
|
|
case MAC_ZC_FUNC_CMD_RESET_HW:
|
|
/* stop mac zc system */
|
|
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
|
|
/* start mac zc system */
|
|
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_START_REQ);
|
|
mac_status_add_zc_reset_hw_cnt();
|
|
break;
|
|
|
|
case MAC_ZC_FUNC_CMD_COLLECT_STOP:
|
|
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYS_STOP_REQ);
|
|
break;
|
|
|
|
case MAC_ZC_FUNC_CMD_DELAY_RESET_HW:
|
|
msg = mac_alloc_msg();
|
|
if (msg) {
|
|
msg->type = MAC_MSG_TYPE_MAC;
|
|
msg->id = MAC_MSG_ID_MAC_ZC_SET_FUNC_CMD;
|
|
msg->data1 = zc_id | (cmd << 8);
|
|
msg->data2 = arg;
|
|
mac_queue_msg(msg, MAC_MSG_QUEUE_HP);
|
|
} else {
|
|
IOT_ASSERT(0);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
#else
|
|
(void)zc_id;
|
|
(void)cmd;
|
|
(void)arg;
|
|
#endif
|
|
}
|
|
|
|
uint8_t IRAM_ATTR mac_zc_is_power_collapsed(uint8_t pdev_id)
|
|
{
|
|
mac_zc_ctxt_t *zc_ctxt = mac_zc_ctxt_get(pdev_id);
|
|
|
|
if (zc_ctxt && mac_zc_is_collecting(zc_ctxt)) {
|
|
return (!mac_zc_get_active_phase_cnt(zc_ctxt));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void mac_dsr_zc_systic_trig_cb(void)
|
|
{
|
|
uint8_t i;
|
|
mac_zc_ctxt_t *zc_ctxt;
|
|
for(i = 0; i < MAC_ZC_NUM_MAX; i++) {
|
|
zc_ctxt = mac_zc_ctxt_get(i);
|
|
if (zc_ctxt) {
|
|
mac_zc_state_machine(zc_ctxt, MAC_ZC_TRIG_SYSTIC_TIMER);
|
|
}
|
|
}
|
|
}
|
|
#endif //MAC_ZC_ENABLE
|
|
|
|
//TODO: will move into MAC_ZC_ENABLE
|
|
uint32_t mac_zc_system_init(uint8_t id, void *task_hdl, void *dsr_tbl,
|
|
void *dsr_set_fn, void *dsr_clr_fn)
|
|
{
|
|
#if MAC_ZC_ENABLE
|
|
uint32_t size;
|
|
mac_zc_ctxt_t *zc_ctxt;
|
|
|
|
iot_printf("zc:sys_init-%d.[%u]\n", id, mac_sched_get_ntb(NULL));
|
|
|
|
if (id >= MAC_ZC_NUM_MAX) {
|
|
return ERR_INVAL;
|
|
}
|
|
|
|
zc_ctxt = mac_zc_ctxt_get(id);
|
|
if (NULL == zc_ctxt) {
|
|
IOT_ASSERT(zc_ctxt);
|
|
return ERR_INVAL;
|
|
}
|
|
/* clean zc ctxt data */
|
|
os_mem_set(zc_ctxt, 0, sizeof(*zc_ctxt));
|
|
|
|
zc_ctxt->ref_pdev_id = id;
|
|
|
|
switch (iot_oem_get_module_type()) {
|
|
case MODULE_TYPE_CCO:
|
|
BUILD_BUG_ON(MAC_ZC_NTB_SUPPORT_CNT_CCO <= MAC_ZC_BUF_SIZE_MAX_CCO);
|
|
size = MAC_ZC_NTB_SUPPORT_CNT_CCO;
|
|
break;
|
|
|
|
case MODULE_TYPE_3_PHASE_STA:
|
|
BUILD_BUG_ON(MAC_ZC_NTB_SUPPORT_CNT_STA_3P
|
|
<= MAC_ZC_BUF_SIZE_MAX_STA_3P);
|
|
if (iot_board_get_tsfm_mode() == HW_REC_MODE_WQ) {
|
|
#if RUN_IN_PSRAM
|
|
size = MAC_ZC_NTB_SUPPORT_CNT_STA_3P;
|
|
#else
|
|
size = MAC_ZC_NTB_SUPPORT_CNT_STA;
|
|
#endif
|
|
} else {
|
|
size = MAC_ZC_NTB_SUPPORT_CNT_STA_3P;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
BUILD_BUG_ON(MAC_ZC_NTB_SUPPORT_CNT_STA <= MAC_ZC_BUF_SIZE_MAX_STA);
|
|
size = MAC_ZC_NTB_SUPPORT_CNT_STA;
|
|
break;
|
|
}
|
|
/* alloc zc ring buffer */
|
|
if (NULL == zc_ctxt->ring) {
|
|
zc_ctxt->ring = os_mem_malloc(PLC_MAC_ZC_MID, size * sizeof(uint32_t));
|
|
if (NULL == zc_ctxt->ring) {
|
|
/* memory must be allocated successfully */
|
|
IOT_ASSERT(0);
|
|
return ERR_NOMEM;
|
|
}
|
|
} else {
|
|
IOT_ASSERT(0);
|
|
}
|
|
zc_ctxt->ring_sz = size;
|
|
|
|
/* init task & dsr ctxt config */
|
|
zc_ctxt->nv_info.hdl = task_hdl;
|
|
zc_ctxt->nv_info.dsr_tbl = dsr_tbl;
|
|
zc_ctxt->nv_info.dsr_set_entry = \
|
|
(mac_zc_dsr_set_entry_fn_t)dsr_set_fn;
|
|
zc_ctxt->nv_info.dsr_clr = (mac_zc_dsr_clr_fn_t)dsr_clr_fn;
|
|
|
|
/* register mac zc systick dsr */
|
|
if (dsr_tbl && dsr_set_fn) {
|
|
zc_ctxt->nv_info.dsr_set_entry(zc_ctxt->nv_info.dsr_tbl,
|
|
(uint8_t)MAC_DSR_ZC_SYSTIC_TRIG_CB_ID,
|
|
(void *)mac_dsr_zc_systic_trig_cb);
|
|
}
|
|
|
|
/* init timer */
|
|
//TODO: mm_mode use message, ftm_mode use timer callback
|
|
zc_ctxt->timer_train = os_create_timer(PLC_MAC_ZC_MID, 0,
|
|
(os_timer_func_t)mac_zc_train_hw_timeout, zc_ctxt);
|
|
if (!zc_ctxt->timer_train) {
|
|
IOT_ASSERT(0);
|
|
return ERR_NOMEM;
|
|
}
|
|
|
|
/* update default support phase bitmap */
|
|
mac_zc_load_oem_info(zc_ctxt);
|
|
|
|
/* stop zc system */
|
|
mac_zc_system_stop(zc_ctxt);
|
|
|
|
/* clean train elapsed time ctxt */
|
|
//TODO: maybe move to mac_zc_system_stop()???
|
|
zc_ctxt->train_elapsed_time = 0;
|
|
|
|
/* init ring */
|
|
mac_zc_phase_info_init(zc_ctxt);
|
|
|
|
zc_ctxt->sm_info.prev_sm = MAC_ZC_SM_IDLE;
|
|
zc_ctxt->sm_info.cur_sm = MAC_ZC_SM_IDLE;
|
|
|
|
return ERR_OK;
|
|
#else
|
|
(void)task_hdl;
|
|
(void)dsr_tbl;
|
|
(void)dsr_set_fn;
|
|
(void)dsr_clr_fn;
|
|
iot_printf("zc:sys_init-%d.[%u]\n", id, mac_sched_get_ntb(NULL));
|
|
|
|
return ERR_NOSUPP;
|
|
#endif
|
|
}
|