Files
kunlun/plc/halmac/mac_hw_tsfm/mac_hw_tsfm.c
2024-09-28 14:24:04 +08:00

432 lines
12 KiB
C
Executable File

/****************************************************************************
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_utils_api.h"
#include "iot_config.h"
#include "iot_errno_api.h"
#include "iot_config_api.h"
#include "iot_io_api.h"
#include "clk.h"
#include "hw_reg_api.h"
#include "phy_dfe_reg.h"
#include "ahb.h"
#include "ada_reg.h"
#include "phy_bb.h"
#include "phy_phase.h"
#include "phy_ana.h"
#include "hw_phy_init.h"
#include "granite_reg.h"
#include "mac.h"
#include "mac_msg.h"
#include "mac_pdev.h"
#include "mac_vdev.h"
#include "mac_pm.h"
#include "mac_tx_power.h"
#include "mac_hw_tsfm.h"
#include "iot_system.h"
#include "iot_dbglog_api.h"
#include "iot_dbglog_parser.h"
#include "iot_module_api.h"
#if PLC_SUPPORT_HW_TSFM_PA
#include "iot_gptmr_api.h"
#define MAC_HW_TSFM_DBG_ENA 0
#if MAC_HW_TSFM_DBG_ENA
#define mac_hw_tsfm_dbg_print(fmt, ...) iot_printf(fmt, ##__VA_ARGS__)
#else
#define mac_hw_tsfm_dbg_print(fmt, ...)
#endif
#define mac_hw_tsfm_timer_is_valid(id) \
((((id) >= GP_TIMER_COUNT) || (0 == (id))) ? 0 : 1)
#define mac_hw_tsfm_signal_tx(tone_num) phy_dfe_tone_cfg(1, tone_num, 0)
#define mac_hw_tsfm_signal_idle() \
phy_dfe_tone_cfg(0, 0, 0)
#define mac_hw_tsfm_ctxt_get() \
(mac_hw_tsfm_ctxt_t *)g_mac_pdev[PLC_PDEV_ID]->hw_tsfm
static void mac_hw_tsfm_complete(void)
{
mac_hw_tsfm_ctxt_t *tsfm = mac_hw_tsfm_ctxt_get();
IOT_ASSERT(tsfm);
/* tx complete. stop timer */
iot_gp_timer_stop(tsfm->timer_id);
/* disable phy atten */
mac_hw_tsfm_signal_idle();
tsfm->tsfm_mode = 0;
/* restore backup */
if (IOT_SUPPORT_RATE_SR == tsfm->backup.tx_rate_mode_ovr) {
phy_tx_rate_mode_ovr_set(0, tsfm->backup.tx_rate_mode_ovr);
} else {
phy_tx_rate_mode_ovr_set(1, tsfm->backup.tx_rate_mode_ovr);
}
/* disable phy tx force */
phy_set_tx_force_enable(0);
/* reset phy */
phy_reset(PHY_RST_REASON_COLD);
/* restore ada clk config */
enable_ada(tsfm->backup.ada_eb);
/* restore ada power on config */
phy_ada_enable(tsfm->backup.ada_power_on);
/* restore tx power */
phy_ana_pga_gain_set(tsfm->backup.ana_pga_gain);
phy_tx_gain_factor_set((uint8_t)tsfm->backup.tx_pwr_scale_factor);
/* record tx execute count to flash */
tsfm->logger.tx_complete_cnt++;
iot_dbglog_input(PLC_MAC_HW_TSFM_MID, DBGLOG_ERR, IOT_MAC_HW_TSFM_ID, 6,
tsfm->config.data[0], tsfm->config.data[1], tsfm->config.data[2],
tsfm->config.data[3], tsfm->logger.tx_req_cnt,
tsfm->logger.tx_complete_cnt);
iot_printf("mac_hw_tsfm:complete.ts=%u\n", os_boot_time32());
}
static uint8_t IRAM_ATTR mac_hw_tsfm_timer_isr_handle(iot_addrword_t data)
{
uint8_t byte_idx, bit_idx;
uint32_t cur_ts = iot_gp_timer_get_curr_ts();
uint32_t delta;
mac_hw_tsfm_ctxt_t *tsfm = (mac_hw_tsfm_ctxt_t *)data;
IOT_ASSERT(tsfm);
if (0 == tsfm->tsfm_mode) {
return 0;
}
if (tsfm->status.encode_idx < tsfm->config.bit_len) {
byte_idx = tsfm->status.encode_idx >> 3;
bit_idx = tsfm->status.encode_idx & 0x07;
delta = cur_ts - tsfm->status.encode_ts;
if (tsfm->config.data[byte_idx] & (1 << (7 - bit_idx))) {
/* encode logic 1 */
if (delta >= (tsfm->status.is_encode_tx
? MAC_HW_TSFM_ENCODE_TX_US : MAC_HW_TSFM_ENCODE_IDLE_US)) {
tsfm->status.encode_ts = cur_ts;
tsfm->status.is_encode_tx = !tsfm->status.is_encode_tx;
}
} else {
/* encode logic 0 */
tsfm->status.is_encode_tx = 0;
}
delta = cur_ts - tsfm->status.tsfm_bit_ts;
if (delta >= MAC_HW_TSFM_PER_BIT_DUR_US) {
tsfm->status.tsfm_bit_ts = cur_ts;
tsfm->status.encode_idx++;
if (tsfm->status.encode_idx >= tsfm->config.bit_len) {
tsfm->status.is_encode_tx = 0;
tsfm->tsfm_mode = 0;
/* set mac dsr */
if (p_mac_glb->task_h) {
os_set_task_event_with_v_from_isr(p_mac_glb->task_h,
(uint32_t)(0x1 << MAC_DSR_HW_TSFM_COMPLETE_ID));
}
}
}
}
if (tsfm->status.is_encode_tx) {
mac_hw_tsfm_signal_tx(tsfm->config.encode_tone_num);
} else {
mac_hw_tsfm_signal_idle();
}
return 0;
}
static uint32_t mac_hw_tsfm_get_duration_time(mac_hw_tsfm_ctxt_t *tsfm)
{
/* us to ms */
return tsfm ? iot_ceil(MAC_HW_TSFM_PER_BIT_DUR_US * tsfm->config.bit_len,
1000) : 0;
}
static uint32_t mac_hw_tsfm_start(mac_hw_tsfm_ctxt_t *tsfm)
{
uint32_t dur_time;
mac_pdev_t *pdev;
if (!tsfm) {
return 0;
}
iot_gp_timer_stop(tsfm->timer_id);
tsfm->tsfm_mode = 1;
/* clear event */
mac_dsr_clear(MAC_DSR_HW_TSFM_COMPLETE_ID);
/* backup ada config */
tsfm->backup.ada_eb = ahb_ada_is_enable();
tsfm->backup.ada_power_on = phy_ada_get_power_on();
/* ada clk enable */
enable_ada(1);
/* ada power on */
phy_ada_enable(1);
phy_reset(PHY_RST_REASON_COLD);
/* pm init wake up */
mac_pm_init_wake_up();
/* disable check spur */
pdev = get_pdev_ptr(tsfm->ref_pdev_id);
IOT_ASSERT(pdev);
mac_check_spur_en(&pdev->mac_check_spur_ctxt, 0);
tsfm->backup.tx_rate_mode_ovr = phy_tx_rate_mode_ovr_get();
phy_tx_rate_mode_ovr_set(1, MAC_HW_TSFM_ENCODE_RATE_MODE);
/* force tx */
phy_set_tx_force_enable(1);
/* enable analog tx */
phy_ana_i2c_write(CFG_ANA_TOP_REG_ADDR,
TOP_EN_TX_MASK | TOP_EN_DAC_MASK | (2 << TOP_ENLIC_OFFSET),
TOP_EN_TX_MASK | TOP_EN_DAC_MASK | TOP_ENLIC_MASK);
/* atten control */
phy_dfe_tone_att_cfg(0, 1, 0);
/* fix tx power and backup */
tsfm->backup.ana_pga_gain = phy_ana_pga_gain_get();
tsfm->backup.tx_pwr_scale_factor = phy_tx_gain_factor_get();
phy_ana_pga_gain_set(3);
phy_tx_gain_factor_set(PHY_PWR_DIG_ATT_MAX);
/* set current status */
tsfm->status.encode_idx = 0;
tsfm->status.is_encode_tx = 1;
tsfm->status.encode_ts = iot_gp_timer_get_curr_ts();
tsfm->status.tsfm_bit_ts = tsfm->status.encode_ts;
if (tsfm->config.data[0] & (1 << 7)) {
mac_hw_tsfm_signal_tx(tsfm->config.encode_tone_num);
tsfm->status.is_encode_tx = 1;
} else {
mac_hw_tsfm_signal_idle();
tsfm->status.is_encode_tx = 0;
}
//start gp timer
dur_time = mac_hw_tsfm_get_duration_time(tsfm);
iot_gp_timer_set(tsfm->timer_id, MAC_HW_TSFM_ENCODE_TIMER_US, 1);
iot_gp_timer_start(tsfm->timer_id);
iot_printf("mac_hw_tsfm:start.freq=%uHZ, ts=%u, dur=%u\n",
mac_hw_tsfm_tonenum_to_freq(tsfm->config.encode_tone_num),
os_boot_time32(), dur_time);
mac_hw_tsfm_dbg_print("mac_hw_tsfm:config. timer_peroid=%u, "
"tx=%u, idle=%u, bit_dur=%u, rate_mode=%u\n",
MAC_HW_TSFM_ENCODE_TIMER_US,
MAC_HW_TSFM_ENCODE_TX_US,
MAC_HW_TSFM_ENCODE_IDLE_US,
MAC_HW_TSFM_PER_BIT_DUR_US,
MAC_HW_TSFM_ENCODE_RATE_MODE);
mac_hw_tsfm_dbg_print("mac_hw_tsfm:backup.tx_mode=%d, ada-%d:%d, "
"pga=%d, tx_scale=%d\n",
tsfm->backup.tx_rate_mode_ovr,
tsfm->backup.ada_eb,
tsfm->backup.ada_power_on,
tsfm->backup.ana_pga_gain,
tsfm->backup.tx_pwr_scale_factor);
return dur_time;
}
void mac_hw_tsfm_init(uint8_t fw_mode, uint8_t pdev_id)
{
uint32_t err_no;
mac_pdev_t *pdev;
mac_hw_tsfm_ctxt_t *tsfm;
if ((MM_MODE != fw_mode) || (PLC_PDEV_ID != pdev_id)) {
return;
}
do {
/* get pdev context */
pdev = get_pdev_ptr(pdev_id);
if (NULL == pdev) {
err_no = __LINE__;
break;
}
/* alloc codec context */
tsfm = os_mem_malloc(PLC_MAC_COMMON_MID, sizeof(*tsfm));
if (NULL == tsfm) {
err_no = __LINE__;
break;
}
/* create timer */
tsfm->timer_id = iot_gp_timer_create(0, NULL,
mac_hw_tsfm_timer_isr_handle, (iot_addrword_t)tsfm);
if (!mac_hw_tsfm_timer_is_valid(tsfm->timer_id)) {
err_no = __LINE__;
break;
}
mac_dsr_set_entry(&p_mac_glb->dsr_table, MAC_DSR_HW_TSFM_COMPLETE_ID,
mac_hw_tsfm_complete);
/* success */
err_no = 0;
pdev->hw_tsfm = tsfm;
tsfm->tsfm_mode = 0;
tsfm->ref_pdev_id = pdev_id;
} while(0);
iot_printf("mac_hw_tsfm:init %d\n", err_no);
IOT_ASSERT_DUMP(!err_no, &err_no, 1);
}
uint32_t mac_hw_tsfm_send_internal(pdevid_t pdev_id, vdevid_t vdev_id,
mac_hw_tsfm_tx_info_t *tx_info)
{
uint8_t i, byte_len;
uint32_t err_no;
uint32_t dur_time;
mac_pdev_t *pdev;
mac_vdev_t *vdev;
mac_hw_tsfm_ctxt_t *tsfm;
byte_len = iot_ceil(tx_info->bit_len, 8);
iot_printf("mac_hw_tsfm:tx para.id:%d-%d.freq:%dHz,bit_len=%d.[",
pdev_id, vdev_id, tx_info->freq_tone_num, tx_info->bit_len);
if (tx_info) {
for (i = 0; i < byte_len; i++) {
iot_printf(" 0x%02x", tx_info->data[i]);
}
iot_printf("]\n");
}
do {
pdev = get_pdev_ptr(pdev_id);
if ((PLC_PDEV_ID != pdev_id) || (byte_len > MAC_HW_TSFM_DATA_BYTE_MAX)
|| !tx_info || !pdev) {
err_no = __LINE__;
break;
}
tsfm = (mac_hw_tsfm_ctxt_t *)pdev->hw_tsfm;
if (NULL == tsfm) {
err_no = __LINE__;
break;
}
/* record receieve tx request count */
tsfm->logger.tx_req_cnt++;
vdev = get_vdev_ptr(pdev_id, vdev_id);
if ((PLC_DEFAULT_VDEV != vdev_id) || !vdev) {
err_no = __LINE__;
break;
}
if (tsfm->tsfm_mode) {
err_no = __LINE__;
break;
}
err_no = 0;
} while (0);
if (0 == err_no) {
tsfm->config.bit_len = tx_info->bit_len;
tsfm->config.encode_tone_num = tx_info->freq_tone_num;
os_mem_cpy(tsfm->config.data, tx_info->data, byte_len);
if (vdev->is_up) {
mac_stop_vdev_internal(pdev_id, vdev_id);
}
dur_time = mac_hw_tsfm_start(tsfm);
} else {
iot_printf("mac_hw_tsfm: send err %u\n", err_no);
dur_time = 0;
}
return dur_time;
}
uint32_t mac_hw_tsfm_send(pdevid_t pdev_id, vdevid_t vdev_id,
mac_hw_tsfm_tx_info_t *tx_info)
{
uint32_t ret;
mac_msg_sync_t *msg = mac_alloc_msg_sync();
if (msg == NULL) {
IOT_ASSERT(0);
return ERR_NOMEM;
}
msg->msg.type = MAC_MSG_TYPE_CVG;
msg->msg.id = MAC_MSG_ID_CVG_HW_TSFM_SEND;
msg->msg.data1 = (((uint32_t)pdev_id) << 8) | vdev_id;
msg->msg.data2 = (void *)tx_info;
mac_queue_msg_sync(msg, MAC_MSG_QUEUE_HP);
ret = msg->msg.data1;
mac_free_msg_sync(msg);
return ret;
}
#else //PLC_SUPPORT_HW_TSFM_PA
uint32_t mac_hw_tsfm_send_internal(pdevid_t pdev_id, vdevid_t vdev_id,
mac_hw_tsfm_tx_info_t *tx_info)
{
(void)pdev_id;
(void)vdev_id;
(void)tx_info;
return 0;
}
uint32_t mac_hw_tsfm_send(pdevid_t pdev_id, vdevid_t vdev_id,
mac_hw_tsfm_tx_info_t *tx_info)
{
(void)pdev_id;
(void)vdev_id;
(void)tx_info;
return 0;
}
void mac_hw_tsfm_init(uint8_t fw_mode, uint8_t pdev_id)
{
(void)fw_mode;
(void)pdev_id;
return;
}
#endif //PLC_SUPPORT_HW_TSFM_PA