summaryrefslogtreecommitdiff
path: root/drivers/pci/controller/dwc/pci-layerscape-ep.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/controller/dwc/pci-layerscape-ep.c')
-rw-r--r--drivers/pci/controller/dwc/pci-layerscape-ep.c117
1 files changed, 116 insertions, 1 deletions
diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
index 39f4664bd84c..2554f891e7db 100644
--- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
+++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
@@ -18,6 +18,22 @@
#include "pcie-designware.h"
+#define PCIE_LINK_CAP 0x7C /* PCIe Link Capabilities*/
+#define MAX_LINK_SP_MASK 0x0F
+#define MAX_LINK_W_MASK 0x3F
+#define MAX_LINK_W_SHIFT 4
+
+/* PEX PFa PCIE pme and message interrupt registers*/
+#define PEX_PF0_PME_MES_DR 0xC0020
+#define PEX_PF0_PME_MES_DR_LUD (1 << 7)
+#define PEX_PF0_PME_MES_DR_LDD (1 << 9)
+#define PEX_PF0_PME_MES_DR_HRD (1 << 10)
+
+#define PEX_PF0_PME_MES_IER 0xC0028
+#define PEX_PF0_PME_MES_IER_LUDIE (1 << 7)
+#define PEX_PF0_PME_MES_IER_LDDIE (1 << 9)
+#define PEX_PF0_PME_MES_IER_HRDIE (1 << 10)
+
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
struct ls_pcie_ep_drvdata {
@@ -30,6 +46,10 @@ struct ls_pcie_ep {
struct dw_pcie *pci;
struct pci_epc_features *ls_epc;
const struct ls_pcie_ep_drvdata *drvdata;
+ u8 max_speed;
+ u8 max_width;
+ bool big_endian;
+ int irq;
};
static int ls_pcie_establish_link(struct dw_pcie *pci)
@@ -41,6 +61,84 @@ static const struct dw_pcie_ops dw_ls_pcie_ep_ops = {
.start_link = ls_pcie_establish_link,
};
+static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
+{
+ struct dw_pcie *pci = pcie->pci;
+
+ if (pcie->big_endian)
+ return ioread32be(pci->dbi_base + offset);
+ else
+ return ioread32(pci->dbi_base + offset);
+}
+
+static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset,
+ u32 value)
+{
+ struct dw_pcie *pci = pcie->pci;
+
+ if (pcie->big_endian)
+ iowrite32be(value, pci->dbi_base + offset);
+ else
+ iowrite32(value, pci->dbi_base + offset);
+}
+
+static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
+{
+ struct ls_pcie_ep *pcie = (struct ls_pcie_ep *)dev_id;
+ struct dw_pcie *pci = pcie->pci;
+ u32 val;
+
+ val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
+ if (!val)
+ return IRQ_NONE;
+
+ if (val & PEX_PF0_PME_MES_DR_LUD)
+ dev_info(pci->dev, "Detect the link up state !\n");
+ else if (val & PEX_PF0_PME_MES_DR_LDD)
+ dev_info(pci->dev, "Detect the link down state !\n");
+ else if (val & PEX_PF0_PME_MES_DR_HRD)
+ dev_info(pci->dev, "Detect the hot reset state !\n");
+
+ dw_pcie_dbi_ro_wr_en(pci);
+ dw_pcie_writew_dbi(pci, PCIE_LINK_CAP,
+ (pcie->max_width << MAX_LINK_W_SHIFT) |
+ pcie->max_speed);
+ dw_pcie_dbi_ro_wr_dis(pci);
+
+ ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
+
+ return IRQ_HANDLED;
+}
+
+static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
+ struct platform_device *pdev)
+{
+ u32 val;
+ int ret;
+
+ pcie->irq = platform_get_irq_byname(pdev, "pme");
+ if (pcie->irq < 0) {
+ dev_err(&pdev->dev, "Can't get 'pme' irq.\n");
+ return pcie->irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, pcie->irq,
+ ls_pcie_ep_event_handler, IRQF_SHARED,
+ pdev->name, pcie);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't register PCIe IRQ.\n");
+ return ret;
+ }
+
+ /* Enable interrupts */
+ val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
+ val |= PEX_PF0_PME_MES_IER_LDDIE | PEX_PF0_PME_MES_IER_HRDIE |
+ PEX_PF0_PME_MES_IER_LUDIE;
+ ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
+
+ return 0;
+}
+
static const struct pci_epc_features*
ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
{
@@ -124,6 +222,7 @@ static const struct ls_pcie_ep_drvdata lx2_ep_drvdata = {
static const struct of_device_id ls_pcie_ep_of_match[] = {
{ .compatible = "fsl,ls1046a-pcie-ep", .data = &ls1_ep_drvdata },
{ .compatible = "fsl,ls1088a-pcie-ep", .data = &ls2_ep_drvdata },
+ { .compatible = "fsl,ls1028a-pcie-ep", .data = &ls1_ep_drvdata },
{ .compatible = "fsl,ls2088a-pcie-ep", .data = &ls2_ep_drvdata },
{ .compatible = "fsl,lx2160ar2-pcie-ep", .data = &lx2_ep_drvdata },
{ },
@@ -136,6 +235,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
struct ls_pcie_ep *pcie;
struct pci_epc_features *ls_epc;
struct resource *dbi_base;
+ int ret;
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
@@ -166,9 +266,24 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
pci->ep.ops = &ls_pcie_ep_ops;
+ pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
+
+ pcie->max_speed = dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) &
+ MAX_LINK_SP_MASK;
+ pcie->max_width = (dw_pcie_readw_dbi(pci, PCIE_LINK_CAP) >>
+ MAX_LINK_W_SHIFT) & MAX_LINK_W_MASK;
+
+ /* set 64-bit DMA mask and coherent DMA mask */
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
+ dev_warn(dev, "Failed to set 64-bit DMA mask.\n");
+
platform_set_drvdata(pdev, pcie);
- return dw_pcie_ep_init(&pci->ep);
+ ret = dw_pcie_ep_init(&pci->ep);
+ if (ret)
+ return ret;
+
+ return ls_pcie_ep_interrupt_init(pcie, pdev);
}
static struct platform_driver ls_pcie_ep_driver = {