[Armadeus-commitlog] armadeus branch, master, updated. armadeus-5.3-772-ge8d6342
Brought to you by:
sszy
|
From: Sébastien S. <ss...@us...> - 2015-06-16 12:33:31
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "armadeus".
The branch, master has been updated
via e8d6342a4b839b518141b43edc11db41c05e37a9 (commit)
via 0f1962ee9d2faf4ecec101cf6ea97f1c2c159e23 (commit)
via 983eadf48153a6bd3179fa57249c8c2f4a8ec522 (commit)
via 0b48deee0d4f8c6e7b7c6961b9b95c88fd701beb (commit)
via 8d9322424b4461b6b348835af46bfe50fda6baed (commit)
from 252b81a8eb8f67a14b9bd67cc32c936accb3e23c (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit e8d6342a4b839b518141b43edc11db41c05e37a9
Author: Sébastien Szymanski <seb...@ar...>
Date: Tue Jun 16 14:31:21 2015 +0200
[LINUX] apf6 (legacy): do not change PCIe clock frequency
U-Boot does it.
commit 0f1962ee9d2faf4ecec101cf6ea97f1c2c159e23
Author: Sébastien Szymanski <seb...@ar...>
Date: Tue Jun 16 14:30:40 2015 +0200
[LINUX] apf6 (legacy): fix fpgaloader building.
commit 983eadf48153a6bd3179fa57249c8c2f4a8ec522
Author: Sébastien Szymanski <seb...@ar...>
Date: Tue Jun 16 14:29:54 2015 +0200
[LINUX] apf6 (legacy): add Armadeus drivers
commit 0b48deee0d4f8c6e7b7c6961b9b95c88fd701beb
Author: Sébastien Szymanski <seb...@ar...>
Date: Tue Jun 16 14:27:48 2015 +0200
[LINUX] apf6 (legacy): add PCIe support (backport PCIe driver from 3.14)
The patches come from Gateworks' github:
https://github.com/Gateworks/linux-imx6/
commit 8d9322424b4461b6b348835af46bfe50fda6baed
Author: Sébastien Szymanski <seb...@ar...>
Date: Tue Jun 16 14:22:10 2015 +0200
[LINUX] apf6 (legacy): add support for eMMC 5.0
-----------------------------------------------------------------------
Summary of changes:
...50-armadeus-add_custom_drivers_to_kconfig.patch | 27 +
..._star_completion_for_source_in_menuconfig.patch | 21 +-
...rmadeus-add-apf6q-and-apf6dl-device-trees.patch | 4 +-
...adeus-allow-forwad-compatibility-for-eMMC.patch | 20 +
...3-PCI-imx6-backport-PCIe-driver-from-3.14.patch | 1943 ++++++++++++++++++++
...6-fix-boot-hang-when-link-already-enabled.patch | 99 +
...ditional-fix-for-boot-hang-when-link-alre.patch | 48 +
...0456-PCI-imx6-fix-occasional-link-failure.patch | 48 +
.../0457-armadeus-pcie-clk-defined-in-uboot.patch | 18 +
.../modules/fpga/dev_tools/loader/altera_cvp.c | 1 +
10 files changed, 2215 insertions(+), 14 deletions(-)
create mode 100644 patches/linux/3.10.mx6_legacy/0050-armadeus-add_custom_drivers_to_kconfig.patch
copy patches/linux/{3.9 => 3.10.mx6_legacy}/0441-armadeus-adding_star_completion_for_source_in_menuconfig.patch (93%)
create mode 100644 patches/linux/3.10.mx6_legacy/0452-armadeus-allow-forwad-compatibility-for-eMMC.patch
create mode 100644 patches/linux/3.10.mx6_legacy/0453-PCI-imx6-backport-PCIe-driver-from-3.14.patch
create mode 100644 patches/linux/3.10.mx6_legacy/0454-PCI-imx6-fix-boot-hang-when-link-already-enabled.patch
create mode 100644 patches/linux/3.10.mx6_legacy/0455-PCI-imx6-additional-fix-for-boot-hang-when-link-alre.patch
create mode 100644 patches/linux/3.10.mx6_legacy/0456-PCI-imx6-fix-occasional-link-failure.patch
create mode 100644 patches/linux/3.10.mx6_legacy/0457-armadeus-pcie-clk-defined-in-uboot.patch
diff --git a/patches/linux/3.10.mx6_legacy/0050-armadeus-add_custom_drivers_to_kconfig.patch b/patches/linux/3.10.mx6_legacy/0050-armadeus-add_custom_drivers_to_kconfig.patch
new file mode 100644
index 0000000..545b09f
--- /dev/null
+++ b/patches/linux/3.10.mx6_legacy/0050-armadeus-add_custom_drivers_to_kconfig.patch
@@ -0,0 +1,27 @@
+This patch adds the possibility to have custom Armadeus drivers built in kernel or compiled as modules.
+
+This patch adds the possibility to have custom Armadeus drivers built in kernel or compiled as modules.
+
+Index: linux-wandboard_imx_3.10.31_1.1.0_beta2/drivers/Kconfig
+===================================================================
+--- linux-wandboard_imx_3.10.31_1.1.0_beta2.orig/drivers/Kconfig
++++ linux-wandboard_imx_3.10.31_1.1.0_beta2/drivers/Kconfig
+@@ -168,4 +168,6 @@ source "drivers/ipack/Kconfig"
+
+ source "drivers/reset/Kconfig"
+
++source "drivers/armadeus/Kconfig"
++
+ endmenu
+Index: linux-wandboard_imx_3.10.31_1.1.0_beta2/drivers/Makefile
+===================================================================
+--- linux-wandboard_imx_3.10.31_1.1.0_beta2.orig/drivers/Makefile
++++ linux-wandboard_imx_3.10.31_1.1.0_beta2/drivers/Makefile
+@@ -126,6 +126,7 @@ obj-$(CONFIG_DCA) += dca/
+ obj-$(CONFIG_HID) += hid/
+ obj-$(CONFIG_PPC_PS3) += ps3/
+ obj-$(CONFIG_OF) += of/
++obj-$(CONFIG_ARMADEUS_DRIVERS) += armadeus/
+ obj-$(CONFIG_SSB) += ssb/
+ obj-$(CONFIG_BCMA) += bcma/
+ obj-$(CONFIG_VHOST_RING) += vhost/
diff --git a/patches/linux/3.9/0441-armadeus-adding_star_completion_for_source_in_menuconfig.patch b/patches/linux/3.10.mx6_legacy/0441-armadeus-adding_star_completion_for_source_in_menuconfig.patch
similarity index 93%
copy from patches/linux/3.9/0441-armadeus-adding_star_completion_for_source_in_menuconfig.patch
copy to patches/linux/3.10.mx6_legacy/0441-armadeus-adding_star_completion_for_source_in_menuconfig.patch
index 18e5b98..75183e5 100644
--- a/patches/linux/3.9/0441-armadeus-adding_star_completion_for_source_in_menuconfig.patch
+++ b/patches/linux/3.10.mx6_legacy/0441-armadeus-adding_star_completion_for_source_in_menuconfig.patch
@@ -8,21 +8,21 @@ Index: linux-3.8-rc1/scripts/kconfig/zconf.tab.c_shipped
#include <stdbool.h>
+#include <dirent.h>
+#include <sys/stat.h>
-
+
#include "lkc.h"
-
+
@@ -93,6 +95,7 @@
-
+
#define PRINTD 0x0001
#define DEBUG_PARSE 0x0002
+#define BUFF_SIZE 300
-
+
int cdebug = PRINTD;
-
+
@@ -109,6 +112,27 @@
-
-
-
+
+
+
+
+static int isDir(const char *, const char *);
+
@@ -49,7 +49,7 @@ Index: linux-3.8-rc1/scripts/kconfig/zconf.tab.c_shipped
# define YYDEBUG 1
@@ -1900,8 +1924,30 @@
case 83:
-
+
{
+ char *name;
+ char *ptr;
@@ -58,7 +58,7 @@ Index: linux-3.8-rc1/scripts/kconfig/zconf.tab.c_shipped
+ struct dirent *lecture;
+ DIR *rep;
+
- printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
- zconf_nextfile((yyvsp[(2) - (3)].string));
+ name = (yyvsp[(2) -(3)].string);
+ ptr = strchr(name, '*');
@@ -78,4 +78,3 @@ Index: linux-3.8-rc1/scripts/kconfig/zconf.tab.c_shipped
+ }
;}
break;
-
diff --git a/patches/linux/3.10.mx6_legacy/0450-armadeus-add-apf6q-and-apf6dl-device-trees.patch b/patches/linux/3.10.mx6_legacy/0450-armadeus-add-apf6q-and-apf6dl-device-trees.patch
index aa65fb7..85c6b8a 100644
--- a/patches/linux/3.10.mx6_legacy/0450-armadeus-add-apf6q-and-apf6dl-device-trees.patch
+++ b/patches/linux/3.10.mx6_legacy/0450-armadeus-add-apf6q-and-apf6dl-device-trees.patch
@@ -174,7 +174,7 @@ Index: linux-wandboard_imx_3.10.31_1.1.0_beta2/arch/arm/boot/dts/imx6qdl-apf6dev
===================================================================
--- /dev/null
+++ linux-wandboard_imx_3.10.31_1.1.0_beta2/arch/arm/boot/dts/imx6qdl-apf6dev.dtsi
-@@ -0,0 +1,543 @@
+@@ -0,0 +1,541 @@
+/*
+ * Copyright 2015 Armadeus Systems
+ *
@@ -444,14 +444,12 @@ Index: linux-wandboard_imx_3.10.31_1.1.0_beta2/arch/arm/boot/dts/imx6qdl-apf6dev
+ status = "okay";
+};
+
-+/*
+&pcie {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pcie>;
+ reset-gpio = <&gpio6 2 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
-+*/
+
+&pwm3 {
+ pinctrl-names = "default";
diff --git a/patches/linux/3.10.mx6_legacy/0452-armadeus-allow-forwad-compatibility-for-eMMC.patch b/patches/linux/3.10.mx6_legacy/0452-armadeus-allow-forwad-compatibility-for-eMMC.patch
new file mode 100644
index 0000000..8b4907c
--- /dev/null
+++ b/patches/linux/3.10.mx6_legacy/0452-armadeus-allow-forwad-compatibility-for-eMMC.patch
@@ -0,0 +1,20 @@
+Add support for eMMC 5.0.
+
+Signed-off-by: Sébastien Szymanski <seb...@ar...>
+Index: linux-wandboard_imx_3.10.31_1.1.0_beta2/drivers/mmc/core/mmc.c
+===================================================================
+--- linux-wandboard_imx_3.10.31_1.1.0_beta2.orig/drivers/mmc/core/mmc.c
++++ linux-wandboard_imx_3.10.31_1.1.0_beta2/drivers/mmc/core/mmc.c
+@@ -293,12 +293,6 @@ static int mmc_read_ext_csd(struct mmc_c
+ }
+
+ card->ext_csd.rev = ext_csd[EXT_CSD_REV];
+- if (card->ext_csd.rev > 6) {
+- pr_err("%s: unrecognised EXT_CSD revision %d\n",
+- mmc_hostname(card->host), card->ext_csd.rev);
+- err = -EINVAL;
+- goto out;
+- }
+
+ card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
+ card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
diff --git a/patches/linux/3.10.mx6_legacy/0453-PCI-imx6-backport-PCIe-driver-from-3.14.patch b/patches/linux/3.10.mx6_legacy/0453-PCI-imx6-backport-PCIe-driver-from-3.14.patch
new file mode 100644
index 0000000..d53d09d
--- /dev/null
+++ b/patches/linux/3.10.mx6_legacy/0453-PCI-imx6-backport-PCIe-driver-from-3.14.patch
@@ -0,0 +1,1943 @@
+From b314869a35fd10005ae21689d744ffee344ec592 Mon Sep 17 00:00:00 2001
+From: Tim Harvey <th...@ga...>
+Date: Tue, 14 Oct 2014 21:30:51 -0700
+Subject: [PATCH 1/4] PCI: imx6: backport PCIe driver from 3.14
+
+Signed-off-by: Tim Harvey <th...@ga...>
+---
+ drivers/pci/host/Kconfig | 21 -
+ drivers/pci/host/Makefile | 1 -
+ drivers/pci/host/pci-imx6.c | 971 ++++++++-----------------------------
+ drivers/pci/host/pcie-designware.c | 321 +++++++-----
+ drivers/pci/host/pcie-designware.h | 52 +-
+ 5 files changed, 396 insertions(+), 970 deletions(-)
+
+diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
+index 0512d10..9402419 100644
+--- a/drivers/pci/host/Kconfig
++++ b/drivers/pci/host/Kconfig
+@@ -20,27 +20,6 @@ config PCI_IMX6
+ select PCIEPORTBUS
+ select PCIE_DW
+
+-config PCI_IMX6SX_EXTREMELY_PWR_SAVE
+- bool "Freescale i.MX6SX PCIe controller extremely power save mode"
+- depends on PCI_IMX6
+-
+-config EP_MODE_IN_EP_RC_SYS
+- bool "PCI Express EP mode in the IMX6 RC/EP interconnection system"
+- depends on PCI_IMX6
+-
+-config EP_SELF_IO_TEST
+- bool "PCI Express EP_SELF_IO_TEST in EP mode"
+- depends on EP_MODE_IN_EP_RC_SYS
+-
+-config RC_MODE_IN_EP_RC_SYS
+- bool "PCI Express RC mode in the IMX6 RC/EP interconnection system"
+- depends on PCI_IMX6
+-
+-config PCI_IMX_EP_DRV
+- bool "i.MX6 PCI Express EP skeleton driver"
+- depends on RC_MODE_IN_EP_RC_SYS
+- default y
+-
+ config PCI_TEGRA
+ bool "NVIDIA Tegra PCIe controller"
+ depends on ARCH_TEGRA
+diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
+index df45c7f..3fe3900 100644
+--- a/drivers/pci/host/Makefile
++++ b/drivers/pci/host/Makefile
+@@ -1,5 +1,4 @@
+ obj-$(CONFIG_PCIE_DW) += pcie-designware.o
+ obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
+ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
+-obj-$(CONFIG_PCI_IMX_EP_DRV) += pci-imx6-ep-driver.o
+ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
+diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
+index 9a0ae16..ee08250 100644
+--- a/drivers/pci/host/pci-imx6.c
++++ b/drivers/pci/host/pci-imx6.c
+@@ -1,7 +1,6 @@
+ /*
+ * PCIe host controller driver for Freescale i.MX6 SoCs
+ *
+- * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2013 Kosagi
+ * http://www.kosagi.com
+ *
+@@ -15,72 +14,48 @@
+ #include <linux/clk.h>
+ #include <linux/delay.h>
+ #include <linux/gpio.h>
+-#include <linux/interrupt.h>
+ #include <linux/kernel.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+ #include <linux/module.h>
+ #include <linux/of_gpio.h>
+-#include <linux/of_device.h>
+-#include <linux/of_address.h>
+ #include <linux/pci.h>
+ #include <linux/platform_device.h>
+ #include <linux/regmap.h>
+ #include <linux/resource.h>
+ #include <linux/signal.h>
+-#include <linux/syscore_ops.h>
+ #include <linux/types.h>
+-#include <linux/busfreq-imx6.h>
+-#include <linux/regulator/consumer.h>
+
+ #include "pcie-designware.h"
+
+ #define to_imx6_pcie(x) container_of(x, struct imx6_pcie, pp)
+
+-/*
+- * The default value of the reserved ddr memory
+- * used to verify EP/RC memory space access operations.
+- * The layout of the 1G ddr on SD boards
+- * [others]0x1000_0000 ~ 0x4FFF_FFFF
+- * [imx6sx]0x8000_0000 ~ 0xBFFF_FFFF
+- *
+- */
+-static u32 ddr_test_region = 0x40000000;
+-static u32 test_region_size = SZ_2M;
+-
+-/* The pcie who have standalone power domain */
+-#define PCIE_PHY_HAS_PWR_DOMAIN BIT(0)
+-
+-struct imx_pcie_data {
+- unsigned int flags;
+-};
+-
+-static const struct imx_pcie_data imx6sx_pcie_data = {
+- .flags = PCIE_PHY_HAS_PWR_DOMAIN,
+-};
+-
+ struct imx6_pcie {
+ int reset_gpio;
+ int power_on_gpio;
+ int wake_up_gpio;
+ int disable_gpio;
+- const struct imx_pcie_data *data;
+ struct clk *lvds_gate;
+ struct clk *sata_ref_100m;
+ struct clk *pcie_ref_125m;
+ struct clk *pcie_axi;
+- struct clk *dis_axi;
+ struct pcie_port pp;
+ struct regmap *iomuxc_gpr;
+- struct regulator *pcie_regulator;
+ void __iomem *mem_base;
+ };
+-static struct imx6_pcie *imx6_pcie;
++
++/* PCIe Root Complex registers (memory-mapped) */
++#define PCIE_RC_LCR 0x7c
++#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1
++#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2
++#define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf
+
+ /* PCIe Port Logic registers (memory-mapped) */
+ #define PL_OFFSET 0x700
+ #define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
+ #define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
++#define PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING (1 << 29)
++#define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP (1 << 4)
+
+ #define PCIE_PHY_CTRL (PL_OFFSET + 0x114)
+ #define PCIE_PHY_CTRL_DATA_LOC 0
+@@ -92,6 +67,9 @@ static struct imx6_pcie *imx6_pcie;
+ #define PCIE_PHY_STAT (PL_OFFSET + 0x110)
+ #define PCIE_PHY_STAT_ACK_LOC 16
+
++#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
++#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
++
+ /* PHY registers (not memory-mapped) */
+ #define PCIE_PHY_RX_ASIC_OUT 0x100D
+
+@@ -99,40 +77,6 @@ static struct imx6_pcie *imx6_pcie;
+ #define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
+ #define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3)
+
+-static inline bool is_imx6sx_pcie(struct imx6_pcie *imx6_pcie)
+-{
+- return imx6_pcie->data == &imx6sx_pcie_data;
+-}
+-
+-#ifdef DEBUG
+-static int pcie_reg_dump(struct imx6_pcie *imx6_pcie)
+-{
+- u32 val;
+- struct regmap *anatop_g;
+-
+- /* GPRs registers */
+- regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, &val);
+- pr_info("<F> %s <L> %d gpr1 0x%08x.\n", __func__, __LINE__, val);
+- regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5, &val);
+- pr_info("<F> %s <L> %d gpr5 0x%08x.\n", __func__, __LINE__, val);
+- regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, &val);
+- pr_info("<F> %s <L> %d gpr8 0x%08x.\n", __func__, __LINE__, val);
+- regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, &val);
+- pr_info("<F> %s <L> %d gpr12 0x%08x.\n", __func__, __LINE__, val);
+- regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR13, &val);
+- pr_info("<F> %s <L> %d gpr13 0x%08x.\n", __func__, __LINE__, val);
+-
+- /* anatop registers: pll6_enet, misc1 */
+- anatop_g = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop");
+- if (IS_ERR(anatop_g))
+- pr_err("failed to find fsl,imx6sx-anatop regmap\n");
+- regmap_read(anatop_g, 0xe0, &val);
+- pr_info("<F> %s <L> %d pll6_enet 0x%08x.\n", __func__, __LINE__, val);
+- regmap_read(anatop_g, 0x160, &val);
+- pr_info("<F> %s <L> %d misc1 0x%08x.\n", __func__, __LINE__, val);
+-}
+-#endif
+-
+ static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)
+ {
+ u32 val;
+@@ -270,6 +214,18 @@ static int imx6q_pcie_abort_handler(unsigned long addr,
+ return 0;
+ }
+
++static int imx6_pcie_assert_core_reset(struct pcie_port *pp)
++{
++ struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
++
++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
++ IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18);
++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
++ IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16);
++
++ return 0;
++}
++
+ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
+ {
+ struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+@@ -278,28 +234,15 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
+ if (gpio_is_valid(imx6_pcie->power_on_gpio))
+ gpio_set_value(imx6_pcie->power_on_gpio, 1);
+
+- request_bus_freq(BUS_FREQ_HIGH);
+-
+- if (is_imx6sx_pcie(imx6_pcie)) {
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+- IMX6Q_GPR12_PCIE_TEST_PD, 0 << 30);
+-
+- ret = clk_prepare_enable(imx6_pcie->dis_axi);
+- if (ret) {
+- dev_err(pp->dev, "unable to enable dis_axi\n");
+- goto err_dis_axi;
+- }
+- } else {
+- /* Those bits are not used anymore on imx6sx */
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+- IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
++ IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
++ IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
+
+- /* sata_ref is not used by pcie on imx6sx */
+- ret = clk_prepare_enable(imx6_pcie->sata_ref_100m);
+- if (ret) {
+- dev_err(pp->dev, "unable to enable sata_ref_100m\n");
+- goto err_sata_ref;
+- }
++ ret = clk_prepare_enable(imx6_pcie->sata_ref_100m);
++ if (ret) {
++ dev_err(pp->dev, "unable to enable sata_ref_100m\n");
++ goto err_sata_ref;
+ }
+
+ ret = clk_prepare_enable(imx6_pcie->pcie_ref_125m);
+@@ -308,13 +251,10 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
+ goto err_pcie_ref;
+ }
+
+- if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)
+- && !IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS)) {
+- ret = clk_prepare_enable(imx6_pcie->lvds_gate);
+- if (ret) {
+- dev_err(pp->dev, "unable to enable lvds_gate\n");
+- goto err_lvds_gate;
+- }
++ ret = clk_prepare_enable(imx6_pcie->lvds_gate);
++ if (ret) {
++ dev_err(pp->dev, "unable to enable lvds_gate\n");
++ goto err_lvds_gate;
+ }
+
+ ret = clk_prepare_enable(imx6_pcie->pcie_axi);
+@@ -323,26 +263,15 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
+ goto err_pcie_axi;
+ }
+
+- if (!is_imx6sx_pcie(imx6_pcie)) {
+- /*
+- * This bit is not used anymore on imx6sx.
+- * wailt for the pcie clks are stable.
+- * ~4us is requried, let it to be 10us here.
+- */
+- udelay(10);
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+- IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
+- }
+-
+ /* allow the clocks to stabilize */
+ usleep_range(200, 500);
+
++ /* Some boards don't have PCIe reset GPIO. */
+ if (gpio_is_valid(imx6_pcie->reset_gpio)) {
+ gpio_set_value(imx6_pcie->reset_gpio, 0);
+- mdelay(1);
++ msleep(100);
+ gpio_set_value(imx6_pcie->reset_gpio, 1);
+ }
+-
+ return 0;
+
+ err_pcie_axi:
+@@ -350,13 +279,8 @@ err_pcie_axi:
+ err_lvds_gate:
+ clk_disable_unprepare(imx6_pcie->pcie_ref_125m);
+ err_pcie_ref:
+- if (!is_imx6sx_pcie(imx6_pcie))
+- clk_disable_unprepare(imx6_pcie->sata_ref_100m);
++ clk_disable_unprepare(imx6_pcie->sata_ref_100m);
+ err_sata_ref:
+- if (is_imx6sx_pcie(imx6_pcie))
+- clk_disable_unprepare(imx6_pcie->dis_axi);
+-err_dis_axi:
+- release_bus_freq(BUS_FREQ_HIGH);
+ return ret;
+
+ }
+@@ -364,36 +288,13 @@ err_dis_axi:
+ static void imx6_pcie_init_phy(struct pcie_port *pp)
+ {
+ struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+- int ret;
+-
+- /*
+- * iMX6SX PCIe has the stand-alone power domain
+- * add the initialization here for iMX6SX PCIe.
+- */
+- if (is_imx6sx_pcie(imx6_pcie)) {
+- /* Force PCIe PHY reset */
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+- BIT(19), 1 << 19);
+
+- /* Power up PCIe PHY, ANATOP_REG_CORE offset 0x140, bit13-9 */
+- regulator_set_voltage(imx6_pcie->pcie_regulator, 1100000, 1100000);
+- ret = regulator_enable(imx6_pcie->pcie_regulator);
+- if (ret)
+- dev_info(pp->dev, "failed to enable pcie regulator.\n");
+-
+- }
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
+
+ /* configure constant input signal to the pcie ctrl and phy */
+- if (IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS))
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+- IMX6Q_GPR12_DEVICE_TYPE,
+- PCI_EXP_TYPE_ENDPOINT << 12);
+- else
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+- IMX6Q_GPR12_DEVICE_TYPE,
+- PCI_EXP_TYPE_ROOT_PORT << 12);
++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
++ IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12);
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_LOS_LEVEL, 9 << 4);
+
+@@ -409,75 +310,155 @@ static void imx6_pcie_init_phy(struct pcie_port *pp)
+ IMX6Q_GPR8_TX_SWING_LOW, 127 << 25);
+ }
+
+-static irqreturn_t imx_pcie_msi_irq_handler(int irq, void *arg)
++static int imx6_pcie_wait_for_link(struct pcie_port *pp)
+ {
+- struct pcie_port *pp = arg;
++ int count = 200;
++
++ while (!dw_pcie_link_up(pp)) {
++ usleep_range(100, 1000);
++ if (--count)
++ continue;
+
+- dw_handle_msi_irq(pp);
++ dev_err(pp->dev, "phy link never came up\n");
++ dev_dbg(pp->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
++ readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
++ readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
++ return -EINVAL;
++ }
+
+- return IRQ_HANDLED;
++ return 0;
+ }
+
+-static void imx6_pcie_host_init(struct pcie_port *pp)
++static int imx6_pcie_start_link(struct pcie_port *pp)
+ {
+- int count = 0;
+ struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+-
+- imx6_pcie_init_phy(pp);
+-
+- imx6_pcie_deassert_core_reset(pp);
++ uint32_t tmp;
++ int ret, count;
+
+ /*
+- * iMX6SX PCIe has the stand-alone power domain.
+- * refer to the initialization for iMX6SX PCIe,
+- * release the PCIe PHY reset here,
+- * before LTSSM enable is set.
++ * Force Gen1 operation when starting the link. In case the link is
++ * started in Gen2 mode, there is a possibility the devices on the
++ * bus will not be detected at all. This happens with PCIe switches.
+ */
+- if (is_imx6sx_pcie(imx6_pcie))
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+- BIT(19), 0 << 19);
++ tmp = readl(pp->dbi_base + PCIE_RC_LCR);
++ tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
++ tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
++ writel(tmp, pp->dbi_base + PCIE_RC_LCR);
+
+-
+- dw_pcie_setup_rc(pp);
+-
+-#ifdef DEBUG
+- pcie_reg_dump(imx6_pcie);
+-#endif
++ /* Start LTSSM. */
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
+
+- while (!dw_pcie_link_up(pp)) {
++ ret = imx6_pcie_wait_for_link(pp);
++ if (ret)
++ return ret;
++
++ /* Allow Gen2 mode after the link is up. */
++ tmp = readl(pp->dbi_base + PCIE_RC_LCR);
++ tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
++ tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
++ writel(tmp, pp->dbi_base + PCIE_RC_LCR);
++
++ /*
++ * Start Directed Speed Change so the best possible speed both link
++ * partners support can be negotiated.
++ */
++ tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
++ tmp |= PORT_LOGIC_SPEED_CHANGE;
++ writel(tmp, pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
++
++ count = 200;
++ while (count--) {
++ tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
++ /* Test if the speed change finished. */
++ if (!(tmp & PORT_LOGIC_SPEED_CHANGE))
++ break;
+ usleep_range(100, 1000);
+- count++;
+- if (count >= 200) {
+- dev_err(pp->dev, "phy link never came up\n");
+- dev_dbg(pp->dev,
+- "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
+- readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
+- readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
+- return;
+- }
+ }
+
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- pp->quirks |= DW_PCIE_QUIRK_NO_MSI_VEC;
+- pp->quirks |= DW_PCIE_QUIRK_MSI_SELF_EN;
+- dw_pcie_msi_init(pp);
++ /* Make sure link training is finished as well! */
++ if (count)
++ ret = imx6_pcie_wait_for_link(pp);
++ else
++ ret = -EINVAL;
++
++ if (ret) {
++ dev_err(pp->dev, "Failed to bring link up!\n");
++ } else {
++ tmp = readl(pp->dbi_base + 0x80);
++ dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf);
+ }
+
+- return;
++ return ret;
+ }
+
+-static int imx6_pcie_link_up(struct pcie_port *pp)
++static void imx6_pcie_host_init(struct pcie_port *pp)
+ {
+- u32 rc, ltssm, rx_valid, temp;
++ imx6_pcie_assert_core_reset(pp);
++
++ imx6_pcie_init_phy(pp);
++
++ imx6_pcie_deassert_core_reset(pp);
+
+- /* link is debug bit 36, debug register 1 starts at bit 32 */
+- rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << (36 - 32));
+- if (rc)
+- return -EAGAIN;
++ dw_pcie_setup_rc(pp);
++
++ imx6_pcie_start_link(pp);
++}
++
++static void imx6_pcie_reset_phy(struct pcie_port *pp)
++{
++ uint32_t temp;
++
++ pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &temp);
++ temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN |
++ PHY_RX_OVRD_IN_LO_RX_PLL_EN);
++ pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, temp);
++
++ usleep_range(2000, 3000);
++
++ pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &temp);
++ temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN |
++ PHY_RX_OVRD_IN_LO_RX_PLL_EN);
++ pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, temp);
++}
++
++static int imx6_pcie_link_up(struct pcie_port *pp)
++{
++ u32 rc, debug_r0, rx_valid;
++ int count = 5;
+
+ /*
++ * Test if the PHY reports that the link is up and also that the LTSSM
++ * training finished. There are three possible states of the link when
++ * this code is called:
++ * 1) The link is DOWN (unlikely)
++ * The link didn't come up yet for some reason. This usually means
++ * we have a real problem somewhere. Reset the PHY and exit. This
++ * state calls for inspection of the DEBUG registers.
++ * 2) The link is UP, but still in LTSSM training
++ * Wait for the training to finish, which should take a very short
++ * time. If the training does not finish, we have a problem and we
++ * need to inspect the DEBUG registers. If the training does finish,
++ * the link is up and operating correctly.
++ * 3) The link is UP and no longer in LTSSM training
++ * The link is up and operating correctly.
++ */
++ while (1) {
++ rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
++ if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP))
++ break;
++ if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
++ return 1;
++ if (!count--)
++ break;
++ dev_dbg(pp->dev, "Link is up, but still in training\n");
++ /*
++ * Wait a little bit, then re-check if the link finished
++ * the training.
++ */
++ usleep_range(1000, 2000);
++ }
++ /*
+ * From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
+ * Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
+ * If (MAC/LTSSM.state == Recovery.RcvrLock)
+@@ -485,31 +466,18 @@ static int imx6_pcie_link_up(struct pcie_port *pp)
+ * to gen2 is stuck
+ */
+ pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
+- ltssm = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0) & 0x3F;
++ debug_r0 = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0);
+
+ if (rx_valid & 0x01)
+ return 0;
+
+- if (ltssm != 0x0d)
++ if ((debug_r0 & 0x3f) != 0x0d)
+ return 0;
+
+ dev_err(pp->dev, "transition to gen2 is stuck, reset PHY!\n");
++ dev_dbg(pp->dev, "debug_r0=%08x debug_r1=%08x\n", debug_r0, rc);
+
+- pcie_phy_read(pp->dbi_base,
+- PHY_RX_OVRD_IN_LO, &temp);
+- temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN
+- | PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+- pcie_phy_write(pp->dbi_base,
+- PHY_RX_OVRD_IN_LO, temp);
+-
+- usleep_range(2000, 3000);
+-
+- pcie_phy_read(pp->dbi_base,
+- PHY_RX_OVRD_IN_LO, &temp);
+- temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN
+- | PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+- pcie_phy_write(pp->dbi_base,
+- PHY_RX_OVRD_IN_LO, temp);
++ imx6_pcie_reset_phy(pp);
+
+ return 0;
+ }
+@@ -530,22 +498,6 @@ static int imx6_add_pcie_port(struct pcie_port *pp,
+ return -ENODEV;
+ }
+
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- pp->msi_irq = pp->irq - 3;
+- if (!pp->msi_irq) {
+- dev_err(&pdev->dev, "failed to get msi irq\n");
+- return -ENODEV;
+- }
+-
+- ret = devm_request_irq(&pdev->dev, pp->msi_irq,
+- imx_pcie_msi_irq_handler,
+- IRQF_SHARED, "imx6q-pcie", pp);
+- if (ret) {
+- dev_err(&pdev->dev, "failed to request msi irq\n");
+- return ret;
+- }
+- }
+-
+ pp->root_bus_nr = -1;
+ pp->ops = &imx6_pcie_host_ops;
+
+@@ -559,359 +511,13 @@ static int imx6_add_pcie_port(struct pcie_port *pp,
+ return 0;
+ }
+
+-static ssize_t imx_pcie_bar0_addr_info(struct device *dev,
+- struct device_attribute *devattr, char *buf)
+-{
+- struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
+- struct pcie_port *pp = &imx6_pcie->pp;
+-
+- return sprintf(buf, "imx-pcie-bar0-addr-info start 0x%08x\n",
+- readl(pp->dbi_base + PCI_BASE_ADDRESS_0));
+-}
+-
+-static ssize_t imx_pcie_bar0_addr_start(struct device *dev,
+- struct device_attribute *attr, const char *buf, size_t count)
+-{
+- u32 bar_start;
+- struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
+- struct pcie_port *pp = &imx6_pcie->pp;
+-
+- sscanf(buf, "%x\n", &bar_start);
+- writel(bar_start, pp->dbi_base + PCI_BASE_ADDRESS_0);
+-
+- return count;
+-}
+-
+-static void imx_pcie_regions_setup(struct device *dev)
+-{
+- struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
+- struct pcie_port *pp = &imx6_pcie->pp;
+-
+- if (is_imx6sx_pcie(imx6_pcie))
+- ddr_test_region = 0xb0000000;
+-
+- if (IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)) {
+- /*
+- * region2 outbound used to access rc mem
+- * in imx6 pcie ep/rc validation system
+- */
+- writel(2, pp->dbi_base + PCIE_ATU_VIEWPORT);
+- writel(pp->mem_base, pp->dbi_base + PCIE_ATU_LOWER_BASE);
+- writel(0, pp->dbi_base + PCIE_ATU_UPPER_BASE);
+- writel(pp->mem_base + test_region_size,
+- pp->dbi_base + PCIE_ATU_LIMIT);
+-
+- writel(ddr_test_region,
+- pp->dbi_base + PCIE_ATU_LOWER_TARGET);
+- writel(0, pp->dbi_base + PCIE_ATU_UPPER_TARGET);
+- writel(PCIE_ATU_TYPE_MEM, pp->dbi_base + PCIE_ATU_CR1);
+- writel(PCIE_ATU_ENABLE, pp->dbi_base + PCIE_ATU_CR2);
+- }
+-
+- if (IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS)) {
+- /*
+- * region2 outbound used to access ep mem
+- * in imx6 pcie ep/rc validation system
+- */
+- writel(2, pp->dbi_base + PCIE_ATU_VIEWPORT);
+- writel(pp->mem_base, pp->dbi_base + PCIE_ATU_LOWER_BASE);
+- writel(0, pp->dbi_base + PCIE_ATU_UPPER_BASE);
+- writel(pp->mem_base + test_region_size,
+- pp->dbi_base + PCIE_ATU_LIMIT);
+-
+- writel(ddr_test_region,
+- pp->dbi_base + PCIE_ATU_LOWER_TARGET);
+- writel(0, pp->dbi_base + PCIE_ATU_UPPER_TARGET);
+- writel(PCIE_ATU_TYPE_MEM, pp->dbi_base + PCIE_ATU_CR1);
+- writel(PCIE_ATU_ENABLE, pp->dbi_base + PCIE_ATU_CR2);
+- }
+-}
+-
+-static ssize_t imx_pcie_memw_info(struct device *dev,
+- struct device_attribute *devattr, char *buf)
+-{
+- return sprintf(buf, "imx-pcie-rc-memw-info start 0x%08x, size 0x%08x\n",
+- ddr_test_region, test_region_size);
+-}
+-
+-static ssize_t
+-imx_pcie_memw_start(struct device *dev, struct device_attribute *attr,
+- const char *buf, size_t count)
+-{
+- u32 memw_start;
+-
+- sscanf(buf, "%x\n", &memw_start);
+-
+- if (memw_start < 0x10000000) {
+- dev_err(dev, "Invalid memory start address.\n");
+- dev_info(dev, "For example: echo 0x41000000 > /sys/...");
+- return -1;
+- }
+-
+- if (ddr_test_region != memw_start) {
+- ddr_test_region = memw_start;
+- /* Re-setup the iATU */
+- imx_pcie_regions_setup(dev);
+- }
+-
+- return count;
+-}
+-
+-static ssize_t
+-imx_pcie_memw_size(struct device *dev, struct device_attribute *attr,
+- const char *buf, size_t count)
+-{
+- u32 memw_size;
+-
+- sscanf(buf, "%x\n", &memw_size);
+-
+- if ((memw_size > (SZ_16M - SZ_1M)) || (memw_size < SZ_64K)) {
+- dev_err(dev, "Invalid, should be [SZ_64K,SZ_16M - SZ_1MB].\n");
+- dev_info(dev, "For example: echo 0x800000 > /sys/...");
+- return -1;
+- }
+-
+- if (test_region_size != memw_size) {
+- test_region_size = memw_size;
+- /* Re-setup the iATU */
+- imx_pcie_regions_setup(dev);
+- }
+-
+- return count;
+-}
+-
+-static DEVICE_ATTR(memw_info, S_IRUGO, imx_pcie_memw_info, NULL);
+-static DEVICE_ATTR(memw_start_set, S_IWUGO, NULL, imx_pcie_memw_start);
+-static DEVICE_ATTR(memw_size_set, S_IWUGO, NULL, imx_pcie_memw_size);
+-static DEVICE_ATTR(ep_bar0_addr, S_IRWXUGO, imx_pcie_bar0_addr_info,
+- imx_pcie_bar0_addr_start);
+-
+-static struct attribute *imx_pcie_attrs[] = {
+- /*
+- * The start address, and the limitation (64KB ~ (16MB - 1MB))
+- * of the ddr mem window reserved by RC, and used for EP to access.
+- * BTW, these attrs are only configured at EP side.
+- */
+- &dev_attr_memw_info.attr,
+- &dev_attr_memw_start_set.attr,
+- &dev_attr_memw_size_set.attr,
+- &dev_attr_ep_bar0_addr.attr,
+- NULL
+-};
+-
+-static struct attribute_group imx_pcie_attrgroup = {
+- .attrs = imx_pcie_attrs,
+-};
+-
+-static const struct of_device_id imx6_pcie_of_match[] = {
+- { .compatible = "fsl,imx6q-pcie", },
+- { .compatible = "fsl,imx6sx-pcie", .data = &imx6sx_pcie_data},
+- { /* sentinel */ }
+-};
+-MODULE_DEVICE_TABLE(of, imx6_pcie_of_match);
+-
+-static void imx6_pcie_setup_ep(struct pcie_port *pp)
+-{
+- /* CMD reg:I/O space, MEM space, and Bus Master Enable */
+- writel(readl(pp->dbi_base + PCI_COMMAND)
+- | PCI_COMMAND_IO
+- | PCI_COMMAND_MEMORY
+- | PCI_COMMAND_MASTER,
+- pp->dbi_base + PCI_COMMAND);
+-
+- /*
+- * configure the class_rev(emaluate one memory ram ep device),
+- * bar0 and bar1 of ep
+- */
+- writel(0xdeadbeaf, pp->dbi_base + PCI_VENDOR_ID);
+- writel(readl(pp->dbi_base + PCI_CLASS_REVISION)
+- | (PCI_CLASS_MEMORY_RAM << 16),
+- pp->dbi_base + PCI_CLASS_REVISION);
+- writel(0xdeadbeaf, pp->dbi_base
+- + PCI_SUBSYSTEM_VENDOR_ID);
+-
+- /* 32bit none-prefetchable 8M bytes memory on bar0 */
+- writel(0x0, pp->dbi_base + PCI_BASE_ADDRESS_0);
+- writel(SZ_8M - 1, pp->dbi_base + (1 << 12)
+- + PCI_BASE_ADDRESS_0);
+-
+- /* None used bar1 */
+- writel(0x0, pp->dbi_base + PCI_BASE_ADDRESS_1);
+- writel(0, pp->dbi_base + (1 << 12) + PCI_BASE_ADDRESS_1);
+-
+- /* 4K bytes IO on bar2 */
+- writel(0x1, pp->dbi_base + PCI_BASE_ADDRESS_2);
+- writel(SZ_4K - 1, pp->dbi_base + (1 << 12) +
+- PCI_BASE_ADDRESS_2);
+-
+- /*
+- * 32bit prefetchable 1M bytes memory on bar3
+- * FIXME BAR MASK3 is not changable, the size
+- * is fixed to 256 bytes.
+- */
+- writel(0x8, pp->dbi_base + PCI_BASE_ADDRESS_3);
+- writel(SZ_1M - 1, pp->dbi_base + (1 << 12)
+- + PCI_BASE_ADDRESS_3);
+-
+- /*
+- * 64bit prefetchable 1M bytes memory on bar4-5.
+- * FIXME BAR4,5 are not enabled yet
+- */
+- writel(0xc, pp->dbi_base + PCI_BASE_ADDRESS_4);
+- writel(SZ_1M - 1, pp->dbi_base + (1 << 12)
+- + PCI_BASE_ADDRESS_4);
+- writel(0, pp->dbi_base + (1 << 12) + PCI_BASE_ADDRESS_5);
+-}
+-
+-#ifdef CONFIG_PM_SLEEP
+-static int pci_imx_suspend(void)
+-{
+- int rc = 0;
+-
+- if (is_imx6sx_pcie(imx6_pcie)) {
+- if (IS_ENABLED(CONFIG_PCI_IMX6SX_EXTREMELY_PWR_SAVE)) {
+- /* Disable clks and power down PCIe PHY */
+- clk_disable_unprepare(imx6_pcie->pcie_axi);
+- if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)
+- && !IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS))
+- clk_disable_unprepare(imx6_pcie->lvds_gate);
+- clk_disable_unprepare(imx6_pcie->pcie_ref_125m);
+- clk_disable_unprepare(imx6_pcie->dis_axi);
+- release_bus_freq(BUS_FREQ_HIGH);
+-
+- /* Put PCIe PHY to be isolation */
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR0,
+- BIT(6), 1 << 6);
+-
+- /*
+- * Power down PCIe PHY.
+- */
+- regulator_disable(imx6_pcie->pcie_regulator);
+- } else {
+- /* PM_TURN_OFF */
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+- BIT(16), 1 << 16);
+- udelay(10);
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+- BIT(16), 0 << 16);
+- clk_disable_unprepare(imx6_pcie->pcie_axi);
+- if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)
+- && !IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS))
+- clk_disable_unprepare(imx6_pcie->lvds_gate);
+- clk_disable_unprepare(imx6_pcie->pcie_ref_125m);
+- clk_disable_unprepare(imx6_pcie->dis_axi);
+- release_bus_freq(BUS_FREQ_HIGH);
+- }
+- }
+-
+- return rc;
+-}
+-
+-static void pci_imx_resume(void)
+-{
+- struct pcie_port *pp = &imx6_pcie->pp;
+-
+- if (is_imx6sx_pcie(imx6_pcie)) {
+- if (IS_ENABLED(CONFIG_PCI_IMX6SX_EXTREMELY_PWR_SAVE)) {
+- /* Power up PCIe PHY, and so on again */
+- imx6_pcie_init_phy(pp);
+- imx6_pcie_deassert_core_reset(pp);
+-
+- /*
+- * iMX6SX PCIe has the stand-alone power domain.
+- * refer to the initialization for iMX6SX PCIe,
+- * release the PCIe PHY reset here,
+- * before LTSSM enable is set
+- * .
+- */
+- regmap_update_bits(imx6_pcie->iomuxc_gpr,
+- IOMUXC_GPR5, BIT(19), 0 << 19);
+-
+- if (IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)) {
+- imx6_pcie_setup_ep(pp);
+- } else {
+- /*
+- * CMD reg:I/O space, MEM space,
+- * and Bus Master
+- */
+- writel(readl(pp->dbi_base + PCI_COMMAND)
+- | PCI_COMMAND_IO
+- | PCI_COMMAND_MEMORY
+- | PCI_COMMAND_MASTER,
+- pp->dbi_base + PCI_COMMAND);
+- /*
+- * Set the CLASS_REV of RC CFG header to
+- * PCI_CLASS_BRIDGE_PCI
+- */
+- writel(readl(pp->dbi_base + PCI_CLASS_REVISION)
+- | (PCI_CLASS_BRIDGE_PCI << 16),
+- pp->dbi_base + PCI_CLASS_REVISION);
+- }
+-
+- /* assert LTSSM enable */
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+- IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
+- } else {
+- /* Wake up re-enable clks */
+- request_bus_freq(BUS_FREQ_HIGH);
+- clk_prepare_enable(imx6_pcie->dis_axi);
+- if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)
+- && !IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS))
+- clk_prepare_enable(imx6_pcie->lvds_gate);
+- clk_prepare_enable(imx6_pcie->pcie_ref_125m);
+- clk_prepare_enable(imx6_pcie->pcie_axi);
+-
+- /* reset iMX6SX PCIe */
+- regmap_update_bits(imx6_pcie->iomuxc_gpr,
+- IOMUXC_GPR5, BIT(18), 1 << 18);
+-
+- regmap_update_bits(imx6_pcie->iomuxc_gpr,
+- IOMUXC_GPR5, BIT(18), 0 << 18);
+-
+- /*
+- * controller maybe turn off, re-configure again
+- * Set the CLASS_REV of RC CFG header to
+- * PCI_CLASS_BRIDGE_PCI
+- */
+- writel(readl(pp->dbi_base + PCI_CLASS_REVISION)
+- | (PCI_CLASS_BRIDGE_PCI << 16),
+- pp->dbi_base + PCI_CLASS_REVISION);
+-
+- dw_pcie_setup_rc(pp);
+-
+- /* reset iMX6SX PCIe */
+- regmap_update_bits(imx6_pcie->iomuxc_gpr,
+- IOMUXC_GPR5, BIT(18), 1 << 18);
+-
+- regmap_update_bits(imx6_pcie->iomuxc_gpr,
+- IOMUXC_GPR5, BIT(18), 0 << 18);
+-
+- /* RESET EP */
+- gpio_set_value(imx6_pcie->reset_gpio, 0);
+- udelay(10);
+- gpio_set_value(imx6_pcie->reset_gpio, 1);
+- }
+- }
+-}
+-#endif
+-
+-static struct syscore_ops pci_imx_syscore_ops = {
+- .suspend = pci_imx_suspend,
+- .resume = pci_imx_resume,
+-};
+-
+ static int __init imx6_pcie_probe(struct platform_device *pdev)
+ {
++ struct imx6_pcie *imx6_pcie;
+ struct pcie_port *pp;
+- const struct of_device_id *of_id =
+- of_match_device(imx6_pcie_of_match, &pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *dbi_base;
+- int ret, i;
+- void *test_reg1, *test_reg2;
+- void __iomem *pcie_arb_base_addr;
+- struct timeval tv1, tv2, tv3;
+- u32 tv_count1, tv_count2;
++ int ret;
+
+ imx6_pcie = devm_kzalloc(&pdev->dev, sizeof(*imx6_pcie), GFP_KERNEL);
+ if (!imx6_pcie)
+@@ -919,41 +525,24 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
+
+ pp = &imx6_pcie->pp;
+ pp->dev = &pdev->dev;
+- imx6_pcie->data = of_id->data;
+-
+- if (IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)) {
+- /* add attributes for device */
+- ret = sysfs_create_group(&pdev->dev.kobj, &imx_pcie_attrgroup);
+- if (ret)
+- return -EINVAL;
+- }
+
+ /* Added for PCI abort handling */
+ hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0,
+ "imprecise external abort");
+
+ dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (!dbi_base) {
+- dev_err(&pdev->dev, "dbi_base memory resource not found\n");
+- return -ENODEV;
+- }
+-
+ pp->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base);
+- if (IS_ERR(pp->dbi_base)) {
+- ret = PTR_ERR(pp->dbi_base);
+- goto err;
+- }
++ if (IS_ERR(pp->dbi_base))
++ return PTR_ERR(pp->dbi_base);
+
+ /* Fetch GPIOs */
+ imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
+ if (gpio_is_valid(imx6_pcie->reset_gpio)) {
+- ret = devm_gpio_request_one(&pdev->dev,
+- imx6_pcie->reset_gpio,
+- GPIOF_OUT_INIT_LOW,
+- "PCIe reset");
++ ret = devm_gpio_request_one(&pdev->dev, imx6_pcie->reset_gpio,
++ GPIOF_OUT_INIT_LOW, "PCIe reset");
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get reset gpio\n");
+- goto err;
++ return ret;
+ }
+ }
+
+@@ -965,7 +554,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
+ "PCIe power enable");
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get power-on gpio\n");
+- goto err;
++ return ret;
+ }
+ }
+
+@@ -977,7 +566,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
+ "PCIe wake up");
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get wake-up gpio\n");
+- goto err;
++ return ret;
+ }
+ }
+
+@@ -989,7 +578,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
+ "PCIe disable endpoint");
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get disable-ep gpio\n");
+- goto err;
++ return ret;
+ }
+ }
+
+@@ -998,208 +587,52 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
+ if (IS_ERR(imx6_pcie->lvds_gate)) {
+ dev_err(&pdev->dev,
+ "lvds_gate clock select missing or invalid\n");
+- ret = PTR_ERR(imx6_pcie->lvds_gate);
+- goto err;
++ return PTR_ERR(imx6_pcie->lvds_gate);
++ }
++
++ imx6_pcie->sata_ref_100m = devm_clk_get(&pdev->dev, "sata_ref_100m");
++ if (IS_ERR(imx6_pcie->sata_ref_100m)) {
++ dev_err(&pdev->dev,
++ "sata_ref_100m clock source missing or invalid\n");
++ return PTR_ERR(imx6_pcie->sata_ref_100m);
+ }
+
+ imx6_pcie->pcie_ref_125m = devm_clk_get(&pdev->dev, "pcie_ref_125m");
+ if (IS_ERR(imx6_pcie->pcie_ref_125m)) {
+ dev_err(&pdev->dev,
+ "pcie_ref_125m clock source missing or invalid\n");
+- ret = PTR_ERR(imx6_pcie->pcie_ref_125m);
+- goto err;
++ return PTR_ERR(imx6_pcie->pcie_ref_125m);
+ }
+
+ imx6_pcie->pcie_axi = devm_clk_get(&pdev->dev, "pcie_axi");
+ if (IS_ERR(imx6_pcie->pcie_axi)) {
+ dev_err(&pdev->dev,
+ "pcie_axi clock source missing or invalid\n");
+- ret = PTR_ERR(imx6_pcie->pcie_axi);
+- goto err;
+- }
+-
+- if (is_imx6sx_pcie(imx6_pcie)) {
+- imx6_pcie->dis_axi = devm_clk_get(&pdev->dev, "display_axi");
+- if (IS_ERR(imx6_pcie->dis_axi)) {
+- dev_err(&pdev->dev,
+- "dis_axi clock source missing or invalid\n");
+- ret = PTR_ERR(imx6_pcie->dis_axi);
+- goto err;
+- }
+-
+- /* Get pcie regulator */
+- imx6_pcie->pcie_regulator = devm_regulator_get(pp->dev, "pcie");
+-
+- /* Grab GPR config register range */
+- imx6_pcie->iomuxc_gpr =
+- syscon_regmap_lookup_by_compatible("fsl,imx6sx-iomuxc-gpr");
+- } else {
+- /* sata_ref is not used by pcie on imx6sx */
+- imx6_pcie->sata_ref_100m = devm_clk_get(&pdev->dev, "sata_ref_100m");
+- if (IS_ERR(imx6_pcie->sata_ref_100m)) {
+- dev_err(&pdev->dev,
+- "sata_ref_100m clock source missing or invalid\n");
+- ret = PTR_ERR(imx6_pcie->sata_ref_100m);
+- goto err;
+- }
+-
+- /* Grab GPR config register range */
+- imx6_pcie->iomuxc_gpr =
+- syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
++ return PTR_ERR(imx6_pcie->pcie_axi);
+ }
+
++ /* Grab GPR config register range */
++ imx6_pcie->iomuxc_gpr =
++ syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+ if (IS_ERR(imx6_pcie->iomuxc_gpr)) {
+ dev_err(&pdev->dev, "unable to find iomuxc registers\n");
+- ret = PTR_ERR(imx6_pcie->iomuxc_gpr);
+- goto err;
++ return PTR_ERR(imx6_pcie->iomuxc_gpr);
+ }
+
+- if (IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)) {
+- struct device_node *np = pp->dev->of_node;
+- struct of_pci_range range;
+- struct of_pci_range_parser parser;
+- unsigned long restype;
+-
+- if (of_pci_range_parser_init(&parser, np)) {
+- dev_err(pp->dev, "missing ranges property\n");
+- return -EINVAL;
+- }
+-
+- /* Get the memory ranges from DT */
+- for_each_of_pci_range(&parser, &range) {
+- restype = range.flags & IORESOURCE_TYPE_BITS;
+- if (restype == IORESOURCE_MEM) {
+- of_pci_range_to_resource(&range,
+- np, &pp->mem);
+- pp->mem.name = "MEM";
+- }
+- }
+-
+- pp->mem_base = pp->mem.start;
+- if (IS_ENABLED(CONFIG_EP_SELF_IO_TEST)) {
+- /* Prepare the test regions and data */
+- test_reg1 = devm_kzalloc(&pdev->dev,
+- test_region_size, GFP_KERNEL);
+- if (!test_reg1) {
+- pr_err("pcie ep: can't alloc the test reg1.\n");
+- ret = PTR_ERR(test_reg1);
+- goto err;
+- }
+-
+- test_reg2 = devm_kzalloc(&pdev->dev,
+- test_region_size, GFP_KERNEL);
+- if (!test_reg2) {
+- pr_err("pcie ep: can't alloc the test reg2.\n");
+- ret = PTR_ERR(test_reg1);
+- goto err;
+- }
+-
+- pcie_arb_base_addr = ioremap_cached(pp->mem_base,
+- test_region_size);
+-
+- if (!pcie_arb_base_addr) {
+- pr_err("error with ioremap in ep selftest\n");
+- ret = PTR_ERR(pcie_arb_base_addr);
+- goto err;
+- }
+-
+- for (i = 0; i < test_region_size; i = i + 4) {
+- writel(0xE6600D00 + i, test_reg1 + i);
+- writel(0xDEADBEAF, test_reg2 + i);
+- }
+- }
+-
+- imx6_pcie_init_phy(pp);
+-
+- imx6_pcie_deassert_core_reset(pp);
+-
+- /*
+- * iMX6SX PCIe has the stand-alone power domain.
+- * refer to the initialization for iMX6SX PCIe,
+- * release the PCIe PHY reset here,
+- * before LTSSM enable is set
+- * .
+- */
+- if (is_imx6sx_pcie(imx6_pcie))
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+- BIT(19), 0 << 19);
+-
+- /* assert LTSSM enable */
+- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+- IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
+-
+- dev_info(&pdev->dev, "PCIe EP: waiting for link up...\n");
+-
+- platform_set_drvdata(pdev, imx6_pcie);
+- /* link is indicated by the bit4 of DB_R1 register */
+- do {
+- usleep_range(10, 20);
+- } while ((readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & 0x10) == 0);
+-
+- imx6_pcie_setup_ep(pp);
+-
+- /* Re-setup the iATU */
+- imx_pcie_regions_setup(&pdev->dev);
+-
+- if (IS_ENABLED(CONFIG_EP_SELF_IO_TEST)) {
+- /* PCIe EP start the data transfer after link up */
+- pr_info("pcie ep: Starting data transfer...\n");
+- do_gettimeofday(&tv1);
+-
+- memcpy((unsigned long *)pcie_arb_base_addr,
+- (unsigned long *)test_reg1,
+- test_region_size);
+-
+- do_gettimeofday(&tv2);
+-
+- memcpy((unsigned long *)test_reg2,
+- (unsigned long *)pcie_arb_base_addr,
+- test_region_size);
+-
+- do_gettimeofday(&tv3);
+-
+- if (memcmp(test_reg2, test_reg1, test_region_size) == 0) {
+- tv_count1 = (tv2.tv_sec - tv1.tv_sec)
+- * USEC_PER_SEC
+- + tv2.tv_usec - tv1.tv_usec;
+- tv_count2 = (tv3.tv_sec - tv2.tv_sec)
+- * USEC_PER_SEC
+- + tv3.tv_usec - tv2.tv_usec;
+-
+- pr_info("pcie ep: Data transfer is successful."
+- " tv_count1 %dus,"
+- " tv_count2 %dus.\n",
+- tv_count1, tv_count2);
+- pr_info("pcie ep: Data write speed:%ldMB/s.\n",
+- ((test_region_size/1024)
+- * MSEC_PER_SEC)
+- /(tv_count1));
+- pr_info("pcie ep: Data read speed:%ldMB/s.\n",
+- ((test_region_size/1024)
+- * MSEC_PER_SEC)
+- /(tv_count2));
+- } else {
+- pr_info("pcie ep: Data transfer is failed.\n");
+- }
+- }
+- } else {
+- ret = imx6_add_pcie_port(pp, pdev);
+- if (ret < 0)
+- goto err;
+-
+- platform_set_drvdata(pdev, imx6_pcie);
+-
+- /* Re-setup the iATU */
+- imx_pcie_regions_setup(&pdev->dev);
+- }
++ ret = imx6_add_pcie_port(pp, pdev);
++ if (ret < 0)
++ return ret;
+
+- register_syscore_ops(&pci_imx_syscore_ops);
++ platform_set_drvdata(pdev, imx6_pcie);
+ return 0;
+-
+-err:
+- return ret;
+ }
+
++static const struct of_device_id imx6_pcie_of_match[] = {
++ { .compatible = "fsl,imx6q-pcie", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, imx6_pcie_of_match);
++
+ static struct platform_driver imx6_pcie_driver = {
+ .driver = {
+ .name = "imx6q-pcie",
+diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
+index e7a82ee..6fa24d6 100644
+--- a/drivers/pci/host/pcie-designware.c
++++ b/drivers/pci/host/pcie-designware.c
+@@ -17,12 +17,55 @@
+ #include <linux/module.h>
+ #include <linux/msi.h>
+ #include <linux/of_address.h>
++#include <linux/of_pci.h>
+ #include <linux/pci.h>
+ #include <linux/pci_regs.h>
+ #include <linux/types.h>
+
+ #include "pcie-designware.h"
+
++/* Synopsis specific PCIE configuration registers */
++#define PCIE_PORT_LINK_CONTROL 0x710
++#define PORT_LINK_MODE_MASK (0x3f << 16)
++#define PORT_LINK_MODE_1_LANES (0x1 << 16)
++#define PORT_LINK_MODE_2_LANES (0x3 << 16)
++#define PORT_LINK_MODE_4_LANES (0x7 << 16)
++
++#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
++#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
++#define PORT_LOGIC_LINK_WIDTH_MASK (0x1ff << 8)
++#define PORT_LOGIC_LINK_WIDTH_1_LANES (0x1 << 8)
++#define PORT_LOGIC_LINK_WIDTH_2_LANES (0x2 << 8)
++#define PORT_LOGIC_LINK_WIDTH_4_LANES (0x4 << 8)
++
++#define PCIE_MSI_ADDR_LO 0x820
++#define PCIE_MSI_ADDR_HI 0x824
++#define PCIE_MSI_INTR0_ENABLE 0x828
++#define PCIE_MSI_INTR0_MASK 0x82C
++#define PCIE_MSI_INTR0_STATUS 0x830
++
++#define PCIE_ATU_VIEWPORT 0x900
++#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
++#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
++#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
++#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
++#define PCIE_ATU_CR1 0x904
++#define PCIE_ATU_TYPE_MEM (0x0 << 0)
++#define PCIE_ATU_TYPE_IO (0x2 << 0)
++#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
++#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
++#define PCIE_ATU_CR2 0x908
++#define PCIE_ATU_ENABLE (0x1 << 31)
++#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
++#define PCIE_ATU_LOWER_BASE 0x90C
++#define PCIE_ATU_UPPER_BASE 0x910
++#define PCIE_ATU_LIMIT 0x914
++#define PCIE_ATU_LOWER_TARGET 0x918
++#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
++#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
++#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
++#define PCIE_ATU_UPPER_TARGET 0x91C
++
+ static struct hw_pci dw_pci;
+
+ static unsigned long global_io_offset;
+@@ -32,7 +75,7 @@ static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+ return sys->private_data;
+ }
+
+-int cfg_read(void __iomem *addr, int where, int size, u32 *val)
++int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
+ {
+ *val = readl(addr);
+
+@@ -46,7 +89,7 @@ int cfg_read(void __iomem *addr, int where, int size, u32 *val)
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+-int cfg_write(void __iomem *addr, int where, int size, u32 val)
++int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val)
+ {
+ if (size == 4)
+ writel(val, addr);
+@@ -60,22 +103,20 @@ int cfg_write(void __iomem *addr, int where, int size, u32 val)
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+-static inline void dw_pcie_readl_rc(struct pcie_port *pp,
+- void __iomem *dbi_addr, u32 *val)
++static inline void dw_pcie_readl_rc(struct pcie_port *pp, u32 reg, u32 *val)
+ {
+ if (pp->ops->readl_rc)
+- pp->ops->readl_rc(pp, dbi_addr, val);
++ pp->ops->readl_rc(pp, pp->dbi_base + reg, val);
+ else
+- *val = readl(dbi_addr);
++ *val = readl(pp->dbi_base + reg);
+ }
+
+-static inline void dw_pcie_writel_rc(struct pcie_port *pp,
+- u32 val, void __iomem *dbi_addr)
++static inline void dw_pcie_writel_rc(struct pcie_port *pp, u32 val, u32 reg)
+ {
+ if (pp->ops->writel_rc)
+- pp->ops->writel_rc(pp, val, dbi_addr);
++ pp->ops->writel_rc(pp, val, pp->dbi_base + reg);
+ else
+- writel(val, dbi_addr);
++ writel(val, pp->dbi_base + reg);
+ }
+
+ static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
+@@ -86,7 +127,8 @@ static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
+ if (pp->ops->rd_own_conf)
+ ret = pp->ops->rd_own_conf(pp, where, size, val);
+ else
+- ret = cfg_read(pp->dbi_base + (where & ~0x3), where, size, val);
++ ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where,
++ size, val);
+
+ return ret;
+ }
+@@ -99,8 +141,8 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
+ if (pp->ops->wr_own_conf)
+ ret = pp->ops->wr_own_conf(pp, where, size, val);
+ else
+- ret = cfg_write(pp->dbi_base + (where & ~0x3), where, size,
+- val);
++ ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3), where,
++ size, val);
+
+ return ret;
+ }
+@@ -127,11 +169,13 @@ void dw_handle_msi_irq(struct pcie_port *pp)
+ while ((pos = find_next_bit(&val, 32, pos)) != 32) {
+ irq = irq_find_mapping(pp->irq_domain,
+ i * 32 + pos);
++ dw_pcie_wr_own_conf(pp,
++ PCIE_MSI_INTR0_STATUS + i * 12,
++ 4, 1 << pos);
+ generic_handle_irq(irq);
+ pos++;
+ }
+ }
+- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, val);
+ }
+ }
+
+@@ -157,7 +201,7 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
+ return -ENOSPC;
+ /*
+ * Check if this position is at correct offset.nvec is always a
+- * power of two. pos0 must be nvec bit alligned.
++ * power of two. pos0 must be nvec bit aligned.
+ */
+ if (pos % msgvec)
+ pos += msgvec - (pos % msgvec);
+@@ -169,6 +213,23 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
+ return 0;
+ }
+
++static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
++ unsigned int nvec, unsigned int pos)
++{
++ unsigned int i, res, bit, val;
++
++ for (i = 0; i < nvec; i++) {
++ irq_set_msi_desc_off(irq_base, i, NULL);
++ clear_bit(pos + i, pp->msi_irq_in_use);
++ /* Disable corresponding interrupt on MSI controller */
++ res = ((pos + i) / 32) * 12;
++ bit = (pos + i) % 32;
++ dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
++ val &= ~(1 << bit);
++ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
++ }
++}
++
+ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
+ {
+ int res, bit, irq, pos0, pos1, i;
+@@ -202,18 +263,25 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
+ if (!irq)
+ goto no_valid_irq;
+
+- i = 0;
+- while (i < no_irqs) {
++ /*
++ * irq_create_mapping (called from dw_pcie_host_init) pre-allocates
++ * descs so there is no need to allocate descs here. We can therefore
++ * assume that if irq_find_mapping above returns non-zero, then the
++ * descs are also successfully allocated.
++ */
++
++ for (i = 0; i < no_irqs; i++) {
++ if (irq_set_msi_desc_off(irq, i, desc) != 0) {
++ clear_irq_range(pp, irq, i, pos0);
++ goto no_valid_irq;
++ }
+ set_bit(pos0 + i, pp->msi_irq_in_use);
+- irq_alloc_descs((irq + i), (irq + i), 1, 0);
+- irq_set_msi_desc(irq + i, desc);
+ /*Enable corresponding interrupt in MSI interrupt controller */
+ res = ((pos0 + i) / 32) * 12;
+ bit = (pos0 + i) % 32;
+ dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+ val |= 1 << bit;
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+- i++;
+ }
+
+ *pos = pos0;
+@@ -226,7 +294,7 @@ no_valid_irq:
+
+ static void clear_irq(unsigned int irq)
+ {
+- int res, bit, val, pos;
++ unsigned int pos, nvec;
+ struct irq_desc *desc;
+ struct msi_desc *msi;
+ struct pcie_port *pp;
+@@ -241,18 +309,15 @@ static void clear_irq(unsigned int irq)
+ return;
+ }
+
++ /* undo what was done in assign_irq */
+ pos = data->hwirq;
++ nvec = 1 << msi->msi_attrib.multiple;
+
+- irq_free_desc(irq);
+-
+- clear_bit(pos, pp->msi_irq_in_use);
++ clear_irq_range(pp, irq, nvec, pos);
+
+- /* Disable corresponding interrupt on MSI interrupt controller */
+- res = (pos / 32) * 12;
+- bit = pos % 32;
+- dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+- val &= ~(1 << bit);
+- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
++ /* all irqs cleared; reset attributes */
++ msi->irq = 0;
++ msi->msi_attrib.multiple = 0;
+ }
+
+ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
+@@ -268,28 +333,23 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
+ return -EINVAL;
+ }
+
+- if (pp->quirks & DW_PCIE_QUIRK_NO_MSI_VEC) {
+- irq = assign_irq(1, desc, &pos);
+- set_irq_flags(irq, IRQF_VALID);
+- } else {
+- pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS,
+- &msg_ctr);
+- msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4;
+- if (msgvec == 0)
+- msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1;
+- if (msgvec > 5)
+- msgvec = 0;
+-
+- irq = assign_irq((1 << msgvec), desc, &pos);
+- if (irq < 0)
+- return irq;
+-
+- msg_ctr &= ~PCI_MSI_FLAGS_QSIZE;
+- msg_ctr |= msgvec << 4;
+- pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
+- msg_ctr);
+- desc->msi_attrib.multiple = msgvec;
+- }
++ pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS,
++ &msg_ctr);
++ msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4;
++ if (msgvec == 0)
++ msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1;
++ if (msgvec > 5)
++ msgvec = 0;
++
++ irq = assign_irq((1 << msgvec), desc, &pos);
++ if (irq < 0)
++ return irq;
++
++ /*
++ * write_msi_msg() will update PCI_MSI_FLAGS so there is
++ * no need to explicitly call pci_write_config_word().
++ */
++ desc->msi_attrib.multiple = msgvec;
+
+ msg.address_lo = virt_to_phys((void *)pp->msi_data);
+ msg.address_hi = 0x0;
+@@ -304,30 +364,9 @@ static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
+ clear_irq(irq);
+ }
+
+-static int dw_msi_check_device(struct msi_chip *chip, struct pci_dev *pdev,
+- int nvec, int type)
+-{
+- struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
+- u32 val;
+-
+- if (pp->quirks & DW_PCIE_QUIRK_MSI_SELF_EN) {
+- if ((type == PCI_CAP_ID_MSI) || (type == PCI_CAP_ID_MSIX)) {
+- /* Set MSI enable of RC here */
+- val = readl(pp->dbi_base + 0x50);
+- if ((val & (PCI_MSI_FLAGS_ENABLE << 16)) == 0) {
+- val |= PCI_MSI_FLAGS_ENABLE << 16;
+- writel(val, pp->dbi_base + 0x50);
+- }
+- }
+- }
+-
+- return 0;
+-}
+-
+ static struct msi_chip dw_pcie_msi_chip = {
+ .setup_irq = dw_msi_setup_irq,
+ .teardown_irq = dw_msi_teardown_irq,
+- .check_device = dw_msi_check_device,
+ };
+
+ int dw_pcie_link_up(struct pcie_port *pp)
+@@ -380,6 +419,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
+ + global_io_offset);
+ pp->config.io_size = resource_size(&pp->io);
+ pp->config.io_bus_addr = range.pci_addr;
++ pp->io_base = range.cpu_addr;
+ }
+ if (restype == IORESOURCE_MEM) {
+ of_pci_range_to_resource(&range, np, &pp->mem);
+@@ -405,7 +445,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
+
+ pp->cfg0_base = pp->cfg.start;
+ pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
+- pp->io_base = pp->io.start;
+ pp->mem_base = pp->mem.start;
+
+ pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
+@@ -465,42 +504,64 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
+
+ static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
+ {
+- u32 val;
+- void __iomem *dbi_base = pp->dbi_base;
+-
+ /* Program viewport 0 : OUTBOUND : CFG0 */
+- val = PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0;
+- dw_pcie_writel_rc(pp, val, dbi_base + PCIE_ATU_VIEWPORT);
+- dw_pcie_writel_rc(pp, pp->cfg0_base, dbi_base + PCIE_ATU_LOWER_BASE);
+- dw_pcie_writel_rc(pp, (pp->cfg0_base >> 32),
+- dbi_base + PCIE_ATU_UPPER_BASE);
++ dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
++ PCIE_ATU_VIEWPORT);
++ dw_pcie_writel_rc(pp, pp->cfg0_base, PCIE_ATU_LOWER_BASE);
++ dw_pcie_writel_rc(pp, (pp->cfg0_base >> 32), PCIE_ATU_UPPER_BASE);
+ dw_pcie_writel_rc(pp, pp->cfg0_base + pp->config.cfg0_size - 1,
+- dbi_base + PCIE_ATU_LIMIT);
+- dw_pcie_writel_rc(pp, busdev, dbi_base + PCIE_ATU_LOWER_TARGET);
+- dw_pcie_writel_rc(pp, 0, dbi_base + PCIE_ATU_UPPER_TARGET);
+- dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG0, dbi_base + PCIE_ATU_CR1);
+- val = PCIE_ATU_ENABLE;
+- dw_pcie_writel_rc(pp, val, dbi_base + PCIE_ATU_CR2);
++ PCIE_ATU_LIMIT);
++ dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
+...
[truncated message content] |