class CPLD:

    CPLD_I2C_BUS = 1
    CPLD_I2C_ADDR = [0x30, 0x39, 0x3A, 0x3B, 0x3C]

    CPLD_PORT_INT_BIT = 0b00000001
    CPLD_GBOX_INT_BIT = 0b00000010
    CPLD_PORT_PRE_BIT = 0b00001000
    CPLD_RTMR_INT_BIT = 0b00000001

    CPLD_QSFP_STATUS_INT_BIT = 0b00000001
    CPLD_QSFP_STATUS_ABS_BIT = 0b00000010
    CPLD_QSFP_CONFIG_RST_BIT = 0b00000001
    CPLD_QSFP_CONFIG_LP_BIT = 0b00000100

    CPLD_QSFPDD_STATUS_INT_BIT = 0b00000001
    CPLD_QSFPDD_STATUS_ABS_BIT = 0b00000010
    CPLD_QSFPDD_CONFIG_RST_BIT = 0b00000001
    CPLD_QSFPDD_CONFIG_LP_BIT = 0b00000100

    CPLD_SFP0_STATUS_PRSNT_BIT = 0b00000001
    CPLD_SFP0_STATUS_TX_FAULT_BIT = 0b00000010
    CPLD_SFP0_STATUS_RX_LOS_BIT = 0b00000100
    CPLD_SFP0_CONFIG_TX_DIS_BIT = 0b00000001

    CPLD_SFP1_STATUS_PRSNT_BIT = 0b00010000
    CPLD_SFP1_STATUS_TX_FAULT_BIT = 0b00100000
    CPLD_SFP1_STATUS_RX_LOS_BIT = 0b01000000
    CPLD_SFP1_CONFIG_TX_DIS_BIT = 0b00010000

    CPLD_PSU0_STATUS_PRSNT_BIT = 0b01000000
    CPLD_PSU0_STATUS_POWER_BIT = 0b00010000

    CPLD_PSU1_STATUS_PRSNT_BIT = 0b10000000
    CPLD_PSU1_STATUS_POWER_BIT = 0b00100000

    CPLD_BMC_PRNST_BIT = 0b00000001

    CPLD_CS4227_RESET_BIT = 0b00010000
    CPLD_GBX_RESET_BIT = 0b00100000
    CPLD_J2_RESET_BIT = 0b01000000
    CPLD_RETIMER_RESET_BIT = 0b00000001
    CPLD_OP2_CRST_RESET_BIT = 0b00000001
    CPLD_OP2_PERST_RESET_BIT = 0b00000010
    CPLD_OP2_SRST_RESET_BIT = 0b00000100

    CPLD_J2_ROV_BIT = 0b00001110

    ATTR_CPLD_VERSION = "cpld_version"
    ATTR_CPLD_ID = "cpld_id"
    ATTR_CPLD_BOARD_TYPE = "cpld_board_type"
    ATTR_CPLD_EXT_BOARD_TYPE = "cpld_ext_board_type"
    ATTR_CPLD_INTR = "cpld_interrupt"
    ATTR_CPLD_INTR_2 = "cpld_interrupt_2"
    ATTR_CPLD_QSFPDD_PORT_STATUS = "cpld_qsfpdd_port_status"
    ATTR_CPLD_QSFPDD_PORT_CONFIG = "cpld_qsfpdd_port_config"
    ATTR_CPLD_QSFP_PORT_STATUS = "cpld_qsfp_port_status"
    ATTR_CPLD_QSFP_PORT_CONFIG = "cpld_qsfp_port_config"
    ATTR_CPLD_SFP_PORT_STATUS = "cpld_sfp_port_status"
    ATTR_CPLD_SFP_PORT_CONFIG = "cpld_sfp_port_config"
    ATTR_CPLD_PSU_STATUS = "cpld_psu_status"
    ATTR_CPLD_SFP_LED = "cpld_sfp_led"
    ATTR_CPLD_QSFPDD_LED = "cpld_qsfpdd_led"
    ATTR_CPLD_SYSTEM_LED = "cpld_system_led"
    ATTR_CPLD_BMC_PRSNT = "cpld_bmc_status"
    ATTR_CPLD_RESET_CTRL = "cpld_reset_control"
    ATTR_CPLD_RESET_MAC = "cpld_reset_mac"
    ATTR_CPLD_RESET_RETIMER = "cpld_reset_retimer"
    ATTR_CPLD_RESET_MAC_2 = "cpld_reset_mac_2"
    ATTR_CPLD_GBOX_INTR = "cpld_gbox_intr"
    ATTR_CPLD_RETIMER_INTR = "cpld_retimer_intr"

    DEV_NAME = "s9700_53dx_cpld"
    DRIVER_NAME = "x86_64_ufispace_s9700_53dx_cpld"

    def __init__(self):
        log = Logger(__name__)
        self.logger = log.getLogger()
        self.i2c = I2C()
        self.lpc = LPC()
        self.sysfs_util = SysfsUtility()
        self.brd_id_util = BrdIDUtility()

        # init i2c devices for CPLD
        self.i2c_dev = []
        for i in range(CPLDConst.CPLD_MAX):
            self.i2c_dev.append(
                I2C_Dev(self.CPLD_I2C_BUS, self.CPLD_I2C_ADDR[i]))

    def init(self):
        try:
            for cpld_index in range(CPLDConst.CPLD_MAX):

                sysfs_path = self.sysfs_util.get_sysfs_path(
                    self.CPLD_I2C_BUS, self.i2c_dev[cpld_index].addr)
                sysfs_new_dev_path = self.sysfs_util.get_new_dev_path(
                    self.i2c_dev[cpld_index].bus)

                if not os.path.exists(sysfs_path):
                    with open(sysfs_new_dev_path, "w") as f:
                        f.write(
                            "{}{} {}".format(self.DEV_NAME, cpld_index + 1,
                                             self.i2c_dev[cpld_index].addr))
                else:
                    self.logger.warning(
                        "sysfs_path already exist: {0}".format(sysfs_path))
                    continue
        except IOError as e:
            self.logger.error("I/O error({0}): {1}".format(
                e.errno, e.strerror))
        except:
            self.logger.error("Unexpected error:", sys.exc_info()[0])
            raise

    def deinit(self):
        try:
            for cpld_index in range(CPLDConst.CPLD_MAX):

                sysfs_path = self.sysfs_util.get_sysfs_path(
                    self.CPLD_I2C_BUS, self.i2c_dev[cpld_index].addr)
                sysfs_del_dev_path = self.sysfs_util.get_del_dev_path(
                    self.i2c_dev[cpld_index].bus)

                if os.path.exists(sysfs_path):
                    with open(sysfs_del_dev_path, "w") as f:
                        f.write("{}".format(self.i2c_dev[cpld_index].addr))
            return
        except IOError as e:
            self.logger.error("I/O error({0}): {1}".format(
                e.errno, e.strerror))
        except:
            self.logger.error("Unexpected error:", sys.exc_info()[0])
            raise

    def _get_sysfs_path(self, cpld_index, cpld_attr, cpld_port_index=-1):
        sysfs_path = self.sysfs_util.get_sysfs_path(
            self.CPLD_I2C_BUS, self.i2c_dev[cpld_index].addr, cpld_attr)

        if cpld_port_index != -1:
            sysfs_path = sysfs_path + "_" + str(cpld_port_index)

        return sysfs_path

    def _read_sysfs(self, sysfs_path, data_type=DataType.INT):

        reg_val = 0

        try:
            if os.path.exists(sysfs_path):
                with open(sysfs_path, "r") as f:
                    # read content
                    content = f.read()

                    # convert data type
                    if data_type == DataType.INT:
                        reg_val = int(content.strip(), 0)
            else:
                raise IOError(
                    "sysfs_path does not exist: {0}".format(sysfs_path))
        except Exception as e:
            self.logger.error(e)
            raise

        return reg_val

    def _write_sysfs(self, sysfs_path, reg_val):

        try:
            if os.path.exists(sysfs_path):
                with open(sysfs_path, "w") as f:
                    f.write(str(reg_val))
                    return True
            else:
                self.logger.error(
                    "sysfs_path does not exist: {0}".format(sysfs_path))

            return False
        except Exception as e:
            self.logger.error(e)
            raise

    # read cpld reg from sysfs
    def _read_cpld_reg(self, cpld_index, cpld_attr, cpld_port_index=-1):
        sysfs_path = self._get_sysfs_path(cpld_index, cpld_attr,
                                          cpld_port_index)
        reg_val = self._read_sysfs(sysfs_path)

        return reg_val

    # write cpld reg via sysfs
    def _write_cpld_reg(self,
                        cpld_index,
                        cpld_attr,
                        reg_val,
                        cpld_port_index=-1):
        sysfs_path = self._get_sysfs_path(cpld_index, cpld_attr,
                                          cpld_port_index)
        return self._write_sysfs(sysfs_path, reg_val)

    # get bit shift from mask
    def _get_shift(self, reg_mask):
        mask_one = 1

        for i in range(8):
            if reg_mask & mask_one == 1:
                return i
            else:
                reg_mask >>= 1

        # not found
        return -1

    ########## FOR CPLD UTILITY ##########
    def get_board_info(self):
        cpld_index = CPLDConst.CPLD_1

        try:
            # read board_id reg
            cpld_attr = self.ATTR_CPLD_BOARD_TYPE
            reg_val = self._read_cpld_reg(cpld_index, cpld_attr)

            #board id
            board_id = self.brd_id_util.get_model_id(reg_val)
            board_id_str = self.brd_id_util.get_model_id_str(board_id)

            #hw_rev
            hw_rev = self.brd_id_util.get_hw_rev(reg_val)
            hw_rev_str = self.brd_id_util.get_hw_rev_str(hw_rev)

            #build_rev
            build_rev = self.brd_id_util.get_build_rev(reg_val)
            build_rev_str = self.brd_id_util.get_build_rev_str(build_rev)

            return {
                "board_id": board_id,
                "board_id_str": board_id_str,
                "hw_rev": hw_rev,
                "hw_rev_str": hw_rev_str,
                "build_rev": build_rev,
                "build_rev_str": build_rev_str
            }
        except Exception as e:
            self.logger.error(e)
            raise

    def get_cpu_board_cpld_version(self):
        try:
            reg_val = self.lpc.regGet(LPCDevType.CPLD_ON_CPU_BOARD,
                                      CPLDCPUReg.REG_CPLD_REVISION)
            return reg_val
        except Exception as e:
            self.logger.error(e)
            raise

    def get_main_board_cpld_version(self):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_VERSION
        reg_vals = []

        for cpld_index in range(CPLDConst.CPLD_MAX):
            reg_val = self._read_cpld_reg(cpld_index, cpld_attr)
            reg_vals.append(reg_val)

        return reg_vals

    def get_main_board_cpld_id(self):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_ID
        reg_vals = []

        for cpld_index in range(CPLDConst.CPLD_MAX):
            reg_val = self._read_cpld_reg(cpld_index, cpld_attr)
            reg_vals.append(reg_val)

        return reg_vals

    def get_port_interrupt(self, cpld_index):
        cpld_attr = self.ATTR_CPLD_INTR
        reg_mask = self.CPLD_PORT_INT_BIT

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr)
        interrupt = (reg_val & reg_mask) >> self._get_shift(reg_mask)

        return interrupt

    def get_intr_reg(self, cpld_index, reg_index):
        cpld_attr = [self.ATTR_CPLD_INTR, self.ATTR_CPLD_INTR_2]

        #only cpld0 has intr 2
        if cpld_index != 0 and reg_index > 0:
            raise ValueError("interrupt_2 reg is only available in cpld 0")

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr[reg_index])

        return reg_val

    def get_port_presence(self, cpld_index):
        cpld_attr = self.ATTR_CPLD_INTR
        reg_mask = self.CPLD_PORT_PRE_BIT

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr)
        presence = (reg_val & reg_mask) >> self._get_shift(reg_mask)

        return presence

    ########## FOR SFP+ ##########
    def sfp_get_presence(self, port_num):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_SFP_PORT_STATUS
        mask = 0

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr)

        if port_num == 0:
            mask = self.CPLD_SFP0_STATUS_PRSNT_BIT
        else:
            mask = self.CPLD_SFP1_STATUS_PRSNT_BIT

        presence = (reg_val & mask) >> self._get_shift(mask)

        return presence

    def sfp_get_tx_fault(self, port_num):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_SFP_PORT_STATUS
        mask = 0

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr)

        if port_num == 0:
            mask = self.CPLD_SFP0_STATUS_TX_FAULT_BIT
        else:
            mask = self.CPLD_SFP1_STATUS_TX_FAULT_BIT

        tx_fault = (reg_val & mask) >> self._get_shift(mask)

        return tx_fault

    def sfp_get_tx_disable(self, port_num):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_SFP_PORT_CONFIG
        mask = 0

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr)

        if port_num == 0:
            mask = self.CPLD_SFP0_CONFIG_TX_DIS_BIT
        else:
            mask = self.CPLD_SFP1_CONFIG_TX_DIS_BIT

        tx_disable = (reg_val & mask) >> self._get_shift(mask)

        return tx_disable

    def sfp_set_tx_disable(self, port_num, tx_disable):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_SFP_PORT_CONFIG
        mask = 0

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr)

        if port_num == 0:
            mask = self.CPLD_SFP0_CONFIG_TX_DIS_BIT
        else:
            mask = self.CPLD_SFP1_CONFIG_TX_DIS_BIT

        if tx_disable == SFP.DISABLED:
            reg_val |= mask
        else:
            reg_val &= ~mask

        return self._write_cpld_reg(cpld_index, cpld_attr, reg_val)

    def sfp_get_rx_los(self, port_num):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_SFP_PORT_STATUS
        mask = 0

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr)

        if port_num == 0:
            mask = self.CPLD_SFP0_STATUS_RX_LOS_BIT
        else:
            mask = self.CPLD_SFP1_STATUS_RX_LOS_BIT

        rx_los = (reg_val & mask) >> self._get_shift(mask)

        return rx_los

    ########## FOR QSFP ##########
    def _qsfp_port_fp2phy(self, fp_port):

        if 0 <= fp_port <= 19:
            phy_port = fp_port
        else:
            if fp_port % 2 == 0:
                phy_port = fp_port + 1
            else:
                phy_port = fp_port - 1

        return phy_port

    def _qsfp_cpld_var_set(self, phy_port):
        if 0 <= phy_port <= 11:
            cpld_index = CPLDConst.CPLD_1
            reg_port_base = 0
        elif 12 <= phy_port <= 24:
            cpld_index = CPLDConst.CPLD_2
            reg_port_base = 12
        elif 25 <= phy_port <= 37:
            cpld_index = CPLDConst.CPLD_3
            reg_port_base = 25
        elif 38 <= phy_port <= 39:
            cpld_index = CPLDConst.CPLD_4
            reg_port_base = 38
        else:
            self.logger.error("invalid port number")

        cpld_var = {
            "cpld_index": cpld_index,
            "cpld_port_index": phy_port - reg_port_base
        }

        return cpld_var

    def _read_qsfp_reg(self, port_num, cpld_attr, reg_mask, reg_shift):
        phy_port = self._qsfp_port_fp2phy(port_num)
        cpld_var = self._qsfp_cpld_var_set(phy_port)

        reg_val = self._read_cpld_reg(cpld_var["cpld_index"], cpld_attr,
                                      cpld_var["cpld_port_index"])
        masked_val = (reg_val & reg_mask) >> reg_shift

        return masked_val

    def _write_qsfp_reg(self, port_num, cpld_attr, reg_val):
        phy_port = self._qsfp_port_fp2phy(port_num)
        cpld_var = self._qsfp_cpld_var_set(phy_port)

        return self._write_cpld_reg(cpld_var["cpld_index"], cpld_attr, reg_val,
                                    cpld_var["cpld_port_index"])

    def qsfp_get_presence(self, port_num):
        cpld_attr = self.ATTR_CPLD_QSFP_PORT_STATUS
        reg_mask = self.CPLD_QSFP_STATUS_ABS_BIT
        reg_shift = self._get_shift(reg_mask)

        presence = self._read_qsfp_reg(port_num, cpld_attr, reg_mask,
                                       reg_shift)

        return presence

    def qsfp_get_interrupt(self, port_num):
        cpld_attr = self.ATTR_CPLD_QSFP_PORT_STATUS
        reg_mask = self.CPLD_QSFP_STATUS_INT_BIT
        reg_shift = self._get_shift(reg_mask)

        interrupt = self._read_qsfp_reg(port_num, cpld_attr, reg_mask,
                                        reg_shift)

        return interrupt

    def qsfp_get_lp_mode(self, port_num):
        cpld_attr = self.ATTR_CPLD_QSFP_PORT_CONFIG
        reg_mask = self.CPLD_QSFP_CONFIG_LP_BIT
        reg_shift = self._get_shift(reg_mask)

        lp_mode = self._read_qsfp_reg(port_num, cpld_attr, reg_mask, reg_shift)

        return lp_mode

    def qsfp_set_lp_mode(self, port_num, lp_mode):
        cpld_attr = self.ATTR_CPLD_QSFP_PORT_CONFIG
        reg_mask = 0xFF
        reg_shift = self._get_shift(reg_mask)

        reg_val = self._read_qsfp_reg(port_num, cpld_attr, reg_mask, reg_shift)

        if lp_mode == LPMode.ENABLE:
            reg_val |= self.CPLD_QSFP_CONFIG_LP_BIT
        else:
            reg_val &= ~self.CPLD_QSFP_CONFIG_LP_BIT

        self._write_qsfp_reg(port_num, cpld_attr, reg_val)

    def qsfp_get_reset(self, port_num):
        cpld_attr = self.ATTR_CPLD_QSFP_PORT_CONFIG
        reg_mask = self.CPLD_QSFP_CONFIG_RST_BIT
        reg_shift = self._get_shift(reg_mask)

        reset = self._read_qsfp_reg(port_num, cpld_attr, reg_mask, reg_shift)

        return reset

    def qsfp_set_reset(self, port_num, reset):
        cpld_attr = self.ATTR_CPLD_QSFP_PORT_CONFIG
        reg_mask = 0xFF
        reg_shift = self._get_shift(reg_mask)

        reg_val = self._read_qsfp_reg(port_num, cpld_attr, reg_mask, reg_shift)

        # high -> low, trigger reset
        if reset == PortStatus.RESET:
            reg_val &= ~self.CPLD_QSFP_CONFIG_RST_BIT
        else:
            reg_val |= self.CPLD_QSFP_CONFIG_RST_BIT

        self._write_qsfp_reg(port_num, cpld_attr, reg_val)

    def qsfp_reset_port(self, port_num):
        cpld_attr = self.ATTR_CPLD_QSFP_PORT_CONFIG
        reg_mask = 0xFF
        reg_shift = self._get_shift(reg_mask)

        reg_val = self._read_qsfp_reg(port_num, cpld_attr, reg_mask, reg_shift)

        # high -> low, trigger reset
        reg_val &= ~self.CPLD_QSFP_CONFIG_RST_BIT
        self._write_qsfp_reg(port_num, cpld_attr, reg_val)

        # By sff-8436, the execution of a reset is max 2000ms
        sleep(2)

        # low -> high, release reset
        reg_val |= self.CPLD_QSFP_CONFIG_RST_BIT
        self._write_qsfp_reg(port_num, cpld_attr, reg_val)

    ########## FOR QSFPDD ##########
    def _qsfpdd_port_fp2phy(self, fp_port):
        phy_port = fp_port

        return phy_port

    def _qsfpdd_cpld_var_set(self, phy_port):
        if 0 <= phy_port <= 2:
            cpld_index = CPLDConst.CPLD_4
            reg_port_base = 0
        elif 3 <= phy_port <= 12:
            cpld_index = CPLDConst.CPLD_5
            reg_port_base = 3
        else:
            self.logger.error("invalid port number")

        cpld_var = {
            "cpld_index": cpld_index,
            "cpld_port_index": phy_port - reg_port_base
        }

        return cpld_var

    def _read_qsfpdd_reg(self, port_num, cpld_attr, reg_mask, reg_shift):
        phy_port = self._qsfpdd_port_fp2phy(port_num)
        cpld_var = self._qsfpdd_cpld_var_set(phy_port)

        reg_val = self._read_cpld_reg(cpld_var["cpld_index"], cpld_attr,
                                      cpld_var["cpld_port_index"])
        masked_val = (reg_val & reg_mask) >> reg_shift

        return masked_val

    def _write_qsfpdd_reg(self, port_num, cpld_attr, reg_val):
        phy_port = self._qsfpdd_port_fp2phy(port_num)
        cpld_var = self._qsfpdd_cpld_var_set(phy_port)

        self._write_cpld_reg(cpld_var["cpld_index"], cpld_attr, reg_val,
                             cpld_var["cpld_port_index"])

    def qsfpdd_get_presence(self, port_num):
        cpld_attr = self.ATTR_CPLD_QSFPDD_PORT_STATUS
        reg_mask = self.CPLD_QSFPDD_STATUS_ABS_BIT
        reg_shift = self._get_shift(reg_mask)

        presence = self._read_qsfpdd_reg(port_num, cpld_attr, reg_mask,
                                         reg_shift)

        return presence

    def qsfpdd_get_interrupt(self, port_num):
        cpld_attr = self.ATTR_CPLD_QSFPDD_PORT_STATUS
        reg_mask = self.CPLD_QSFPDD_STATUS_INT_BIT
        reg_shift = self._get_shift(reg_mask)

        interrupt = self._read_qsfpdd_reg(port_num, cpld_attr, reg_mask,
                                          reg_shift)

        return interrupt

    def qsfpdd_get_lp_mode(self, port_num):
        cpld_attr = self.ATTR_CPLD_QSFPDD_PORT_CONFIG
        reg_mask = self.CPLD_QSFPDD_CONFIG_LP_BIT
        reg_shift = self._get_shift(reg_mask)

        lp_mode = self._read_qsfpdd_reg(port_num, cpld_attr, reg_mask,
                                        reg_shift)

        return lp_mode

    def qsfpdd_set_lp_mode(self, port_num, lp_mode):
        cpld_attr = self.ATTR_CPLD_QSFPDD_PORT_CONFIG
        reg_mask = 0xFF
        reg_shift = self._get_shift(reg_mask)

        reg_val = self._read_qsfpdd_reg(port_num, cpld_attr, reg_mask,
                                        reg_shift)

        if lp_mode == LPMode.ENABLE:
            reg_val |= self.CPLD_QSFPDD_CONFIG_LP_BIT
        else:
            reg_val &= ~self.CPLD_QSFPDD_CONFIG_LP_BIT

        self._write_qsfpdd_reg(port_num, cpld_attr, reg_val)

    def qsfpdd_get_reset(self, port_num):
        cpld_attr = self.ATTR_CPLD_QSFPDD_PORT_CONFIG
        reg_mask = self.CPLD_QSFPDD_CONFIG_RST_BIT
        reg_shift = self._get_shift(reg_mask)

        reset = self._read_qsfpdd_reg(port_num, cpld_attr, reg_mask, reg_shift)

        return reset

    def qsfpdd_set_reset(self, port_num, reset):
        cpld_attr = self.ATTR_CPLD_QSFPDD_PORT_CONFIG
        reg_mask = 0xFF
        reg_shift = self._get_shift(reg_mask)

        reg_val = self._read_qsfpdd_reg(port_num, cpld_attr, reg_mask,
                                        reg_shift)

        # high -> low, trigger reset
        if reset == PortStatus.RESET:
            reg_val &= ~self.CPLD_QSFPDD_CONFIG_RST_BIT
        else:
            reg_val |= self.CPLD_QSFPDD_CONFIG_RST_BIT

        self._write_qsfpdd_reg(port_num, cpld_attr, reg_val)

    def qsfpdd_reset_port(self, port_num):
        cpld_attr = self.ATTR_CPLD_QSFPDD_PORT_CONFIG
        reg_mask = 0xFF
        reg_shift = self._get_shift(reg_mask)

        reg_val = self._read_qsfpdd_reg(port_num, cpld_attr, reg_mask,
                                        reg_shift)

        # high -> low, trigger reset
        reg_val &= ~self.CPLD_QSFPDD_CONFIG_RST_BIT
        self._write_qsfpdd_reg(port_num, cpld_attr, reg_val)

        # By sff-8436, the execution of a reset is max 2000ms
        sleep(2)

        # low -> high, release reset
        reg_val |= self.CPLD_QSFPDD_CONFIG_RST_BIT
        self._write_qsfpdd_reg(port_num, cpld_attr, reg_val)

    ########## FOR PSU ##########
    def get_psu_presence(self, psu_num):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_PSU_STATUS

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr, psu_num)

        if psu_num == PSU.PSU0:
            mask = self.CPLD_PSU0_STATUS_PRSNT_BIT
        else:
            mask = self.CPLD_PSU1_STATUS_PRSNT_BIT

        presence = (reg_val & mask) >> self._get_shift(mask)

        return presence

    def get_psu_power_ok(self, psu_num):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_PSU_STATUS

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr, psu_num)

        if psu_num == PSU.PSU0:
            mask = self.CPLD_PSU0_STATUS_POWER_BIT
        else:
            mask = self.CPLD_PSU1_STATUS_POWER_BIT

        power_ok = (reg_val & mask) >> self._get_shift(mask)

        return power_ok

    ########## FOR QSFPDD LED ##########
    def set_qsfpdd_led(self, port, color, blink):
        cpld_attr = self.ATTR_CPLD_QSFPDD_LED
        cpld_index = CPLDConst.CPLD_5
        mask = 0
        reg_shift = 0

        if color == Led.COLOR_OFF and blink == Led.BLINK_STATUS_BLINKING:
            raise ValueError("LED blinking off is invalid operation")

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr, port)

        if port % 2 == 0:
            reg_shift = 0
            mask = 0b11111000
        else:
            reg_shift = 4
            mask = 0b10001111

        # clear color
        reg_val &= mask

        # set color
        if color == Led.COLOR_GREEN:
            reg_val |= (QSFPDD.LED_MASK_GREEN << reg_shift)
        elif color == Led.COLOR_RED:
            reg_val |= (QSFPDD.LED_MASK_RED << reg_shift)
        elif color == Led.COLOR_BLUE:
            reg_val |= (QSFPDD.LED_MASK_BLUE << reg_shift)
        elif color == Led.COLOR_OFF:
            pass
        else:
            raise ValueError("LED color is out of range")

        # set blink
        if blink == Led.BLINK_STATUS_BLINKING:
            reg_val |= (QSFPDD.LED_MASK_BLINK << reg_shift)
        else:
            reg_val &= ~(QSFPDD.LED_MASK_BLINK << reg_shift)

        self._write_cpld_reg(cpld_index, cpld_attr, reg_val, port)

    def get_qsfpdd_led(self, port):
        cpld_attr = self.ATTR_CPLD_QSFPDD_LED
        cpld_index = CPLDConst.CPLD_5
        mask = 0
        color = 0
        blink = 0

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr, port)

        if port % 2 == 0:
            mask = 0x0F
        else:
            mask = 0xF0

        # put data in lower lower 4 bits regardless of port
        reg_val = (reg_val & mask) >> self._get_shift(mask)

        # get color
        if reg_val & QSFPDD.LED_MASK_GREEN == QSFPDD.LED_MASK_GREEN:
            color = Led.COLOR_GREEN
        elif reg_val & QSFPDD.LED_MASK_RED == QSFPDD.LED_MASK_RED:
            color = Led.COLOR_RED
        elif reg_val & QSFPDD.LED_MASK_BLUE == QSFPDD.LED_MASK_BLUE:
            color = Led.COLOR_BLUE
        else:
            color = Led.COLOR_OFF

        # get blink
        if reg_val & QSFPDD.LED_MASK_BLINK == QSFPDD.LED_MASK_BLINK:
            blink = Led.BLINK_STATUS_BLINKING
        else:
            blink = Led.BLINK_STATUS_SOLID

        return (color, blink)

    ########## FOR BMC ##########
    def get_bmc_presence(self):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_BMC_PRSNT

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr)

        presence = (reg_val & self.CPLD_BMC_PRNST_BIT)

        return presence

    ########## FOR RESET ##########

    def reset_dev(self, devType):
        cpld_index = CPLDConst.CPLD_1

        if devType == DevType.J2:
            cpld_attr = self.ATTR_CPLD_RESET_MAC
            mask = self.CPLD_J2_RESET_BIT
        elif devType == DevType.OP2_CRST:
            cpld_attr = self.ATTR_CPLD_RESET_MAC
            mask = self.CPLD_OP2_CRST_RESET_BIT
        elif devType == DevType.OP2_PERST:
            cpld_attr = self.ATTR_CPLD_RESET_MAC
            mask = self.CPLD_OP2_PERST_RESET_BIT
        elif devType == DevType.OP2_SRST:
            cpld_attr = self.ATTR_CPLD_RESET_MAC
            mask = self.CPLD_OP2_SRST_RESET_BIT
        elif devType == DevType.GEARBOX:
            cpld_attr = self.ATTR_CPLD_RESET_MAC
            mask = self.CPLD_GBX_RESET_BIT
        elif devType == DevType.RETIMER:
            cpld_attr = self.ATTR_CPLD_RESET_RETIMER
            mask = self.CPLD_RETIMER_RESET_BIT
        elif devType == DevType.CS4227:
            cpld_attr = self.ATTR_CPLD_RESET_MAC
            mask = self.CPLD_CS4227_RESET_BIT
        else:
            return

        board_info = self.get_board_info()

        # proto
        if board_info["hw_rev"] == 0:
            if devType == DevType.J2:
                try:
                    # reset J2
                    reg_val = self.lpc.regSet(LPCDevType.CPLD_ON_CPU_BOARD,
                                              CPLDCPUReg.REG_RESET_CTRL, 0xF0)
                    sleep(0.1)
                    # unset J2
                    reg_val = self.lpc.regSet(LPCDevType.CPLD_ON_CPU_BOARD,
                                              CPLDCPUReg.REG_RESET_CTRL, 0xF1)
                    return reg_val
                except Exception as e:
                    self.logger.error(e)
                    raise
            else:
                pass
        else:  # alpha and later
            reg_val = self._read_cpld_reg(cpld_index, cpld_attr)

            # pull low the bit
            reg_val &= ~mask

            self._write_cpld_reg(cpld_index, cpld_attr, reg_val)

    def get_reset_ctrl(self, devType):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_RESET_MAC_2
        ret = 0

        if devType == DevType.J2:
            mask = self.CPLD_J2_RESET_BIT
        elif devType == DevType.OP2_CRST:
            mask = self.CPLD_OP2_CRST_RESET_BIT
        elif devType == DevType.OP2_PERST:
            mask = self.CPLD_OP2_PERST_RESET_BIT
        elif devType == DevType.OP2_SRST:
            mask = self.CPLD_OP2_SRST_RESET_BIT
        else:
            return -1

        board_info = self.get_board_info()

        # proto
        if board_info["hw_rev"] < 2:
            return -1
        else:  # alpha and later
            reg_val = self._read_cpld_reg(cpld_index, cpld_attr)
            ret = (reg_val & mask) >> self._get_shift(mask)

        return ret

    def set_reset_ctrl(self, devType, reset_status):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_RESET_MAC_2

        if devType == DevType.J2:
            mask = self.CPLD_J2_RESET_BIT
        elif devType == DevType.OP2_CRST:
            mask = self.CPLD_OP2_CRST_RESET_BIT
        elif devType == DevType.OP2_PERST:
            mask = self.CPLD_OP2_PERST_RESET_BIT
        elif devType == DevType.OP2_SRST:
            mask = self.CPLD_OP2_SRST_RESET_BIT
        else:
            return False

        board_info = self.get_board_info()

        # proto
        if board_info["hw_rev"] < 2:
            return False
        else:  # alpha and later
            reg_val = self._read_cpld_reg(cpld_index, cpld_attr)

            if reset_status == ResetStatus.RESET:
                # pull low the bit
                reg_val &= ~mask
            else:
                # pull high the bit
                reg_val |= mask

            return self._write_cpld_reg(cpld_index, cpld_attr, reg_val)

    ########## FOR System LED ##########
    def get_sys_led(self, target):
        cpld_attr = self.ATTR_CPLD_SYSTEM_LED
        cpld_index = CPLDConst.CPLD_1
        reg_index = 0
        attr_index = 0
        mask = 0
        reg_shift = 0

        if target == Led.FAN:
            attr_index = 0
            reg_index = 0
        elif target == Led.SYSTEM:
            attr_index = 0
            reg_index = 1
        elif target == Led.PSU0:
            attr_index = 1
            reg_index = 0
        elif target == Led.PSU1:
            attr_index = 1
            reg_index = 1
        else:
            raise ValueError(
                "LED target is out of range, target is {}".format(target))

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr, attr_index)

        if reg_index % 2 == 0:
            reg_shift = 0
            mask = 0b00001111
        else:
            reg_shift = 4
            mask = 0b11110000

        return (reg_val & mask) >> reg_shift

    def set_sys_led(self, target, color, blink):
        cpld_attr = self.ATTR_CPLD_SYSTEM_LED
        cpld_index = CPLDConst.CPLD_1
        reg_index = 0
        attr_index = 0
        mask = 0
        reg_shift = 0

        if target == Led.SYSTEM:
            attr_index = 0
            reg_index = 1
        elif target == Led.FAN:
            attr_index = 0
            reg_index = 0
        else:
            attr_index = 1
            reg_index = target

        if color == Led.COLOR_OFF and blink == Led.BLINK_STATUS_BLINKING:
            raise ValueError("LED blinking off is invalid operation")

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr, attr_index)

        if reg_index % 2 == 0:
            reg_shift = 0
            mask = 0b11110000
        else:
            reg_shift = 4
            mask = 0b00001111

        # clear color
        reg_val &= mask

        # set color
        if color == Led.COLOR_GREEN:
            reg_val |= (Led.MASK_COLOR << reg_shift)
            reg_val |= (Led.MASK_ONOFF << reg_shift)
        elif color == Led.COLOR_YELLOW:
            reg_val &= ~(Led.MASK_COLOR << reg_shift)
            reg_val |= (Led.MASK_ONOFF << reg_shift)
        elif color == Led.COLOR_OFF:
            reg_val &= ~(Led.MASK_ONOFF << reg_shift)
        else:
            raise ValueError("LED color is out of range")

        # set blink
        if blink == Led.BLINK_STATUS_BLINKING:
            reg_val |= (Led.MASK_BLINK << reg_shift)
        else:
            reg_val &= ~(Led.MASK_BLINK << reg_shift)

        self._write_cpld_reg(cpld_index, cpld_attr, reg_val, attr_index)

    ########## FOR J2 ROV ##########
    def get_j2_rov_stamp(self):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_PSU_STATUS
        index = 0
        reg_val = self._read_cpld_reg(cpld_index, cpld_attr, index)

        mask = self.CPLD_J2_ROV_BIT
        j2_rov_stamp = (reg_val & mask) >> self._get_shift(mask)

        return j2_rov_stamp

    ########## FOR Gearbox ##########
    def gbox_get_intr(self):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_GBOX_INTR
        index = 0

        reg_val_1 = self._read_cpld_reg(cpld_index, cpld_attr, index)
        reg_val_2 = self._read_cpld_reg(cpld_index, cpld_attr, index + 1)

        return reg_val_1, reg_val_2

    ########## FOR Retimer ##########
    def retimer_get_intr(self):
        cpld_index = CPLDConst.CPLD_1
        cpld_attr = self.ATTR_CPLD_RETIMER_INTR

        reg_val = self._read_cpld_reg(cpld_index, cpld_attr)

        return reg_val
class PlatformUtility:

    builtin_pca954x_path = "/lib/modules/{}/kernel/drivers/i2c/muxes/i2c-mux-pca954x.ko"
    #kernel release version
    kr_version_cmd = "uname -r"
    depmod_cmd = "depmod -a"
    #pci device
    PCI_CHECK_LIST = {
        "00:14.0": "USB controller",
        "00:1d.0": "USB controller",
        "00:1f.2": "SATA controller",
        "00:1f.3": "SMBus",
        "02:00.0": "10 GbE SFP+",
        "02:00.1": "10 GbE SFP+",
        "06:00.0": "PEX 8724",
        "07:01.0": "PEX 8724",
        "07:02.0": "PEX 8724",
        "07:08.0": "PEX 8724",
        "07:09.0": "PEX 8724",
        "07:0a.0": "PEX 8724",
        "0b:00.0": "J2",
        "0c:00.0": "OP2",
        "0d:00.0": "I210"
    }
    USB_CHECK_LIST = {"046b:ff20": "BMC", "046b:ff01": "BMC"}
    BSP_INIT_STOP = "[BSP Init Stop]"
    IGNORE_ERR = True

    def __init__(self):
        try:
            log = Logger(__name__)
            self.logger = log.getLogger()

            # I2C drivers
            self._load_i2c_drivers()

            #Check Mux Ctrl
            self.lpc = LPC()
            self._check_i2c_mux_ctrl()

            self.ioexp = IOExpander()

            self.i2c_mux = I2CMux()
            self.eeprom = EEPRom()
            self.cpld = CPLD()
            self.thermal = Thermal()
            self.rov_util = ROVUtility()
            self.intr_util = INTRUtility()
            self.bsp_util = BSPUtility()
        except Exception:
            raise

    def device_init(self):
        try:
            # Unmount kernel modules
            self._unload_kernel_module("gpio_ich")

            # Mount kernel modules

            # I2C Mux
            subprocess.run(
                ['modprobe', 'i2c_mux_pca954x', 'force_deselect_on_exit=1'])
            self.i2c_mux.init()

            # EEPROM
            self._load_kernel_module("x86_64_ufispace_s9700_53dx_eeprom_mb")
            self._load_kernel_module("x86_64_ufispace_s9700_53dx_optoe")
            self.eeprom.init()

            # Thermal
            self._load_kernel_module("lm75")
            self.thermal.init()

            # GPIO
            self._load_kernel_module("gpio-pca953x")
            self.ioexp.init(self.i2c_mux.MUXs)

            # IPMI
            self._load_kernel_module("ipmi_devintf")
            self._load_kernel_module("ipmi_si")

            # CPLD
            self._load_kernel_module(self.cpld.DRIVER_NAME)
            self.cpld.init()

        except Exception:
            raise

    def device_deinit(self):
        try:
            # Remove kernel modules
            # CPLD
            self.cpld.deinit()
            self._unload_kernel_module(self.cpld.DRIVER_NAME)

            # GPIO
            self.ioexp.deinit(self.i2c_mux.MUXs)
            self._unload_kernel_module("gpio-pca953x")

            # Thermal
            self.thermal.deinit()
            self._unload_kernel_module("lm75")

            # MB EEPROM
            self._unload_kernel_module("x86_64_ufispace_s9700_53dx_eeprom_mb")

            # OPTOE EEPROM
            self._unload_kernel_module("x86_64_ufispace_s9700_53dx_optoe")

            # I2C Mux
            self.i2c_mux.deinit()
            self._unload_kernel_module("i2c_mux_pca954x")

        except Exception:
            raise

    def _get_kernel_release(self):
        try:
            return subprocess.getoutput(self.kr_version_cmd)
        except Exception:
            raise

    def _check_bsp_init(self):
        try:
            is_bsp_inited = self.bsp_util.is_bsp_inited()

            if is_bsp_inited:
                self.logger.error(
                    "BSP may be already initialized. Please run 'platform_utility.py deinit' first"
                )
                self.logger.error(self.BSP_INIT_STOP)
                sys.exit()
        except Exception:
            raise

    def _check_ko(self):
        try:
            #get kernel release
            kr = self._get_kernel_release()

            #remove built-in i2c-mux-pca954x.ko if exist
            pca954x_path = self.builtin_pca954x_path.format(kr)
            if os.path.exists(pca954x_path):
                os.remove(pca954x_path)
                #generate modules.dep
                subprocess.run(self.depmod_cmd, shell=True)

        except Exception:
            raise

    def check_idt(self):
        try:
            #Open Mux(0x73) for IDT(0x53)
            retcode, _ = subprocess.getstatusoutput("i2cset -y 0 0x73 0x8")
            if retcode != 0:
                self.logger.error(
                    "Open I2C Mux channel (0x73) for IDT failed.")
                return

            #Check IDT
            retcode, _ = subprocess.getstatusoutput("i2cget -y 0 0x53 0x0")
            if retcode != 0:
                self.logger.error(
                    "Access IDT(0x53) failed. Trying to reset IDT")

                #Reset IDT
                self.lpc.regSet(LPCDevType.CPLD_ON_MAIN_BOARD, 0x4D, 0xF7)
                sleep(0.5)

                #Access IDT again
                retcode, _ = subprocess.getstatusoutput("i2cget -y 0 0x53 0x0")
                if retcode != 0:
                    self.logger.error(
                        "Access IDT(0x53) failed and reset still failed")
                else:
                    self.logger.error(
                        "Access IDT(0x53) failed and reset succeed")

            #Close Mux(0x73)
            retcode, _ = subprocess.getstatusoutput("i2cset -y 0 0x73 0x0")
            if retcode != 0:
                self.logger.error("Close I2C Mux channel (0x73) failed.")

        except Exception:
            raise

    def _check_intr(self):
        try:
            alert_dis = self.intr_util.get_alert_dis()
            if alert_dis == 0:
                self.logger.warning(
                    "I2C Alert is already enabled. I2C tree performance may be affected."
                )
        except Exception:
            raise

    def _check_i2c_mux_ctrl(self):
        try:
            default_val = 0x80
            reg_val = self.lpc.regGet(LPCDevType.CPLD_ON_MAIN_BOARD,
                                      CPLDMBReg.REG_MUX_CTRL)

            if reg_val != default_val:
                self.logger.error(
                    "I2C Mux Ctrl [0x{:02X}] is not valid. Expected [0x{:02X}]"
                    .format(reg_val, default_val))
                self.logger.error(self.BSP_INIT_STOP)
                sys.exit()
            else:
                self.logger.info("[Check Mux Control Register] Pass")
        except Exception as e:
            self.logger.error(e)
            raise

    def _check_cpld(self):

        #CPLD missing workaround :BEGIN

        #open mux 0x75
        retcode, _ = subprocess.getstatusoutput("i2cset -y 0 0x75 0x1")
        if retcode != 0:
            self.logger.error(
                "Open I2C Mux channel 0x75 for CPLD WA failed, return code = {}, exit"
                .format(retcode))
            self.logger.error(self.BSP_INIT_STOP)
            sys.exit()

        #Read CPLD version
        for i in range(len(self.cpld.CPLD_I2C_ADDR)):
            retcode, _ = subprocess.getstatusoutput(
                "i2cget -y 0 {} 0x2".format(self.cpld.CPLD_I2C_ADDR[i]))
            if retcode != 0:
                #log info for reading cpld version
                self.logger.info("Reading CPLD{} 0x{:02X} failed".format(
                    i + 1, self.cpld.CPLD_I2C_ADDR[i]))

        #Check CPLD version
        for i in range(len(self.cpld.CPLD_I2C_ADDR)):
            retcode, _ = subprocess.getstatusoutput(
                "i2cget -y 0 {} 0x2".format(self.cpld.CPLD_I2C_ADDR[i]))
            if retcode != 0:
                #log error for checking cpld version
                self.logger.error(
                    "Reading CPLD{} 0x{:02X} failed, return code = {}, exit".
                    format(i + 1, self.cpld.CPLD_I2C_ADDR[i], retcode))
                self.logger.error(self.BSP_INIT_STOP)
                sys.exit()

        #close mux 0x75
        retcode, _ = subprocess.getstatusoutput("i2cset -y 0 0x75 0x0")
        if retcode != 0:
            self.logger.error(
                "Close I2C Mux channel for CPLD WA failed, return code = {}, exit"
                .format(retcode))
            self.logger.error(self.BSP_INIT_STOP)
            sys.exit()

        #CPLD missing workaround :END

        self.logger.info("[Check CPLD] Pass")

    def _check_pci(self):
        err_cnt = 0
        result = ""
        err_list = ["rev ff"]
        err_desc = ["under reset"]
        cmd_lspci = "lspci"
        cmd_lspci_s = "lspci -s {}"

        #check lspci command
        retcode, _ = subprocess.getstatusoutput(cmd_lspci)
        if retcode != 0:
            self.logger.warning(
                "lspci commnad not found, skip checking pci devices")
            return

        #check pci devices
        for pci_id in self.PCI_CHECK_LIST.keys():
            pci_name = self.PCI_CHECK_LIST[pci_id]
            retcode, output = subprocess.getstatusoutput(
                cmd_lspci_s.format(pci_id))
            #check device existence
            if retcode != 0:
                self.logger.error(
                    "Invalid PCI device {} ({}), retcode={}, output={}".format(
                        pci_name, pci_id, retcode, output))
                err_cnt += 1
            elif len(output) == 0:
                self.logger.error("PCI device {} ({}) not found".format(
                    pci_name, pci_id))
                if not self.IGNORE_ERR:
                    self.logger.error(self.BSP_INIT_STOP)
                    sys.exit()
            else:
                #check device error status
                for i in range(len(err_list)):
                    if output.find(err_list[i]) >= 0:
                        self.logger.warning("PCI device {} ({}) {}".format(
                            pci_name, pci_id, err_desc[i]))
                        err_cnt += 1

        if err_cnt == 0:
            result = "Pass"
            self.logger.info("[Check PCI] {}".format(result))
        else:
            result = "Fail"
            self.logger.warning("[Check PCI] {}".format(result))

    def _check_usb(self):
        warn_cnt = 0
        result = ""
        cmd_lsusb = "lsusb"
        cmd_lsusb_s = "lsusb -d {}"

        #check lsusb command
        retcode, _ = subprocess.getstatusoutput(cmd_lsusb)
        if retcode != 0:
            self.logger.warning(
                "cmd_lsusb commnad not found, skip checking usb devices")
            return

        #check usb devices
        for usb_id in self.USB_CHECK_LIST.keys():
            usb_name = self.USB_CHECK_LIST[usb_id]
            retcode, output = subprocess.getstatusoutput(
                cmd_lsusb_s.format(usb_id))
            #check device existence
            if retcode != 0:
                self.logger.warning("USB device {} ({}) not found".format(
                    usb_name, usb_id))
                warn_cnt += 1
            elif len(output) == 0:
                self.logger.warning("USB device {} ({}) not found".format(
                    usb_name, usb_id))
                warn_cnt += 1
            else:
                if output.find(usb_id) < 0:
                    self.logger.warning("USB device {} ({}) not found".format(
                        usb_name, usb_id))
                    warn_cnt += 1

        if warn_cnt == 0:
            result = "Pass"
            self.logger.info("[Check USB] {}".format(result))
        else:
            result = "Warning"
            self.logger.warning("[Check USB] {}".format(result))
        return 0

    def pre_init(self):
        self._check_bsp_init()
        # don't check ko for sonic platform
        #self._check_ko()
        self._check_intr()
        retcode = self.i2c_mux.pre_init()
        if retcode != 0:
            self.logger.error(self.BSP_INIT_STOP)
            sys.exit()
        self._check_cpld()
        self.check_idt()
        self._check_pci()
        self._check_usb()

    def post_init(self):
        try:
            #set j2 rov
            if self.rov_util.platform_check():
                self.rov_util.set_j2_rov()
        except Exception:
            raise

    def _load_i2c_drivers(self):
        # I2C I801
        self._load_kernel_module("i2c_i801")
        # I2C Dev
        self._load_kernel_module("i2c_dev")

    def _load_kernel_module(self, module_name):
        #replace "-" to "_" since lsmod show module name with "_"
        module_name = module_name.replace("-", "_")

        #check if module is already loaded
        retcode, _ = subprocess.getstatusoutput(
            "lsmod | grep {}".format(module_name))
        #module is not loaded yet
        if retcode != 0:
            retcode, _ = subprocess.getstatusoutput(
                "modprobe {}".format(module_name))
            #load module failed
            if retcode != 0:
                self.logger.error(
                    "Load kernel module {} failed, retcode={}".format(
                        module_name, retcode))
                if not self.IGNORE_ERR:
                    self.logger.error(self.BSP_INIT_STOP)
                    sys.exit()

    def _unload_kernel_module(self, module_name):
        #replace "-" to "_" since lsmod show module name with "_"
        module_name = module_name.replace("-", "_")

        #check if module is already loaded
        retcode, _ = subprocess.getstatusoutput(
            "lsmod | grep {}".format(module_name))
        #module is loaded
        if retcode == 0:
            retcode, _ = subprocess.getstatusoutput(
                "rmmod {}".format(module_name))
            #unload module failed
            if retcode != 0:
                self.logger.error(
                    "Unload kernel module {} failed, retcode={}".format(
                        module_name, retcode))
Exemple #3
0
class BrdIDUtility:

    PATH_DIR = "/tmp/bsp/"
    PATH_BOARD_ID = PATH_DIR + "board_id"

    MASK_MODEL_ID = 0b01110000
    MASK_HW_REV = 0b00001100
    MASK_BUILD_REV = 0b00000011
    MASK_BUILD_REV_EXT = 0b10000000

    #EXT_BOARD_ID = 0b1110

    BOARD_ID_MAP = {
        0b000: "Reserved",
        0b001: "Reserved",
        0b010: "Apollo NCP1-1 40+13P",
        0b011: "Reserved",
        0b100: "Apollo NCP2-1 10+13P",
        0b101: "Reserved",
        0b110: "Reserved",
        0b111: "Apollo NCF 48P",
    }

    #EXT_BOARD_ID_MAP = {}

    HARDWARE_REV_MAP = {
        0b00: "Proto",
        0b01: "Alpha",
        0b10: "Beta",
        0b11: "PVT"
    }

    BUILD_REV_MAP = {
        0b000: "A1",
        0b001: "A2",
        0b010: "A3",
        0b011: "A4",
        0b100: "A5",
        0b101: "A6",
        0b110: "A7",
        0b111: "A8"
    }

    def __init__(self):
        log = Logger(__name__)
        self.logger = log.getLogger()
        self.lpc = LPC()

    # get bit shift from mask
    def _get_shift(self, reg_mask):
        mask_one = 1

        for i in range(8):
            if reg_mask & mask_one == 1:
                return i
            else:
                reg_mask >>= 1

        # not found
        return -1

    def get_board_id(self):
        path_dir = self.PATH_DIR
        path_board_id = self.PATH_BOARD_ID
        try:
            if os.path.exists(path_board_id):
                #board_id file exists
                with open(path_board_id, "r") as f:
                    # read content
                    content = f.read()
                    board_id = int(content.strip(), 0)
            else:
                #read board id from LPC
                board_id = self.lpc.regGet(LPCDevType.CPLD_ON_MAIN_BOARD,
                                           CPLDMBReg.REG_BRD_ID)

                #create board_id parent directories
                os.makedirs(os.path.dirname(path_dir), exist_ok=True)

                #write to board_id file
                if os.path.exists(path_dir):
                    with open(path_board_id, "w") as f:
                        f.write(str(board_id))
                else:
                    self.logger.error(
                        "create board_id file failed: path={}".format(
                            path_board_id))
                    return -1

            return board_id
        except Exception as e:
            self.logger.error(e)
            raise

    def get_model_id(self, board_id):
        return (board_id & self.MASK_MODEL_ID) >> self._get_shift(
            self.MASK_MODEL_ID)

    def get_hw_rev(self, board_id):
        return (board_id & self.MASK_HW_REV) >> self._get_shift(
            self.MASK_HW_REV)

    def get_build_rev(self, board_id):
        #bit[7], bit[1], bit[0]
        return  ((board_id & self.MASK_BUILD_REV) >> self._get_shift(self.MASK_BUILD_REV)) | \
                (((board_id & self.MASK_BUILD_REV_EXT) >> self._get_shift(self.MASK_BUILD_REV_EXT)) << 2)

    def get_model_id_str(self, model_id):
        if model_id in self.BOARD_ID_MAP.keys():
            model_id_str = self.BOARD_ID_MAP[model_id]
        else:
            model_id_str = "unknown"
        return model_id_str

    def get_hw_rev_str(self, hw_rev):
        if hw_rev in self.HARDWARE_REV_MAP.keys():
            hw_rev_str = self.HARDWARE_REV_MAP[hw_rev]
        else:
            hw_rev_str = "unknown"
        return hw_rev_str

    def get_build_rev_str(self, build_rev):
        if build_rev in self.BUILD_REV_MAP.keys():
            build_rev_str = self.BUILD_REV_MAP[build_rev]
        else:
            build_rev_str = "unknown"
        return build_rev_str
Exemple #4
0
class INTRUtility:
    def __init__(self):
        log = Logger(__name__)
        self.logger = log.getLogger()
        self.ioexp = IOExpander()
        self.cpld = CPLD()
        self.lpc = LPC()
        self.ioexp = IOExpander()

        #GPIO REGs
        self.ALERT_GPIO_REG = 0x1
        #I2C Alert REGs
        self.ALERT_STATUS_REG = 0x0
        self.ALERT_DIS_REG = 0x11

    def init_i2c_alert(self):
        i2c_detect_cmd = "i2cdetect -y 0"

        #i2cdetect -y 0
        retcode, _ = subprocess.getstatusoutput(i2c_detect_cmd)
        if retcode != 0:
            self.logger.error("i2c command error: {}".format(i2c_detect_cmd))

        #Set pin function to alert mode on CPU
        #./ioset 0x501 0xf7
        #IO_x500[11]  SMBALERT_N_GPIO11
        #0/Alert mode,1/GPIO mode
        #Default is 0
        regVal = self.lpc.regGet(LPCDevType.BDE_GPIO_ON_CPU_BOARD,
                                 self.ALERT_GPIO_REG)
        self.lpc.regSet(LPCDevType.BDE_GPIO_ON_CPU_BOARD, self.ALERT_GPIO_REG,
                        regVal & 0xF7)

        #Enable alert function on CPU
        #./ioset 0xf011 0x0
        #IO_xF011[2]  SMBALERT_DIS
        #0/Enable Alert, 1/Disable alert
        #Default is 1
        regVal = self.lpc.regGet(LPCDevType.CPU_I2C_ALERT, self.ALERT_DIS_REG)
        self.lpc.regSet(LPCDevType.CPU_I2C_ALERT, self.ALERT_DIS_REG,
                        regVal & 0xFB)

    def deinit_i2c_alert(self):
        regVal = self.lpc.regGet(LPCDevType.CPU_I2C_ALERT, self.ALERT_DIS_REG)
        self.lpc.regSet(LPCDevType.CPU_I2C_ALERT, self.ALERT_DIS_REG,
                        regVal | 0x04)

    def get_alert_gpio(self):
        regVal = self.lpc.regGet(LPCDevType.BDE_GPIO_ON_CPU_BOARD,
                                 self.ALERT_GPIO_REG)
        return (regVal >> 3) & 1

    def get_alert_dis(self):
        regVal = self.lpc.regGet(LPCDevType.CPU_I2C_ALERT, self.ALERT_DIS_REG)
        return (regVal >> 2) & 1

    def get_alert_sts(self):
        regVal = self.lpc.regGet(LPCDevType.CPU_I2C_ALERT,
                                 self.ALERT_STATUS_REG)
        return (regVal >> 5) & 1

    def clear_i2c_alert(self):
        intr_reg = "9539_HOST_GPIO_I2C"
        cpu_gpio_reg = "9539_CPU_I2C"

        #clear alert on ioexpander
        #i2cdump -y 0 0x74
        reg_vals = self.ioexp.dump_reg(intr_reg)
        self.logger.info("clear_i2c_alert() intr_reg_vals={}".format(reg_vals))

        #i2cdump -y 0 0x77
        reg_vals = self.ioexp.dump_reg(cpu_gpio_reg)
        self.logger.info(
            "clear_i2c_alert() cpu_gpio_reg_vals={}".format(reg_vals))

        #clear i2c alert status on CPU
        #./ioset 0xf000 0x60
        self.lpc.regSet(LPCDevType.CPU_I2C_ALERT, self.ALERT_STATUS_REG, 0x60)

    def get_cpld_to_cpu_intr(self):
        cpld_intr_name = [
            "op2", "cpld_1_2", "cpld_3", "cpld_4", "cpld_5", "j2"
        ]
        cpld_intr = {}
        try:
            cpld_intr_val = self.ioexp.get_cpld_to_cpu_intr()
            for i in range(len(cpld_intr_val)):
                cpld_intr[cpld_intr_name[i]] = cpld_intr_val[i]

            return cpld_intr

        except Exception as e:
            self.logger.error(
                "get_cpld_to_cpu_intr failed, error: {}".format(e))

    def get_all_cpld_intr(self):
        cpld_name = "cpld_"
        all_cpld_intr = {}
        try:
            for i in range(CPLDConst.CPLD_MAX):
                cpld_intr = self.get_cpld_intr(i)
                all_cpld_intr[cpld_name + str(i + 1)] = cpld_intr

            return all_cpld_intr
        except Exception as e:
            self.logger.error("get_cpld_intr failed, error: {}".format(e))

    def get_cpld_intr(self, cpld_num):
        cpld_intr_name = [
            "port_intr", "gearbox", "usb", "port_presence", "psu0", "psu1",
            "pex8724", "cs4227", "retimer"
        ]
        cpld_intr = {}
        try:
            intr_reg = self.cpld.get_intr_reg(cpld_num, 0)

            if cpld_num == CPLDConst.CPLD_1:
                intr_reg_2 = self.cpld.get_intr_reg(cpld_num, 1)

                for i in range(8):
                    cpld_intr[cpld_intr_name[i]] = intr_reg >> i & 0b1

                cpld_intr[cpld_intr_name[8]] = intr_reg_2 & 0b1
            else:
                cpld_intr[cpld_intr_name[0]] = intr_reg >> 0 & 0b1
                cpld_intr[cpld_intr_name[3]] = intr_reg >> 3 & 0b1

            return cpld_intr

        except Exception as e:
            self.logger.error("get_cpld_intr failed, error: {}".format(e))

    def clear_all_intr(self):
        try:
            for i in range(CPLDConst.CPLD_MAX):
                self.get_cpld_intr(i)
            self.clear_i2c_alert()

        except Exception as e:
            self.logger.error("clear_all_intr failed, error: {}".format(e))

    def get_gbox_intr(self):
        gbox_name = "gearbox"
        gbox_intr = {}
        gbox_max_1 = 8
        gbox_max_2 = 2

        try:
            reg1, reg2 = self.cpld.gbox_get_intr()

            for i in range(gbox_max_1):
                gbox_intr[gbox_name + "_" + str(i)] = reg1 >> i & 0b1

            for i in range(gbox_max_2):
                gbox_intr[gbox_name + "_" +
                          str(gbox_max_1 + i)] = reg2 >> i & 0b1

            return gbox_intr
        except Exception as e:
            self.logger.error("get_gbox_intr failed, error: {}".format(e))

    def get_retimer_intr(self):
        retimer_name = "retimer"
        retimer_intr = {}
        retimer_max = 5

        try:
            reg = self.cpld.retimer_get_intr()

            for i in range(retimer_max):
                retimer_intr[retimer_name + "_" + str(i)] = reg >> i & 0b1

            return retimer_intr
        except Exception as e:
            self.logger.error("get_retimer_intr failed, error: {}".format(e))