summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/pci/qcom,pcie.txt6
-rw-r--r--Documentation/devicetree/bindings/pci/samsung,exynos-pcie.yaml119
-rw-r--r--Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt58
-rw-r--r--Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml51
-rw-r--r--drivers/pci/controller/dwc/Kconfig10
-rw-r--r--drivers/pci/controller/dwc/pci-dra7xx.c141
-rw-r--r--drivers/pci/controller/dwc/pci-exynos.c389
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c39
-rw-r--r--drivers/pci/controller/dwc/pci-keystone.c79
-rw-r--r--drivers/pci/controller/dwc/pci-layerscape-ep.c37
-rw-r--r--drivers/pci/controller/dwc/pci-layerscape.c67
-rw-r--r--drivers/pci/controller/dwc/pci-meson.c53
-rw-r--r--drivers/pci/controller/dwc/pcie-al.c29
-rw-r--r--drivers/pci/controller/dwc/pcie-armada8k.c37
-rw-r--r--drivers/pci/controller/dwc/pcie-artpec6.c76
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-ep.c58
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-host.c147
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-plat.c70
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.c105
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.h27
-rw-r--r--drivers/pci/controller/dwc/pcie-histb.c37
-rw-r--r--drivers/pci/controller/dwc/pcie-intel-gw.c67
-rw-r--r--drivers/pci/controller/dwc/pcie-kirin.c62
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom.c127
-rw-r--r--drivers/pci/controller/dwc/pcie-spear13xx.c62
-rw-r--r--drivers/pci/controller/dwc/pcie-tegra194.c129
-rw-r--r--drivers/pci/controller/dwc/pcie-uniphier-ep.c38
-rw-r--r--drivers/pci/controller/dwc/pcie-uniphier.c51
-rw-r--r--drivers/pci/of.c5
-rw-r--r--drivers/pci/quirks.c1
-rw-r--r--drivers/phy/samsung/phy-exynos-pcie.c304
31 files changed, 946 insertions, 1535 deletions
diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.txt b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
index 02bc81bb8b2d..3b55310390a0 100644
--- a/Documentation/devicetree/bindings/pci/qcom,pcie.txt
+++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
@@ -13,6 +13,7 @@
- "qcom,pcie-ipq8074" for ipq8074
- "qcom,pcie-qcs404" for qcs404
- "qcom,pcie-sdm845" for sdm845
+ - "qcom,pcie-sm8250" for sm8250
- reg:
Usage: required
@@ -27,6 +28,7 @@
- "dbi" DesignWare PCIe registers
- "elbi" External local bus interface registers
- "config" PCIe configuration space
+ - "atu" ATU address space (optional)
- device_type:
Usage: required
@@ -131,7 +133,7 @@
- "slave_bus" AXI Slave clock
-clock-names:
- Usage: required for sdm845
+ Usage: required for sdm845 and sm8250
Value type: <stringlist>
Definition: Should contain the following entries
- "aux" Auxiliary clock
@@ -206,7 +208,7 @@
- "ahb" AHB reset
- reset-names:
- Usage: required for sdm845
+ Usage: required for sdm845 and sm8250
Value type: <stringlist>
Definition: Should contain the following entries
- "pci" PCIe core reset
diff --git a/Documentation/devicetree/bindings/pci/samsung,exynos-pcie.yaml b/Documentation/devicetree/bindings/pci/samsung,exynos-pcie.yaml
new file mode 100644
index 000000000000..1810bf722350
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/samsung,exynos-pcie.yaml
@@ -0,0 +1,119 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/samsung,exynos-pcie.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung SoC series PCIe Host Controller Device Tree Bindings
+
+maintainers:
+ - Marek Szyprowski <m.szyprowski@samsung.com>
+ - Jaehoon Chung <jh80.chung@samsung.com>
+
+description: |+
+ Exynos5433 SoC PCIe host controller is based on the Synopsys DesignWare
+ PCIe IP and thus inherits all the common properties defined in
+ designware-pcie.txt.
+
+allOf:
+ - $ref: /schemas/pci/pci-bus.yaml#
+
+properties:
+ compatible:
+ const: samsung,exynos5433-pcie
+
+ reg:
+ items:
+ - description: Data Bus Interface (DBI) registers.
+ - description: External Local Bus interface (ELBI) registers.
+ - description: PCIe configuration space region.
+
+ reg-names:
+ items:
+ - const: dbi
+ - const: elbi
+ - const: config
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: PCIe bridge clock
+ - description: PCIe bus clock
+
+ clock-names:
+ items:
+ - const: pcie
+ - const: pcie_bus
+
+ phys:
+ maxItems: 1
+
+ vdd10-supply:
+ description:
+ Phandle to a regulator that provides 1.0V power to the PCIe block.
+
+ vdd18-supply:
+ description:
+ Phandle to a regulator that provides 1.8V power to the PCIe block.
+
+ num-lanes:
+ const: 1
+
+ num-viewport:
+ const: 3
+
+required:
+ - reg
+ - reg-names
+ - interrupts
+ - "#address-cells"
+ - "#size-cells"
+ - "#interrupt-cells"
+ - interrupt-map
+ - interrupt-map-mask
+ - ranges
+ - bus-range
+ - device_type
+ - num-lanes
+ - num-viewport
+ - clocks
+ - clock-names
+ - phys
+ - vdd10-supply
+ - vdd18-supply
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/exynos5433.h>
+
+ pcie: pcie@15700000 {
+ compatible = "samsung,exynos5433-pcie";
+ reg = <0x15700000 0x1000>, <0x156b0000 0x1000>, <0x0c000000 0x1000>;
+ reg-names = "dbi", "elbi", "config";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ device_type = "pci";
+ interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cmu_fsys CLK_PCIE>, <&cmu_fsys CLK_PCLK_PCIE_PHY>;
+ clock-names = "pcie", "pcie_bus";
+ phys = <&pcie_phy>;
+ pinctrl-0 = <&pcie_bus &pcie_wlanen>;
+ pinctrl-names = "default";
+ num-lanes = <1>;
+ num-viewport = <3>;
+ bus-range = <0x00 0xff>;
+ ranges = <0x81000000 0 0 0x0c001000 0 0x00010000>,
+ <0x82000000 0 0x0c011000 0x0c011000 0 0x03feefff>;
+ vdd10-supply = <&ldo6_reg>;
+ vdd18-supply = <&ldo7_reg>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
+ };
+...
diff --git a/Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt b/Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt
deleted file mode 100644
index 651d957d1051..000000000000
--- a/Documentation/devicetree/bindings/pci/samsung,exynos5440-pcie.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-* Samsung Exynos 5440 PCIe interface
-
-This PCIe host controller is based on the Synopsys DesignWare PCIe IP
-and thus inherits all the common properties defined in designware-pcie.txt.
-
-Required properties:
-- compatible: "samsung,exynos5440-pcie"
-- reg: base addresses and lengths of the PCIe controller,
-- reg-names : First name should be set to "elbi".
- And use the "config" instead of getting the configuration address space
- from "ranges".
- NOTE: When using the "config" property, reg-names must be set.
-- interrupts: A list of interrupt outputs for level interrupt,
- pulse interrupt, special interrupt.
-- phys: From PHY binding. Phandle for the generic PHY.
- Refer to Documentation/devicetree/bindings/phy/samsung-phy.txt
-
-For other common properties, refer to
- Documentation/devicetree/bindings/pci/designware-pcie.txt
-
-Example:
-
-SoC-specific DT Entry (with using PHY framework):
-
- pcie_phy0: pcie-phy@270000 {
- ...
- reg = <0x270000 0x1000>, <0x271000 0x40>;
- reg-names = "phy", "block";
- ...
- };
-
- pcie@290000 {
- compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
- reg = <0x290000 0x1000>, <0x40000000 0x1000>;
- reg-names = "elbi", "config";
- clocks = <&clock 28>, <&clock 27>;
- clock-names = "pcie", "pcie_bus";
- #address-cells = <3>;
- #size-cells = <2>;
- device_type = "pci";
- phys = <&pcie_phy0>;
- ranges = <0x81000000 0 0 0x60001000 0 0x00010000
- 0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
- num-lanes = <4>;
- };
-
-Board-specific DT Entry:
-
- pcie@290000 {
- reset-gpio = <&pin_ctrl 5 0>;
- };
-
- pcie@2a0000 {
- reset-gpio = <&pin_ctrl 22 0>;
- };
diff --git a/Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml
new file mode 100644
index 000000000000..ac0af40be52d
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/samsung,exynos-pcie-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung SoC series PCIe PHY Device Tree Bindings
+
+maintainers:
+ - Marek Szyprowski <m.szyprowski@samsung.com>
+ - Jaehoon Chung <jh80.chung@samsung.com>
+
+properties:
+ "#phy-cells":
+ const: 0
+
+ compatible:
+ const: samsung,exynos5433-pcie-phy
+
+ reg:
+ maxItems: 1
+
+ samsung,pmu-syscon:
+ $ref: '/schemas/types.yaml#/definitions/phandle'
+ description: phandle for PMU system controller interface, used to
+ control PMU registers bits for PCIe PHY
+
+ samsung,fsys-sysreg:
+ $ref: '/schemas/types.yaml#/definitions/phandle'
+ description: phandle for FSYS sysreg interface, used to control
+ sysreg registers bits for PCIe PHY
+
+required:
+ - "#phy-cells"
+ - compatible
+ - reg
+ - samsung,pmu-syscon
+ - samsung,fsys-sysreg
+
+additionalProperties: false
+
+examples:
+ - |
+ pcie_phy: pcie-phy@15680000 {
+ compatible = "samsung,exynos5433-pcie-phy";
+ reg = <0x15680000 0x1000>;
+ samsung,pmu-syscon = <&pmu_system_controller>;
+ samsung,fsys-sysreg = <&syscon_fsys>;
+ #phy-cells = <0>;
+ };
+...
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index bc049865f8e0..dd4596bdda49 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -83,10 +83,15 @@ config PCIE_DW_PLAT_EP
selected.
config PCI_EXYNOS
- bool "Samsung Exynos PCIe controller"
- depends on SOC_EXYNOS5440 || COMPILE_TEST
+ tristate "Samsung Exynos PCIe controller"
+ depends on ARCH_EXYNOS || COMPILE_TEST
depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST
+ help
+ Enables support for the PCIe controller in the Samsung Exynos SoCs
+ to work in host mode. The PCI controller is based on the DesignWare
+ hardware and therefore the driver re-uses the DesignWare core
+ functions to implement the driver.
config PCI_IMX6
bool "Freescale i.MX6/7/8 PCIe controller"
@@ -169,6 +174,7 @@ config PCIE_QCOM
depends on OF && (ARCH_QCOM || COMPILE_TEST)
depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST
+ select CRC8
help
Say Y here to enable PCIe controller support on Qualcomm SoCs. The
PCIe controller uses the DesignWare core plus Qualcomm-specific
diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
index 6d012d2b1e90..b105af63854a 100644
--- a/drivers/pci/controller/dwc/pci-dra7xx.c
+++ b/drivers/pci/controller/dwc/pci-dra7xx.c
@@ -181,11 +181,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
- dw_pcie_setup_rc(pp);
-
- dra7xx_pcie_establish_link(pci);
- dw_pcie_wait_for_link(pci);
- dw_pcie_msi_init(pp);
dra7xx_pcie_enable_interrupts(dra7xx);
return 0;
@@ -377,133 +372,8 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
return 0;
}
-static void dra7xx_pcie_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
-{
- struct pcie_port *pp = irq_data_get_irq_chip_data(d);
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- u64 msi_target;
-
- msi_target = (u64)pp->msi_data;
-
- msg->address_lo = lower_32_bits(msi_target);
- msg->address_hi = upper_32_bits(msi_target);
-
- msg->data = d->hwirq;
-
- dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
- (int)d->hwirq, msg->address_hi, msg->address_lo);
-}
-
-static int dra7xx_pcie_msi_set_affinity(struct irq_data *d,
- const struct cpumask *mask,
- bool force)
-{
- return -EINVAL;
-}
-
-static void dra7xx_pcie_bottom_mask(struct irq_data *d)
-{
- struct pcie_port *pp = irq_data_get_irq_chip_data(d);
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- unsigned int res, bit, ctrl;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&pp->lock, flags);
-
- ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
- res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
- bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
-
- pp->irq_mask[ctrl] |= BIT(bit);
- dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res,
- pp->irq_mask[ctrl]);
-
- raw_spin_unlock_irqrestore(&pp->lock, flags);
-}
-
-static void dra7xx_pcie_bottom_unmask(struct irq_data *d)
-{
- struct pcie_port *pp = irq_data_get_irq_chip_data(d);
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- unsigned int res, bit, ctrl;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&pp->lock, flags);
-
- ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
- res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
- bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
-
- pp->irq_mask[ctrl] &= ~BIT(bit);
- dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res,
- pp->irq_mask[ctrl]);
-
- raw_spin_unlock_irqrestore(&pp->lock, flags);
-}
-
-static void dra7xx_pcie_bottom_ack(struct irq_data *d)
-{
- struct pcie_port *pp = irq_data_get_irq_chip_data(d);
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- unsigned int res, bit, ctrl;
-
- ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
- res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
- bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
-
- dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_STATUS + res, BIT(bit));
-}
-
-static struct irq_chip dra7xx_pci_msi_bottom_irq_chip = {
- .name = "DRA7XX-PCI-MSI",
- .irq_ack = dra7xx_pcie_bottom_ack,
- .irq_compose_msi_msg = dra7xx_pcie_setup_msi_msg,
- .irq_set_affinity = dra7xx_pcie_msi_set_affinity,
- .irq_mask = dra7xx_pcie_bottom_mask,
- .irq_unmask = dra7xx_pcie_bottom_unmask,
-};
-
-static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
-{
- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
- struct device *dev = pci->dev;
- u32 ctrl, num_ctrls;
- int ret;
-
- pp->msi_irq_chip = &dra7xx_pci_msi_bottom_irq_chip;
-
- num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
- /* Initialize IRQ Status array */
- for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
- pp->irq_mask[ctrl] = ~0;
- dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK +
- (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
- pp->irq_mask[ctrl]);
- dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE +
- (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
- ~0);
- }
-
- ret = dw_pcie_allocate_domains(pp);
- if (ret)
- return ret;
-
- pp->msi_data = dma_map_single_attrs(dev, &pp->msi_msg,
- sizeof(pp->msi_msg),
- DMA_FROM_DEVICE,
- DMA_ATTR_SKIP_CPU_SYNC);
- ret = dma_mapping_error(dev, pp->msi_data);
- if (ret) {
- dev_err(dev, "Failed to map MSI data\n");
- pp->msi_data = 0;
- dw_pcie_free_msi(pp);
- }
- return ret;
-}
-
static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
.host_init = dra7xx_pcie_host_init,
- .msi_host_init = dra7xx_pcie_msi_host_init,
};
static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
@@ -578,7 +448,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
{
int ret;
struct dw_pcie_ep *ep;
- struct resource *res;
struct device *dev = &pdev->dev;
struct dw_pcie *pci = dra7xx->pci;
@@ -594,13 +463,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
- if (!res)
- return -EINVAL;
-
- ep->phys_base = res->start;
- ep->addr_size = resource_size(res);
-
ret = dw_pcie_ep_init(ep);
if (ret) {
dev_err(dev, "failed to initialize endpoint\n");
@@ -622,6 +484,9 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
if (pp->irq < 0)
return pp->irq;
+ /* MSI IRQ is muxed */
+ pp->msi_irq = -ENODEV;
+
ret = dra7xx_pcie_init_irq_domain(pp);
if (ret < 0)
return ret;
diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c
index 242683cde04a..c24dab383654 100644
--- a/drivers/pci/controller/dwc/pci-exynos.c
+++ b/drivers/pci/controller/dwc/pci-exynos.c
@@ -2,26 +2,23 @@
/*
* PCIe host controller driver for Samsung Exynos SoCs
*
- * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd.
* https://www.samsung.com
*
* Author: Jingoo Han <jg1.han@samsung.com>
+ * Jaehoon Chung <jh80.chung@samsung.com>
*/
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
-#include <linux/resource.h>
-#include <linux/signal.h>
-#include <linux/types.h>
+#include <linux/regulator/consumer.h>
#include "pcie-designware.h"
@@ -37,102 +34,43 @@
#define PCIE_IRQ_SPECIAL 0x008
#define PCIE_IRQ_EN_PULSE 0x00c
#define PCIE_IRQ_EN_LEVEL 0x010
-#define IRQ_MSI_ENABLE BIT(2)
#define PCIE_IRQ_EN_SPECIAL 0x014
-#define PCIE_PWR_RESET 0x018
+#define PCIE_SW_WAKE 0x018
+#define PCIE_BUS_EN BIT(1)
#define PCIE_CORE_RESET 0x01c
#define PCIE_CORE_RESET_ENABLE BIT(0)
#define PCIE_STICKY_RESET 0x020
#define PCIE_NONSTICKY_RESET 0x024
#define PCIE_APP_INIT_RESET 0x028
#define PCIE_APP_LTSSM_ENABLE 0x02c
-#define PCIE_ELBI_RDLH_LINKUP 0x064
+#define PCIE_ELBI_RDLH_LINKUP 0x074
+#define PCIE_ELBI_XMLH_LINKUP BIT(4)
#define PCIE_ELBI_LTSSM_ENABLE 0x1
#define PCIE_ELBI_SLV_AWMISC 0x11c
#define PCIE_ELBI_SLV_ARMISC 0x120
#define PCIE_ELBI_SLV_DBI_ENABLE BIT(21)
-struct exynos_pcie_mem_res {
- void __iomem *elbi_base; /* DT 0th resource: PCIe CTRL */
-};
-
-struct exynos_pcie_clk_res {
- struct clk *clk;
- struct clk *bus_clk;
-};
-
struct exynos_pcie {
- 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;
-
+ struct dw_pcie pci;
+ void __iomem *elbi_base;
+ struct clk *clk;
+ struct clk *bus_clk;
struct phy *phy;
+ struct regulator_bulk_data supplies[2];
};
-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)
-{
- struct dw_pcie *pci = ep->pci;
- struct device *dev = pci->dev;
-
- ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL);
- if (!ep->mem_res)
- return -ENOMEM;
-
- ep->mem_res->elbi_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(ep->mem_res->elbi_base))
- return PTR_ERR(ep->mem_res->elbi_base);
-
- return 0;
-}
-
-static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep)
+static int exynos_pcie_init_clk_resources(struct exynos_pcie *ep)
{
- 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 int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
-{
- struct dw_pcie *pci = ep->pci;
- struct device *dev = pci->dev;
+ struct device *dev = ep->pci.dev;
int ret;
- ret = clk_prepare_enable(ep->clk_res->clk);
+ ret = clk_prepare_enable(ep->clk);
if (ret) {
dev_err(dev, "cannot enable pcie rc clock");
return ret;
}
- ret = clk_prepare_enable(ep->clk_res->bus_clk);
+ ret = clk_prepare_enable(ep->bus_clk);
if (ret) {
dev_err(dev, "cannot enable pcie bus clock");
goto err_bus_clk;
@@ -141,24 +79,17 @@ static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
return 0;
err_bus_clk:
- clk_disable_unprepare(ep->clk_res->clk);
+ clk_disable_unprepare(ep->clk);
return ret;
}
-static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep)
+static void exynos_pcie_deinit_clk_resources(struct exynos_pcie *ep)
{
- clk_disable_unprepare(ep->clk_res->bus_clk);
- clk_disable_unprepare(ep->clk_res->clk);
+ clk_disable_unprepare(ep->bus_clk);
+ clk_disable_unprepare(ep->clk);
}
-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, base + reg);
@@ -173,115 +104,71 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on)
{
u32 val;
- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC);
+ val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC);
if (on)
val |= PCIE_ELBI_SLV_DBI_ENABLE;
else
val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
+ exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
}
static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on)
{
u32 val;
- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC);
+ val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC);
if (on)
val |= PCIE_ELBI_SLV_DBI_ENABLE;
else
val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
+ exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
}
static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep)
{
u32 val;
- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
+ val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
val &= ~PCIE_CORE_RESET_ENABLE;
- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
- exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET);
- exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET);
- exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET);
+ exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
+ exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET);
+ exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET);
}
static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep)
{
u32 val;
- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
+ val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
val |= PCIE_CORE_RESET_ENABLE;
- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
- exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET);
- exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET);
- exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET);
- exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET);
-}
-
-static void exynos_pcie_assert_reset(struct exynos_pcie *ep)
-{
- struct dw_pcie *pci = ep->pci;
- struct device *dev = pci->dev;
-
- if (ep->reset_gpio >= 0)
- devm_gpio_request_one(dev, ep->reset_gpio,
- GPIOF_OUT_INIT_HIGH, "RESET");
+ exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
+ exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET);
+ exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET);
+ exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET);
+ exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET);
}
-static int exynos_pcie_establish_link(struct exynos_pcie *ep)
+static int exynos_pcie_start_link(struct dw_pcie *pci)
{
- struct dw_pcie *pci = ep->pci;
- struct pcie_port *pp = &pci->pp;
- struct device *dev = pci->dev;
-
- if (dw_pcie_link_up(pci)) {
- dev_err(dev, "Link already up\n");
- return 0;
- }
-
- exynos_pcie_assert_core_reset(ep);
-
- phy_reset(ep->phy);
-
- exynos_pcie_writel(ep->mem_res->elbi_base, 1,
- PCIE_PWR_RESET);
+ struct exynos_pcie *ep = to_exynos_pcie(pci);
+ u32 val;
- phy_power_on(ep->phy);
- phy_init(ep->phy);
-
- exynos_pcie_deassert_core_reset(ep);
- dw_pcie_setup_rc(pp);
- exynos_pcie_assert_reset(ep);
+ val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE);
+ val &= ~PCIE_BUS_EN;
+ exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE);
/* assert LTSSM enable */
- exynos_pcie_writel(ep->mem_res->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
+ exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
PCIE_APP_LTSSM_ENABLE);
-
- /* check if the link is up or not */
- if (!dw_pcie_wait_for_link(pci))
- return 0;
-
- phy_power_off(ep->phy);
- return -ETIMEDOUT;
+ return 0;
}
static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep)
{
- u32 val;
+ u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE);
- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE);
- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE);
-}
-
-static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
-{
- u32 val;
-
- /* enable INTX interrupt */
- val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
- IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE);
+ exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE);
}
static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
@@ -292,26 +179,14 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
-static void exynos_pcie_msi_init(struct exynos_pcie *ep)
-{
- struct dw_pcie *pci = ep->pci;
- struct pcie_port *pp = &pci->pp;
- u32 val;
-
- dw_pcie_msi_init(pp);
-