int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct pci_epc *epc = ep->epc; u16 msg_ctrl, msg_data; u32 msg_addr_lower, msg_addr_upper; u64 msg_addr; bool has_upper; int ret; /* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */ msg_ctrl = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL); has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT); msg_addr_lower = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32); if (has_upper) { msg_addr_upper = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32); msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_64); } else { msg_addr_upper = 0; msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_32); } msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, epc->mem->page_size); if (ret) return ret; writel(msg_data | (interrupt_num - 1), ep->msi_mem); dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys); return 0; }
/** * ks_dw_pcie_link_up() - Check if link up */ int ks_dw_pcie_link_up(struct dw_pcie *pci) { u32 val; val = dw_pcie_readl_dbi(pci, DEBUG0); return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0; }
static int dw_pcie_ep_get_msi(struct pci_epc *epc) { int val; u32 lower_addr; u32 upper_addr; struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); val = dw_pcie_readb_dbi(pci, MSI_MESSAGE_CONTROL); val = (val & MSI_CAP_MME_MASK) >> MSI_CAP_MME_SHIFT; lower_addr = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32); upper_addr = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32); if (!(lower_addr || upper_addr)) return -EINVAL; return val; }
static int armada8k_pcie_link_up(struct dw_pcie *pci) { u32 reg; u32 mask = PCIE_GLB_STS_RDLH_LINK_UP | PCIE_GLB_STS_PHY_LINK_UP; reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_STATUS_REG); if ((reg & mask) == mask) return 1; dev_dbg(pci->dev, "No link detected (Global-Status: 0x%08x).\n", reg); return 0; }
static irqreturn_t armada8k_pcie_irq_handler(int irq, void *arg) { struct armada8k_pcie *pcie = arg; struct dw_pcie *pci = pcie->pci; u32 val; /* * Interrupts are directly handled by the device driver of the * PCI device. However, they are also latched into the PCIe * controller, so we simply discard them. */ val = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_INT_CAUSE1_REG); dw_pcie_writel_dbi(pci, PCIE_GLOBAL_INT_CAUSE1_REG, val); return IRQ_HANDLED; }
static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie) { struct dw_pcie *pci = pcie->pci; u32 reg; if (!dw_pcie_link_up(pci)) { /* Disable LTSSM state machine to enable configuration */ reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG); reg &= ~(PCIE_APP_LTSSM_EN); dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg); } /* Set the device to root complex mode */ reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG); reg &= ~(PCIE_DEVICE_TYPE_MASK << PCIE_DEVICE_TYPE_SHIFT); reg |= PCIE_DEVICE_TYPE_RC << PCIE_DEVICE_TYPE_SHIFT; dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg); /* Set the PCIe master AxCache attributes */ dw_pcie_writel_dbi(pci, PCIE_ARCACHE_TRC_REG, ARCACHE_DEFAULT_VALUE); dw_pcie_writel_dbi(pci, PCIE_AWCACHE_TRC_REG, AWCACHE_DEFAULT_VALUE); /* Set the PCIe master AxDomain attributes */ reg = dw_pcie_readl_dbi(pci, PCIE_ARUSER_REG); reg &= ~(AX_USER_DOMAIN_MASK << AX_USER_DOMAIN_SHIFT); reg |= DOMAIN_OUTER_SHAREABLE << AX_USER_DOMAIN_SHIFT; dw_pcie_writel_dbi(pci, PCIE_ARUSER_REG, reg); reg = dw_pcie_readl_dbi(pci, PCIE_AWUSER_REG); reg &= ~(AX_USER_DOMAIN_MASK << AX_USER_DOMAIN_SHIFT); reg |= DOMAIN_OUTER_SHAREABLE << AX_USER_DOMAIN_SHIFT; dw_pcie_writel_dbi(pci, PCIE_AWUSER_REG, reg); /* Enable INT A-D interrupts */ reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_INT_MASK1_REG); reg |= PCIE_INT_A_ASSERT_MASK | PCIE_INT_B_ASSERT_MASK | PCIE_INT_C_ASSERT_MASK | PCIE_INT_D_ASSERT_MASK; dw_pcie_writel_dbi(pci, PCIE_GLOBAL_INT_MASK1_REG, reg); if (!dw_pcie_link_up(pci)) { /* Configuration done. Start LTSSM */ reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG); reg |= PCIE_APP_LTSSM_EN; dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg); } /* Wait until the link becomes active again */ if (dw_pcie_wait_for_link(pci)) dev_err(pci->dev, "Link not up after reconfiguration\n"); }