From: Bjorn Helgaas Date: Tue, 21 Feb 2017 21:13:30 +0000 (-0600) Subject: Merge branch 'pci/host-exynos' into next X-Git-Tag: v4.11-rc1~92^2~15 X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=b2e6d3055d5545b97533d4e8376fa848639d9951;p=linux.git Merge branch 'pci/host-exynos' into next * pci/host-exynos: PCI: exynos: Support the PHY generic framework Documentation: binding: Modify the exynos5440 PCIe binding phy: phy-exynos-pcie: Add support for Exynos PCIe PHY Documentation: samsung-phy: Add exynos-pcie-phy binding PCI: exynos: Refactor to make it easier to support other SoCs PCI: exynos: Remove duplicated code PCI: exynos: Use the bitops BIT() macro to build bitmasks PCI: exynos: Remove unnecessary local variables PCI: exynos: Replace the *_blk/*_phy/*_elb accessors PCI: exynos: Rename all pointer names from "exynos_pcie" to "ep" Conflicts: drivers/pci/dwc/pci-exynos.c --- b2e6d3055d5545b97533d4e8376fa848639d9951 diff --cc drivers/pci/dwc/pci-exynos.c index 0295ec96f3d0,c86961feaa6f..001c91a945aa --- a/drivers/pci/dwc/pci-exynos.c +++ b/drivers/pci/dwc/pci-exynos.c @@@ -26,24 -28,14 +28,14 @@@ #include "pcie-designware.h" -#define to_exynos_pcie(x) container_of(x, struct exynos_pcie, pp) +#define to_exynos_pcie(x) dev_get_drvdata((x)->dev) - struct exynos_pcie { - struct dw_pcie *pci; - void __iomem *elbi_base; /* DT 0th resource */ - void __iomem *phy_base; /* DT 1st resource */ - void __iomem *block_base; /* DT 2nd resource */ - int reset_gpio; - struct clk *clk; - struct clk *bus_clk; - }; - /* PCIe ELBI registers */ #define PCIE_IRQ_PULSE 0x000 - #define IRQ_INTA_ASSERT (0x1 << 0) - #define IRQ_INTB_ASSERT (0x1 << 2) - #define IRQ_INTC_ASSERT (0x1 << 4) - #define IRQ_INTD_ASSERT (0x1 << 6) + #define IRQ_INTA_ASSERT BIT(0) + #define IRQ_INTB_ASSERT BIT(2) + #define IRQ_INTC_ASSERT BIT(4) + #define IRQ_INTD_ASSERT BIT(6) #define PCIE_IRQ_LEVEL 0x004 #define PCIE_IRQ_SPECIAL 0x008 #define PCIE_IRQ_EN_PULSE 0x00c @@@ -99,41 -91,144 +91,147 @@@ #define PCIE_PHY_TRSV3_EMP_LVL 0x2c4 #define PCIE_PHY_TRSV3_RXCDR 0x2ec #define PCIE_PHY_TRSV3_POWER 0x304 - #define PCIE_PHY_TRSV3_PD_TSV (0x1 << 7) + #define PCIE_PHY_TRSV3_PD_TSV BIT(7) #define PCIE_PHY_TRSV3_LVCC 0x31c - static void exynos_elb_writel(struct exynos_pcie *exynos_pcie, u32 val, u32 reg) + struct exynos_pcie_mem_res { + void __iomem *elbi_base; /* DT 0th resource: PCIe CTRL */ + void __iomem *phy_base; /* DT 1st resource: PHY CTRL */ + void __iomem *block_base; /* DT 2nd resource: PHY ADDITIONAL CTRL */ + }; + + struct exynos_pcie_clk_res { + struct clk *clk; + struct clk *bus_clk; + }; + + struct exynos_pcie { - struct pcie_port pp; ++ struct dw_pcie *pci; + struct exynos_pcie_mem_res *mem_res; + struct exynos_pcie_clk_res *clk_res; + const struct exynos_pcie_ops *ops; + int reset_gpio; + + /* For Generic PHY Framework */ + bool using_phy; + struct phy *phy; + }; + + struct exynos_pcie_ops { + int (*get_mem_resources)(struct platform_device *pdev, + struct exynos_pcie *ep); + int (*get_clk_resources)(struct exynos_pcie *ep); + int (*init_clk_resources)(struct exynos_pcie *ep); + void (*deinit_clk_resources)(struct exynos_pcie *ep); + }; + + static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev, + struct exynos_pcie *ep) { - writel(val, exynos_pcie->elbi_base + reg); ++ struct dw_pcie *pci = ep->pci; ++ struct device *dev = pci->dev; + struct resource *res; - struct device *dev = ep->pp.dev; + + /* If using the PHY framework, doesn't need to get other resource */ + if (ep->using_phy) + return 0; + + ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL); + if (!ep->mem_res) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ep->mem_res->elbi_base = devm_ioremap_resource(dev, res); + if (IS_ERR(ep->mem_res->elbi_base)) + return PTR_ERR(ep->mem_res->elbi_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ep->mem_res->phy_base = devm_ioremap_resource(dev, res); + if (IS_ERR(ep->mem_res->phy_base)) + return PTR_ERR(ep->mem_res->phy_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + ep->mem_res->block_base = devm_ioremap_resource(dev, res); + if (IS_ERR(ep->mem_res->block_base)) + return PTR_ERR(ep->mem_res->block_base); + + return 0; } - static u32 exynos_elb_readl(struct exynos_pcie *exynos_pcie, u32 reg) + static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep) { - return readl(exynos_pcie->elbi_base + reg); - struct device *dev = ep->pp.dev; ++ struct dw_pcie *pci = ep->pci; ++ struct device *dev = pci->dev; + + ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL); + if (!ep->clk_res) + return -ENOMEM; + + ep->clk_res->clk = devm_clk_get(dev, "pcie"); + if (IS_ERR(ep->clk_res->clk)) { + dev_err(dev, "Failed to get pcie rc clock\n"); + return PTR_ERR(ep->clk_res->clk); + } + + ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus"); + if (IS_ERR(ep->clk_res->bus_clk)) { + dev_err(dev, "Failed to get pcie bus clock\n"); + return PTR_ERR(ep->clk_res->bus_clk); + } + + return 0; } - static void exynos_phy_writel(struct exynos_pcie *exynos_pcie, u32 val, u32 reg) + static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep) { - writel(val, exynos_pcie->phy_base + reg); - struct device *dev = ep->pp.dev; ++ struct dw_pcie *pci = ep->pci; ++ struct device *dev = pci->dev; + int ret; + + ret = clk_prepare_enable(ep->clk_res->clk); + if (ret) { + dev_err(dev, "cannot enable pcie rc clock"); + return ret; + } + + ret = clk_prepare_enable(ep->clk_res->bus_clk); + if (ret) { + dev_err(dev, "cannot enable pcie bus clock"); + goto err_bus_clk; + } + + return 0; + + err_bus_clk: + clk_disable_unprepare(ep->clk_res->clk); + + return ret; } - static u32 exynos_phy_readl(struct exynos_pcie *exynos_pcie, u32 reg) + static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep) { - return readl(exynos_pcie->phy_base + reg); + clk_disable_unprepare(ep->clk_res->bus_clk); + clk_disable_unprepare(ep->clk_res->clk); } - static void exynos_blk_writel(struct exynos_pcie *exynos_pcie, u32 val, u32 reg) + static const struct exynos_pcie_ops exynos5440_pcie_ops = { + .get_mem_resources = exynos5440_pcie_get_mem_resources, + .get_clk_resources = exynos5440_pcie_get_clk_resources, + .init_clk_resources = exynos5440_pcie_init_clk_resources, + .deinit_clk_resources = exynos5440_pcie_deinit_clk_resources, + }; + + static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg) { - writel(val, exynos_pcie->block_base + reg); + writel(val, base + reg); } - static u32 exynos_blk_readl(struct exynos_pcie *exynos_pcie, u32 reg) + static u32 exynos_pcie_readl(void __iomem *base, u32 reg) { - return readl(exynos_pcie->block_base + reg); + return readl(base + reg); } - static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *exynos_pcie, - bool on) + static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on) { u32 val; @@@ -236,83 -324,82 +327,83 @@@ static void exynos_pcie_power_off_phy(s { u32 val; - val = exynos_phy_readl(exynos_pcie, PCIE_PHY_COMMON_POWER); + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_COMMON_POWER); val |= PCIE_PHY_COMMON_PD_CMN; - exynos_phy_writel(exynos_pcie, val, PCIE_PHY_COMMON_POWER); + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_COMMON_POWER); - val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV0_POWER); + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV0_POWER); val |= PCIE_PHY_TRSV0_PD_TSV; - exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV0_POWER); + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV0_POWER); - val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV1_POWER); + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV1_POWER); val |= PCIE_PHY_TRSV1_PD_TSV; - exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV1_POWER); + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV1_POWER); - val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV2_POWER); + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV2_POWER); val |= PCIE_PHY_TRSV2_PD_TSV; - exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV2_POWER); + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV2_POWER); - val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV3_POWER); + val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV3_POWER); val |= PCIE_PHY_TRSV3_PD_TSV; - exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV3_POWER); + exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV3_POWER); } - static void exynos_pcie_init_phy(struct exynos_pcie *exynos_pcie) + static void exynos_pcie_init_phy(struct exynos_pcie *ep) { /* DCC feedback control off */ - exynos_phy_writel(exynos_pcie, 0x29, PCIE_PHY_DCC_FEEDBACK); + exynos_pcie_writel(ep->mem_res->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK); /* set TX/RX impedance */ - exynos_phy_writel(exynos_pcie, 0xd5, PCIE_PHY_IMPEDANCE); + exynos_pcie_writel(ep->mem_res->phy_base, 0xd5, PCIE_PHY_IMPEDANCE); /* set 50Mhz PHY clock */ - exynos_phy_writel(exynos_pcie, 0x14, PCIE_PHY_PLL_DIV_0); - exynos_phy_writel(exynos_pcie, 0x12, PCIE_PHY_PLL_DIV_1); + exynos_pcie_writel(ep->mem_res->phy_base, 0x14, PCIE_PHY_PLL_DIV_0); + exynos_pcie_writel(ep->mem_res->phy_base, 0x12, PCIE_PHY_PLL_DIV_1); /* set TX Differential output for lane 0 */ - exynos_phy_writel(exynos_pcie, 0x7f, PCIE_PHY_TRSV0_DRV_LVL); + exynos_pcie_writel(ep->mem_res->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL); /* set TX Pre-emphasis Level Control for lane 0 to minimum */ - exynos_phy_writel(exynos_pcie, 0x0, PCIE_PHY_TRSV0_EMP_LVL); + exynos_pcie_writel(ep->mem_res->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL); /* set RX clock and data recovery bandwidth */ - exynos_phy_writel(exynos_pcie, 0xe7, PCIE_PHY_PLL_BIAS); - exynos_phy_writel(exynos_pcie, 0x82, PCIE_PHY_TRSV0_RXCDR); - exynos_phy_writel(exynos_pcie, 0x82, PCIE_PHY_TRSV1_RXCDR); - exynos_phy_writel(exynos_pcie, 0x82, PCIE_PHY_TRSV2_RXCDR); - exynos_phy_writel(exynos_pcie, 0x82, PCIE_PHY_TRSV3_RXCDR); + exynos_pcie_writel(ep->mem_res->phy_base, 0xe7, PCIE_PHY_PLL_BIAS); + exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR); + exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR); + exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR); + exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR); /* change TX Pre-emphasis Level Control for lanes */ - exynos_phy_writel(exynos_pcie, 0x39, PCIE_PHY_TRSV0_EMP_LVL); - exynos_phy_writel(exynos_pcie, 0x39, PCIE_PHY_TRSV1_EMP_LVL); - exynos_phy_writel(exynos_pcie, 0x39, PCIE_PHY_TRSV2_EMP_LVL); - exynos_phy_writel(exynos_pcie, 0x39, PCIE_PHY_TRSV3_EMP_LVL); + exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL); + exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL); + exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL); + exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL); /* set LVCC */ - exynos_phy_writel(exynos_pcie, 0x20, PCIE_PHY_TRSV0_LVCC); - exynos_phy_writel(exynos_pcie, 0xa0, PCIE_PHY_TRSV1_LVCC); - exynos_phy_writel(exynos_pcie, 0xa0, PCIE_PHY_TRSV2_LVCC); - exynos_phy_writel(exynos_pcie, 0xa0, PCIE_PHY_TRSV3_LVCC); + exynos_pcie_writel(ep->mem_res->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC); + exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC); + exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC); + exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC); } - static void exynos_pcie_assert_reset(struct exynos_pcie *exynos_pcie) + static void exynos_pcie_assert_reset(struct exynos_pcie *ep) { - struct dw_pcie *pci = exynos_pcie->pci; - struct pcie_port *pp = &ep->pp; - struct device *dev = pp->dev; ++ struct dw_pcie *pci = ep->pci; + struct device *dev = pci->dev; - if (exynos_pcie->reset_gpio >= 0) - devm_gpio_request_one(dev, exynos_pcie->reset_gpio, + if (ep->reset_gpio >= 0) + devm_gpio_request_one(dev, ep->reset_gpio, GPIOF_OUT_INIT_HIGH, "RESET"); } - static int exynos_pcie_establish_link(struct exynos_pcie *exynos_pcie) + static int exynos_pcie_establish_link(struct exynos_pcie *ep) { - struct dw_pcie *pci = exynos_pcie->pci; - struct pcie_port *pp = &ep->pp; - struct device *dev = pp->dev; ++ struct dw_pcie *pci = ep->pci; + struct pcie_port *pp = &pci->pp; + struct device *dev = pci->dev; u32 val; - if (dw_pcie_link_up(pp)) { + if (dw_pcie_link_up(pci)) { dev_err(dev, "Link already up\n"); return 0; } @@@ -337,14 -442,21 +446,21 @@@ PCIE_APP_LTSSM_ENABLE); /* check if the link is up or not */ - if (!dw_pcie_wait_for_link(pp)) + if (!dw_pcie_wait_for_link(pci)) return 0; - while (exynos_phy_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED) == 0) { - val = exynos_blk_readl(exynos_pcie, PCIE_PHY_PLL_LOCKED); + if (ep->using_phy) { + phy_power_off(ep->phy); + return -ETIMEDOUT; + } + + while (exynos_pcie_readl(ep->mem_res->phy_base, + PCIE_PHY_PLL_LOCKED) == 0) { + val = exynos_pcie_readl(ep->mem_res->block_base, + PCIE_PHY_PLL_LOCKED); dev_info(dev, "PLL Locked: 0x%x\n", val); } - exynos_pcie_power_off_phy(exynos_pcie); + exynos_pcie_power_off_phy(ep); return -ETIMEDOUT; } @@@ -376,87 -488,83 +492,87 @@@ static irqreturn_t exynos_pcie_irq_hand static irqreturn_t exynos_pcie_msi_irq_handler(int irq, void *arg) { - struct exynos_pcie *exynos_pcie = arg; - struct dw_pcie *pci = exynos_pcie->pci; + struct exynos_pcie *ep = arg; - struct pcie_port *pp = &ep->pp; ++ struct dw_pcie *pci = ep->pci; + struct pcie_port *pp = &pci->pp; return dw_handle_msi_irq(pp); } - static void exynos_pcie_msi_init(struct exynos_pcie *exynos_pcie) + static void exynos_pcie_msi_init(struct exynos_pcie *ep) { - struct dw_pcie *pci = exynos_pcie->pci; - struct pcie_port *pp = &ep->pp; ++ struct dw_pcie *pci = ep->pci; + struct pcie_port *pp = &pci->pp; u32 val; dw_pcie_msi_init(pp); /* enable MSI interrupt */ - val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_EN_LEVEL); + val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL); val |= IRQ_MSI_ENABLE; - exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_LEVEL); + exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL); } - static void exynos_pcie_enable_interrupts(struct exynos_pcie *exynos_pcie) + static void exynos_pcie_enable_interrupts(struct exynos_pcie *ep) { - exynos_pcie_enable_irq_pulse(exynos_pcie); + exynos_pcie_enable_irq_pulse(ep); if (IS_ENABLED(CONFIG_PCI_MSI)) - exynos_pcie_msi_init(exynos_pcie); + exynos_pcie_msi_init(ep); } -static u32 exynos_pcie_readl_rc(struct pcie_port *pp, u32 reg) +static u32 exynos_pcie_readl_dbi(struct dw_pcie *pci, u32 reg) { - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci); - struct exynos_pcie *ep = to_exynos_pcie(pp); ++ struct exynos_pcie *ep = to_exynos_pcie(pci); u32 val; - exynos_pcie_sideband_dbi_r_mode(exynos_pcie, true); + exynos_pcie_sideband_dbi_r_mode(ep, true); - val = readl(pp->dbi_base + reg); + val = readl(pci->dbi_base + reg); - exynos_pcie_sideband_dbi_r_mode(exynos_pcie, false); + exynos_pcie_sideband_dbi_r_mode(ep, false); return val; } -static void exynos_pcie_writel_rc(struct pcie_port *pp, u32 reg, u32 val) +static void exynos_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val) { - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci); - struct exynos_pcie *ep = to_exynos_pcie(pp); ++ struct exynos_pcie *ep = to_exynos_pcie(pci); - exynos_pcie_sideband_dbi_w_mode(exynos_pcie, true); + exynos_pcie_sideband_dbi_w_mode(ep, true); - writel(val, pp->dbi_base + reg); + writel(val, pci->dbi_base + reg); - exynos_pcie_sideband_dbi_w_mode(exynos_pcie, false); + exynos_pcie_sideband_dbi_w_mode(ep, false); } static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, u32 *val) { - struct exynos_pcie *ep = to_exynos_pcie(pp); + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci); ++ struct exynos_pcie *ep = to_exynos_pcie(pci); int ret; - exynos_pcie_sideband_dbi_r_mode(exynos_pcie, true); + exynos_pcie_sideband_dbi_r_mode(ep, true); - ret = dw_pcie_cfg_read(pp->dbi_base + where, size, val); + ret = dw_pcie_read(pci->dbi_base + where, size, val); - exynos_pcie_sideband_dbi_r_mode(exynos_pcie, false); + exynos_pcie_sideband_dbi_r_mode(ep, false); return ret; } static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, u32 val) { - struct exynos_pcie *ep = to_exynos_pcie(pp); + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci); ++ struct exynos_pcie *ep = to_exynos_pcie(pci); int ret; - exynos_pcie_sideband_dbi_w_mode(exynos_pcie, true); + exynos_pcie_sideband_dbi_w_mode(ep, true); - ret = dw_pcie_cfg_write(pp->dbi_base + where, size, val); + ret = dw_pcie_write(pci->dbi_base + where, size, val); - exynos_pcie_sideband_dbi_w_mode(exynos_pcie, false); + exynos_pcie_sideband_dbi_w_mode(ep, false); return ret; } -static int exynos_pcie_link_up(struct pcie_port *pp) +static int exynos_pcie_link_up(struct dw_pcie *pci) { - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci); - struct exynos_pcie *ep = to_exynos_pcie(pp); ++ struct exynos_pcie *ep = to_exynos_pcie(pci); u32 val; - val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_RDLH_LINKUP); + val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_RDLH_LINKUP); if (val == PCIE_ELBI_LTSSM_ENABLE) return 1; @@@ -465,25 -573,26 +581,25 @@@ static void exynos_pcie_host_init(struct pcie_port *pp) { - struct exynos_pcie *ep = to_exynos_pcie(pp); + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct exynos_pcie *exynos_pcie = to_exynos_pcie(pci); ++ struct exynos_pcie *ep = to_exynos_pcie(pci); - exynos_pcie_establish_link(exynos_pcie); - exynos_pcie_enable_interrupts(exynos_pcie); + exynos_pcie_establish_link(ep); + exynos_pcie_enable_interrupts(ep); } -static struct pcie_host_ops exynos_pcie_host_ops = { - .readl_rc = exynos_pcie_readl_rc, - .writel_rc = exynos_pcie_writel_rc, +static struct dw_pcie_host_ops exynos_pcie_host_ops = { .rd_own_conf = exynos_pcie_rd_own_conf, .wr_own_conf = exynos_pcie_wr_own_conf, - .link_up = exynos_pcie_link_up, .host_init = exynos_pcie_host_init, }; - static int __init exynos_add_pcie_port(struct exynos_pcie *exynos_pcie, + static int __init exynos_add_pcie_port(struct exynos_pcie *ep, struct platform_device *pdev) { - struct dw_pcie *pci = exynos_pcie->pci; - struct pcie_port *pp = &ep->pp; - struct device *dev = pp->dev; ++ struct dw_pcie *pci = ep->pci; + struct pcie_port *pp = &pci->pp; + struct device *dev = &pdev->dev; int ret; pp->irq = platform_get_irq(pdev, 1); @@@ -536,79 -639,62 +652,67 @@@ static const struct dw_pcie_ops dw_pcie static int __init exynos_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct dw_pcie *pci; - struct exynos_pcie *exynos_pcie; + struct exynos_pcie *ep; - struct pcie_port *pp; struct device_node *np = dev->of_node; - struct resource *elbi_base; - struct resource *phy_base; - struct resource *block_base; int ret; - exynos_pcie = devm_kzalloc(dev, sizeof(*exynos_pcie), GFP_KERNEL); - if (!exynos_pcie) + ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); + if (!ep) return -ENOMEM; - pp = &ep->pp; - pp->dev = dev; + pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); + if (!pci) + return -ENOMEM; + + pci->dev = dev; + pci->ops = &dw_pcie_ops; - exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + ep->ops = (const struct exynos_pcie_ops *) + of_device_get_match_data(dev); - exynos_pcie->clk = devm_clk_get(dev, "pcie"); - if (IS_ERR(exynos_pcie->clk)) { - dev_err(dev, "Failed to get pcie rc clock\n"); - return PTR_ERR(exynos_pcie->clk); - } - ret = clk_prepare_enable(exynos_pcie->clk); - if (ret) - return ret; + ep->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); - exynos_pcie->bus_clk = devm_clk_get(dev, "pcie_bus"); - if (IS_ERR(exynos_pcie->bus_clk)) { - dev_err(dev, "Failed to get pcie bus clock\n"); - ret = PTR_ERR(exynos_pcie->bus_clk); - goto fail_clk; - } - ret = clk_prepare_enable(exynos_pcie->bus_clk); - if (ret) - goto fail_clk; - - elbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); - exynos_pcie->elbi_base = devm_ioremap_resource(dev, elbi_base); - if (IS_ERR(exynos_pcie->elbi_base)) { - ret = PTR_ERR(exynos_pcie->elbi_base); - goto fail_bus_clk; - } + /* Assume that controller doesn't use the PHY framework */ + ep->using_phy = false; - phy_base = platform_get_resource(pdev, IORESOURCE_MEM, 1); - exynos_pcie->phy_base = devm_ioremap_resource(dev, phy_base); - if (IS_ERR(exynos_pcie->phy_base)) { - ret = PTR_ERR(exynos_pcie->phy_base); - goto fail_bus_clk; + ep->phy = devm_of_phy_get(dev, np, NULL); + if (IS_ERR(ep->phy)) { + if (PTR_ERR(ep->phy) == -EPROBE_DEFER) + return PTR_ERR(ep->phy); + dev_warn(dev, "Use the 'phy' property. Current DT of pci-exynos was deprecated!!\n"); + } else + ep->using_phy = true; + + if (ep->ops && ep->ops->get_mem_resources) { + ret = ep->ops->get_mem_resources(pdev, ep); + if (ret) + return ret; } - block_base = platform_get_resource(pdev, IORESOURCE_MEM, 2); - exynos_pcie->block_base = devm_ioremap_resource(dev, block_base); - if (IS_ERR(exynos_pcie->block_base)) { - ret = PTR_ERR(exynos_pcie->block_base); - goto fail_bus_clk; + if (ep->ops && ep->ops->get_clk_resources) { + ret = ep->ops->get_clk_resources(ep); + if (ret) + return ret; + ret = ep->ops->init_clk_resources(ep); + if (ret) + return ret; } - platform_set_drvdata(pdev, exynos_pcie); ++ platform_set_drvdata(pdev, ep); + - ret = exynos_add_pcie_port(exynos_pcie, pdev); + ret = exynos_add_pcie_port(ep, pdev); if (ret < 0) - goto fail_bus_clk; + goto fail_probe; - platform_set_drvdata(pdev, ep); return 0; - fail_bus_clk: - clk_disable_unprepare(exynos_pcie->bus_clk); - fail_clk: - clk_disable_unprepare(exynos_pcie->clk); + fail_probe: + if (ep->using_phy) + phy_exit(ep->phy); + + if (ep->ops && ep->ops->deinit_clk_resources) + ep->ops->deinit_clk_resources(ep); return ret; }