/* * Run _EJ0 method to turn off power to the slot. */ static ACPI_STATUS pciehpc_acpi_power_off_slot(pcie_hp_ctrl_t *ctrl_p) { int status = AE_OK; pciehpc_acpi_t *acpi_p = ctrl_p->hc_misc_data; int dev_state = 0; pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; PCIE_DBG("turn OFF power to the slot #%d\n", slot_p->hs_phy_slot_num); status = AcpiEvaluateObject(acpi_p->slot_dev_obj, "_EJ0", NULL, NULL); /* get the state of the device (from _STA method) */ if (status == AE_OK) { if (pciehpc_acpi_get_dev_state(acpi_p->slot_dev_obj, &dev_state) != AE_OK) cmn_err(CE_WARN, "failed to get device status " "on slot #%d", slot_p->hs_phy_slot_num); } PCIE_DBG("(2)device state on slot #%d: 0x%x\n", slot_p->hs_phy_slot_num, dev_state); pciehpc_get_slot_state(slot_p); if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) { cmn_err(CE_WARN, "failed to power OFF the slot #%d" "(dev_state 0x%x, ACPI_STATUS 0x%x)", slot_p->hs_phy_slot_num, dev_state, status); return (AE_ERROR); } return (status); }
/*ARGSUSED*/ static int pciehpc_acpi_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result) { pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); uint16_t status; ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); /* get the current state of the slot */ pciehpc_get_slot_state(slot_p); /* check if the slot is already in the state less than 'powered' */ if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) { /* slot is in the 'disconnected' state */ PCIE_DBG("slot %d already disconnected\n", slot_p->hs_phy_slot_num); ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF); *result = slot_p->hs_info.cn_state; return (DDI_SUCCESS); } /* read the Slot Status Register */ status = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS); /* make sure the slot has a device present */ if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) { /* slot is empty */ PCIE_DBG("slot %d is empty", slot_p->hs_phy_slot_num); goto cleanup; } /* turn off power to the slot using ACPI method (EJ0) */ if (pciehpc_acpi_power_off_slot(ctrl_p) != AE_OK) goto cleanup; /* get the current state of the slot */ pciehpc_get_slot_state(slot_p); *result = slot_p->hs_info.cn_state; return (DDI_SUCCESS); cleanup: return (DDI_FAILURE); }
void pcie_phy_init(struct msm_pcie_dev_t *dev) { PCIE_DBG(dev, "RC%d: Initializing 28nm ATE phy - 100MHz\n", dev->rc_idx); /* 1 */ write_phy(dev->phy, PCIE_PHY_POWER_DOWN_CONTROL, 0x01); /* 2 */ write_phy(dev->phy, QSERDES_COM_SYS_CLK_CTRL, 0x3e); /* 3 */ write_phy(dev->phy, QSERDES_COM_PLL_CP_SETI, 0x0f); /* 4 */ write_phy(dev->phy, QSERDES_COM_PLL_IP_SETP, 0x23); /* 5 */ write_phy(dev->phy, QSERDES_COM_PLL_IP_SETI, 0x3f); /* 6 */ write_phy(dev->phy, QSERDES_RX_CDR_CONTROL, 0xf3); /* 7 */ write_phy(dev->phy, QSERDES_RX_CDR_CONTROL2, 0x6b); /* 8 */ write_phy(dev->phy, QSERDES_COM_RESETSM_CNTRL, 0x10); /* 9 */ write_phy(dev->phy, QSERDES_RX_RX_TERM_HIGHZ_CM_AC_COUPLE, 0x87); /* 10 */ write_phy(dev->phy, QSERDES_RX_RX_EQ_GAIN12, 0x54); /* 11 */ write_phy(dev->phy, PCIE_PHY_POWER_STATE_CONFIG1, 0xa3); /* 12 */ write_phy(dev->phy, PCIE_PHY_POWER_STATE_CONFIG2, 0x1b); /* 13 */ write_phy(dev->phy, PCIE_PHY_SW_RESET, 0x00); /* 14 */ write_phy(dev->phy, PCIE_PHY_START, 0x03); }
/* * This function is similar to pciehpc_slotinfo_init() with some * changes: * - no need for kernel thread to handle ATTN button events * - function ops for connect/disconnect are different * * ASSUMPTION: No conflict in doing reads to HP registers directly. * Otherwise, there are no ACPI interfaces to do LED control or to get * the hot plug capabilities (ATTN button, MRL, etc.). */ static int pciehpc_acpi_slotinfo_init(pcie_hp_ctrl_t *ctrl_p) { uint32_t slot_capabilities; pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); mutex_enter(&ctrl_p->hc_mutex); /* * setup DDI HP framework slot information structure */ slot_p->hs_device_num = 0; slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE; slot_p->hs_info.cn_type_str = PCIE_ACPI_HP_TYPE; slot_p->hs_info.cn_child = NULL; slot_p->hs_minor = PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip), slot_p->hs_device_num); /* read Slot Capabilities Register */ slot_capabilities = pciehpc_reg_get32(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCAP); /* setup slot number/name */ pciehpc_set_slot_name(ctrl_p); /* check if Attn Button present */ ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ? B_TRUE : B_FALSE; /* check if Manual Retention Latch sensor present */ ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ? B_TRUE : B_FALSE; /* * PCI-E (draft) version 1.1 defines EMI Lock Present bit * in Slot Capabilities register. Check for it. */ ctrl_p->hc_has_emi_lock = (slot_capabilities & PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE; /* get current slot state from the hw */ pciehpc_get_slot_state(slot_p); if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED) slot_p->hs_condition = AP_COND_OK; mutex_exit(&ctrl_p->hc_mutex); /* setup Notify() handler for hot plug events from ACPI BIOS */ if (pciehpc_acpi_install_event_handler(ctrl_p) != AE_OK) return (DDI_FAILURE); PCIE_DBG("ACPI hot plug is enabled for slot #%d\n", slot_p->hs_phy_slot_num); return (DDI_SUCCESS); }
void pcie_phy_init(struct msm_pcie_dev_t *dev) { PCIE_DBG(dev, "RC%d: Initializing 20nm QMP phy - 19.2MHz\n", dev->rc_idx); write_phy(dev->phy, PCIE_PHY_POWER_DOWN_CONTROL, 0x03); write_phy(dev->phy, QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08); write_phy(dev->phy, QSERDES_COM_DEC_START1, 0x82); write_phy(dev->phy, QSERDES_COM_DEC_START2, 0x03); write_phy(dev->phy, QSERDES_COM_DIV_FRAC_START1, 0xD5); write_phy(dev->phy, QSERDES_COM_DIV_FRAC_START2, 0xAA); write_phy(dev->phy, QSERDES_COM_DIV_FRAC_START3, 0x4D); write_phy(dev->phy, QSERDES_COM_PLLLOCK_CMP_EN, 0x01); write_phy(dev->phy, QSERDES_COM_PLLLOCK_CMP1, 0x2B); write_phy(dev->phy, QSERDES_COM_PLLLOCK_CMP2, 0x68); write_phy(dev->phy, QSERDES_COM_PLL_CRCTRL, 0x7C); write_phy(dev->phy, QSERDES_COM_PLL_CP_SETI, 0x02); write_phy(dev->phy, QSERDES_COM_PLL_IP_SETP, 0x1F); write_phy(dev->phy, QSERDES_COM_PLL_CP_SETP, 0x0F); write_phy(dev->phy, QSERDES_COM_PLL_IP_SETI, 0x01); write_phy(dev->phy, QSERDES_COM_IE_TRIM, 0x0F); write_phy(dev->phy, QSERDES_COM_IP_TRIM, 0x0F); write_phy(dev->phy, QSERDES_COM_PLL_CNTRL, 0x46); /* CDR Settings */ write_phy(dev->phy, QSERDES_RX_CDR_CONTROL1, 0xF3); write_phy(dev->phy, QSERDES_RX_CDR_CONTROL_HALF, 0x2B); /* Calibration Settings */ write_phy(dev->phy, QSERDES_COM_RESETSM_CNTRL, 0x90); write_phy(dev->phy, QSERDES_COM_RESETSM_CNTRL2, 0x05); /* Additional writes */ write_phy(dev->phy, QSERDES_COM_RES_CODE_START_SEG1, 0x20); write_phy(dev->phy, QSERDES_COM_RES_CODE_CAL_CSR, 0x77); write_phy(dev->phy, QSERDES_COM_RES_TRIM_CONTROL, 0x15); write_phy(dev->phy, QSERDES_TX_RCV_DETECT_LVL, 0x03); write_phy(dev->phy, QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF); write_phy(dev->phy, QSERDES_RX_RX_EQ_GAIN1_MSB, 0x1F); write_phy(dev->phy, QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF); write_phy(dev->phy, QSERDES_RX_RX_EQ_GAIN2_MSB, 0x00); write_phy(dev->phy, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x1A); write_phy(dev->phy, QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x80); write_phy(dev->phy, QSERDES_RX_SIGDET_ENABLES, 0x40); write_phy(dev->phy, QSERDES_RX_SIGDET_CNTRL, 0x70); write_phy(dev->phy, QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x06); write_phy(dev->phy, QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10); write_phy(dev->phy, PCIE_PHY_ENDPOINT_REFCLK_DRIVE, 0x10); write_phy(dev->phy, PCIE_PHY_POWER_STATE_CONFIG1, 0x23); write_phy(dev->phy, PCIE_PHY_POWER_STATE_CONFIG2, 0xCB); write_phy(dev->phy, QSERDES_RX_RX_RCVR_IQ_EN, 0x31); write_phy(dev->phy, PCIE_PHY_SW_RESET, 0x00); write_phy(dev->phy, PCIE_PHY_START, 0x03); }
static void pciehpc_acpi_uninstall_event_handler(pcie_hp_ctrl_t *ctrl_p) { pciehpc_acpi_t *acpi_p = ctrl_p->hc_misc_data; pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; PCIE_DBG("Uninstall event handler for slot #%d\n", slot_p->hs_phy_slot_num); (void) AcpiRemoveNotifyHandler(acpi_p->slot_dev_obj, ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler); (void) AcpiRemoveNotifyHandler(acpi_p->bus_obj, ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler); }
uint32_t __init msm_pcie_irq_init(struct msm_pcie_dev_t *dev) { int i, rc; PCIE_DBG("\n"); /* program MSI controller and enable all interrupts */ writel_relaxed(MSM_PCIE_MSI_PHY, dev->pcie20 + PCIE20_MSI_CTRL_ADDR); writel_relaxed(0, dev->pcie20 + PCIE20_MSI_CTRL_UPPER_ADDR); for (i = 0; i < PCIE20_MSI_CTRL_MAX; i++) writel_relaxed(~0, dev->pcie20 + PCIE20_MSI_CTRL_INTR_EN + (i * 12)); /* ensure that hardware is configured before proceeding */ wmb(); /* register handler for physical MSI interrupt line */ rc = request_irq(PCIE20_INT_MSI, handle_msi_irq, IRQF_TRIGGER_RISING, "msm_pcie_msi", dev); if (rc) { pr_err("Unable to allocate msi interrupt\n"); goto out; } /* register handler for PCIE_WAKE_N interrupt line */ rc = request_irq(dev->wake_n, handle_wake_irq, IRQF_TRIGGER_FALLING, "msm_pcie_wake", dev); if (rc) { pr_err("Unable to allocate wake interrupt\n"); free_irq(PCIE20_INT_MSI, dev); goto out; } enable_irq_wake(dev->wake_n); /* PCIE_WAKE_N should be enabled only during system suspend */ disable_irq(dev->wake_n); out: return rc; }
void pcie_phy_init(struct msm_pcie_dev_t *dev) { PCIE_DBG(dev, "RC%d: Initializing 28nm QMP phy - 19.2MHz\n", dev->rc_idx); write_phy(dev->phy, PCIE_PHY_POWER_DOWN_CONTROL, 0x03); write_phy(dev->phy, QSERDES_COM_SYSCLK_EN_SEL, 0x08); write_phy(dev->phy, QSERDES_COM_DEC_START1, 0x82); write_phy(dev->phy, QSERDES_COM_DEC_START2, 0x03); write_phy(dev->phy, QSERDES_COM_DIV_FRAC_START1, 0xd5); write_phy(dev->phy, QSERDES_COM_DIV_FRAC_START2, 0xaa); write_phy(dev->phy, QSERDES_COM_DIV_FRAC_START3, 0x13); write_phy(dev->phy, QSERDES_COM_PLLLOCK_CMP_EN, 0x01); write_phy(dev->phy, QSERDES_COM_PLLLOCK_CMP1, 0x2b); write_phy(dev->phy, QSERDES_COM_PLLLOCK_CMP2, 0x68); write_phy(dev->phy, QSERDES_COM_PLL_CRCTRL, 0xff); write_phy(dev->phy, QSERDES_COM_PLL_CP_SETI, 0x3f); write_phy(dev->phy, QSERDES_COM_PLL_IP_SETP, 0x07); write_phy(dev->phy, QSERDES_COM_PLL_CP_SETP, 0x03); if(dev->rc_idx == 1) { write_phy(dev->phy, QSERDES_TX_TX_EMP_POST1_LVL, 0x21); write_phy(dev->phy, QSERDES_TX_TX_DRV_LVL, 0x18); } write_phy(dev->phy, QSERDES_RX_CDR_CONTROL, 0xf3); write_phy(dev->phy, QSERDES_RX_CDR_CONTROL2, 0x6b); write_phy(dev->phy, QSERDES_COM_RESETSM_CNTRL, 0x10); write_phy(dev->phy, QSERDES_RX_RX_TERM_HIGHZ_CM_AC_COUPLE, 0x87); write_phy(dev->phy, QSERDES_RX_RX_EQ_GAIN12, 0x54); write_phy(dev->phy, PCIE_PHY_POWER_STATE_CONFIG1, 0xa3); write_phy(dev->phy, PCIE_PHY_POWER_STATE_CONFIG2, 0x4b); if(dev->rc_idx == 0) { write_phy(dev->phy, QSERDES_RX_SIGDET_CNTRL, 0x50); } write_phy(dev->phy, QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10); write_phy(dev->phy, PCIE_PHY_ENDPOINT_REFCLK_DRIVE, 0x10); write_phy(dev->phy, PCIE_PHY_SW_RESET, 0x00); write_phy(dev->phy, PCIE_PHY_START, 0x03); }
/* * Install event handler for the hot plug events on the bus node as well * as device function (dev=0,func=0). */ static ACPI_STATUS pciehpc_acpi_install_event_handler(pcie_hp_ctrl_t *ctrl_p) { pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; int status = AE_OK; pciehpc_acpi_t *acpi_p; PCIE_DBG("install event handler for slot %d\n", slot_p->hs_phy_slot_num); acpi_p = ctrl_p->hc_misc_data; if (acpi_p->slot_dev_obj == NULL) return (AE_NOT_FOUND); /* * Install event hanlder for events on the bus object. * (Note: Insert event (hot-insert) is delivered on this object) */ status = AcpiInstallNotifyHandler(acpi_p->slot_dev_obj, ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler, (void *)ctrl_p); if (status != AE_OK) goto cleanup; /* * Install event hanlder for events on the device function object. * (Note: Eject device event (hot-remove) is delivered on this object) * * NOTE: Here the assumption is that Notify events are delivered * on all of the 8 possible device functions so, subscribing to * one of them is sufficient. */ status = AcpiInstallNotifyHandler(acpi_p->bus_obj, ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler, (void *)ctrl_p); return (status); cleanup: (void) AcpiRemoveNotifyHandler(acpi_p->slot_dev_obj, ACPI_SYSTEM_NOTIFY, pciehpc_acpi_notify_handler); return (status); }
/* hookup to linux pci msi framework */ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { int irq; struct msi_msg msg; irq = msm_pcie_create_irq(); if (irq < 0) return irq; PCIE_DBG("irq %d allocated\n", irq); irq_set_msi_desc(irq, desc); /* write msi vector and data */ msg.address_hi = 0; msg.address_lo = MSM_PCIE_MSI_PHY; msg.data = irq - MSM_PCIE_MSI_INT(0); write_msi_msg(irq, &msg); irq_set_chip_and_handler(irq, &pcie_msi_chip, handle_simple_irq); set_irq_flags(irq, IRQF_VALID); return 0; }
static irqreturn_t handle_wake_irq(int irq, void *data) { PCIE_DBG("\n"); return IRQ_HANDLED; }
/* hookup to linux pci msi framework */ void arch_teardown_msi_irq(unsigned int irq) { PCIE_DBG("irq %d deallocated\n", irq); msm_pcie_destroy_irq(irq); }
void pcie_phy_dump(struct msm_pcie_dev_t *dev) { int i; int control_offset[2] = {0x60, 0x70}; PCIE_DBG(dev, "RC%d\n", dev->rc_idx); for (i = 0; i < 2; i++) { write_phy(dev->phy, PCIE_PHY_TEST_CONTROL, control_offset[i]); PCIE_REG(dev, "RC%d: TEST_CONTROL: 0x%08x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_TEST_CONTROL)); PCIE_REG(dev, "RC%d: DEBUG_BUS_0_STATUS: 0x%08x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_DEBUG_BUS_0_STATUS)); PCIE_REG(dev, "RC%d: DEBUG_BUS_1_STATUS: 0x%08x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_DEBUG_BUS_1_STATUS)); PCIE_REG(dev, "RC%d: DEBUG_BUS_2_STATUS: 0x%08x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_DEBUG_BUS_2_STATUS)); PCIE_REG(dev, "RC%d: DEBUG_BUS_3_STATUS: 0x%08x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_DEBUG_BUS_3_STATUS)); } PCIE_REG(dev, "RC%d QSERDES_COM_PLL_VCO_HIGH: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_COM_PLL_VCO_HIGH)); PCIE_REG(dev, "RC%d QSERDES_COM_RESET_SM: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_COM_RESET_SM)); PCIE_REG(dev, "RC%d QSERDES_RX_PI_CTRL1: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_RX_PI_CTRL1)); PCIE_REG(dev, "RC%d QSERDES_RX_PI_CTRL2: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_RX_PI_CTRL2)); PCIE_REG(dev, "RC%d QSERDES_RX_PI_QUAD: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_RX_PI_QUAD)); PCIE_REG(dev, "RC%d QSERDES_RX_IDATA1: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_RX_IDATA1)); PCIE_REG(dev, "RC%d QSERDES_RX_IDATA2: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_RX_IDATA2)); PCIE_REG(dev, "RC%d QSERDES_RX_AUX_DATA1: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_RX_AUX_DATA1)); PCIE_REG(dev, "RC%d QSERDES_RX_AUX_DATA2: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_RX_AUX_DATA2)); PCIE_REG(dev, "RC%d QSERDES_RX_AC_JTAG_OUTP: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_RX_AC_JTAG_OUTP)); PCIE_REG(dev, "RC%d QSERDES_RX_AC_JTAG_OUTN: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_RX_AC_JTAG_OUTN)); PCIE_REG(dev, "RC%d QSERDES_TX_BIST_STATUS: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_TX_BIST_STATUS)); PCIE_REG(dev, "RC%d QSERDES_TX_BIST_ERROR_COUNT1: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_TX_BIST_ERROR_COUNT1)); PCIE_REG(dev, "RC%d QSERDES_TX_BIST_ERROR_COUNT2: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + QSERDES_TX_BIST_ERROR_COUNT2)); PCIE_REG(dev, "RC%d PCIE_PHY_BIST_CHK_ERR_CNT_L: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_BIST_CHK_ERR_CNT_L)); PCIE_REG(dev, "RC%d PCIE_PHY_BIST_CHK_ERR_CNT_H: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_BIST_CHK_ERR_CNT_H)); PCIE_REG(dev, "RC%d PCIE_PHY_BIST_CHK_STATUS: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_BIST_CHK_STATUS)); PCIE_REG(dev, "RC%d PCIE_PHY_PCS_STATUS: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_PCS_STATUS)); PCIE_REG(dev, "RC%d PCIE_PHY_REVISION_ID0: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_REVISION_ID0)); PCIE_REG(dev, "RC%d PCIE_PHY_REVISION_ID1: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_REVISION_ID1)); PCIE_REG(dev, "RC%d PCIE_PHY_REVISION_ID2: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_REVISION_ID2)); PCIE_REG(dev, "RC%d PCIE_PHY_REVISION_ID3: 0x%x\n", dev->rc_idx, readl_relaxed(dev->phy + PCIE_PHY_REVISION_ID3)); }
/*ARGSUSED*/ static void pciehpc_acpi_notify_handler(ACPI_HANDLE device, uint32_t val, void *context) { pcie_hp_ctrl_t *ctrl_p = context; pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; pciehpc_acpi_t *acpi_p; ddi_hp_cn_state_t curr_state; int dev_state = 0; PCIE_DBG("received Notify(%d) event on slot #%d\n", val, slot_p->hs_phy_slot_num); mutex_enter(&ctrl_p->hc_mutex); /* * get the state of the device (from _STA method) */ acpi_p = ctrl_p->hc_misc_data; if (pciehpc_acpi_get_dev_state(acpi_p->slot_dev_obj, &dev_state) != AE_OK) { cmn_err(CE_WARN, "failed to get device status on slot %d", slot_p->hs_phy_slot_num); } PCIE_DBG("(1)device state on slot #%d: 0x%x\n", slot_p->hs_phy_slot_num, dev_state); curr_state = slot_p->hs_info.cn_state; pciehpc_get_slot_state(slot_p); switch (val) { case 0: /* (re)enumerate the device */ case 3: /* Request Eject */ { ddi_hp_cn_state_t target_state; /* * Ignore the event if ATTN button is not present (ACPI BIOS * problem). * * NOTE: This situation has been observed on some platforms * where the ACPI BIOS is generating the event for some other * (non hot-plug) operations (bug). */ if (ctrl_p->hc_has_attn == B_FALSE) { PCIE_DBG("Ignore the unexpected event " "on slot #%d (state 0x%x)", slot_p->hs_phy_slot_num, dev_state); break; } /* send the event to DDI Hotplug framework */ if (curr_state < DDI_HP_CN_STATE_POWERED) { /* Insertion. Upgrade state to ENABLED */ target_state = DDI_HP_CN_STATE_ENABLED; /* * When pressing ATTN button to enable a card, the slot * could be powered. Keep the slot state on PWOERED * other than ENABLED. */ if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_ENABLED) slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED; } else { /* Want to remove; Power off Connection */ target_state = DDI_HP_CN_STATE_EMPTY; } (void) ndi_hp_state_change_req(slot_p->hs_ctrl->hc_dip, slot_p->hs_info.cn_name, target_state, DDI_HP_REQ_ASYNC); break; } default: cmn_err(CE_NOTE, "Unknown Notify() event %d on slot #%d\n", val, slot_p->hs_phy_slot_num); break; } mutex_exit(&ctrl_p->hc_mutex); }
/*ARGSUSED*/ static int pciehpc_acpi_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result) { pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); uint16_t status, control; ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); /* get the current state of the slot */ pciehpc_get_slot_state(slot_p); /* check if the slot is already in the 'ENABLED' state */ if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_ENABLED) { /* slot is already in the 'connected' state */ PCIE_DBG("slot %d already connected\n", slot_p->hs_phy_slot_num); *result = slot_p->hs_info.cn_state; return (DDI_SUCCESS); } /* read the Slot Status Register */ status = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS); /* make sure the MRL switch is closed if present */ if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) { /* MRL switch is open */ cmn_err(CE_WARN, "MRL switch is open on slot %d", slot_p->hs_phy_slot_num); goto cleanup; } /* make sure the slot has a device present */ if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) { /* slot is empty */ PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num); goto cleanup; } /* get the current state of Slot Control Register */ control = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL); /* check if the slot's power state is ON */ if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) { /* slot is already powered up */ PCIE_DBG("slot %d already connected\n", slot_p->hs_phy_slot_num); *result = slot_p->hs_info.cn_state; return (DDI_SUCCESS); } /* turn on power to the slot using ACPI method (PS0) */ if (pciehpc_acpi_power_on_slot(ctrl_p) != AE_OK) goto cleanup; *result = slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED; return (DDI_SUCCESS); cleanup: return (DDI_FAILURE); }