diff options
author | Luka Perkov <luka@openwrt.org> | 2013-09-20 01:59:32 +0000 |
---|---|---|
committer | Luka Perkov <luka@openwrt.org> | 2013-09-20 01:59:32 +0000 |
commit | 3f059f58dba3a1fb9e1e5035b437273f095040f6 (patch) | |
tree | 44c82a0cd9241d3fc277920c5887520abc1ca419 /target/linux/imx6/patches-3.10 | |
parent | 19bd25f4ecd20066554eb0c4df4cbff0213a9ae5 (diff) | |
download | mtk-20170518-3f059f58dba3a1fb9e1e5035b437273f095040f6.zip mtk-20170518-3f059f58dba3a1fb9e1e5035b437273f095040f6.tar.gz mtk-20170518-3f059f58dba3a1fb9e1e5035b437273f095040f6.tar.bz2 |
imx6: update PCIe driver
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
Signed-off-by: Luka Perkov <luka@openwrt.org>
SVN-Revision: 38080
Diffstat (limited to 'target/linux/imx6/patches-3.10')
7 files changed, 1021 insertions, 91 deletions
diff --git a/target/linux/imx6/patches-3.10/0009-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch b/target/linux/imx6/patches-3.10/0009-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch new file mode 100644 index 0000000..1ee8b4c --- /dev/null +++ b/target/linux/imx6/patches-3.10/0009-of-pci-Provide-support-for-parsing-PCI-DT-ranges-pro.patch @@ -0,0 +1,201 @@ +From: Andrew Murray <Andrew.Murray@arm.com> +Subject: [PATCH] of/pci: Provide support for parsing PCI DT ranges property + +This patch factors out common implementation patterns to reduce overall kernel +code and provide a means for host bridge drivers to directly obtain struct +resources from the DT's ranges property without relying on architecture specific +DT handling. This will make it easier to write archiecture independent host bridge +drivers and mitigate against further duplication of DT parsing code. + +This patch can be used in the following way: + + struct of_pci_range_parser parser; + struct of_pci_range range; + + if (of_pci_range_parser_init(&parser, np)) + ; //no ranges property + + for_each_of_pci_range(&parser, &range) { + + /* + directly access properties of the address range, e.g.: + range.pci_space, range.pci_addr, range.cpu_addr, + range.size, range.flags + + alternatively obtain a struct resource, e.g.: + struct resource res; + of_pci_range_to_resource(&range, np, &res); + */ + } + +Additionally the implementation takes care of adjacent ranges and merges them +into a single range (as was the case with powerpc and microblaze). + +Signed-off-by: Andrew Murray <Andrew.Murray@arm.com> +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Reviewed-by: Rob Herring <rob.herring@calxeda.com> +Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> +Tested-by: Linus Walleij <linus.walleij@linaro.org> +Tested-by: Jingoo Han <jg1.han@samsung.com> +Acked-by: Grant Likely <grant.likely@secretlab.ca> +Signed-off-by: Jason Cooper <jason@lakedaemon.net> +--- + drivers/of/address.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++ + include/linux/of_address.h | 48 +++++++++++++++++++++++++++++++++ + 2 files changed, 115 insertions(+) + +diff --git a/drivers/of/address.c b/drivers/of/address.c +index 04da786..fdd0636 100644 +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -227,6 +227,73 @@ int of_pci_address_to_resource(struct device_node *dev, int bar, + return __of_address_to_resource(dev, addrp, size, flags, NULL, r); + } + EXPORT_SYMBOL_GPL(of_pci_address_to_resource); ++ ++int of_pci_range_parser_init(struct of_pci_range_parser *parser, ++ struct device_node *node) ++{ ++ const int na = 3, ns = 2; ++ int rlen; ++ ++ parser->node = node; ++ parser->pna = of_n_addr_cells(node); ++ parser->np = parser->pna + na + ns; ++ ++ parser->range = of_get_property(node, "ranges", &rlen); ++ if (parser->range == NULL) ++ return -ENOENT; ++ ++ parser->end = parser->range + rlen / sizeof(__be32); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(of_pci_range_parser_init); ++ ++struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, ++ struct of_pci_range *range) ++{ ++ const int na = 3, ns = 2; ++ ++ if (!range) ++ return NULL; ++ ++ if (!parser->range || parser->range + parser->np > parser->end) ++ return NULL; ++ ++ range->pci_space = parser->range[0]; ++ range->flags = of_bus_pci_get_flags(parser->range); ++ range->pci_addr = of_read_number(parser->range + 1, ns); ++ range->cpu_addr = of_translate_address(parser->node, ++ parser->range + na); ++ range->size = of_read_number(parser->range + parser->pna + na, ns); ++ ++ parser->range += parser->np; ++ ++ /* Now consume following elements while they are contiguous */ ++ while (parser->range + parser->np <= parser->end) { ++ u32 flags, pci_space; ++ u64 pci_addr, cpu_addr, size; ++ ++ pci_space = be32_to_cpup(parser->range); ++ flags = of_bus_pci_get_flags(parser->range); ++ pci_addr = of_read_number(parser->range + 1, ns); ++ cpu_addr = of_translate_address(parser->node, ++ parser->range + na); ++ size = of_read_number(parser->range + parser->pna + na, ns); ++ ++ if (flags != range->flags) ++ break; ++ if (pci_addr != range->pci_addr + range->size || ++ cpu_addr != range->cpu_addr + range->size) ++ break; ++ ++ range->size += size; ++ parser->range += parser->np; ++ } ++ ++ return range; ++} ++EXPORT_SYMBOL_GPL(of_pci_range_parser_one); ++ + #endif /* CONFIG_PCI */ + + /* +diff --git a/include/linux/of_address.h b/include/linux/of_address.h +index 0506eb5..4c2e6f2 100644 +--- a/include/linux/of_address.h ++++ b/include/linux/of_address.h +@@ -4,6 +4,36 @@ + #include <linux/errno.h> + #include <linux/of.h> + ++struct of_pci_range_parser { ++ struct device_node *node; ++ const __be32 *range; ++ const __be32 *end; ++ int np; ++ int pna; ++}; ++ ++struct of_pci_range { ++ u32 pci_space; ++ u64 pci_addr; ++ u64 cpu_addr; ++ u64 size; ++ u32 flags; ++}; ++ ++#define for_each_of_pci_range(parser, range) \ ++ for (; of_pci_range_parser_one(parser, range);) ++ ++static inline void of_pci_range_to_resource(struct of_pci_range *range, ++ struct device_node *np, ++ struct resource *res) ++{ ++ res->flags = range->flags; ++ res->start = range->cpu_addr; ++ res->end = range->cpu_addr + range->size - 1; ++ res->parent = res->child = res->sibling = NULL; ++ res->name = np->full_name; ++} ++ + #ifdef CONFIG_OF_ADDRESS + extern u64 of_translate_address(struct device_node *np, const __be32 *addr); + extern bool of_can_translate_address(struct device_node *dev); +@@ -27,6 +57,11 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; } + #define pci_address_to_pio pci_address_to_pio + #endif + ++extern int of_pci_range_parser_init(struct of_pci_range_parser *parser, ++ struct device_node *node); ++extern struct of_pci_range *of_pci_range_parser_one( ++ struct of_pci_range_parser *parser, ++ struct of_pci_range *range); + #else /* CONFIG_OF_ADDRESS */ + #ifndef of_address_to_resource + static inline int of_address_to_resource(struct device_node *dev, int index, +@@ -53,6 +88,19 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index, + { + return NULL; + } ++ ++static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser, ++ struct device_node *node) ++{ ++ return -1; ++} ++ ++static inline struct of_pci_range *of_pci_range_parser_one( ++ struct of_pci_range_parser *parser, ++ struct of_pci_range *range) ++{ ++ return NULL; ++} + #endif /* CONFIG_OF_ADDRESS */ + + +-- +1.8.4 + diff --git a/target/linux/imx6/patches-3.10/0010-ARM-imx-Add-LVDS-general-purpose-clocks-to-i.MX6Q.patch b/target/linux/imx6/patches-3.10/0010-ARM-imx-Add-LVDS-general-purpose-clocks-to-i.MX6Q.patch new file mode 100644 index 0000000..9a5c162 --- /dev/null +++ b/target/linux/imx6/patches-3.10/0010-ARM-imx-Add-LVDS-general-purpose-clocks-to-i.MX6Q.patch @@ -0,0 +1,57 @@ +Subject: [v6,1/3] ARM: imx: Add LVDS general-purpose clocks to i.MX6Q +From: Sean Cross <xobs@kosagi.com> + +The i.MX6 has two general-purpose LVDS clocks that can be driven +from a variety of sources. This patch adds a mux and a gate for +both of these clocks. + +Signed-off-by: Sean Cross <xobs@kosagi.com> +--- + arch/arm/mach-imx/clk-imx6q.c | 20 +++++++++++++++++++- + 2 files changed, 23 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c +index 9181a24..d94be84 100644 +--- a/arch/arm/mach-imx/clk-imx6q.c ++++ b/arch/arm/mach-imx/clk-imx6q.c +@@ -205,6 +205,11 @@ static const char *vpu_axi_sels[] = { "a + static const char *cko1_sels[] = { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div", + "dummy", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0", + "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_post_div", }; ++static const char *lvds_sels[] = { ++ "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", ++ "pll4_audio", "pll5_video", "pll8_mlb", "enet_ref", ++ "pcie_ref", "sata_ref", ++}; + + enum mx6q_clks { + dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m, +@@ -238,7 +243,8 @@ enum mx6q_clks { + pll4_audio, pll5_video, pll8_mlb, pll7_usb_host, pll6_enet, ssi1_ipg, + ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5, + sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate, +- usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, clk_max ++ usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, ++ lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, clk_max + }; + + static struct clk *clk[clk_max]; +@@ -340,6 +347,18 @@ int __init mx6q_clocks_init(void) + base + 0xe0, 0, 2, 0, clk_enet_ref_table, + &imx_ccm_lock); + ++ clk[lvds1_sel] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); ++ clk[lvds2_sel] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); ++ ++ /* ++ * lvds1_gate and lvds2_gate are pseudo-gates. Both can be ++ * independently configured as clock inputs or outputs. We treat ++ * the "output_enable" bit as a gate, even though it's really just ++ * enabling clock output. ++ */ ++ clk[lvds1_gate] = imx_clk_gate("lvds1_gate", "dummy", base + 0x160, 10); ++ clk[lvds2_gate] = imx_clk_gate("lvds2_gate", "dummy", base + 0x160, 11); ++ + /* name parent_name reg idx */ + clk[pll2_pfd0_352m] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); + clk[pll2_pfd1_594m] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); diff --git a/target/linux/imx6/patches-3.10/0011-ARM-imx6q-Add-PCIe-bits-to-GPR-syscon-definition.patch b/target/linux/imx6/patches-3.10/0011-ARM-imx6q-Add-PCIe-bits-to-GPR-syscon-definition.patch new file mode 100644 index 0000000..0e65fb9 --- /dev/null +++ b/target/linux/imx6/patches-3.10/0011-ARM-imx6q-Add-PCIe-bits-to-GPR-syscon-definition.patch @@ -0,0 +1,37 @@ +Subject: [v6,2/3] ARM: imx6q: Add PCIe bits to GPR syscon definition +From: Sean Cross <xobs@kosagi.com> + +PCIe requires additional bits be defined for GPR8 and GPR12. + +Signed-off-by: Sean Cross <xobs@kosagi.com> +--- + include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h +index b6bdcd6..e00e9f3 100644 +--- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h ++++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h +@@ -241,6 +241,12 @@ + + #define IMX6Q_GPR5_L2_CLK_STOP BIT(8) + ++#define IMX6Q_GPR8_TX_SWING_LOW (0x7f << 25) ++#define IMX6Q_GPR8_TX_SWING_FULL (0x7f << 18) ++#define IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB (0x3f << 12) ++#define IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB (0x3f << 6) ++#define IMX6Q_GPR8_TX_DEEMPH_GEN1 (0x3f << 0) ++ + #define IMX6Q_GPR9_TZASC2_BYP BIT(1) + #define IMX6Q_GPR9_TZASC1_BYP BIT(0) + +@@ -273,7 +279,9 @@ + #define IMX6Q_GPR12_ARMP_AHB_CLK_EN BIT(26) + #define IMX6Q_GPR12_ARMP_ATB_CLK_EN BIT(25) + #define IMX6Q_GPR12_ARMP_APB_CLK_EN BIT(24) ++#define IMX6Q_GPR12_DEVICE_TYPE (0xf << 12) + #define IMX6Q_GPR12_PCIE_CTL_2 BIT(10) ++#define IMX6Q_GPR12_LOS_LEVEL (0x1f << 4) + + #define IMX6Q_GPR13_SDMA_STOP_REQ BIT(30) + #define IMX6Q_GPR13_CAN2_STOP_REQ BIT(29) diff --git a/target/linux/imx6/patches-3.10/0012-PCI-imx6-Add-support-for-i.MX6-PCIe-controller.patch b/target/linux/imx6/patches-3.10/0012-PCI-imx6-Add-support-for-i.MX6-PCIe-controller.patch new file mode 100644 index 0000000..029245a --- /dev/null +++ b/target/linux/imx6/patches-3.10/0012-PCI-imx6-Add-support-for-i.MX6-PCIe-controller.patch @@ -0,0 +1,674 @@ +Subject: [v6,3/3] PCI: imx6: Add support for i.MX6 PCIe controller +From: Sean Cross <xobs@kosagi.com> + +Add support for the PCIe port present on the i.MX6 family of controllers. +These use the Synopsis Designware core tied to their own PHY. + +Signed-off-by: Sean Cross <xobs@kosagi.com> +Acked-by: Bjorn Helgaas <bhelgaas@google.com> +Acked-by: Sascha Hauer <s.hauer@pengutronix.de> +--- + arch/arm/boot/dts/imx6qdl.dtsi | 16 + + arch/arm/mach-imx/Kconfig | 2 + + arch/arm/mach-imx/clk-imx6q.c | 4 + + drivers/pci/host/Kconfig | 6 + + drivers/pci/host/Makefile | 1 + + drivers/pci/host/pci-imx6.c | 576 ++++++++++++++++++++ + 7 files changed, 611 insertions(+), 1 deletion(-) + create mode 100644 drivers/pci/host/pci-imx6.c + +diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi +index ccd55c2..125202e 100644 +--- a/arch/arm/boot/dts/imx6qdl.dtsi ++++ b/arch/arm/boot/dts/imx6qdl.dtsi +@@ -116,6 +116,22 @@ + arm,data-latency = <4 2 3>; + }; + ++ pcie: pcie@0x01000000 { ++ compatible = "fsl,imx6q-pcie", "snps,dw-pcie"; ++ reg = <0x01ffc000 0x4000>; /* DBI */ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000 /* configuration space */ ++ 0x81000000 0 0 0x01f80000 0 0x00010000 /* downstream I/O */ ++ 0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */ ++ num-lanes = <1>; ++ interrupts = <0 123 0x04>; ++ clocks = <&clks 189>, <&clks 187>, <&clks 205>, <&clks 144>; ++ clock-names = "pcie_ref_125m", "sata_ref_100m", "lvds_gate", "pcie_axi"; ++ status = "disabled"; ++ }; ++ + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <0 94 0x04>; +diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig +index 29a8af6..e6ac281 100644 +--- a/arch/arm/mach-imx/Kconfig ++++ b/arch/arm/mach-imx/Kconfig +@@ -801,6 +801,8 @@ config SOC_IMX6Q + select HAVE_IMX_SRC + select HAVE_SMP + select MFD_SYSCON ++ select MIGHT_HAVE_PCI ++ select PCI_DOMAINS if PCI + select PINCTRL + select PINCTRL_IMX6Q + select PL310_ERRATA_588369 if CACHE_PL310 +diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c +index d94be84..6956995 100644 +--- a/arch/arm/mach-imx/clk-imx6q.c ++++ b/arch/arm/mach-imx/clk-imx6q.c +@@ -621,6 +621,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) + if (ret) + pr_warn("failed to set up CLKO: %d\n", ret); + ++ /* All existing boards with PCIe use LVDS1 */ ++ if (IS_ENABLED(CONFIG_PCI_IMX6)) ++ clk_set_parent(clk[lvds1_sel], clk[sata_ref]); ++ + /* Set initial power mode */ + imx6q_set_lpm(WAIT_CLOCKED); + +--- /dev/null ++++ b/drivers/pci/host/Kconfig +@@ -0,0 +1,13 @@ ++menu "PCI host controller drivers" ++ depends on PCI ++ ++config PCIE_DW ++ bool ++ ++config PCI_IMX6 ++ bool "Freescale i.MX6 PCIe controller" ++ depends on SOC_IMX6Q ++ select PCIEPORTBUS ++ select PCIE_DW ++ ++endmenu +--- /dev/null ++++ b/drivers/pci/host/Makefile +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_PCIE_DW) += pcie-designware.o ++obj-$(CONFIG_PCI_IMX6) += pci-imx6.o +--- /dev/null ++++ b/drivers/pci/host/pci-imx6.c +@@ -0,0 +1,576 @@ ++/* ++ * PCIe host controller driver for Freescale i.MX6 SoCs ++ * ++ * Copyright (C) 2013 Kosagi ++ * http://www.kosagi.com ++ * ++ * Author: Sean Cross <xobs@kosagi.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/gpio.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/pci.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/resource.h> ++#include <linux/signal.h> ++#include <linux/types.h> ++ ++#include "pcie-designware.h" ++ ++#define to_imx6_pcie(x) container_of(x, struct imx6_pcie, pp) ++ ++struct imx6_pcie { ++ int reset_gpio; ++ int power_on_gpio; ++ int wake_up_gpio; ++ int disable_gpio; ++ struct clk *lvds_gate; ++ struct clk *sata_ref_100m; ++ struct clk *pcie_ref_125m; ++ struct clk *pcie_axi; ++ struct pcie_port pp; ++ struct regmap *iomuxc_gpr; ++ void __iomem *mem_base; ++}; ++ ++/* 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_CTRL (PL_OFFSET + 0x114) ++#define PCIE_PHY_CTRL_DATA_LOC 0 ++#define PCIE_PHY_CTRL_CAP_ADR_LOC 16 ++#define PCIE_PHY_CTRL_CAP_DAT_LOC 17 ++#define PCIE_PHY_CTRL_WR_LOC 18 ++#define PCIE_PHY_CTRL_RD_LOC 19 ++ ++#define PCIE_PHY_STAT (PL_OFFSET + 0x110) ++#define PCIE_PHY_STAT_ACK_LOC 16 ++ ++/* PHY registers (not memory-mapped) */ ++#define PCIE_PHY_RX_ASIC_OUT 0x100D ++ ++#define PHY_RX_OVRD_IN_LO 0x1005 ++#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5) ++#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3) ++ ++static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val) ++{ ++ u32 val; ++ u32 max_iterations = 10; ++ u32 wait_counter = 0; ++ ++ do { ++ val = readl(dbi_base + PCIE_PHY_STAT); ++ val = (val >> PCIE_PHY_STAT_ACK_LOC) & 0x1; ++ wait_counter++; ++ ++ if (val == exp_val) ++ return 0; ++ ++ udelay(1); ++ } while ((wait_counter < max_iterations) && (val != exp_val)); ++ ++ return -ETIMEDOUT; ++} ++ ++static int pcie_phy_wait_ack(void __iomem *dbi_base, int addr) ++{ ++ u32 val; ++ int ret; ++ ++ val = addr << PCIE_PHY_CTRL_DATA_LOC; ++ writel(val, dbi_base + PCIE_PHY_CTRL); ++ ++ val |= (0x1 << PCIE_PHY_CTRL_CAP_ADR_LOC); ++ writel(val, dbi_base + PCIE_PHY_CTRL); ++ ++ ret = pcie_phy_poll_ack(dbi_base, 1); ++ if (ret) ++ return ret; ++ ++ val = addr << PCIE_PHY_CTRL_DATA_LOC; ++ writel(val, dbi_base + PCIE_PHY_CTRL); ++ ++ ret = pcie_phy_poll_ack(dbi_base, 0); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++/* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */ ++static int pcie_phy_read(void __iomem *dbi_base, int addr , int *data) ++{ ++ u32 val, phy_ctl; ++ int ret; ++ ++ ret = pcie_phy_wait_ack(dbi_base, addr); ++ if (ret) ++ return ret; ++ ++ /* assert Read signal */ ++ phy_ctl = 0x1 << PCIE_PHY_CTRL_RD_LOC; ++ writel(phy_ctl, dbi_base + PCIE_PHY_CTRL); ++ ++ ret = pcie_phy_poll_ack(dbi_base, 1); ++ if (ret) ++ return ret; ++ ++ val = readl(dbi_base + PCIE_PHY_STAT); ++ *data = val & 0xffff; ++ ++ /* deassert Read signal */ ++ writel(0x00, dbi_base + PCIE_PHY_CTRL); ++ ++ ret = pcie_phy_poll_ack(dbi_base, 0); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int pcie_phy_write(void __iomem *dbi_base, int addr, int data) ++{ ++ u32 var; ++ int ret; ++ ++ /* write addr */ ++ /* cap addr */ ++ ret = pcie_phy_wait_ack(dbi_base, addr); ++ if (ret) ++ return ret; ++ ++ var = data << PCIE_PHY_CTRL_DATA_LOC; ++ writel(var, dbi_base + PCIE_PHY_CTRL); ++ ++ /* capture data */ ++ var |= (0x1 << PCIE_PHY_CTRL_CAP_DAT_LOC); ++ writel(var, dbi_base + PCIE_PHY_CTRL); ++ ++ ret = pcie_phy_poll_ack(dbi_base, 1); ++ if (ret) ++ return ret; ++ ++ /* deassert cap data */ ++ var = data << PCIE_PHY_CTRL_DATA_LOC; ++ writel(var, dbi_base + PCIE_PHY_CTRL); ++ ++ /* wait for ack de-assetion */ ++ ret = pcie_phy_poll_ack(dbi_base, 0); ++ if (ret) ++ return ret; ++ ++ /* assert wr signal */ ++ var = 0x1 << PCIE_PHY_CTRL_WR_LOC; ++ writel(var, dbi_base + PCIE_PHY_CTRL); ++ ++ /* wait for ack */ ++ ret = pcie_phy_poll_ack(dbi_base, 1); ++ if (ret) ++ return ret; ++ ++ /* deassert wr signal */ ++ var = data << PCIE_PHY_CTRL_DATA_LOC; ++ writel(var, dbi_base + PCIE_PHY_CTRL); ++ ++ /* wait for ack de-assetion */ ++ ret = pcie_phy_poll_ack(dbi_base, 0); ++ if (ret) ++ return ret; ++ ++ writel(0x0, dbi_base + PCIE_PHY_CTRL); ++ ++ return 0; ++} ++ ++/* Added for PCI abort handling */ ++static int imx6q_pcie_abort_handler(unsigned long addr, ++ unsigned int fsr, struct pt_regs *regs) ++{ ++ /* ++ * If it was an imprecise abort, then we need to correct the ++ * return address to be _after_ the instruction. ++ */ ++ if (fsr & (1 << 10)) ++ regs->ARM_pc += 4; ++ 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_GPR12, ++ IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); ++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, ++ IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16); ++ ++ gpio_set_value(imx6_pcie->reset_gpio, 0); ++ msleep(100); ++ gpio_set_value(imx6_pcie->reset_gpio, 1); ++ ++ return 0; ++} ++ ++static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) ++{ ++ struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); ++ int ret; ++ ++ if (gpio_is_valid(imx6_pcie->power_on_gpio)) ++ gpio_set_value(imx6_pcie->power_on_gpio, 1); ++ ++ 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); ++ ++ 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); ++ if (ret) { ++ dev_err(pp->dev, "unable to enable pcie_ref_125m\n"); ++ goto err_pcie_ref; ++ } ++ ++ 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); ++ if (ret) { ++ dev_err(pp->dev, "unable to enable pcie_axi\n"); ++ goto err_pcie_axi; ++ } ++ ++ /* allow the clocks to stabilize */ ++ usleep_range(200, 500); ++ ++ return 0; ++ ++err_pcie_axi: ++ clk_disable_unprepare(imx6_pcie->lvds_gate); ++err_lvds_gate: ++ clk_disable_unprepare(imx6_pcie->pcie_ref_125m); ++err_pcie_ref: ++ clk_disable_unprepare(imx6_pcie->sata_ref_100m); ++err_sata_ref: ++ return ret; ++ ++} ++ ++static void imx6_pcie_init_phy(struct pcie_port *pp) ++{ ++ struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); ++ ++ 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 */ ++ 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); ++ ++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, ++ IMX6Q_GPR8_TX_DEEMPH_GEN1, 0 << 0); ++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, ++ IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB, 0 << 6); ++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, ++ IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB, 20 << 12); ++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, ++ IMX6Q_GPR8_TX_SWING_FULL, 127 << 18); ++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, ++ IMX6Q_GPR8_TX_SWING_LOW, 127 << 25); ++} ++ ++static void imx6_pcie_host_init(struct pcie_port *pp) ++{ ++ int count = 0; ++ struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); ++ ++ imx6_pcie_assert_core_reset(pp); ++ ++ imx6_pcie_init_phy(pp); ++ ++ imx6_pcie_deassert_core_reset(pp); ++ ++ dw_pcie_setup_rc(pp); ++ ++ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, ++ IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); ++ ++ while (!dw_pcie_link_up(pp)) { ++ usleep_range(100, 1000); ++ count++; ++ if (count >= 10) { ++ 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)); ++ break; ++ } ++ } ++ ++ return; ++} ++ ++static int imx6_pcie_link_up(struct pcie_port *pp) ++{ ++ u32 rc, ltssm, rx_valid, temp; ++ ++ /* 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; ++ ++ /* ++ * 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) ++ * && (PHY/rx_valid==0) then pulse PHY/rx_reset. Transition ++ * 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; ++ ++ if (rx_valid & 0x01) ++ return 0; ++ ++ if (ltssm != 0x0d) ++ return 0; ++ ++ dev_err(pp->dev, ++ "transition to gen2 is stuck, reset PHY!\n"); ++ ++ 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); ++ ++ return 0; ++} ++ ++static struct pcie_host_ops imx6_pcie_host_ops = { ++ .link_up = imx6_pcie_link_up, ++ .host_init = imx6_pcie_host_init, ++}; ++ ++static int imx6_add_pcie_port(struct pcie_port *pp, ++ struct platform_device *pdev) ++{ ++ int ret; ++ ++ pp->irq = platform_get_irq(pdev, 0); ++ if (!pp->irq) { ++ dev_err(&pdev->dev, "failed to get irq\n"); ++ return -ENODEV; ++ } ++ ++ pp->root_bus_nr = -1; ++ pp->ops = &imx6_pcie_host_ops; ++ ++ spin_lock_init(&pp->conf_lock); ++ ret = dw_pcie_host_init(pp); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to initialize host\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int __init imx6_pcie_probe(struct platform_device *pdev) ++{ ++ struct imx6_pcie *imx6_pcie; ++ struct pcie_port *pp; ++ struct device_node *np = pdev->dev.of_node; ++ struct resource *dbi_base; ++ int ret; ++ ++ imx6_pcie = devm_kzalloc(&pdev->dev, sizeof(*imx6_pcie), GFP_KERNEL); ++ if (!imx6_pcie) ++ return -ENOMEM; ++ ++ pp = &imx6_pcie->pp; ++ pp->dev = &pdev->dev; ++ ++ /* 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)) { ++ dev_err(&pdev->dev, "unable to remap dbi_base\n"); ++ ret = PTR_ERR(pp->dbi_base); ++ goto err; ++ } ++ ++ /* Fetch GPIOs */ ++ imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); ++ if (!gpio_is_valid(imx6_pcie->reset_gpio)) { ++ dev_err(&pdev->dev, "no reset-gpio defined\n"); ++ ret = -ENODEV; ++ } ++ 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; ++ } ++ ++ imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0); ++ if (gpio_is_valid(imx6_pcie->power_on_gpio)) { ++ ret = devm_gpio_request_one(&pdev->dev, ++ imx6_pcie->power_on_gpio, ++ GPIOF_OUT_INIT_LOW, ++ "PCIe power enable"); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to get power-on gpio\n"); ++ goto err; ++ } ++ } ++ ++ imx6_pcie->wake_up_gpio = of_get_named_gpio(np, "wake-up-gpio", 0); ++ if (gpio_is_valid(imx6_pcie->wake_up_gpio)) { ++ ret = devm_gpio_request_one(&pdev->dev, ++ imx6_pcie->wake_up_gpio, ++ GPIOF_IN, ++ "PCIe wake up"); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to get wake-up gpio\n"); ++ goto err; ++ } ++ } ++ ++ imx6_pcie->disable_gpio = of_get_named_gpio(np, "disable-gpio", 0); ++ if (gpio_is_valid(imx6_pcie->disable_gpio)) { ++ ret = devm_gpio_request_one(&pdev->dev, ++ imx6_pcie->disable_gpio, ++ GPIOF_OUT_INIT_HIGH, ++ "PCIe disable endpoint"); ++ if (ret) { ++ dev_err(&pdev->dev, "unable to get disable-ep gpio\n"); ++ goto err; ++ } ++ } ++ ++ /* Fetch clocks */ ++ imx6_pcie->lvds_gate = clk_get(&pdev->dev, "lvds_gate"); ++ 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; ++ } ++ ++ imx6_pcie->sata_ref_100m = 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; ++ } ++ ++ imx6_pcie->pcie_ref_125m = 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; ++ } ++ ++ imx6_pcie->pcie_axi = 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; ++ } ++ ++ /* 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; ++ } ++ ++ ret = imx6_add_pcie_port(pp, pdev); ++ if (ret < 0) ++ goto err; ++ ++ 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", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(imx6_pcie_of_match), ++ }, ++}; ++ ++/* Freescale PCIe driver does not allow module unload */ ++ ++static int __init imx6_init(void) ++{ ++ return platform_driver_probe(&imx6_pcie_driver, imx6_pcie_probe); ++} ++module_init(imx6_init); ++ ++MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); ++MODULE_DESCRIPTION("Freescale i.MX6 PCIe host controller driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/imx6/patches-3.10/010-pcie-backport-fixes.patch b/target/linux/imx6/patches-3.10/010-pcie-backport-fixes.patch new file mode 100644 index 0000000..aef6b05 --- /dev/null +++ b/target/linux/imx6/patches-3.10/010-pcie-backport-fixes.patch @@ -0,0 +1,17 @@ +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -125,3 +125,5 @@ config PCI_IOAPIC + config PCI_LABEL + def_bool y if (DMI || ACPI) + select NLS ++ ++source "drivers/pci/host/Kconfig" +--- a/drivers/pci/Makefile ++++ b/drivers/pci/Makefile +@@ -67,3 +67,6 @@ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen + obj-$(CONFIG_OF) += of.o + + ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG ++ ++# PCI host controller drivers ++obj-y += host/ diff --git a/target/linux/imx6/patches-3.10/011-pci-tweaks.patch b/target/linux/imx6/patches-3.10/011-pci-tweaks.patch new file mode 100644 index 0000000..3e0dcca --- /dev/null +++ b/target/linux/imx6/patches-3.10/011-pci-tweaks.patch @@ -0,0 +1,35 @@ +--- a/arch/arm/boot/dts/imx6qdl.dtsi ++++ b/arch/arm/boot/dts/imx6qdl.dtsi +@@ -119,7 +119,7 @@ + 0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */ + num-lanes = <1>; + interrupts = <0 123 0x04>; +- clocks = <&clks 189>, <&clks 187>, <&clks 205>, <&clks 144>; ++ clocks = <&clks 189>, <&clks 187>, <&clks 198>, <&clks 144>; + clock-names = "pcie_ref_125m", "sata_ref_100m", "lvds_gate", "pcie_axi"; + status = "disabled"; + }; +--- a/drivers/pci/host/pci-imx6.c ++++ b/drivers/pci/host/pci-imx6.c +@@ -200,12 +200,6 @@ + static int imx6q_pcie_abort_handler(unsigned long addr, + unsigned int fsr, struct pt_regs *regs) + { +- /* +- * If it was an imprecise abort, then we need to correct the +- * return address to be _after_ the instruction. +- */ +- if (fsr & (1 << 10)) +- regs->ARM_pc += 4; + return 0; + } + +@@ -322,7 +316,7 @@ + IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); + + while (!dw_pcie_link_up(pp)) { +- usleep_range(100, 1000); ++ usleep_range(2000, 3000); + count++; + if (count >= 10) { + dev_err(pp->dev, "phy link never came up\n"); diff --git a/target/linux/imx6/patches-3.10/200-imx6_pcie.patch b/target/linux/imx6/patches-3.10/200-imx6_pcie.patch deleted file mode 100644 index 534ce9e..0000000 --- a/target/linux/imx6/patches-3.10/200-imx6_pcie.patch +++ /dev/null @@ -1,91 +0,0 @@ ---- a/arch/arm/boot/dts/imx6q.dtsi -+++ b/arch/arm/boot/dts/imx6q.dtsi -@@ -391,6 +391,15 @@ - status = "disabled"; - }; - -+ pcie: pcie@01ffc000 { -+ #crtc-cells = <1>; -+ compatible = "fsl,imx6q-pcie", "fsl,pcie"; -+ reg = <0x01ffc000 0x4000>; -+ clocks = <&clks 144>, <&clks 189>; -+ clock-names = "pcie_axi", "pcie_ref_125m"; -+ status = "disabled"; -+ }; -+ - ipu2: ipu@02800000 { - #crtc-cells = <1>; - compatible = "fsl,imx6q-ipu"; ---- a/arch/arm/mach-imx/Kconfig -+++ b/arch/arm/mach-imx/Kconfig -@@ -790,6 +790,8 @@ config SOC_IMX6Q - bool "i.MX6 Quad/DualLite support" - select ARCH_HAS_CPUFREQ - select ARCH_HAS_OPP -+ select ARCH_HAS_IMX_PCIE -+ select ARCH_SUPPORTS_MSI - select ARM_CPU_SUSPEND if PM - select ARM_ERRATA_754322 - select ARM_ERRATA_764369 if SMP -@@ -816,6 +818,10 @@ config SOC_IMX6Q - help - This enables support for Freescale i.MX6 Quad processor. - -+config IMX_PCIE -+ bool "PCI Express support" -+ select PCI -+ - endif - - source "arch/arm/mach-imx/devices/Kconfig" ---- a/arch/arm/mach-imx/Makefile -+++ b/arch/arm/mach-imx/Makefile -@@ -98,6 +98,8 @@ AFLAGS_headsmp.o :=-Wa,-march=armv7-a - obj-$(CONFIG_SMP) += headsmp.o platsmp.o - obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o - obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o -+obj-$(CONFIG_IMX_PCIE) += pcie.o -+obj-$(CONFIG_PCI_MSI) += msi.o - - ifeq ($(CONFIG_PM),y) - obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o ---- a/arch/arm/mach-imx/clk-imx6q.c -+++ b/arch/arm/mach-imx/clk-imx6q.c -@@ -547,6 +547,12 @@ int __init mx6q_clocks_init(void) - clk_register_clkdev(clk[ahb], "ahb", NULL); - clk_register_clkdev(clk[cko1], "cko1", NULL); - clk_register_clkdev(clk[arm], NULL, "cpu0"); -+ clk_register_clkdev(clk[pcie_axi_sel], "pcie_axi_sel", NULL); -+ clk_register_clkdev(clk[axi], "axi", NULL); -+ clk_register_clkdev(clk[pll6_enet], "pll6_enet", NULL); -+ clk_register_clkdev(clk[pcie_ref], "pcie_ref", NULL); -+ clk_register_clkdev(clk[pcie_ref_125m], "pcie_ref_125m", NULL); -+ clk_register_clkdev(clk[pcie_axi], "pcie_axi", NULL); - - if (imx6q_revision() != IMX_CHIP_REVISION_1_0) { - clk_set_parent(clk[ldb_di0_sel], clk[pll5_video_div]); ---- a/arch/arm/mach-imx/mxc.h -+++ b/arch/arm/mach-imx/mxc.h -@@ -151,6 +151,10 @@ extern unsigned int __mxc_cpu_type; - # define cpu_is_mx53() (0) - #endif - -+#ifdef CONFIG_SOC_IMX6Q -+# define mxc_cpu_type __mxc_cpu_type -+#endif -+ - #ifndef __ASSEMBLY__ - static inline bool cpu_is_imx6dl(void) - { ---- a/arch/arm/include/asm/io.h -+++ b/arch/arm/include/asm/io.h -@@ -178,6 +178,9 @@ extern int pci_ioremap_io(unsigned int o - */ - #ifdef CONFIG_NEED_MACH_IO_H - #include <mach/io.h> -+#elif defined(CONFIG_SOC_IMX6Q) && defined(CONFIG_IMX_PCIE) -+#define IO_SPACE_LIMIT ((resource_size_t)0xffffffff) -+#define __io(a) __typesafe_io((a) & IO_SPACE_LIMIT) - #elif defined(CONFIG_PCI) - #define IO_SPACE_LIMIT ((resource_size_t)0xfffff) - #define __io(a) __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT)) |