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

642 lines
19 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 "plc_fr.h"
#include "hw_tonemask.h"
#include "plc_utils.h"
#include "phy_bb.h"
#include "phy_ana.h"
#include "hw_phy_api.h"
#include "iot_io.h"
#include "hw_desc.h"
#include "hw_reg_api.h"
#include "plc_protocol.h"
#if HW_PLATFORM >= HW_PLATFORM_FPGA
#include "granite_reg.h"
#endif
#include "iot_errno_api.h"
#include "phy_txrx_pwr.h"
#include "phy_cfg.h"
#include "phy_dfe_reg.h"
#include "phy_rxtd_reg.h"
#include "iot_config.h"
#include "phy_chn.h"
#include "iot_system.h"
#include "iot_io_api.h"
void phy_tone_amp_reduce_set(uint32_t start_tone, uint32_t end_tone,
uint8_t reduce_db)
{
uint32_t tmp = 0;
uint32_t mask_begin_col_idx = 0;
uint32_t mask_begin_group_idx = 0;
uint32_t ampdata, tone_id;
uint32_t *p_tone_addr = (uint32_t *)BB_TONE_MASK_PHASE_BASEADDR;
IOT_ASSERT(start_tone <= end_tone);
if (reduce_db <= 28) {
ampdata = reduce_db >> 1;
} else {
ampdata = 0x0F;
}
ampdata <<= 4;
enable_sw_access_tmi_buf(true);
for (tone_id = start_tone; tone_id <= end_tone; tone_id++) {
mask_begin_col_idx = tone_id & 0x3;
mask_begin_group_idx = tone_id >> 2;
tmp = *(p_tone_addr + mask_begin_group_idx);
tmp &= ~(0xF0 << (8 * mask_begin_col_idx));
tmp |= ampdata << (8 * mask_begin_col_idx);
*(p_tone_addr + mask_begin_group_idx) = tmp;
}
enable_sw_access_tmi_buf(false);
}
void phy_tone_amp_set(uint32_t start_tone, uint32_t end_tone, uint8_t amp_value)
{
#if HW_PLATFORM >= HW_PLATFORM_FPGA
uint32_t tmp = 0;
uint32_t index = 0;
uint32_t mask_begin_col_idx = 0;
uint32_t mask_begin_group_idx = 0;
uint32_t mask_end_col_idx = 0;
uint32_t mask_end_group_idx = 0;
uint32_t *p_tone_addr = \
(uint32_t *)BB_TONE_MASK_PHASE_BASEADDR;
IOT_ASSERT(start_tone <= end_tone);
enable_sw_access_tmi_buf(true);
/* get start tone */
mask_begin_col_idx = (start_tone) & 0x3;
mask_begin_group_idx = (start_tone) >> 2;
/* get end tone */
mask_end_col_idx = (end_tone) & 0x3;
mask_end_group_idx = (end_tone) >> 2;
if (mask_begin_group_idx == mask_end_group_idx) {
tmp = *(p_tone_addr + mask_begin_group_idx);
tmp |= ((0xF0F0F0F0 & (amp_value<<24 | amp_value<<16 | \
amp_value<<8 | amp_value)) & \
(0xFFFFFFFF << 8*mask_begin_col_idx) & \
(0xFFFFFFFF >> 8*(3-mask_end_col_idx)));
*(p_tone_addr + mask_begin_group_idx) = tmp;
}else {
/* start group */
tmp = *(p_tone_addr + mask_begin_group_idx);
tmp |= ((0xF0F0F0F0 & (amp_value<<24 | amp_value<<16 | \
amp_value<<8 | amp_value)) & \
(0xFFFFFFFF << 8*mask_begin_col_idx));
*(p_tone_addr + mask_begin_group_idx) = tmp;
/* end group */
tmp = *(p_tone_addr + mask_end_group_idx);
tmp |= ((0xF0F0F0F0 & (amp_value<<24 | amp_value<<16 | \
amp_value<<8 | amp_value)) & \
(0xFFFFFFFF >> 8*(3-mask_end_col_idx)));
*(p_tone_addr + mask_end_group_idx) = tmp;
/* cover */
index = mask_begin_group_idx + 1;
for(; index < mask_end_group_idx; index++)
{
tmp = *(p_tone_addr + index);
tmp |= (0xF0F0F0F0 & (amp_value<<24 | amp_value<<16 | \
amp_value<<8 | amp_value));
*(p_tone_addr + index) = tmp;
}
}
enable_sw_access_tmi_buf(false);
#else
(void)start_tone;
(void)end_tone;
(void)amp_value;
#endif
}
void phy_tone_amp_clr(uint32_t start_tone, uint32_t end_tone)
{
#if HW_PLATFORM >= HW_PLATFORM_FPGA
uint32_t tmp = 0;
uint32_t index = 0;
uint32_t mask_begin_col_idx = 0;
uint32_t mask_begin_group_idx = 0;
uint32_t mask_end_col_idx = 0;
uint32_t mask_end_group_idx = 0;
uint32_t *p_tone_addr = \
(uint32_t *)BB_TONE_MASK_PHASE_BASEADDR;
IOT_ASSERT(start_tone <= end_tone);
enable_sw_access_tmi_buf(true);
/* get start tone */
mask_begin_col_idx = (start_tone) & 0x3;
mask_begin_group_idx = (start_tone) >> 2;
/* get end tone */
mask_end_col_idx = (end_tone) & 0x3;
mask_end_group_idx = (end_tone) >> 2;
if (mask_begin_group_idx == mask_end_group_idx) {
tmp = *(p_tone_addr + mask_begin_group_idx);
tmp &= (0x0F0F0F0F &\
(0xFFFFFFFF << 8*mask_begin_col_idx) & \
(0xFFFFFFFF >> 8*(3-mask_end_col_idx)));
*(p_tone_addr + mask_begin_group_idx) = tmp;
} else {
/* start group */
tmp = *(p_tone_addr + mask_begin_group_idx);
tmp &= (0x0F0F0F0F &\
(0xFFFFFFFF << 8*mask_begin_col_idx));
*(p_tone_addr + mask_begin_group_idx) = tmp;
/* end group */
tmp = *(p_tone_addr + mask_end_group_idx);
tmp &= (0x0F0F0F0F0 &\
(0xFFFFFFFF >> 8*(3-mask_end_col_idx)));
*(p_tone_addr + mask_end_group_idx) = tmp;
/* cover */
index = mask_begin_group_idx + 1;
for(; index < mask_end_group_idx; index++)
{
tmp = *(p_tone_addr + index);
tmp &= 0xF0F0F0F0;
*(p_tone_addr + index) = tmp;
}
}
enable_sw_access_tmi_buf(false);
#else
(void)start_tone;
(void)end_tone;
#endif
}
static uint32_t phy_rms_get_in_band_tbl(const plc_phy_band_table_t *band_tbl,
uint8_t tbl_len, uint16_t valid_tone_num, uint8_t *fd_rms)
{
uint32_t ret = ERR_FAIL;
uint8_t band_idx = 0;
#if IOT_DTEST_ONLY_SUPPORT == 0
if (g_phy_ctxt.indep.tx_pwr_psd_fix_db > 0) {
if (g_phy_cpu_share_ctxt.tx_pwr_ctl_ena) {
*fd_rms = (uint8_t)(g_phy_ctxt.indep.tx_pwr_psd_fix_db -
PHY_PWR_DIG_ATT_MAX);
} else {
*fd_rms = (uint8_t)(g_phy_ctxt.indep.tx_pwr_psd_fix_db);
}
return ERR_OK;
}
#endif
if (band_tbl == NULL) {
IOT_ASSERT(0);
return ret;
}
for (band_idx = 0; band_idx < tbl_len; band_idx++) {
if (band_tbl[band_idx].band_info.valid_tone_number == valid_tone_num) {
*fd_rms = (uint8_t)(band_tbl[band_idx].band_info.fd_rms_max);
ret = ERR_OK;
break;
}
}
#if IOT_DTEST_ONLY_SUPPORT == 0
if (!g_phy_cpu_share_ctxt.tx_pwr_ctl_ena) {
if (ret == ERR_OK) {
*fd_rms -= (uint8_t)g_phy_ctxt.indep.tx_pwr_reduce_db;
}
*fd_rms += PHY_PWR_DIG_ATT_MAX;
}
#else
if (ret == ERR_OK) {
*fd_rms -= (uint8_t)g_phy_ctxt.indep.tx_pwr_reduce_db;
}
#endif
return ret;
}
uint32_t phy_rms_get_by_valid_tone(uint16_t valid_tone_num, uint8_t *fd_rms)
{
uint32_t ret = ERR_FAIL;
uint32_t mac_proto = PHY_PROTO_TYPE_GET();
const plc_phy_band_table_t *band_tbl = NULL;
uint8_t tbl_len = 0;
tbl_len = (uint8_t)phy_support_band_table_get(mac_proto, (void **)&band_tbl);
ret = phy_rms_get_in_band_tbl(band_tbl, tbl_len, valid_tone_num, fd_rms);
return ret;
}
/* get fd rms info depend on proto and band id */
uint32_t phy_gp_band_rms_get_by_valid_tone(uint16_t valid_tone_num,
uint8_t *fd_rms)
{
uint32_t ret = ERR_FAIL;
// TODO: maybe some customer need to use gp's config
#if 1 // SUPPORT_GREEN_PHY
const plc_phy_band_table_t *band_tbl = NULL;
uint8_t tbl_len = 0;
tbl_len = phy_get_plc_gp_band_tab_info(&band_tbl);
ret = phy_rms_get_in_band_tbl(band_tbl, tbl_len, valid_tone_num, fd_rms);
#endif
return ret;
}
/*
* TARGET_TD_RMS valid_tone_num FD_RMS
* 128 131 58.86
* 128 260 55.88
* 128 411 53.89
* 128 664 51.81
*/
uint32_t phy_fd_rms_get(uint32_t valid_tone_num, uint8_t *para_int, uint8_t *para_frac)
{
#if HW_PLATFORM >= HW_PLATFORM_FPGA
uint32_t ret = ERR_FAIL;
uint32_t mask_id = phy_mask_id_get();
/* check tonemask or not */
if (mask_id == TONE_MASK_ID_NULL) {
ret = phy_rms_get_by_valid_tone(valid_tone_num, para_int);
} else {
ret = phy_tone_msk_rms_get_by_valid_tone(valid_tone_num, para_int);
}
if (ret != ERR_OK) {
/* make sure work firstly */
*para_int = PHY_DEF_RMS;
}
/* frac */
*para_frac = 3;
return ret;
#else
(void)valid_tone_num;
(void)para_int;
(void)para_frac;
return 0;
#endif
}
void phy_fd_rms_band_set(uint32_t rate_id, uint32_t hw_band_id, uint8_t rms_cal)
{
#if HW_PLATFORM >= HW_PLATFORM_FPGA
uint32_t valid_tone_num = 0;
uint8_t para_int = 0, para_frac = 0;
valid_tone_num = phy_vld_tone_num_get(rate_id, hw_band_id);
phy_fd_rms_get(valid_tone_num, &para_int, &para_frac);
para_int = para_int + rms_cal;
phy_tx_rms_set(rate_id, hw_band_id, para_int, para_frac);
#else
(void)rate_id;
(void)hw_band_id;
(void)rms_cal;
#endif
}
void phy_fd_rms_batch_set(uint8_t rms_cal)
{
#if HW_PLATFORM >= HW_PLATFORM_FPGA
/* rate0/1 band0/1/2 */
phy_fd_rms_band_set(0, HW_FULL_BAND, rms_cal);
phy_fd_rms_band_set(0, HW_LOW_BAND, rms_cal);
phy_fd_rms_band_set(0, HW_HIGH_BAND, rms_cal);
phy_fd_rms_band_set(1, HW_FULL_BAND, rms_cal);
phy_fd_rms_band_set(1, HW_LOW_BAND, rms_cal);
phy_fd_rms_band_set(1, HW_HIGH_BAND, rms_cal);
#else
(void)rms_cal;
#endif
}
void phy_fd_short_band_rms_get(uint32_t valid_tone_num, \
uint8_t *para_int, \
uint8_t *para_frac)
{
#if HW_PLATFORM >= HW_PLATFORM_FPGA
uint32_t ret = ERR_FAIL;
ret = phy_gp_band_rms_get_by_valid_tone(valid_tone_num, para_int);
if (ret == ERR_OK) {
/* fractional part */
*para_frac = 3;
} else {
iot_printf("phy short band rms get failed by valid tone num %d\n", \
valid_tone_num);
IOT_ASSERT(0);
}
#else
(void)valid_tone_num;
(void)para_int;
(void)para_frac;
#endif
}
void phy_fd_rms_update(void)
{
uint32_t valid_tone_num = 0;
uint8_t para_int = 0, para_frac = 0;
/* rate0 band0/1/2 */
valid_tone_num = phy_vld_tone_num_get(0, HW_FULL_BAND);
phy_fd_rms_get(valid_tone_num, &para_int, &para_frac);
phy_tx_rms_set(0, HW_FULL_BAND, para_int, para_frac);
valid_tone_num = phy_vld_tone_num_get(0, HW_LOW_BAND);
phy_fd_rms_get(valid_tone_num, &para_int, &para_frac);
phy_tx_rms_set(0, HW_LOW_BAND, para_int, para_frac);
valid_tone_num = phy_vld_tone_num_get(0, HW_HIGH_BAND);
phy_fd_rms_get(valid_tone_num, &para_int, &para_frac);
phy_tx_rms_set(0, HW_HIGH_BAND, para_int, para_frac);
/* rate1 band0/1/2 */
valid_tone_num = phy_vld_tone_num_get(1, HW_FULL_BAND);
phy_fd_rms_get(valid_tone_num, &para_int, &para_frac);
phy_tx_rms_set(1, HW_FULL_BAND, para_int, para_frac);
valid_tone_num = phy_vld_tone_num_get(1, HW_LOW_BAND);
phy_fd_rms_get(valid_tone_num, &para_int, &para_frac);
phy_tx_rms_set(1, HW_LOW_BAND, para_int, para_frac);
valid_tone_num = phy_vld_tone_num_get(1, HW_HIGH_BAND);
phy_fd_rms_get(valid_tone_num, &para_int, &para_frac);
phy_tx_rms_set(1, HW_HIGH_BAND, para_int, para_frac);
}
void phy_time_rms_set(void)
{
uint32_t valid_tone_num = 0;
uint8_t para_int = 0, para_frac = 0;
uint16_t b0_full = 0, b0_low = 0, b0_high = 0;
uint16_t b1_full = 0, b1_low = 0, b1_high = 0;
/* update rms value */
phy_fd_rms_update();
/* short band init */
if (PHY_PROTO_TYPE_GET() == PLC_PROTO_TYPE_SG){
/* short band rms for mix mode */
valid_tone_num = phy_short_vld_tone_num_get();
phy_fd_short_band_rms_get(valid_tone_num, &para_int, &para_frac);
phy_tx_rms_set(2, 0, para_int, para_frac);
}
/* fd -12dB, td att +12dB */
#if PHY_LOAD_CFG_FROM_PIB_EN == 1 && \
IOT_DTEST_ONLY_SUPPORT == 0
if (g_phy_cpu_share_ctxt.tx_pwr_ctl_ena) {
if (!g_phy_ctxt.indep.tx_pwr_psd_fix_db) {
/* load global tx pwr reduce */
if (g_phy_ctxt.indep.tx_pwr_reduce_db <= PHY_PWR_DIG_ATT_MAX) {
phy_tx_gain_factor_set( \
(uint8_t)(PHY_PWR_DIG_ATT_MAX - \
g_phy_ctxt.indep.tx_pwr_reduce_db));
} else if (g_phy_ctxt.indep.tx_pwr_reduce_db <= \
(PHY_PWR_DIG_ATT_MAX << 1)) {
phy_tx_gain_factor_set( \
(uint8_t)(( \
SW_TX_PWR_SCALE_FACTOR_MASK >> SW_TX_PWR_SCALE_FACTOR_OFFSET) \
+ 1 - (g_phy_ctxt.indep.tx_pwr_reduce_db - PHY_PWR_DIG_ATT_MAX)));
} else {
IOT_ASSERT(0);
}
} else {
/* for dynamic adjust pwr */
phy_tx_gain_factor_set(PHY_PWR_DIG_ATT_MAX);
}
} else {
/* more snr by reduce analog */
if (!g_phy_ctxt.indep.tx_pwr_psd_fix_db) {
/* att config */
phy_tx_gain_factor_set(0);
if (g_phy_ctxt.indep.tx_pwr_reduce_db <= 5) {
/* tx pga config */
g_phy_ctxt.indep.tx_pga = 3;
} else if (g_phy_ctxt.indep.tx_pwr_reduce_db <= 23) {
/* reduce number */
uint8_t reduce_int = (uint8_t)( \
(g_phy_ctxt.indep.tx_pwr_reduce_db - 6) / 6);
uint8_t reduce_frac = (uint8_t)( \
(g_phy_ctxt.indep.tx_pwr_reduce_db - 6) % 6);
/* tx pga config */
g_phy_ctxt.indep.tx_pga = 3 - reduce_int;
uint8_t rms_cal_val = (uint8_t)( \
g_phy_ctxt.indep.tx_pwr_reduce_db - 6 - reduce_frac);
phy_fd_rms_batch_set(rms_cal_val);
} else if (g_phy_ctxt.indep.tx_pwr_reduce_db <= 41) {
phy_fd_rms_batch_set(18);
/* tx pga config */
g_phy_ctxt.indep.tx_pga = 0;
} else {
/* pwr too small */
IOT_ASSERT(0);
}
}
}
#else
#if IOT_PLC_PHY_TX_PWR_REDUCE <= PHY_PWR_DIG_ATT_MAX
phy_tx_gain_factor_set( \
PHY_PWR_DIG_ATT_MAX - IOT_PLC_PHY_TX_PWR_REDUCE);
#elif IOT_PLC_PHY_TX_PWR_REDUCE <= (PHY_PWR_DIG_ATT_MAX << 1)
phy_tx_gain_factor_set( \
(SW_TX_PWR_SCALE_FACTOR_MASK >> SW_TX_PWR_SCALE_FACTOR_OFFSET) \
+ 1 - (IOT_PLC_PHY_TX_PWR_REDUCE - PHY_PWR_DIG_ATT_MAX));
#else
IOT_ASSERT(0);
#endif
#endif
/* print all the rms setting */
phy_tx_rms_get(0, HW_FULL_BAND, &b0_full, &para_frac);
phy_tx_rms_get(0, HW_LOW_BAND, &b0_low, &para_frac);
phy_tx_rms_get(0, HW_HIGH_BAND, &b0_high, &para_frac);
phy_tx_rms_get(1, HW_FULL_BAND, &b1_full, &para_frac);
phy_tx_rms_get(1, HW_LOW_BAND, &b1_low, &para_frac);
phy_tx_rms_get(1, HW_HIGH_BAND, &b1_high, &para_frac);
iot_printf( \
"b0_full_rms = %d, b0_low_rms = %d, b0_high_rms = %d\n" \
"b1_full_rms = %d, b1_low_rms = %d, b1_high_rms = %d " \
"td_att = %d, reduce: %d\n", \
b0_full, b0_low, b0_high, b1_full, b1_low, b1_high, \
phy_tx_gain_factor_get(), IOT_PLC_PHY_TX_PWR_REDUCE);
}
uint32_t phy_get_def_tx_power( \
uint32_t hw_rate_id, \
uint32_t hw_band_id, \
uint8_t *para_int, \
uint8_t *para_frac)
{
uint32_t ret = ERR_OK;
uint32_t vld_tone_num = 0;
/* get valid tone number from current protocol, rate id and band id */
vld_tone_num = phy_vld_tone_num_get(hw_rate_id, hw_band_id);
/* get tx power from global array */
phy_fd_rms_get(vld_tone_num, para_int, para_frac);
return ret;
}
uint32_t phy_get_proto_band_fc_num_from_band_table(uint32_t proto_band_id)
{
uint32_t proto = PHY_PROTO_TYPE_GET();
uint32_t proto_band_idx;
const plc_phy_band_table_t *band_tab;
#if SUPPORT_SMART_GRID || SUPPORT_SOUTHERN_POWER_GRID
if (proto == PLC_PROTO_TYPE_SG || proto == PLC_PROTO_TYPE_SPG) {
uint32_t support_band_max = phy_get_plc_nsg_band_tab_info(&band_tab);
for(proto_band_idx = 0; proto_band_idx < support_band_max;
proto_band_idx++) {
if (band_tab[proto_band_idx].band_id == proto_band_id) {
return band_tab[proto_band_idx].band_info.fc_sym_num;
}
}
iot_printf("phy not support this proto band:%d\n", proto_band_id);
IOT_ASSERT(0);
}
#endif
#if SUPPORT_GREEN_PHY
if (proto == PLC_PROTO_TYPE_GP) {
/* TODO: need add */
}
#endif
return 0;
}
uint32_t phy_get_pwr_psd_fix_db()
{
return g_phy_ctxt.indep.tx_pwr_psd_fix_db;
}
uint32_t phy_get_pwr_ctl_en()
{
return !!g_phy_cpu_share_ctxt.tx_pwr_ctl_ena;
}
uint32_t phy_get_pwr_reduce_db()
{
return g_phy_ctxt.indep.tx_pwr_reduce_db;
}
uint32_t phy_set_tx_pwr_limit(uint32_t pwr_db)
{
g_phy_ctxt.dep.is_valid_power = 1;
g_phy_ctxt.dep.power_limit_db = pwr_db;
/* set mpdu pwr reg */
phy_set_common_pwr_reg(pwr_db);
/* set sack pwr reg */
phy_set_sack_tx_power(pwr_db);
return 0;
}
static uint32_t phy_get_init_tx_pwr(uint32_t single_proto_band)
{
uint8_t tx_power = 0;
uint8_t dlt_max = 0;
int8_t reduce = 0;
if (phy_get_default_tx_pwr(single_proto_band, &tx_power, &dlt_max)) {
iot_printf("%s band %d get power fail!\n", __FUNCTION__,
single_proto_band);
IOT_ASSERT(0);
}
/* NOTE: if psd != 0, recuce is invaild on lp */
if (phy_get_pwr_ctl_en() || !phy_get_pwr_psd_fix_db()) {
if (phy_get_pwr_reduce_db() & 0x80) {
reduce = phy_get_pwr_reduce_db() & 0x7f;
if (reduce > dlt_max) {
reduce = dlt_max;
}
tx_power = tx_power + reduce;
} else {
reduce = (uint8_t)phy_get_pwr_reduce_db();
if (tx_power < (uint8_t)reduce) {
tx_power = reduce;
}
tx_power = tx_power - reduce;
}
}
return (uint32_t)tx_power;
}
uint32_t phy_get_tx_pwr_limit(uint32_t single_proto_band)
{
uint32_t tx_power;
/* uplayer set tx power */
if (g_phy_ctxt.dep.is_valid_power == 1) {
tx_power = g_phy_ctxt.dep.power_limit_db;
} else {
tx_power = phy_get_init_tx_pwr(single_proto_band);
}
return tx_power;
}
uint32_t phy_pwr_adjust_set(uint8_t uint_dbuv)
{
uint32_t ret = ERR_OK;
#if (HW_PLATFORM > HW_PLATFORM_SIMU)
uint32_t power = uint_dbuv;
if (power == 0) {
power = phy_get_init_tx_pwr(phy_proto_single_band_id_get());
}
/* set power by sw */
g_phy_ctxt.dep.sw_set_pwr = power;
phy_overstress_ctxt_t *ovs_ctxt = &g_phy_ctxt.indep.ovs_ctxt;
if (ovs_ctxt->ovr_stress) {
/* set power */
phy_set_tx_pwr_limit(min(power, ovs_ctxt->ovr_pwr));
} else {
/* set power */
phy_set_tx_pwr_limit(power);
}
#else
(void)uint_dbuv;
#endif
return ret;
}