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

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
...@@ -10,8 +10,10 @@ Required properties: ...@@ -10,8 +10,10 @@ Required properties:
interrupt source. The value must be 1. interrupt source. The value must be 1.
- compatible: Should contain "mbvl,gpex40-pcie" - compatible: Should contain "mbvl,gpex40-pcie"
- reg: Should contain PCIe registers location and length - reg: Should contain PCIe registers location and length
Mandatory:
"config_axi_slave": PCIe controller registers "config_axi_slave": PCIe controller registers
"csr_axi_slave" : Bridge config registers "csr_axi_slave" : Bridge config registers
Optional:
"gpio_slave" : GPIO registers to control slot power "gpio_slave" : GPIO registers to control slot power
"apb_csr" : MSI registers "apb_csr" : MSI registers
......
...@@ -34,8 +34,10 @@ ...@@ -34,8 +34,10 @@
#define PAB_REG_BLOCK_SIZE 16 #define PAB_REG_BLOCK_SIZE 16
#define PAB_EXT_REG_BLOCK_SIZE 4 #define PAB_EXT_REG_BLOCK_SIZE 4
#define PAB_REG_ADDR(offset, win) (offset + (win * PAB_REG_BLOCK_SIZE)) #define PAB_REG_ADDR(offset, win) \
#define PAB_EXT_REG_ADDR(offset, win) (offset + (win * PAB_EXT_REG_BLOCK_SIZE)) (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 0x0404
#define LTSSM_STATUS_L0_MASK 0x3f #define LTSSM_STATUS_L0_MASK 0x3f
...@@ -47,7 +49,6 @@ ...@@ -47,7 +49,6 @@
#define PAGE_SEL_SHIFT 13 #define PAGE_SEL_SHIFT 13
#define PAGE_SEL_MASK 0x3f #define PAGE_SEL_MASK 0x3f
#define PAGE_LO_MASK 0x3ff #define PAGE_LO_MASK 0x3ff
#define PAGE_SEL_EN 0xc00
#define PAGE_SEL_OFFSET_SHIFT 10 #define PAGE_SEL_OFFSET_SHIFT 10
#define PAB_AXI_PIO_CTRL 0x0840 #define PAB_AXI_PIO_CTRL 0x0840
...@@ -64,9 +65,12 @@ ...@@ -64,9 +65,12 @@
#define PAB_AXI_AMAP_CTRL(win) PAB_REG_ADDR(0x0ba0, win) #define PAB_AXI_AMAP_CTRL(win) PAB_REG_ADDR(0x0ba0, win)
#define WIN_ENABLE_SHIFT 0 #define WIN_ENABLE_SHIFT 0
#define WIN_TYPE_SHIFT 1 #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_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 PAB_AXI_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x0ba4, win)
#define AXI_WINDOW_ALIGN_MASK 3 #define AXI_WINDOW_ALIGN_MASK 3
...@@ -81,6 +85,7 @@ ...@@ -81,6 +85,7 @@
#define PAB_PEX_AMAP_CTRL(win) PAB_REG_ADDR(0x4ba0, win) #define PAB_PEX_AMAP_CTRL(win) PAB_REG_ADDR(0x4ba0, win)
#define AMAP_CTRL_EN_SHIFT 0 #define AMAP_CTRL_EN_SHIFT 0
#define AMAP_CTRL_TYPE_SHIFT 1 #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_EXT_PEX_AMAP_SIZEN(win) PAB_EXT_REG_ADDR(0xbef0, win)
#define PAB_PEX_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x4ba4, win) #define PAB_PEX_AMAP_AXI_WIN(win) PAB_REG_ADDR(0x4ba4, win)
...@@ -117,6 +122,12 @@ ...@@ -117,6 +122,12 @@
#define LINK_WAIT_MIN 90000 #define LINK_WAIT_MIN 90000
#define LINK_WAIT_MAX 100000 #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 mobiveil_msi { /* MSI information */
struct mutex lock; /* protect bitmap variable */ struct mutex lock; /* protect bitmap variable */
struct irq_domain *msi_domain; struct irq_domain *msi_domain;
...@@ -145,15 +156,119 @@ struct mobiveil_pcie { ...@@ -145,15 +156,119 @@ struct mobiveil_pcie {
struct mobiveil_msi msi; 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;
}
return PCIBIOS_SUCCESSFUL;
} }
static inline u32 csr_readl(struct mobiveil_pcie *pcie, const u32 reg) 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) 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) ...@@ -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 * Do not read more than one device on the bus directly
* attached to RC * 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 false;
return true; return true;
...@@ -188,14 +303,14 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus, ...@@ -188,14 +303,14 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
unsigned int devfn, int where) unsigned int devfn, int where)
{ {
struct mobiveil_pcie *pcie = bus->sysdata; struct mobiveil_pcie *pcie = bus->sysdata;
u32 value;
if (!mobiveil_pcie_valid_device(bus, devfn)) if (!mobiveil_pcie_valid_device(bus, devfn))
return NULL; return NULL;
if (bus->number == pcie->root_bus_nr) {
/* RC config access */ /* RC config access */
if (bus->number == pcie->root_bus_nr)
return pcie->csr_axi_slave_base + where; return pcie->csr_axi_slave_base + where;
}
/* /*
* EP config access (in Config/APIO space) * EP config access (in Config/APIO space)
...@@ -203,10 +318,12 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus, ...@@ -203,10 +318,12 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus,
* (BDF) in PAB_AXI_AMAP_PEX_WIN_L0 Register. * (BDF) in PAB_AXI_AMAP_PEX_WIN_L0 Register.
* Relies on pci_lock serialization * 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_SLOT(devfn) << PAB_DEVICE_SHIFT |
PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT, PCI_FUNC(devfn) << PAB_FUNCTION_SHIFT;
PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
csr_writel(pcie, value, PAB_AXI_AMAP_PEX_WIN_L(WIN_NUM_0));
return pcie->config_axi_slave_base + where; return pcie->config_axi_slave_base + where;
} }
...@@ -241,8 +358,9 @@ static void mobiveil_pcie_isr(struct irq_desc *desc) ...@@ -241,8 +358,9 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
/* Handle INTx */ /* Handle INTx */
if (intr_status & PAB_INTP_INTX_MASK) { if (intr_status & PAB_INTP_INTX_MASK) {
shifted_status = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT) >> shifted_status = csr_readl(pcie, PAB_INTP_AMBA_MISC_STAT);
PAB_INTX_START; shifted_status &= PAB_INTP_INTX_MASK;
shifted_status >>= PAB_INTX_START;
do { do {
for_each_set_bit(bit, &shifted_status, PCI_NUM_INTX) { for_each_set_bit(bit, &shifted_status, PCI_NUM_INTX) {
virq = irq_find_mapping(pcie->intx_domain, virq = irq_find_mapping(pcie->intx_domain,
...@@ -250,15 +368,19 @@ static void mobiveil_pcie_isr(struct irq_desc *desc) ...@@ -250,15 +368,19 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
if (virq) if (virq)
generic_handle_irq(virq); generic_handle_irq(virq);
else else
dev_err_ratelimited(dev, dev_err_ratelimited(dev, "unexpected IRQ, INT%d\n",
"unexpected IRQ, INT%d\n", bit); bit);
/* clear interrupt */ /* clear interrupt handled */
csr_writel(pcie, csr_writel(pcie, 1 << (PAB_INTX_START + bit),
shifted_status << PAB_INTX_START,
PAB_INTP_AMBA_MISC_STAT); 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 */ /* read extra MSI status register */
...@@ -266,8 +388,7 @@ static void mobiveil_pcie_isr(struct irq_desc *desc) ...@@ -266,8 +388,7 @@ static void mobiveil_pcie_isr(struct irq_desc *desc)
/* handle MSI interrupts */ /* handle MSI interrupts */
while (msi_status & 1) { while (msi_status & 1) {
msi_data = readl_relaxed(pcie->apb_csr_base msi_data = readl_relaxed(pcie->apb_csr_base + MSI_DATA_OFFSET);
+ MSI_DATA_OFFSET);
/* /*
* MSI_STATUS_OFFSET register gets updated to zero * MSI_STATUS_OFFSET register gets updated to zero
...@@ -337,92 +458,50 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie) ...@@ -337,92 +458,50 @@ static int mobiveil_pcie_parse_dt(struct mobiveil_pcie *pcie)
return -ENODEV; return -ENODEV;
} }
irq_set_chained_handler_and_data(pcie->irq, mobiveil_pcie_isr, pcie);
return 0; 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, 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; u32 value;
int amap_ctrl_dw;
u64 size64 = ~(size - 1); u64 size64 = ~(size - 1);
if ((pcie->ib_wins_configured + 1) > pcie->ppio_wins) { if (win_num >= pcie->ppio_wins) {
dev_err(&pcie->pdev->dev, dev_err(&pcie->pdev->dev,
"ERROR: max inbound windows reached !\n"); "ERROR: max inbound windows reached !\n");
return; return;
} }
pio_ctrl_val = csr_readl(pcie, PAB_PEX_PIO_CTRL); value = csr_readl(pcie, PAB_PEX_AMAP_CTRL(win_num));
csr_writel(pcie, value &= ~(AMAP_CTRL_TYPE_MASK << AMAP_CTRL_TYPE_SHIFT | WIN_SIZE_MASK);
pio_ctrl_val | (1 << PIO_ENABLE_SHIFT), PAB_PEX_PIO_CTRL); value |= type << AMAP_CTRL_TYPE_SHIFT | 1 << AMAP_CTRL_EN_SHIFT |
amap_ctrl_dw = read_paged_register(pcie, PAB_PEX_AMAP_CTRL(win_num)); (lower_32_bits(size64) & WIN_SIZE_MASK);
amap_ctrl_dw = (amap_ctrl_dw | (type << AMAP_CTRL_TYPE_SHIFT)); csr_writel(pcie, value, PAB_PEX_AMAP_CTRL(win_num));
amap_ctrl_dw = (amap_ctrl_dw | (1 << AMAP_CTRL_EN_SHIFT));
write_paged_register(pcie, amap_ctrl_dw | lower_32_bits(size64), csr_writel(pcie, upper_32_bits(size64),
PAB_PEX_AMAP_CTRL(win_num));
write_paged_register(pcie, upper_32_bits(size64),
PAB_EXT_PEX_AMAP_SIZEN(win_num)); PAB_EXT_PEX_AMAP_SIZEN(win_num));
write_paged_register(pcie, pci_addr, PAB_PEX_AMAP_AXI_WIN(win_num)); csr_writel(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, 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 * routine to program the outbound windows
*/ */
static void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, 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;
u32 value, type;
u64 size64 = ~(size - 1); u64 size64 = ~(size - 1);
if ((pcie->ob_wins_configured + 1) > pcie->apio_wins) { if (win_num >= pcie->apio_wins) {
dev_err(&pcie->pdev->dev, dev_err(&pcie->pdev->dev,
"ERROR: max outbound windows reached !\n"); "ERROR: max outbound windows reached !\n");
return; return;
...@@ -432,23 +511,22 @@ static void program_ob_windows(struct mobiveil_pcie *pcie, int win_num, ...@@ -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 * program Enable Bit to 1, Type Bit to (00) base 2, AXI Window Size Bit
* to 4 KB in PAB_AXI_AMAP_CTRL register * to 4 KB in PAB_AXI_AMAP_CTRL register
*/ */
type = config_io_bit;
value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num)); value = csr_readl(pcie, PAB_AXI_AMAP_CTRL(win_num));
csr_writel(pcie, 1 << WIN_ENABLE_SHIFT | type << WIN_TYPE_SHIFT | value &= ~(WIN_TYPE_MASK << WIN_TYPE_SHIFT | WIN_SIZE_MASK);
lower_32_bits(size64), PAB_AXI_AMAP_CTRL(win_num)); 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), csr_writel(pcie, upper_32_bits(size64), PAB_EXT_AXI_AMAP_SIZE(win_num));
PAB_EXT_AXI_AMAP_SIZE(win_num));
/* /*
* program AXI window base with appropriate value in * program AXI window base with appropriate value in
* PAB_AXI_AMAP_AXI_WIN0 register * PAB_AXI_AMAP_AXI_WIN0 register
*/ */
value = csr_readl(pcie, PAB_AXI_AMAP_AXI_WIN(win_num)); csr_writel(pcie, lower_32_bits(cpu_addr) & (~AXI_WINDOW_ALIGN_MASK),
csr_writel(pcie, cpu_addr & (~AXI_WINDOW_ALIGN_MASK),
PAB_AXI_AMAP_AXI_WIN(win_num)); PAB_AXI_AMAP_AXI_WIN(win_num));
csr_writel(pcie, upper_32_bits(cpu_addr),
value = csr_readl(pcie, PAB_AXI_AMAP_PEX_WIN_H(win_num)); PAB_EXT_AXI_AMAP_AXI_WIN(win_num));
csr_writel(pcie, lower_32_bits(pci_addr), csr_writel(pcie, lower_32_bits(pci_addr),
PAB_AXI_AMAP_PEX_WIN_L(win_num)); PAB_AXI_AMAP_PEX_WIN_L(win_num));
...@@ -469,7 +547,9 @@ static int mobiveil_bringup_link(struct mobiveil_pcie *pcie) ...@@ -469,7 +547,9 @@ static int mobiveil_bringup_link(struct mobiveil_pcie *pcie)
usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX); usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
} }
dev_err(&pcie->pdev->dev, "link never came up\n"); dev_err(&pcie->pdev->dev, "link never came up\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -491,31 +571,30 @@ static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie) ...@@ -491,31 +571,30 @@ static void mobiveil_pcie_enable_msi(struct mobiveil_pcie *pcie)
static int mobiveil_host_init(struct mobiveil_pcie *pcie) static int mobiveil_host_init(struct mobiveil_pcie *pcie)
{ {
u32 value, pab_ctrl, type = 0; u32 value, pab_ctrl, type;
int err; struct resource_entry *win;
struct resource_entry *win, *tmp;
/* setup bus numbers */
err = mobiveil_bringup_link(pcie); value = csr_readl(pcie, PCI_PRIMARY_BUS);
if (err) { value &= 0xff000000;
dev_info(&pcie->pdev->dev, "link bring-up failed\n"); value |= 0x00ff0100;
return err; csr_writel(pcie, value, PCI_PRIMARY_BUS);
}
/* /*
* program Bus Master Enable Bit in Command Register in PAB Config * program Bus Master Enable Bit in Command Register in PAB Config
* Space * Space
*/ */
value = csr_readl(pcie, PCI_COMMAND); value = csr_readl(pcie, PCI_COMMAND);
csr_writel(pcie, value | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | value |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
PCI_COMMAND_MASTER, PCI_COMMAND); csr_writel(pcie, value, PCI_COMMAND);
/* /*
* program PIO Enable Bit to 1 (and PEX PIO Enable to 1) in PAB_CTRL * program PIO Enable Bit to 1 (and PEX PIO Enable to 1) in PAB_CTRL
* register * register
*/ */
pab_ctrl = csr_readl(pcie, PAB_CTRL); pab_ctrl = csr_readl(pcie, PAB_CTRL);
csr_writel(pcie, pab_ctrl | (1 << AMBA_PIO_ENABLE_SHIFT) | pab_ctrl |= (1 << AMBA_PIO_ENABLE_SHIFT) | (1 << PEX_PIO_ENABLE_SHIFT);
(1 << PEX_PIO_ENABLE_SHIFT), PAB_CTRL); csr_writel(pcie, pab_ctrl, PAB_CTRL);
csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK), csr_writel(pcie, (PAB_INTP_INTX_MASK | PAB_INTP_MSI_MASK),
PAB_INTP_AMBA_MISC_ENB); PAB_INTP_AMBA_MISC_ENB);
...@@ -525,7 +604,13 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie) ...@@ -525,7 +604,13 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
* PAB_AXI_PIO_CTRL Register * PAB_AXI_PIO_CTRL Register
*/ */
value = csr_readl(pcie, PAB_AXI_PIO_CTRL); 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 * we'll program one outbound window for config reads and
...@@ -535,32 +620,38 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie) ...@@ -535,32 +620,38 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
*/ */
/* config outbound translation window */ /* config outbound translation window */
program_ob_windows(pcie, pcie->ob_wins_configured, program_ob_windows(pcie, WIN_NUM_0, pcie->ob_io_res->start, 0,
pcie->ob_io_res->start, 0, CFG_WINDOW_TYPE, CFG_WINDOW_TYPE, resource_size(pcie->ob_io_res));
resource_size(pcie->ob_io_res));
/* memory inbound translation window */ /* 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 */ /* Get the I/O and memory ranges from DT */
resource_list_for_each_entry_safe(win, tmp, &pcie->resources) { resource_list_for_each_entry(win, &pcie->resources) {
type = 0;
if (resource_type(win->res) == IORESOURCE_MEM) if (resource_type(win->res) == IORESOURCE_MEM)
type = MEM_WINDOW_TYPE; type = MEM_WINDOW_TYPE;
if (resource_type(win->res) == IORESOURCE_IO) else if (resource_type(win->res) == IORESOURCE_IO)
type = IO_WINDOW_TYPE; type = IO_WINDOW_TYPE;
if (type) { else
continue;
/* configure outbound translation window */ /* configure outbound translation window */
program_ob_windows(pcie, pcie->ob_wins_configured, program_ob_windows(pcie, pcie->ob_wins_configured,
win->res->start, 0, type, win->res->start,
resource_size(win->res)); 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 */ /* setup MSI hardware registers */
mobiveil_pcie_enable_msi(pcie); mobiveil_pcie_enable_msi(pcie);
return err; return 0;
} }
static void mobiveil_mask_intx_irq(struct irq_data *data) static void mobiveil_mask_intx_irq(struct irq_data *data)
...@@ -574,7 +665,8 @@ 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); mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags); raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB); 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); raw_spin_unlock_irqrestore(&pcie->intx_mask_lock, flags);
} }
...@@ -589,7 +681,8 @@ static void mobiveil_unmask_intx_irq(struct irq_data *data) ...@@ -589,7 +681,8 @@ static void mobiveil_unmask_intx_irq(struct irq_data *data)
mask = 1 << ((data->hwirq + PAB_INTX_START) - 1); mask = 1 << ((data->hwirq + PAB_INTX_START) - 1);
raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags); raw_spin_lock_irqsave(&pcie->intx_mask_lock, flags);
shifted_val = csr_readl(pcie, PAB_INTP_AMBA_MISC_ENB); 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); 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, ...@@ -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_and_handler(irq, &intx_irq_chip, handle_level_irq);
irq_set_chip_data(irq, domain->host_data); irq_set_chip_data(irq, domain->host_data);
return 0; return 0;
} }
...@@ -623,7 +717,7 @@ static struct irq_chip mobiveil_msi_irq_chip = { ...@@ -623,7 +717,7 @@ static struct irq_chip mobiveil_msi_irq_chip = {
static struct msi_domain_info mobiveil_msi_domain_info = { static struct msi_domain_info mobiveil_msi_domain_info = {
.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | .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, .chip = &mobiveil_msi_irq_chip,
}; };
...@@ -653,7 +747,8 @@ static struct irq_chip mobiveil_msi_bottom_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, 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_pcie *pcie = domain->host_data;
struct mobiveil_msi *msi = &pcie->msi; struct mobiveil_msi *msi = &pcie->msi;
...@@ -673,13 +768,13 @@ static int mobiveil_irq_msi_domain_alloc(struct irq_domain *domain, ...@@ -673,13 +768,13 @@ static int mobiveil_irq_msi_domain_alloc(struct irq_domain *domain,
mutex_unlock(&msi->lock); mutex_unlock(&msi->lock);
irq_domain_set_info(domain, virq, bit, &mobiveil_msi_bottom_irq_chip, irq_domain_set_info(domain, virq, bit, &mobiveil_msi_bottom_irq_chip,
domain->host_data, handle_level_irq, domain->host_data, handle_level_irq, NULL, NULL);
NULL, NULL);
return 0; return 0;
} }
static void mobiveil_irq_msi_domain_free(struct irq_domain *domain, 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 irq_data *d = irq_domain_get_irq_data(domain, virq);
struct mobiveil_pcie *pcie = irq_data_get_irq_chip_data(d); 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, ...@@ -687,12 +782,11 @@ static void mobiveil_irq_msi_domain_free(struct irq_domain *domain,
mutex_lock(&msi->lock); 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", dev_err(&pcie->pdev->dev, "trying to free unused MSI#%lu\n",
d->hwirq); d->hwirq);
} else { else
__clear_bit(d->hwirq, msi->msi_irq_in_use); __clear_bit(d->hwirq, msi->msi_irq_in_use);
}
mutex_unlock(&msi->lock); mutex_unlock(&msi->lock);
} }
...@@ -716,12 +810,14 @@ static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie) ...@@ -716,12 +810,14 @@ static int mobiveil_allocate_msi_domains(struct mobiveil_pcie *pcie)
} }
msi->msi_domain = pci_msi_create_irq_domain(fwnode, 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) { if (!msi->msi_domain) {
dev_err(dev, "failed to create MSI domain\n"); dev_err(dev, "failed to create MSI domain\n");
irq_domain_remove(msi->dev_domain); irq_domain_remove(msi->dev_domain);
return -ENOMEM; return -ENOMEM;
} }
return 0; return 0;
} }
...@@ -732,12 +828,12 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie) ...@@ -732,12 +828,12 @@ static int mobiveil_pcie_init_irq_domain(struct mobiveil_pcie *pcie)
int ret; int ret;
/* setup INTx */ /* setup INTx */
pcie->intx_domain = irq_domain_add_linear(node, pcie->intx_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
PCI_NUM_INTX, &intx_domain_ops, pcie); &intx_domain_ops, pcie);
if (!pcie->intx_domain) { if (!pcie->intx_domain) {
dev_err(dev, "Failed to get a INTx IRQ domain\n"); dev_err(dev, "Failed to get a INTx IRQ domain\n");
return -ENODEV; return -ENOMEM;
} }
raw_spin_lock_init(&pcie->intx_mask_lock); raw_spin_lock_init(&pcie->intx_mask_lock);
...@@ -763,11 +859,9 @@ static int mobiveil_pcie_probe(struct platform_device *pdev) ...@@ -763,11 +859,9 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
/* allocate the PCIe port */ /* allocate the PCIe port */
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie)); bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
if (!bridge) if (!bridge)
return -ENODEV; return -ENOMEM;
pcie = pci_host_bridge_priv(bridge); pcie = pci_host_bridge_priv(bridge);
if (!pcie)
return -ENOMEM;
pcie->pdev = pdev; pcie->pdev = pdev;
...@@ -784,7 +878,7 @@ static int mobiveil_pcie_probe(struct platform_device *pdev) ...@@ -784,7 +878,7 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
&pcie->resources, &iobase); &pcie->resources, &iobase);
if (ret) { if (ret) {
dev_err(dev, "Getting bridge resources failed\n"); 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) ...@@ -797,9 +891,6 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
goto error; goto error;
} }
/* fixup for PCIe class register */
csr_writel(pcie, 0x060402ab, PAB_INTP_AXI_PIO_CLASS);
/* initialize the IRQ domains */ /* initialize the IRQ domains */
ret = mobiveil_pcie_init_irq_domain(pcie); ret = mobiveil_pcie_init_irq_domain(pcie);
if (ret) { if (ret) {
...@@ -807,6 +898,8 @@ static int mobiveil_pcie_probe(struct platform_device *pdev) ...@@ -807,6 +898,8 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
goto error; goto error;
} }
irq_set_chained_handler_and_data(pcie->irq, mobiveil_pcie_isr, pcie);
ret = devm_request_pci_bus_resources(dev, &pcie->resources); ret = devm_request_pci_bus_resources(dev, &pcie->resources);
if (ret) if (ret)
goto error; goto error;
...@@ -820,6 +913,12 @@ static int mobiveil_pcie_probe(struct platform_device *pdev) ...@@ -820,6 +913,12 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
bridge->map_irq = of_irq_parse_and_map_pci; bridge->map_irq = of_irq_parse_and_map_pci;
bridge->swizzle_irq = pci_common_swizzle; 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 */ /* setup the kernel resources for the newly added PCIe root bus */
ret = pci_scan_root_bus_bridge(bridge); ret = pci_scan_root_bus_bridge(bridge);
if (ret) if (ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment