Merge branch 'pci/controller/microchip'

- Add DT and driver support for using either of the two PolarFire Root
  Ports (Conor Dooley)

* pci/controller/microchip:
  PCI: microchip: Add support for using either Root Port 1 or 2
  dt-bindings: PCI: microchip,pcie-host: Add reg for Root Port 2
This commit is contained in:
Bjorn Helgaas 2024-11-25 13:40:59 -06:00
commit 7b5d234e69
4 changed files with 93 additions and 65 deletions

View File

@ -17,6 +17,12 @@ properties:
compatible:
const: microchip,pcie-host-1.0 # PolarFire
reg:
minItems: 3
reg-names:
minItems: 3
clocks:
description:
Fabric Interface Controllers, FICs, are the interface between the FPGA
@ -62,8 +68,9 @@ examples:
pcie0: pcie@2030000000 {
compatible = "microchip,pcie-host-1.0";
reg = <0x0 0x70000000 0x0 0x08000000>,
<0x0 0x43000000 0x0 0x00010000>;
reg-names = "cfg", "apb";
<0x0 0x43008000 0x0 0x00002000>,
<0x0 0x4300a000 0x0 0x00002000>;
reg-names = "cfg", "bridge", "ctrl";
device_type = "pci";
#address-cells = <3>;
#size-cells = <2>;

View File

@ -18,12 +18,18 @@ allOf:
properties:
reg:
maxItems: 2
maxItems: 3
minItems: 2
reg-names:
items:
- const: cfg
- const: apb
oneOf:
- items:
- const: cfg
- const: apb
- items:
- const: cfg
- const: bridge
- const: ctrl
interrupts:
minItems: 1

View File

@ -16,6 +16,13 @@ properties:
compatible:
const: starfive,jh7110-pcie
reg:
maxItems: 2
reg-names:
maxItems: 2
clocks:
items:
- description: NOC bus clock

View File

@ -25,9 +25,6 @@
#define MC_PCIE1_BRIDGE_ADDR 0x00008000u
#define MC_PCIE1_CTRL_ADDR 0x0000a000u
#define MC_PCIE_BRIDGE_ADDR (MC_PCIE1_BRIDGE_ADDR)
#define MC_PCIE_CTRL_ADDR (MC_PCIE1_CTRL_ADDR)
/* PCIe Controller Phy Regs */
#define SEC_ERROR_EVENT_CNT 0x20
#define DED_ERROR_EVENT_CNT 0x24
@ -128,7 +125,6 @@
[EVENT_LOCAL_ ## x] = { __stringify(x), s }
#define PCIE_EVENT(x) \
.base = MC_PCIE_CTRL_ADDR, \
.offset = PCIE_EVENT_INT, \
.mask_offset = PCIE_EVENT_INT, \
.mask_high = 1, \
@ -136,7 +132,6 @@
.enb_mask = PCIE_EVENT_INT_ENB_MASK
#define SEC_EVENT(x) \
.base = MC_PCIE_CTRL_ADDR, \
.offset = SEC_ERROR_INT, \
.mask_offset = SEC_ERROR_INT_MASK, \
.mask = SEC_ERROR_INT_ ## x ## _INT, \
@ -144,7 +139,6 @@
.enb_mask = 0
#define DED_EVENT(x) \
.base = MC_PCIE_CTRL_ADDR, \
.offset = DED_ERROR_INT, \
.mask_offset = DED_ERROR_INT_MASK, \
.mask_high = 1, \
@ -152,7 +146,6 @@
.enb_mask = 0
#define LOCAL_EVENT(x) \
.base = MC_PCIE_BRIDGE_ADDR, \
.offset = ISTATUS_LOCAL, \
.mask_offset = IMASK_LOCAL, \
.mask_high = 0, \
@ -179,7 +172,8 @@ struct event_map {
struct mc_pcie {
struct plda_pcie_rp plda;
void __iomem *axi_base_addr;
void __iomem *bridge_base_addr;
void __iomem *ctrl_base_addr;
};
struct cause {
@ -253,7 +247,6 @@ static struct event_map local_status_to_event[] = {
};
static struct {
u32 base;
u32 offset;
u32 mask;
u32 shift;
@ -325,8 +318,7 @@ static inline u32 reg_to_event(u32 reg, struct event_map field)
static u32 pcie_events(struct mc_pcie *port)
{
void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
u32 reg = readl_relaxed(ctrl_base_addr + PCIE_EVENT_INT);
u32 reg = readl_relaxed(port->ctrl_base_addr + PCIE_EVENT_INT);
u32 val = 0;
int i;
@ -338,8 +330,7 @@ static u32 pcie_events(struct mc_pcie *port)
static u32 sec_errors(struct mc_pcie *port)
{
void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
u32 reg = readl_relaxed(ctrl_base_addr + SEC_ERROR_INT);
u32 reg = readl_relaxed(port->ctrl_base_addr + SEC_ERROR_INT);
u32 val = 0;
int i;
@ -351,8 +342,7 @@ static u32 sec_errors(struct mc_pcie *port)
static u32 ded_errors(struct mc_pcie *port)
{
void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
u32 reg = readl_relaxed(ctrl_base_addr + DED_ERROR_INT);
u32 reg = readl_relaxed(port->ctrl_base_addr + DED_ERROR_INT);
u32 val = 0;
int i;
@ -364,8 +354,7 @@ static u32 ded_errors(struct mc_pcie *port)
static u32 local_events(struct mc_pcie *port)
{
void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
u32 reg = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
u32 reg = readl_relaxed(port->bridge_base_addr + ISTATUS_LOCAL);
u32 val = 0;
int i;
@ -412,8 +401,12 @@ static void mc_ack_event_irq(struct irq_data *data)
void __iomem *addr;
u32 mask;
addr = mc_port->axi_base_addr + event_descs[event].base +
event_descs[event].offset;
if (event_descs[event].offset == ISTATUS_LOCAL)
addr = mc_port->bridge_base_addr;
else
addr = mc_port->ctrl_base_addr;
addr += event_descs[event].offset;
mask = event_descs[event].mask;
mask |= event_descs[event].enb_mask;
@ -429,8 +422,12 @@ static void mc_mask_event_irq(struct irq_data *data)
u32 mask;
u32 val;
addr = mc_port->axi_base_addr + event_descs[event].base +
event_descs[event].mask_offset;
if (event_descs[event].offset == ISTATUS_LOCAL)
addr = mc_port->bridge_base_addr;
else
addr = mc_port->ctrl_base_addr;
addr += event_descs[event].mask_offset;
mask = event_descs[event].mask;
if (event_descs[event].enb_mask) {
mask <<= PCIE_EVENT_INT_ENB_SHIFT;
@ -460,8 +457,12 @@ static void mc_unmask_event_irq(struct irq_data *data)
u32 mask;
u32 val;
addr = mc_port->axi_base_addr + event_descs[event].base +
event_descs[event].mask_offset;
if (event_descs[event].offset == ISTATUS_LOCAL)
addr = mc_port->bridge_base_addr;
else
addr = mc_port->ctrl_base_addr;
addr += event_descs[event].mask_offset;
mask = event_descs[event].mask;
if (event_descs[event].enb_mask)
@ -554,26 +555,20 @@ static const struct plda_event mc_event = {
static inline void mc_clear_secs(struct mc_pcie *port)
{
void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, ctrl_base_addr +
SEC_ERROR_INT);
writel_relaxed(0, ctrl_base_addr + SEC_ERROR_EVENT_CNT);
writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT,
port->ctrl_base_addr + SEC_ERROR_INT);
writel_relaxed(0, port->ctrl_base_addr + SEC_ERROR_EVENT_CNT);
}
static inline void mc_clear_deds(struct mc_pcie *port)
{
void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, ctrl_base_addr +
DED_ERROR_INT);
writel_relaxed(0, ctrl_base_addr + DED_ERROR_EVENT_CNT);
writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT,
port->ctrl_base_addr + DED_ERROR_INT);
writel_relaxed(0, port->ctrl_base_addr + DED_ERROR_EVENT_CNT);
}
static void mc_disable_interrupts(struct mc_pcie *port)
{
void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
u32 val;
/* Ensure ECC bypass is enabled */
@ -581,22 +576,22 @@ static void mc_disable_interrupts(struct mc_pcie *port)
ECC_CONTROL_RX_RAM_ECC_BYPASS |
ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS |
ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS;
writel_relaxed(val, ctrl_base_addr + ECC_CONTROL);
writel_relaxed(val, port->ctrl_base_addr + ECC_CONTROL);
/* Disable SEC errors and clear any outstanding */
writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, ctrl_base_addr +
SEC_ERROR_INT_MASK);
writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT,
port->ctrl_base_addr + SEC_ERROR_INT_MASK);
mc_clear_secs(port);
/* Disable DED errors and clear any outstanding */
writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, ctrl_base_addr +
DED_ERROR_INT_MASK);
writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT,
port->ctrl_base_addr + DED_ERROR_INT_MASK);
mc_clear_deds(port);
/* Disable local interrupts and clear any outstanding */
writel_relaxed(0, bridge_base_addr + IMASK_LOCAL);
writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_LOCAL);
writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_MSI);
writel_relaxed(0, port->bridge_base_addr + IMASK_LOCAL);
writel_relaxed(GENMASK(31, 0), port->bridge_base_addr + ISTATUS_LOCAL);
writel_relaxed(GENMASK(31, 0), port->bridge_base_addr + ISTATUS_MSI);
/* Disable PCIe events and clear any outstanding */
val = PCIE_EVENT_INT_L2_EXIT_INT |
@ -605,11 +600,11 @@ static void mc_disable_interrupts(struct mc_pcie *port)
PCIE_EVENT_INT_L2_EXIT_INT_MASK |
PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK |
PCIE_EVENT_INT_DLUP_EXIT_INT_MASK;
writel_relaxed(val, ctrl_base_addr + PCIE_EVENT_INT);
writel_relaxed(val, port->ctrl_base_addr + PCIE_EVENT_INT);
/* Disable host interrupts and clear any outstanding */
writel_relaxed(0, bridge_base_addr + IMASK_HOST);
writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
writel_relaxed(0, port->bridge_base_addr + IMASK_HOST);
writel_relaxed(GENMASK(31, 0), port->bridge_base_addr + ISTATUS_HOST);
}
static int mc_platform_init(struct pci_config_window *cfg)
@ -617,12 +612,10 @@ static int mc_platform_init(struct pci_config_window *cfg)
struct device *dev = cfg->parent;
struct platform_device *pdev = to_platform_device(dev);
struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
void __iomem *bridge_base_addr =
port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
int ret;
/* Configure address translation table 0 for PCIe config space */
plda_pcie_setup_window(bridge_base_addr, 0, cfg->res.start,
plda_pcie_setup_window(port->bridge_base_addr, 0, cfg->res.start,
cfg->res.start,
resource_size(&cfg->res));
@ -649,7 +642,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
static int mc_host_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
void __iomem *bridge_base_addr;
void __iomem *apb_base_addr;
struct plda_pcie_rp *plda;
int ret;
u32 val;
@ -661,30 +654,45 @@ static int mc_host_probe(struct platform_device *pdev)
plda = &port->plda;
plda->dev = dev;
port->axi_base_addr = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(port->axi_base_addr))
return PTR_ERR(port->axi_base_addr);
port->bridge_base_addr = devm_platform_ioremap_resource_byname(pdev,
"bridge");
port->ctrl_base_addr = devm_platform_ioremap_resource_byname(pdev,
"ctrl");
if (!IS_ERR(port->bridge_base_addr) && !IS_ERR(port->ctrl_base_addr))
goto addrs_set;
/*
* The original, incorrect, binding that lumped the control and
* bridge addresses together still needs to be handled by the driver.
*/
apb_base_addr = devm_platform_ioremap_resource_byname(pdev, "apb");
if (IS_ERR(apb_base_addr))
return dev_err_probe(dev, PTR_ERR(apb_base_addr),
"both legacy apb register and ctrl/bridge regions missing");
port->bridge_base_addr = apb_base_addr + MC_PCIE1_BRIDGE_ADDR;
port->ctrl_base_addr = apb_base_addr + MC_PCIE1_CTRL_ADDR;
addrs_set:
mc_disable_interrupts(port);
bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
plda->bridge_addr = bridge_base_addr;
plda->bridge_addr = port->bridge_base_addr;
plda->num_events = NUM_EVENTS;
/* Allow enabling MSI by disabling MSI-X */
val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
val = readl(port->bridge_base_addr + PCIE_PCI_IRQ_DW0);
val &= ~MSIX_CAP_MASK;
writel(val, bridge_base_addr + PCIE_PCI_IRQ_DW0);
writel(val, port->bridge_base_addr + PCIE_PCI_IRQ_DW0);
/* Pick num vectors from bitfile programmed onto FPGA fabric */
val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
val = readl(port->bridge_base_addr + PCIE_PCI_IRQ_DW0);
val &= NUM_MSI_MSGS_MASK;
val >>= NUM_MSI_MSGS_SHIFT;
plda->msi.num_vectors = 1 << val;
/* Pick vector address from design */
plda->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR);
plda->msi.vector_phy = readl_relaxed(port->bridge_base_addr + IMSI_ADDR);
ret = mc_pcie_init_clks(dev);
if (ret) {