diff options
Diffstat (limited to 'drivers/pci/controller/pci-aardvark.c')
| -rw-r--r-- | drivers/pci/controller/pci-aardvark.c | 79 | 
1 files changed, 65 insertions, 14 deletions
diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index c3b725afa11f..4f5b44827d21 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -115,6 +115,7 @@  #define PCIE_MSI_ADDR_HIGH_REG			(CONTROL_BASE_ADDR + 0x54)  #define PCIE_MSI_STATUS_REG			(CONTROL_BASE_ADDR + 0x58)  #define PCIE_MSI_MASK_REG			(CONTROL_BASE_ADDR + 0x5C) +#define     PCIE_MSI_ALL_MASK			GENMASK(31, 0)  #define PCIE_MSI_PAYLOAD_REG			(CONTROL_BASE_ADDR + 0x9C)  #define     PCIE_MSI_DATA_MASK			GENMASK(15, 0) @@ -570,6 +571,7 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)  	advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG);  	/* Clear all interrupts */ +	advk_writel(pcie, PCIE_MSI_ALL_MASK, PCIE_MSI_STATUS_REG);  	advk_writel(pcie, PCIE_ISR0_ALL_MASK, PCIE_ISR0_REG);  	advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_REG);  	advk_writel(pcie, PCIE_IRQ_ALL_MASK, HOST_CTRL_INT_STATUS_REG); @@ -582,7 +584,7 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)  	advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_MASK_REG);  	/* Unmask all MSIs */ -	advk_writel(pcie, 0, PCIE_MSI_MASK_REG); +	advk_writel(pcie, ~(u32)PCIE_MSI_ALL_MASK, PCIE_MSI_MASK_REG);  	/* Enable summary interrupt for GIC SPI source */  	reg = PCIE_IRQ_ALL_MASK & (~PCIE_IRQ_ENABLE_INTS_MASK); @@ -872,11 +874,15 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,  		return PCI_BRIDGE_EMUL_HANDLED;  	} -	case PCI_CAP_LIST_ID:  	case PCI_EXP_DEVCAP:  	case PCI_EXP_DEVCTL: +	case PCI_EXP_DEVCAP2: +	case PCI_EXP_DEVCTL2: +	case PCI_EXP_LNKCAP2: +	case PCI_EXP_LNKCTL2:  		*value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);  		return PCI_BRIDGE_EMUL_HANDLED; +  	default:  		return PCI_BRIDGE_EMUL_NOT_HANDLED;  	} @@ -890,10 +896,6 @@ advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,  	struct advk_pcie *pcie = bridge->data;  	switch (reg) { -	case PCI_EXP_DEVCTL: -		advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg); -		break; -  	case PCI_EXP_LNKCTL:  		advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);  		if (new & PCI_EXP_LNKCTL_RL) @@ -915,6 +917,12 @@ advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,  		advk_writel(pcie, new, PCIE_ISR0_REG);  		break; +	case PCI_EXP_DEVCTL: +	case PCI_EXP_DEVCTL2: +	case PCI_EXP_LNKCTL2: +		advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg); +		break; +  	default:  		break;  	} @@ -953,6 +961,9 @@ static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)  	/* Support interrupt A for MSI feature */  	bridge->conf.intpin = PCIE_CORE_INT_A_ASSERT_ENABLE; +	/* Aardvark HW provides PCIe Capability structure in version 2 */ +	bridge->pcie_conf.cap = cpu_to_le16(2); +  	/* Indicates supports for Completion Retry Status */  	bridge->pcie_conf.rootcap = cpu_to_le16(PCI_EXP_RTCAP_CRSVIS); @@ -1017,10 +1028,8 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,  	u32 reg;  	int ret; -	if (!advk_pcie_valid_device(pcie, bus, devfn)) { -		*val = 0xffffffff; +	if (!advk_pcie_valid_device(pcie, bus, devfn))  		return PCIBIOS_DEVICE_NOT_FOUND; -	}  	if (pci_is_root_bus(bus))  		return pci_bridge_emul_conf_read(&pcie->bridge, where, @@ -1383,7 +1392,7 @@ static void advk_pcie_handle_msi(struct advk_pcie *pcie)  	msi_mask = advk_readl(pcie, PCIE_MSI_MASK_REG);  	msi_val = advk_readl(pcie, PCIE_MSI_STATUS_REG); -	msi_status = msi_val & ~msi_mask; +	msi_status = msi_val & ((~msi_mask) & PCIE_MSI_ALL_MASK);  	for (msi_idx = 0; msi_idx < MSI_IRQ_NUM; msi_idx++) {  		if (!(BIT(msi_idx) & msi_status)) @@ -1535,8 +1544,7 @@ static int advk_pcie_probe(struct platform_device *pdev)  		 * only PIO for issuing configuration transfers which does  		 * not use PCIe window configuration.  		 */ -		if (type != IORESOURCE_MEM && type != IORESOURCE_MEM_64 && -		    type != IORESOURCE_IO) +		if (type != IORESOURCE_MEM && type != IORESOURCE_IO)  			continue;  		/* @@ -1544,8 +1552,7 @@ static int advk_pcie_probe(struct platform_device *pdev)  		 * configuration is set to transparent memory access so it  		 * does not need window configuration.  		 */ -		if ((type == IORESOURCE_MEM || type == IORESOURCE_MEM_64) && -		    entry->offset == 0) +		if (type == IORESOURCE_MEM && entry->offset == 0)  			continue;  		/* @@ -1677,20 +1684,64 @@ static int advk_pcie_remove(struct platform_device *pdev)  {  	struct advk_pcie *pcie = platform_get_drvdata(pdev);  	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); +	u32 val;  	int i; +	/* Remove PCI bus with all devices */  	pci_lock_rescan_remove();  	pci_stop_root_bus(bridge->bus);  	pci_remove_root_bus(bridge->bus);  	pci_unlock_rescan_remove(); +	/* Disable Root Bridge I/O space, memory space and bus mastering */ +	val = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG); +	val &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); +	advk_writel(pcie, val, PCIE_CORE_CMD_STATUS_REG); + +	/* Disable MSI */ +	val = advk_readl(pcie, PCIE_CORE_CTRL2_REG); +	val &= ~PCIE_CORE_CTRL2_MSI_ENABLE; +	advk_writel(pcie, val, PCIE_CORE_CTRL2_REG); + +	/* Clear MSI address */ +	advk_writel(pcie, 0, PCIE_MSI_ADDR_LOW_REG); +	advk_writel(pcie, 0, PCIE_MSI_ADDR_HIGH_REG); + +	/* Mask all interrupts */ +	advk_writel(pcie, PCIE_MSI_ALL_MASK, PCIE_MSI_MASK_REG); +	advk_writel(pcie, PCIE_ISR0_ALL_MASK, PCIE_ISR0_MASK_REG); +	advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_MASK_REG); +	advk_writel(pcie, PCIE_IRQ_ALL_MASK, HOST_CTRL_INT_MASK_REG); + +	/* Clear all interrupts */ +	advk_writel(pcie, PCIE_MSI_ALL_MASK, PCIE_MSI_STATUS_REG); +	advk_writel(pcie, PCIE_ISR0_ALL_MASK, PCIE_ISR0_REG); +	advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_REG); +	advk_writel(pcie, PCIE_IRQ_ALL_MASK, HOST_CTRL_INT_STATUS_REG); + +	/* Remove IRQ domains */  	advk_pcie_remove_msi_irq_domain(pcie);  	advk_pcie_remove_irq_domain(pcie); +	/* Free config space for emulated root bridge */ +	pci_bridge_emul_cleanup(&pcie->bridge); + +	/* Assert PERST# signal which prepares PCIe card for power down */ +	if (pcie->reset_gpio) +		gpiod_set_value_cansleep(pcie->reset_gpio, 1); + +	/* Disable link training */ +	val = advk_readl(pcie, PCIE_CORE_CTRL0_REG); +	val &= ~LINK_TRAINING_EN; +	advk_writel(pcie, val, PCIE_CORE_CTRL0_REG); +  	/* Disable outbound address windows mapping */  	for (i = 0; i < OB_WIN_COUNT; i++)  		advk_pcie_disable_ob_win(pcie, i); +	/* Disable phy */ +	advk_pcie_disable_phy(pcie); +  	return 0;  }  |