/**************************************************************************** Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED. This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT be copied by any method or incorporated into another program without the express written consent of Aerospace C.Power. This Information or any portion thereof remains the property of Aerospace C.Power. The Information contained herein is believed to be accurate and Aerospace C.Power assumes no responsibility or liability for its use in any way and conveys no license or title under any patent or copyright and makes no representation or warranty that this Information is free from patent or copyright infringement. ****************************************************************************/ /* os shim includes */ #include "iot_config.h" #include "os_types.h" #include "hw_reg_api.h" #include "iot_mem.h" /* plc public api includes */ #include "plc_fr.h" #include "plc_const.h" #include "iot_bitops.h" /* driver includes */ #include "iot_system.h" #include "iot_irq.h" #include "iot_gpio_api.h" #include "iot_board_api.h" #include "iot_errno_api.h" #include "pin_rf.h" #include "mpdu_header.h" #include "mac_sys_reg.h" #include "plc_protocol.h" #include "mac_raw_reg.h" #include "mac_rawdata_hw.h" #include "phy_reg.h" #include "phy_bb.h" #include "phy_phase.h" #include "phy_isr.h" #include "ahb.h" #include "os_timer_api.h" #include "phy_overstress.h" #include "hw_phy_api.h" iot_plc_over_stress_cb_t mac_ovr_stress_isr_cb = NULL; /* MAC callback func register */ void register_over_stress_cb(iot_plc_over_stress_cb_t cb) { mac_ovr_stress_isr_cb = cb; } bool_t phy_overstress_is_on(void) { bool_t overstress_is_on = false; #if HW_PLATFORM >= HW_PLATFORM_FPGA uint8_t over_stress_gpio = 0; uint32_t irq_type_reg = 0; uint32_t reg_int = 0; /* lic with geode in and other geode out */ if(iot_chip_check_lic()) {/* internal PA */ /* clr intr*/ reg_int = PHY_READ_REG(CFG_BB_INT_CLR_1_ADDR); reg_int |=PHY_LIC_OVR_STRESS; PHY_WRITE_REG(CFG_BB_INT_CLR_1_ADDR, reg_int); /* check intr src */ irq_type_reg = PHY_READ_REG(CFG_BB_INT_RAW_1_ADDR); if(irq_type_reg & PHY_LIC_OVR_STRESS){ return true; } else { return false; } } else {/* external PA */ over_stress_gpio = iot_board_get_gpio(GPIO_GEODE_OVT); if(iot_gpio_value_get(over_stress_gpio)) { return false; } else { return true; } } #endif return overstress_is_on; } /* TODO: use macro distinguish WARID, as WAR_BUGID_244 in iot_config.h */ uint32_t IRAM_ATTR phy_get_hw_interrupt_type(void) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t irq_type_reg = 0; uint32_t irq_type = 0; /* get int 1 mask */ irq_type_reg = PHY_READ_REG(CFG_BB_INT_MASK_1_ADDR); if(irq_type_reg & PHY_LIC_OVR_STRESS){ irq_type |= INTR_TYPE_PHY_LIC_OVR_STRESS; } return irq_type; #else return 0; #endif } void IRAM_ATTR phy_disable_hw_interrupt(uint32_t irq_type) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t reg_int = 0; /* disable int 1 */ if (irq_type & INTR_TYPE_PHY_LIC_OVR_STRESS) { reg_int = PHY_READ_REG(CFG_BB_INT_EN_1_ADDR); reg_int &= (~PHY_LIC_OVR_STRESS); PHY_WRITE_REG(CFG_BB_INT_EN_1_ADDR, reg_int); } #else (void)irq_type; #endif return; } void IRAM_ATTR phy_clear_hw_interrupt(uint32_t irq_type) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t reg_int = 0; /* clear int 1 */ if (irq_type & INTR_TYPE_PHY_LIC_OVR_STRESS) { reg_int = PHY_READ_REG(CFG_BB_INT_CLR_1_ADDR); reg_int |=PHY_LIC_OVR_STRESS; PHY_WRITE_REG(CFG_BB_INT_CLR_1_ADDR, reg_int); } #else (void)irq_type; #endif } void IRAM_ATTR phy_enable_hw_interrupt(uint32_t irq_type) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t reg_int = 0; /* enable int 1 */ if (irq_type & INTR_TYPE_PHY_LIC_OVR_STRESS) { reg_int = PHY_READ_REG(CFG_BB_INT_EN_1_ADDR); reg_int |=PHY_LIC_OVR_STRESS; PHY_WRITE_REG(CFG_BB_INT_EN_1_ADDR, reg_int); } #else (void)irq_type; #endif return; } uint32_t IRAM_ATTR phy_interrupt_handler(uint32_t vector, iot_addrword_t data) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t isr_flag = 0; isr_flag = phy_get_hw_interrupt_type(); /* clear cpu0 int */ phy_clear_hw_interrupt(isr_flag); /* disable interrupt mask */ phy_disable_hw_interrupt(isr_flag); /* turn down gain */ if (isr_flag & INTR_TYPE_PHY_LIC_OVR_STRESS) { /* update cnt */ phy_add_overstress_cnt(); /* turn down power */ if (!g_phy_ctxt.indep.ovs_ctxt.ovr_stress) { /* update global flag */ g_phy_ctxt.indep.ovs_ctxt.ovr_stress = 1; } /* mac callback */ if (mac_ovr_stress_isr_cb != NULL) { mac_ovr_stress_isr_cb(NULL, 1); } } if (isr_flag & INTR_TYPE_PHY_LIC_OVR_STRESS){ /* disable over stress interrupt */ isr_flag &= ~INTR_TYPE_PHY_LIC_OVR_STRESS; phy_enable_hw_interrupt(isr_flag); } else{ phy_enable_hw_interrupt(isr_flag); } #else (void)vector; (void)data; #endif return ERR_OK; } void phy_gpio_interrupt_handler(int arg) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint8_t over_stress_gpio = iot_board_get_gpio(GPIO_GEODE_OVT); /* disable overstress gpio interrupt */ iot_gpio_interrupt_enable(over_stress_gpio, 0); /* add event cnt */ phy_add_overstress_cnt(); /* turn down tx power with rms */ if(!g_phy_ctxt.indep.ovs_ctxt.ovr_stress) { /* update global flag */ g_phy_ctxt.indep.ovs_ctxt.ovr_stress = 1; } /* mac callback */ if(mac_ovr_stress_isr_cb != NULL){ mac_ovr_stress_isr_cb(NULL, 0); } #endif (void)arg; return; } uint32_t phy_gpio_interrupt_init() { uint32_t ret = ERR_FAIL; #if HW_PLATFORM >= HW_PLATFORM_FPGA uint8_t over_stress_gpio = iot_board_get_gpio(GPIO_GEODE_OVT); ret = iot_gpio_open_as_interrupt(over_stress_gpio); ret |= iot_gpio_interrupt_config(over_stress_gpio, GPIO_INT_LEVEL_LOW, phy_gpio_interrupt_handler, 0, GPIO_INT_FUNC_ENABLE_AUTOSTOP); ret |= iot_gpio_interrupt_enable(over_stress_gpio, 1); if(ret){ iot_gpio_close(over_stress_gpio); } #endif return ret; } static void phy_isr_clean(void) { /* disable all interrupt and clean up any pending interrupt */ PHY_WRITE_REG(CFG_BB_INT_EN_0_ADDR, 0); PHY_WRITE_REG(CFG_BB_INT_EN_1_ADDR, 0); PHY_WRITE_REG(CFG_BB_INT_EN_2_ADDR, 0); //INT_EN_3 map to cpu1 /* clean up all pending interrupt */ PHY_WRITE_REG(CFG_BB_INT_CLR_0_ADDR, BB_INT_CLR_0_MASK); PHY_WRITE_REG(CFG_BB_INT_CLR_1_ADDR, BB_INT_CLR_1_MASK); PHY_WRITE_REG(CFG_BB_INT_CLR_2_ADDR, BB_INT_CLR_2_MASK); } void phy_isr_clean_cpu1(void) { /* disable all interrupt and clean up any pending interrupt */ PHY_WRITE_REG(CFG_BB_INT_EN_3_ADDR, 0); /* clean up all pending interrupt */ PHY_WRITE_REG(CFG_BB_INT_CLR_3_ADDR, BB_INT_CLR_3_MASK); } void phy_isr_init() { #if HW_PLATFORM >= HW_PLATFORM_FPGA iot_irq_t phy_fd_fc_err_irqhdl; iot_irq_t phy_lic_ovr_stress_irqhdl; /* reset phy interrupt reg */ phy_isr_clean(); /* k48 or k68 */ if(iot_chip_check_lic()) {/* internal PA */ phy_lic_ovr_stress_irqhdl = \ iot_interrupt_create(IRQ_NUM_PHY_LIC_OVR_STRESS, HAL_INTR_PRI_0, 0, phy_interrupt_handler); iot_interrupt_attach(phy_lic_ovr_stress_irqhdl); iot_interrupt_unmask(phy_lic_ovr_stress_irqhdl); } else {/* external PA */ phy_gpio_interrupt_init(); } phy_fd_fc_err_irqhdl = \ iot_interrupt_create(HAL_VECTOR_PHY_2, HAL_INTR_PRI_6, 0, phy_interrupt_handler); iot_interrupt_attach(phy_fd_fc_err_irqhdl); iot_interrupt_unmask(phy_fd_fc_err_irqhdl); #endif return; } void phy_isr_start() { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t reg_int; /* bind phy int 1 */ if(iot_chip_check_lic()){/* internal PA */ reg_int = PHY_READ_REG(CFG_BB_INT_EN_1_ADDR); reg_int |= PHY_LIC_OVR_STRESS; PHY_WRITE_REG(CFG_BB_INT_EN_1_ADDR, reg_int); } #endif return; } void phy_isr_start_cpu1(void) { #if HW_PLATFORM >= HW_PLATFORM_FPGA uint32_t reg_int = 0; phy_isr_clean_cpu1(); /* TODO: enable isr need use api phy_enable_hw_interrupt_cpu1() */ /* bind phy int 3 */ reg_int = PHY_RECV_FD_FC_OK; reg_int |= PHY_RECV_FD_FC_FAIL; reg_int |= PHY_TX_FD_TX_DONE; #if ENA_WAR_NSG_EXTMI || MAC_SYM_NUM_FIX reg_int |= PHY_RECV_FD_CH_EST_DONE; #endif/* ENA_WAR_NSG_EXTMI || MAC_SYM_NUM_FIX */ #if ENA_WAR_NSG_EXTMI reg_int |= PHY_RECV_FD_PB_OK; reg_int |= PHY_RECV_FD_PB_FAIL; reg_int |= PHY_RECV_FC_RAW_RECEIVE; #endif/* ENA_WAR_NSG_EXTMI */ #if (ENA_WAR_NSG_EXTMI || ENA_SW_SYNC_PPM_WAR) reg_int |= PHY_TX_FD_INSERT_PREAM_DONE; #endif #if (ENA_WAR_SPG_TX_OK || DEBUG_NID_ERR || ENA_CCO_RX_THR_PHASE_CHANGE) reg_int |= PHY_TX_TD_FC_DONE; #endif #if ENA_WAR_244 reg_int |= PHY_FD_TX_ABORT; reg_int |= PHY_FD_TX_STUCK; reg_int |= PHY_TX_TD_START; #endif #if MAC_SYM_NUM_FIX || MAC_TIMESTAMPING || ENA_CCO_RX_THR_PHASE_CHANGE reg_int |= PHY_RECV_FD_PLD_OK; reg_int |= PHY_RECV_FD_PLD_FAIL; #endif PHY_WRITE_REG(CFG_BB_INT_EN_3_ADDR, reg_int); #endif return; }