/**************************************************************************** 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" #include "iot_io_api.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 "phy_txrx_pwr.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; } /* get int 2 mask */ irq_type_reg = PHY_READ_REG(CFG_BB_INT_MASK_2_ADDR); if (irq_type_reg & PHY_RECV_FD_FC_OK) { irq_type |= INTR_TYPE_PHY_FD_FC_OK; } irq_type_reg = PHY_READ_REG(CFG_BB_INT_MASK_2_ADDR); if (irq_type_reg & PHY_FD_TX_ABORT) { irq_type |= INTR_TYPE_PHY_FD_TX_ABORT; } #if MAC_TIMESTAMPING if (irq_type_reg & PHY_RECV_FD_PLD_OK) { irq_type |= INTR_TYPE_PHY_FD_PLD_OK; } if (irq_type_reg & PHY_RECV_FD_PLD_FAIL) { irq_type |= INTR_TYPE_PHY_FD_PLD_FAIL; } #endif #if (ENA_HW_SYNC_PPM_WAR) if (irq_type_reg & PHY_TX_FD_INSERT_PREAM_DONE) { irq_type |= INTR_TYPE_PHY_INSERT_PREAM_DONE; } #endif 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); } if (irq_type & INTR_TYPE_PHY_FD_FC_OK) { reg_int = PHY_READ_REG(CFG_BB_INT_EN_2_ADDR); reg_int &= (~PHY_RECV_FD_FC_OK); PHY_WRITE_REG(CFG_BB_INT_EN_2_ADDR, reg_int); } if (irq_type & INTR_TYPE_PHY_FD_TX_ABORT) { reg_int = PHY_READ_REG(CFG_BB_INT_EN_2_ADDR); reg_int &= (~PHY_FD_TX_ABORT); PHY_WRITE_REG(CFG_BB_INT_EN_2_ADDR, reg_int); } /* disable int 2 */ #if MAC_TIMESTAMPING if (irq_type & (INTR_TYPE_PHY_FD_PLD_OK | INTR_TYPE_PHY_FD_PLD_FAIL)) { reg_int = PHY_READ_REG(CFG_BB_INT_EN_2_ADDR); if (irq_type & INTR_TYPE_PHY_FD_PLD_OK) { reg_int &= (~PHY_RECV_FD_PLD_OK); } if (irq_type & INTR_TYPE_PHY_FD_PLD_FAIL) { reg_int &= (~PHY_RECV_FD_PLD_FAIL); } PHY_WRITE_REG(CFG_BB_INT_EN_2_ADDR, reg_int); } #endif #if (ENA_HW_SYNC_PPM_WAR) if (irq_type & INTR_TYPE_PHY_INSERT_PREAM_DONE) { reg_int = PHY_READ_REG(CFG_BB_INT_EN_2_ADDR); reg_int &= (~PHY_TX_FD_INSERT_PREAM_DONE); PHY_WRITE_REG(CFG_BB_INT_EN_2_ADDR, reg_int); } #endif #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); } if (irq_type & INTR_TYPE_PHY_FD_FC_OK) { reg_int = PHY_READ_REG(CFG_BB_INT_CLR_2_ADDR); reg_int |=PHY_RECV_FD_FC_OK; PHY_WRITE_REG(CFG_BB_INT_CLR_2_ADDR, reg_int); } if (irq_type & INTR_TYPE_PHY_FD_TX_ABORT) { reg_int = PHY_READ_REG(CFG_BB_INT_CLR_2_ADDR); reg_int |=PHY_FD_TX_ABORT; PHY_WRITE_REG(CFG_BB_INT_CLR_2_ADDR, reg_int); } /* clear int 2 */ #if MAC_TIMESTAMPING if (irq_type & (INTR_TYPE_PHY_FD_PLD_OK | INTR_TYPE_PHY_FD_PLD_FAIL)) { reg_int = PHY_READ_REG(CFG_BB_INT_CLR_2_ADDR); if (irq_type & INTR_TYPE_PHY_FD_PLD_OK) { reg_int |=PHY_RECV_FD_PLD_OK; } if (irq_type & INTR_TYPE_PHY_FD_PLD_FAIL) { reg_int |= PHY_RECV_FD_PLD_FAIL; } PHY_WRITE_REG(CFG_BB_INT_CLR_2_ADDR, reg_int); } #endif #if (ENA_HW_SYNC_PPM_WAR) if (irq_type & INTR_TYPE_PHY_INSERT_PREAM_DONE) { reg_int = PHY_READ_REG(CFG_BB_INT_CLR_2_ADDR); reg_int |=PHY_TX_FD_INSERT_PREAM_DONE; PHY_WRITE_REG(CFG_BB_INT_CLR_2_ADDR, reg_int); } #endif #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); } if (irq_type & INTR_TYPE_PHY_FD_FC_OK) { reg_int = PHY_READ_REG(CFG_BB_INT_EN_2_ADDR); reg_int |=PHY_RECV_FD_FC_OK; PHY_WRITE_REG(CFG_BB_INT_EN_2_ADDR, reg_int); } if (irq_type & INTR_TYPE_PHY_FD_TX_ABORT) { reg_int = PHY_READ_REG(CFG_BB_INT_EN_2_ADDR); reg_int |=PHY_FD_TX_ABORT; PHY_WRITE_REG(CFG_BB_INT_EN_2_ADDR, reg_int); } /* enable int 2 */ #if MAC_TIMESTAMPING if (irq_type & (INTR_TYPE_PHY_FD_PLD_OK | INTR_TYPE_PHY_FD_PLD_FAIL)) { reg_int = PHY_READ_REG(CFG_BB_INT_EN_2_ADDR); if (irq_type & INTR_TYPE_PHY_FD_PLD_OK) { reg_int |=PHY_RECV_FD_PLD_OK; } if (irq_type & INTR_TYPE_PHY_FD_PLD_FAIL) { reg_int |= PHY_RECV_FD_PLD_FAIL; } PHY_WRITE_REG(CFG_BB_INT_EN_2_ADDR, reg_int); } #endif #if (ENA_HW_SYNC_PPM_WAR) if (irq_type & INTR_TYPE_PHY_INSERT_PREAM_DONE) { reg_int = PHY_READ_REG(CFG_BB_INT_EN_2_ADDR); reg_int |= PHY_TX_FD_INSERT_PREAM_DONE; PHY_WRITE_REG(CFG_BB_INT_EN_2_ADDR, reg_int); } #endif #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); #if MAC_TIMESTAMPING /* PLD ok or fail interrupt */ if(isr_flag & INTR_TYPE_PHY_FD_PLD_OK \ || isr_flag & INTR_TYPE_PHY_FD_PLD_FAIL) { g_phy_cpu_share_ctxt.phy_pld_int_ntb = \ RGF_MAC_READ_REG(CFG_RD_NTB_ADDR); } #endif if (isr_flag & INTR_TYPE_PHY_FD_FC_OK) { g_phy_ctxt.dep.reg_phase = phy_get_mac_rx_phase(); } #if DEG_TX_ABORT if (isr_flag & INTR_TYPE_PHY_FD_TX_ABORT) { phy_dbg_get_tx_abort_lock_value(); } #endif /* 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); } #if (ENA_HW_SYNC_PPM_WAR) /* kl2 tx ppm war */ if (isr_flag & INTR_TYPE_PHY_INSERT_PREAM_DONE) { uint32_t proto = PHY_PROTO_TYPE_GET(); rx_fc_msg_t msg; uint32_t bb_fc[4] = {0}; bb_fc[0] = RGF_RAW_READ_REG(CFG_TX_FC_DATA0_ADDR); bb_fc[1] = RGF_RAW_READ_REG(CFG_TX_FC_DATA1_ADDR); bb_fc[2] = RGF_RAW_READ_REG(CFG_TX_FC_DATA2_ADDR); bb_fc[3] = RGF_RAW_READ_REG(CFG_TX_FC_DATA3_ADDR); phy_ppm_status_ctxt_t *ppm_ctxt = phy_multi_sync_get_ppm_status(); mac_get_rx_frm_msg_from_fc(proto, bb_fc, &msg); phy_multi_sync_apply_bb_ppm(ppm_ctxt, msg.nid, BB_PPM_TX_ONLY); } #endif #else (void)vector; (void)data; #endif return ERR_OK; } 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(); /* kl2 just have 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); 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 */ /* 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); /* bind phy int 2 */ reg_int = PHY_READ_REG(CFG_BB_INT_EN_2_ADDR); reg_int |= PHY_RECV_FD_FC_OK; reg_int |= PHY_FD_TX_ABORT; #if MAC_TIMESTAMPING reg_int |= PHY_RECV_FD_PLD_OK; reg_int |= PHY_RECV_FD_PLD_FAIL; #endif #if (ENA_HW_SYNC_PPM_WAR) reg_int |= PHY_TX_FD_INSERT_PREAM_DONE; #endif PHY_WRITE_REG(CFG_BB_INT_EN_2_ADDR, reg_int); #endif return; } void phy_isr_start_cpu1(void) { /* currently we don't have cpu1 for kl3 */ return; }