Commit 3d663fc0 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'remotes/lorenzo/pci/mobiveil'

  - Unify mobiveil register accessors (Hou Zhiqiang)

  - Remove MSI_FLAG_MULTI_PCI_MSI since mobiveil hardware doesn't support
    Multiple MSI (Hou Zhiqiang)

  - Program outbound windows with base address from DT instead of assuming
    zero (Hou Zhiqiang)

  - Skip "safe" list traversal when it's unnecessary (Hou Zhiqiang)

  - Initialize WIN_NUM_0 explicitly for CFG outbound transactions (Hou
    Zhiqiang)

  - Use WIN_NUM_0 for MEM inbound transactions (Hou Zhiqiang)

  - Fix up mobiveil Class Code to PCI_CLASS_BRIDGE_PCI (Hou Zhiqiang)

  - Wait for link-up before enumerating devices, not while initializing
    host (Hou Zhiqiang)

  - Move IRQ chained handler setup out of DT code (Hou Zhiqiang)

  - Set primary/secondary/subordinate bus numbers (Hou Zhiqiang)

  - Fix "valid device" check to allow root bus device 0 to be
    multi-function (Hou Zhiqiang)

  - Make DT "gpio_slave" and "apb_csr" properties optional (Hou Zhiqiang)

  - Refactor MEM/IO outbound window initialization (Hou Zhiqiang)

  - Fix validity check for inbound/outbound window programming (Hou
    Zhiqiang)

  - Initialize and preserve window control bits (Hou Zhiqiang)

  - Fix 64-bit outbound window setup (both CPU and PCI addresses) (Hou
    Zhiqiang)

  - Move IO port setup to host init (Hou Zhiqiang)

  - Fix infinite loop in INTx ISR (Hou Zhiqiang)

  - Fix INTx interrupt clearing to avoid missed interrupts (Hou Zhiqiang)

* remotes/lorenzo/pci/mobiveil:
  PCI: mobiveil: Fix INTx interrupt clearing in mobiveil_pcie_isr()
  PCI: mobiveil: Fix infinite-loop in the INTx handling function
  PCI: mobiveil: Move PCIe PIO enablement out of inbound window routine
  PCI: mobiveil: Add upper 32-bit PCI base address setup in inbound window
  PCI: mobiveil: Add upper 32-bit CPU base address setup in outbound window
  PCI: mobiveil: Mask out hardcoded bits in inbound/outbound windows setup
  PCI: mobiveil: Clear the control fields before updating it
  PCI: mobiveil: Add configured inbound windows counter
  PCI: mobiveil: Fix the valid check for inbound and outbound windows
  PCI: mobiveil: Clean-up program_{ib/ob}_windows()
  PCI: mobiveil: Remove an unnecessary return value check
  PCI: mobiveil: Fix error return values
  PCI: mobiveil: Refactor the MEM/IO outbound window initialization
  PCI: mobiveil: Make some register updates more readable
  PCI: mobiveil: Reformat the code for readability
  dt-bindings: PCI: mobiveil: Change gpio_slave and apb_csr to optional
  PCI: mobiveil: Fix devfn check in mobiveil_pcie_valid_device()
  PCI: mobiveil: Initialize Primary/Secondary/Subordinate bus numbers
  PCI: mobiveil: Move IRQ chained handler setup out of DT parse
  PCI: mobiveil: Move the link up waiting out of mobiveil_host_init()
  PCI: mobiveil: Fix the Class Code field
  PCI: mobiveil: Use the 1st inbound window for MEM inbound transactions
  PCI: mobiveil: Use WIN_NUM_0 explicitly for CFG outbound window
  PCI: mobiveil: Update the resource list traversal function
  PCI: mobiveil: Fix PCI base address in MEM/IO outbound windows
  PCI: mobiveil: Remove the flag MSI_FLAG_MULTI_PCI_MSI
  PCI: mobiveil: Unify register accessors
parents caa98440 8a4f9fea
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -10,8 +10,10 @@ Required properties:
	interrupt source. The value must be 1.
- compatible: Should contain "mbvl,gpex40-pcie"
- reg: Should contain PCIe registers location and length
	Mandatory:
	"config_axi_slave": PCIe controller registers
	"csr_axi_slave"	  : Bridge config registers
	Optional:
	"gpio_slave"	  : GPIO registers to control slot power
	"apb_csr"	  : MSI registers

+312 −213
Original line number Diff line number Diff line
@@ -34,8 +34,10 @@
#define PAB_REG_BLOCK_SIZE		16
#define PAB_EXT_REG_BLOCK_SIZE		4

#define PAB_REG_ADDR(offset, win) (offset + (win * PAB_REG_BLOCK_SIZE))
#define PAB_EXT_REG_ADDR(offset, win) (offset + (win * PAB_EXT_REG_BLOCK_SIZE))
#define PAB_REG_ADDR(offset, win)	\
	(offset + (win * PAB_REG_BLOCK_SIZE))
#define PAB_EXT_REG_ADDR(offset, win)	\
	(offset + (win * PAB_EXT_REG_BLOCK_SIZE))

#define LTSSM_STATUS			0x0404
#define  LTSSM_STATUS_L0_MASK		0x3f
@@ -47,7 +49,6 @@
#define  PAGE_SEL_SHIFT			13
#define  PAGE_SEL_MASK			0x3f
#define  PAGE_LO_MASK			0x3ff
#define  PAGE_SEL_EN		0xc00
#define  PAGE_SEL_OFFSET_SHIFT		10

#define PAB_AXI_PIO_CTRL		0x0840
@@ -64,9 +65,12 @@
#define PAB_AXI_AMAP_CTRL(win)		PAB_REG_ADDR(0x0ba0, win)
#define  WIN_ENABLE_SHIFT		0
#define  WIN_TYPE_SHIFT			1
#define  WIN_TYPE_MASK			0x3
#define  WIN_SIZE_MASK			0xfffffc00

#define PAB_EXT_AXI_AMAP_SIZE(win)	PAB_EXT_REG_ADDR(0xbaf0, win)

#define PAB_EXT_AXI_AMAP_AXI_WIN(win)	PAB_EXT_REG_ADDR(0x80a0, win)
#define PAB_AXI_AMAP_AXI_WIN(win)	PAB_REG_ADDR(0x0ba4, win)
#define  AXI_WINDOW_ALIGN_MASK		3

@@ -81,6 +85,7 @@
#define PAB_PEX_AMAP_CTRL(win)		PAB_REG_ADDR(0x4ba0, win)
#define  AMAP_CTRL_EN_SHIFT		0
#define  AMAP_CTRL_TYPE_SHIFT		1
#define  AMAP_CTRL_TYPE_MASK		3

#define PAB_EXT_PEX_AMAP_SIZEN(win)	PAB_EXT_REG_ADDR(0xbef0, win)
#define PAB_PEX_AMAP_AXI_WIN(win)	PAB_REG_ADDR(0x4ba4, win)
@@ -117,6 +122,12 @@
#define LINK_WAIT_MIN			90000
#define LINK_WAIT_MAX			100000

#define PAGED_ADDR_BNDRY		0xc00
#define OFFSET_TO_PAGE_ADDR(off)	\
	((off & PAGE_LO_MASK) | PAGED_ADDR_BNDRY)
#define OFFSET_TO_PAGE_IDX(off)		\
	((off >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK)

struct mobiveil_msi {			/* MSI information */
	struct mutex lock;		/* protect bitmap variable */
	struct irq_domain *msi_domain;
@@ -145,15 +156,119 @@ struct mobiveil_pcie {
	struct mobiveil_msi msi;
};

static inline void csr_writel(struct mobiveil_pcie *pcie, const u32 value,
		const u32 reg)
/*
 * mobiveil_pcie_sel_page - routine to access paged register
 *
 * Registers whose address greater than PAGED_ADDR_BNDRY (0xc00) are paged,
 * for this scheme to work extracted higher 6 bits of the offset will be
 * written to pg_sel field of PAB_CTRL register and rest of the lower 10
 * bits enabled with PAGED_ADDR_BNDRY are used as offset of the register.
 */
static void mobiveil_pcie_sel_page(struct mobiveil_pcie *pcie, u8 pg_idx)
{
	u32 val;

	val = readl(pcie->csr_axi_slave_base + PAB_CTRL);
	val &= ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT);
	val |= (pg_idx & PAGE_SEL_MASK) << PAGE_SEL_SHIFT;

	writel(val, pcie->csr_axi_slave_base + PAB_CTRL);
}

static void *mobiveil_pcie_comp_addr(struct mobiveil_pcie *pcie, u32 off)
{
	if (off < PAGED_ADDR_BNDRY) {
		/* For directly accessed registers, clear the pg_sel field */
		mobiveil_pcie_sel_page(pcie, 0);
		return pcie->csr_axi_slave_base + off;
	}

	mobiveil_pcie_sel_page(pcie, OFFSET_TO_PAGE_IDX(off));
	return pcie->csr_axi_slave_base + OFFSET_TO_PAGE_ADDR(off);
}

static int mobiveil_pcie_read(void __iomem *addr, int size, u32 *val)
{
	writel_relaxed(value, pcie->csr_axi_slave_base + reg);
	if ((uintptr_t)addr & (size - 1)) {
		*val = 0;
		return PCIBIOS_BAD_REGISTER_NUMBER;
	}

	switch (size) {
	case 4:
		*val = readl(addr);
		break;
	case 2:
		*val = readw(addr);
		break;
	case 1:
		*val = readb(addr);
		break;
	default:
		*val = 0;
		return PCIBIOS_BAD_REGISTER_NUMBER;
	}

static inline u32 csr_readl(struct mobiveil_pcie *pcie, const u32 reg)
	return PCIBIOS_SUCCESSFUL;
}

static int mobiveil_pcie_write(void __iomem *addr, int size, u32 val)
{
	return readl_relaxed(pcie->csr_axi_slave_base + reg);
	if ((uintptr_t)addr & (size - 1))
		return PCIBIOS_BAD_REGISTER_NUMBER;

	switch (size) {
	case 4:
		writel(val, addr);
		break;
	case 2:
		writew(val, addr);
		break;
	case 1:
		writeb(val, addr);
		break;
	default:
		return PCIBIOS_BAD_REGISTER_NUMBER;
	}

	return PCIBIOS_SUCCESSFUL;
}

static u32 csr_read(struct mobiveil_pcie *pcie, u32 off, size_t size)
{
	void *addr;
	u32 val;
	int ret;

	addr = mobiveil_pcie_comp_addr(pcie, off);

	ret = mobiveil_pcie_read(addr, size, &val);
	if (ret)
		dev_err(&pcie->pdev->dev, "read CSR address failed\n");

	return val;
}

static void csr_write(struct mobiveil_pcie *pcie, u32 val, u32 off, size_t size)
{
	void *addr;
	int ret;

	addr = mobiveil_pcie_comp_addr(pcie, off);

	ret = mobiveil_pcie_write(addr, size, val);
	if (ret)
		dev_err(&pcie->pdev->dev, "write CSR address failed\n");
}

static u32 csr_readl(struct mobiveil_pcie *pcie, u32 off)
{
	return csr_read(pcie, off, 0x4);
}

static void csr_writel(struct mobiveil_pcie *pcie, u32 val, u32 off)
{
	csr_write(pcie, val, off, 0x4);
}

static bool mobiveil_pcie_link_up(struct mobiveil_pcie *pcie)
@@ -174,7 +289,7 @@ static bool mobiveil_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
	 * Do not read more than one device on the bus directly
	 * attached to RC
	 */
	if ((bus->primary == pcie->root_bus_nr) && (devfn > 0))
	if ((bus->primary == pcie->root_bus_nr) && (PCI_SLOT(devfn) > 0))
		return false;

	return true;
@@ -188,14 +303,14 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
					   unsigned int devfn, int where)
{
	struct mobiveil_pcie *pcie = bus->sysdata;
	u32 value;

	if (!mobiveil_pcie_valid_device(bus, devfn))
		return NULL;

	if (bus->number == pcie->root_bus_nr) {
	/* RC config access */
	if (bus->number == pcie->root_bus_nr)
		return pcie->csr_axi_slave_base + where;
	}

	/*
	 * EP config access (in Config/APIO space)
@@ -203,10 +318,12 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
	 * (BDF) in PAB_AXI_AMAP_PEX_WIN_L0 Register.
	 * Relies on pci_lock serialization
	 */
	csr_writel(pcie, bus->number << PAB_BUS_SHIFT |
	value = bus->number << PAB_BUS_SHIFT |
		PCI_SLOT(devfn) << PAB_DEVICE_SHIFT |
			PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT,
			PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
		PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT;

	csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));

	return pcie->config_axi_slave_base + where;
}

@@ -241,8 +358,9 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)

	/* Handle INTx */
	if (intr_status & PAB_INTP_INTX_MASK) {
		shifted_status = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT) >>
			PAB_INTX_START;
		shifted_status = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
		shifted_status &= PAB_INTP_INTX_MASK;
		shifted_status >>= PAB_INTX_START;
		do {
			for_each_set_bit(bit, &shifted_status, PCI_NUM_INTX) {
				virq = irq_find_mapping(pcie->intx_domain,
@@ -250,15 +368,19 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
				if (virq)
					generic_handle_irq(virq);
				else
					dev_err_ratelimited(dev,
						"unexpected IRQ, INT%d\n", bit);
					dev_err_ratelimited(dev, "unexpected IRQ, INT%d\n",
							    bit);

				/* clear interrupt */
				csr_writel(pcie,
					shifted_status << PAB_INTX_START,
				/* clear interrupt handled */
				csr_writel(pcie, 1 << (PAB_INTX_START + bit),
					   PAB_INTP_AMBA_MISC_STAT);
			}
		} while ((shifted_status >> PAB_INTX_START) != 0);

			shifted_status = csr_readl(pcie,
						   PAB_INTP_AMBA_MISC_STAT);
			shifted_status &= PAB_INTP_INTX_MASK;
			shifted_status >>= PAB_INTX_START;
		} while (shifted_status != 0);
	}

	/* read extra MSI status register */
@@ -266,8 +388,7 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)

	/* handle MSI interrupts */
	while (msi_status & 1) {
		msi_data = readl_relaxed(pcie->apb_csr_base
				+ MSI_DATA_OFFSET);
		msi_data = readl_relaxed(pcie->apb_csr_base + MSI_DATA_OFFSET);

		/*
		 * MSI_STATUS_OFFSET register gets updated to zero
@@ -337,92 +458,50 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
		return -ENODEV;
	}

	irq_set_chained_handler_and_data(pcie->irq, mobiveil_pcie_isr, pcie);

	return 0;
}

/*
 * select_paged_register - routine to access paged register of root complex
 *
 * registers of RC are paged, for this scheme to work
 * extracted higher 6 bits of the offset will be written to pg_sel
 * field of PAB_CTRL register and rest of the lower 10 bits enabled with
 * PAGE_SEL_EN are used as offset of the register.
 */
static void select_paged_register(struct mobiveil_pcie *pcie, u32 offset)
{
	int pab_ctrl_dw, pg_sel;

	/* clear pg_sel field */
	pab_ctrl_dw = csr_readl(pcie, PAB_CTRL);
	pab_ctrl_dw = (pab_ctrl_dw & ~(PAGE_SEL_MASK << PAGE_SEL_SHIFT));

	/* set pg_sel field */
	pg_sel = (offset >> PAGE_SEL_OFFSET_SHIFT) & PAGE_SEL_MASK;
	pab_ctrl_dw |= ((pg_sel << PAGE_SEL_SHIFT));
	csr_writel(pcie, pab_ctrl_dw, PAB_CTRL);
}

static void write_paged_register(struct mobiveil_pcie *pcie,
		u32 val, u32 offset)
{
	u32 off = (offset & PAGE_LO_MASK) | PAGE_SEL_EN;

	select_paged_register(pcie, offset);
	csr_writel(pcie, val, off);
}

static u32 read_paged_register(struct mobiveil_pcie *pcie, u32 offset)
{
	u32 off = (offset & PAGE_LO_MASK) | PAGE_SEL_EN;

	select_paged_register(pcie, offset);
	return csr_readl(pcie, off);
}

static void program_ib_windows(struct mobiveil_pcie *pcie, int win_num,
		int pci_addr, u32 type, u64 size)
			       u64 pci_addr, u32 type, u64 size)
{
	int pio_ctrl_val;
	int amap_ctrl_dw;
	u32 value;
	u64 size64 = ~(size - 1);

	if ((pcie->ib_wins_configured + 1) > pcie->ppio_wins) {
	if (win_num >= pcie->ppio_wins) {
		dev_err(&pcie->pdev->dev,
			"ERROR: max inbound windows reached !\n");
		return;
	}

	pio_ctrl_val = csr_readl(pcie, PAB_PEX_PIO_CTRL);
	csr_writel(pcie,
		pio_ctrl_val | (1 << PIO_ENABLE_SHIFT), PAB_PEX_PIO_CTRL);
	amap_ctrl_dw = read_paged_register(pcie, PAB_PEX_AMAP_CTRL(win_num));
	amap_ctrl_dw = (amap_ctrl_dw | (type << AMAP_CTRL_TYPE_SHIFT));
	amap_ctrl_dw = (amap_ctrl_dw | (1 << AMAP_CTRL_EN_SHIFT));

	write_paged_register(pcie, amap_ctrl_dw | lower_32_bits(size64),
				PAB_PEX_AMAP_CTRL(win_num));
	value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
	value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
	value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
		 (lower_32_bits(size64) & WIN_SIZE_MASK);
	csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));

	write_paged_register(pcie, upper_32_bits(size64),
	csr_writel(pcie, upper_32_bits(size64),
		   PAB_EXT_PEX_AMAP_SIZEN(win_num));

	write_paged_register(pcie, pci_addr, PAB_PEX_AMAP_AXI_WIN(win_num));
	write_paged_register(pcie, pci_addr, PAB_PEX_AMAP_PEX_WIN_L(win_num));
	write_paged_register(pcie, 0, PAB_PEX_AMAP_PEX_WIN_H(win_num));
	csr_writel(pcie, pci_addr, PAB_PEX_AMAP_AXI_WIN(win_num));

	csr_writel(pcie, lower_32_bits(pci_addr),
		   PAB_PEX_AMAP_PEX_WIN_L(win_num));
	csr_writel(pcie, upper_32_bits(pci_addr),
		   PAB_PEX_AMAP_PEX_WIN_H(win_num));

	pcie->ib_wins_configured++;
}

/*
 * routine to program the outbound windows
 */
static void program_ob_windows(struct mobiveil_pcie *pcie, int win_num,
		u64 cpu_addr, u64 pci_addr, u32 config_io_bit, u64 size)
			       u64 cpu_addr, u64 pci_addr, u32 type, u64 size)
{

	u32 value, type;
	u32 value;
	u64 size64 = ~(size - 1);

	if ((pcie->ob_wins_configured + 1) > pcie->apio_wins) {
	if (win_num >= pcie->apio_wins) {
		dev_err(&pcie->pdev->dev,
			"ERROR: max outbound windows reached !\n");
		return;
@@ -432,23 +511,22 @@ static void program_ob_windows(struct mobiveil_pcie *pcie, int win_num,
	 * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
	 * to 4 KB in PAB_AXI_AMAP_CTRL register
	 */
	type = config_io_bit;
	value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
	csr_writel(pcie, 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
			lower_32_bits(size64), PAB_AXI_AMAP_CTRL(win_num));
	value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
	value |= 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT |
		 (lower_32_bits(size64) & WIN_SIZE_MASK);
	csr_writel(pcie, value, PAB_AXI_AMAP_CTRL(win_num));

	write_paged_register(pcie, upper_32_bits(size64),
				PAB_EXT_AXI_AMAP_SIZE(win_num));
	csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));

	/*
	 * program AXI window base with appropriate value in
	 * PAB_AXI_AMAP_AXI_WIN0 register
	 */
	value = csr_readl(pcie, PAB_AXI_AMAP_AXI_WIN(win_num));
	csr_writel(pcie, cpu_addr & (~AXI_WINDOW_ALIGN_MASK),
	csr_writel(pcie, lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
		   PAB_AXI_AMAP_AXI_WIN(win_num));

	value = csr_readl(pcie, PAB_AXI_AMAP_PEX_WIN_H(win_num));
	csr_writel(pcie, upper_32_bits(cpu_addr),
		   PAB_EXT_AXI_AMAP_AXI_WIN(win_num));

	csr_writel(pcie, lower_32_bits(pci_addr),
		   PAB_AXI_AMAP_PEX_WIN_L(win_num));
@@ -469,7 +547,9 @@ static int mobiveil_bringup_link(struct mobiveil_pcie *pcie)

		usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
	}

	dev_err(&pcie->pdev->dev, "link never came up\n");

	return -ETIMEDOUT;
}

@@ -491,31 +571,30 @@ static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie)

static int mobiveil_host_init(struct mobiveil_pcie *pcie)
{
	u32 value, pab_ctrl, type = 0;
	int err;
	struct resource_entry *win, *tmp;
	u32 value, pab_ctrl, type;
	struct resource_entry *win;

	err = mobiveil_bringup_link(pcie);
	if (err) {
		dev_info(&pcie->pdev->dev, "link bring-up failed\n");
		return err;
	}
	/* setup bus numbers */
	value = csr_readl(pcie, PCI_PRIMARY_BUS);
	value &= 0xff000000;
	value |= 0x00ff0100;
	csr_writel(pcie, value, PCI_PRIMARY_BUS);

	/*
	 * program Bus Master Enable Bit in Command Register in PAB Config
	 * Space
	 */
	value = csr_readl(pcie, PCI_COMMAND);
	csr_writel(pcie, value | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
		PCI_COMMAND_MASTER, PCI_COMMAND);
	value |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
	csr_writel(pcie, value, PCI_COMMAND);

	/*
	 * program PIO Enable Bit to 1 (and PEX PIO Enable to 1) in PAB_CTRL
	 * register
	 */
	pab_ctrl = csr_readl(pcie, PAB_CTRL);
	csr_writel(pcie, pab_ctrl | (1 << AMBA_PIO_ENABLE_SHIFT) |
		(1 << PEX_PIO_ENABLE_SHIFT), PAB_CTRL);
	pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 << PEX_PIO_ENABLE_SHIFT);
	csr_writel(pcie, pab_ctrl, PAB_CTRL);

	csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
		   PAB_INTP_AMBA_MISC_ENB);
@@ -525,7 +604,13 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
	 * PAB_AXI_PIO_CTRL Register
	 */
	value = csr_readl(pcie, PAB_AXI_PIO_CTRL);
	csr_writel(pcie, value | APIO_EN_MASK, PAB_AXI_PIO_CTRL);
	value |= APIO_EN_MASK;
	csr_writel(pcie, value, PAB_AXI_PIO_CTRL);

	/* Enable PCIe PIO master */
	value = csr_readl(pcie, PAB_PEX_PIO_CTRL);
	value |= 1 << PIO_ENABLE_SHIFT;
	csr_writel(pcie, value, PAB_PEX_PIO_CTRL);

	/*
	 * we'll program one outbound window for config reads and
@@ -535,32 +620,38 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
	 */

	/* config outbound translation window */
	program_ob_windows(pcie, pcie->ob_wins_configured,
			pcie->ob_io_res->start, 0, CFG_WINDOW_TYPE,
			resource_size(pcie->ob_io_res));
	program_ob_windows(pcie, WIN_NUM_0, pcie->ob_io_res->start, 0,
			   CFG_WINDOW_TYPE, resource_size(pcie->ob_io_res));

	/* memory inbound translation window */
	program_ib_windows(pcie, WIN_NUM_1, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
	program_ib_windows(pcie, WIN_NUM_0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);

	/* Get the I/O and memory ranges from DT */
	resource_list_for_each_entry_safe(win, tmp, &pcie->resources) {
		type = 0;
	resource_list_for_each_entry(win, &pcie->resources) {
		if (resource_type(win->res) == IORESOURCE_MEM)
			type = MEM_WINDOW_TYPE;
		if (resource_type(win->res) == IORESOURCE_IO)
		else if (resource_type(win->res) == IORESOURCE_IO)
			type = IO_WINDOW_TYPE;
		if (type) {
		else
			continue;

		/* configure outbound translation window */
		program_ob_windows(pcie, pcie->ob_wins_configured,
				win->res->start, 0, type,
				resource_size(win->res));
		}
				   win->res->start,
				   win->res->start - win->offset,
				   type, resource_size(win->res));
	}

	/* fixup for PCIe class register */
	value = csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS);
	value &= 0xff;
	value |= (PCI_CLASS_BRIDGE_PCI << 16);
	csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);

	/* setup MSI hardware registers */
	mobiveil_pcie_enable_msi(pcie);

	return err;
	return 0;
}

static void mobiveil_mask_intx_irq(struct irq_data *data)
@@ -574,7 +665,8 @@ static void mobiveil_mask_intx_irq(struct irq_data *data)
	mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
	raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
	shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
	csr_writel(pcie, (shifted_val & (~mask)), PAB_INTP_AMBA_MISC_ENB);
	shifted_val &= ~mask;
	csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
	raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
}

@@ -589,7 +681,8 @@ static void mobiveil_unmask_intx_irq(struct irq_data *data)
	mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
	raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
	shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB);
	csr_writel(pcie, (shifted_val | mask), PAB_INTP_AMBA_MISC_ENB);
	shifted_val |= mask;
	csr_writel(pcie, shifted_val, PAB_INTP_AMBA_MISC_ENB);
	raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
}

@@ -607,6 +700,7 @@ static int mobiveil_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
{
	irq_set_chip_and_handler(irq, &intx_irq_chip, handle_level_irq);
	irq_set_chip_data(irq, domain->host_data);

	return 0;
}

@@ -623,7 +717,7 @@ static struct irq_chip mobiveil_msi_irq_chip = {

static struct msi_domain_info mobiveil_msi_domain_info = {
	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
		MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
		   MSI_FLAG_PCI_MSIX),
	.chip	= &mobiveil_msi_irq_chip,
};

@@ -653,7 +747,8 @@ static struct irq_chip mobiveil_msi_bottom_irq_chip = {
};

static int mobiveil_irq_msi_domain_alloc(struct irq_domain *domain,
		unsigned int virq, unsigned int nr_irqs, void *args)
					 unsigned int virq,
					 unsigned int nr_irqs, void *args)
{
	struct mobiveil_pcie *pcie = domain->host_data;
	struct mobiveil_msi *msi = &pcie->msi;
@@ -673,13 +768,13 @@ static int mobiveil_irq_msi_domain_alloc(struct irq_domain *domain,
	mutex_unlock(&msi->lock);

	irq_domain_set_info(domain, virq, bit, &mobiveil_msi_bottom_irq_chip,
				domain->host_data, handle_level_irq,
				NULL, NULL);
			    domain->host_data, handle_level_irq, NULL, NULL);
	return 0;
}

static void mobiveil_irq_msi_domain_free(struct irq_domain *domain,
		unsigned int virq, unsigned int nr_irqs)
					 unsigned int virq,
					 unsigned int nr_irqs)
{
	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
	struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(d);
@@ -687,12 +782,11 @@ static void mobiveil_irq_msi_domain_free(struct irq_domain *domain,

	mutex_lock(&msi->lock);

	if (!test_bit(d->hwirq, msi->msi_irq_in_use)) {
	if (!test_bit(d->hwirq, msi->msi_irq_in_use))
		dev_err(&pcie->pdev->dev, "trying to free unused MSI#%lu\n",
			d->hwirq);
	} else {
	else
		__clear_bit(d->hwirq, msi->msi_irq_in_use);
	}

	mutex_unlock(&msi->lock);
}
@@ -716,12 +810,14 @@ static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie)
	}

	msi->msi_domain = pci_msi_create_irq_domain(fwnode,
				&mobiveil_msi_domain_info, msi->dev_domain);
						    &mobiveil_msi_domain_info,
						    msi->dev_domain);
	if (!msi->msi_domain) {
		dev_err(dev, "failed to create MSI domain\n");
		irq_domain_remove(msi->dev_domain);
		return -ENOMEM;
	}

	return 0;
}

@@ -732,12 +828,12 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
	int ret;

	/* setup INTx */
	pcie->intx_domain = irq_domain_add_linear(node,
				PCI_NUM_INTX, &intx_domain_ops, pcie);
	pcie->intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
						  &intx_domain_ops, pcie);

	if (!pcie->intx_domain) {
		dev_err(dev, "Failed to get a INTx IRQ domain\n");
		return -ENODEV;
		return -ENOMEM;
	}

	raw_spin_lock_init(&pcie->intx_mask_lock);
@@ -763,11 +859,9 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
	/* allocate the PCIe port */
	bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
	if (!bridge)
		return -ENODEV;
		return -ENOMEM;

	pcie = pci_host_bridge_priv(bridge);
	if (!pcie)
		return -ENOMEM;

	pcie->pdev = pdev;

@@ -784,7 +878,7 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
						    &pcie->resources, &iobase);
	if (ret) {
		dev_err(dev, "Getting bridge resources failed\n");
		return -ENOMEM;
		return ret;
	}

	/*
@@ -797,9 +891,6 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
		goto error;
	}

	/* fixup for PCIe class register */
	csr_writel(pcie, 0x060402ab, PAB_INTP_AXI_PIO_CLASS);

	/* initialize the IRQ domains */
	ret = mobiveil_pcie_init_irq_domain(pcie);
	if (ret) {
@@ -807,6 +898,8 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
		goto error;
	}

	irq_set_chained_handler_and_data(pcie->irq, mobiveil_pcie_isr, pcie);

	ret = devm_request_pci_bus_resources(dev, &pcie->resources);
	if (ret)
		goto error;
@@ -820,6 +913,12 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
	bridge->map_irq = of_irq_parse_and_map_pci;
	bridge->swizzle_irq = pci_common_swizzle;

	ret = mobiveil_bringup_link(pcie);
	if (ret) {
		dev_info(dev, "link bring-up failed\n");
		goto error;
	}

	/* setup the kernel resources for the newly added PCIe root bus */
	ret = pci_scan_root_bus_bridge(bridge);
	if (ret)