PCI support for IMX6

Pavel Machek pavel at ucw.cz
Sat Mar 30 07:37:03 EDT 2013


Hi!

> What is the state of PCI support for IMX6? I have board that has
> e1000e connected via PCI, and I'd like to get network to work.
> 
> I'm currently trying to port PCI support from 3.0, but it does not
> look exactly easy.

This is what I ended up with. Currently it is unable to turn on clock
for PCI, thus it hangs. If someone has any ideas, let me know...
									Pavel

diff --git a/arch/arm/boot/dts/imx6q-sbc6x.dts b/arch/arm/boot/dts/imx6q-sbc6x.dts
index 9549b6f..6066625 100644
--- a/arch/arm/boot/dts/imx6q-sbc6x.dts
+++ b/arch/arm/boot/dts/imx6q-sbc6x.dts
@@ -23,4 +23,10 @@
 	status = "okay";
 };
 
+&fec {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet_1>;
+	phy-mode = "rgmii";
+	status = "okay";
+};
 
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 4c9c6f9..75ef3b0 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -7,6 +7,7 @@ config ARCH_MXC
 	select CLKSRC_MMIO
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_IRQ_CHIP
+	select MIGHT_HAVE_PCI
 	select MULTI_IRQ_HANDLER
 	select SPARSE_IRQ
 	select USE_OF
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index c4ce090..b8b70c7 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -112,4 +112,6 @@ obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd51-baseboard.o
 obj-$(CONFIG_MACH_IMX51_DT) += imx51-dt.o
 obj-$(CONFIG_SOC_IMX53) += mach-imx53.o
 
+obj-$(CONFIG_PCI) += pcie.o
+
 obj-y += devices/
diff --git a/arch/arm/mach-imx/crm_regs.h b/arch/arm/mach-imx/crm_regs.h
new file mode 100644
index 0000000..417894b
--- /dev/null
+++ b/arch/arm/mach-imx/crm_regs.h
@@ -0,0 +1,542 @@
+/*
+ * Copyright 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __ARCH_ARM_MACH_MX6_CRM_REGS_H__
+#define __ARCH_ARM_MACH_MX6_CRM_REGS_H__
+
+/* IOMUXC */
+#define MXC_IOMUXC_BASE			MX6_IO_ADDRESS(MX6Q_IOMUXC_BASE_ADDR)
+#define IOMUXC_GPR0			(iomux_base + 0x00)
+#define IOMUXC_GPR1			(iomux_base + 0x04)
+#define IOMUXC_GPR2			(iomux_base + 0x08)
+#define IOMUXC_GPR3			(iomux_base + 0x0C)
+#define IOMUXC_GPR4			(iomux_base + 0x10)
+#define IOMUXC_GPR5			(iomux_base + 0x14)
+#define IOMUXC_GPR6			(iomux_base + 0x18)
+#define IOMUXC_GPR7			(iomux_base + 0x1C)
+#define IOMUXC_GPR8			(iomux_base + 0x20)
+#define IOMUXC_GPR9			(iomux_base + 0x24)
+#define IOMUXC_GPR10			(iomux_base + 0x28)
+#define IOMUXC_GPR11			(iomux_base + 0x2C)
+#define IOMUXC_GPR12			(iomux_base + 0x30)
+#define IOMUXC_GPR13			(iomux_base + 0x34)
+
+#define IOMUXC_GPR3_OCRAM_CTL_EN	(0xf << 21)
+#define IOMUXC_GPR4_VDOA_CACHE_EN	(0xf << 28)
+#define IOMUXC_GPR4_VPU_CACHE_EN	(0xcc)
+#define IOMUXC_GPR4_IPU_CACHE_EN	(0x3)
+#define IOMUXC_GPR6_IPU1_QOS		(0x007f007f)
+#define IOMUXC_GPR7_IPU2_QOS		(0x007f007f)
+
+/* MMDC */
+#define MXC_MMDC_P0_BASE		MX6_IO_ADDRESS(MMDC_P0_BASE_ADDR)
+#define MMDC_MDMISC_OFFSET		(MXC_MMDC_P0_BASE + 0x18)
+#define MMDC_MDMISC_DDR_TYPE_MASK	(0x3 << 3)
+#define MMDC_MDMISC_DDR_TYPE_OFFSET	(3)
+
+/* PLLs */
+#define MXC_PLL_BASE			MX6_IO_ADDRESS(ANATOP_BASE_ADDR)
+#define PLL1_SYS_BASE_ADDR		(MXC_PLL_BASE + 0x0)
+#define PLL2_528_BASE_ADDR		(MXC_PLL_BASE + 0x30)
+#define PLL3_480_USB1_BASE_ADDR		(MXC_PLL_BASE + 0x10)
+#define PLL4_AUDIO_BASE_ADDR		(MXC_PLL_BASE + 0x70)
+#define PLL5_VIDEO_BASE_ADDR		(MXC_PLL_BASE + 0xA0)
+#define PLL6_MLB_BASE_ADDR		(MXC_PLL_BASE + 0xD0)
+#define PLL7_480_USB2_BASE_ADDR		(MXC_PLL_BASE + 0x20)
+#define PLL8_ENET_BASE_ADDR		(MXC_PLL_BASE + 0xE0)
+#define PFD_480_BASE_ADDR		(MXC_PLL_BASE + 0xF0)
+#define PFD_528_BASE_ADDR		(MXC_PLL_BASE + 0x100)
+#define ANADIG_REG_CORE		(MXC_PLL_BASE + 0x140)
+#define ANADIG_MISC1_REG		(MXC_PLL_BASE + 0x160)
+#define ANATOP_LVDS_CLK1_SRC_SATA	0xB
+#define ANATOP_LVDS_CLK1_OBEN_MASK	0x400
+#define ANATOP_LVDS_CLK1_IBEN_MASK	0x1000
+#define ANATOP_LVDS_CLK2_OBEN_MASK  0x800
+#define ANATOP_LVDS_CLK2_IBEN_MASK  0x2000
+#define ANA_MISC2_BASE_ADDR		(MXC_PLL_BASE + 0x170)
+
+#define PLL_SETREG_OFFSET		0x4
+#define PLL_CLRREG_OFFSET		0x8
+#define PLL_TOGGLE_OFFSET		0x0C
+#define PLL_NUM_DIV_OFFSET		0x10
+#define PLL_DENOM_DIV_OFFSET		0x20
+#define PLL_528_SS_OFFSET		0x10
+#define PLL_528_NUM_DIV_OFFSET		0x20
+#define PLL_528_DENOM_DIV_OFFSET	0x30
+
+/* Common PLL register bit defines. */
+#define ANADIG_PLL_LOCK				(1 << 31)
+#define ANADIG_PLL_BYPASS			(1 << 16)
+#define ANADIG_PLL_BYPASS_CLK_SRC_MASK		(0x3 << 14)
+#define ANADIG_PLL_BYPASS_CLK_SRC_OFFSET	(14)
+#define ANADIG_PLL_ENABLE			(1 << 13)
+#define ANADIG_PLL_POWER_DOWN			(1 << 12)
+#define ANADIG_PLL_HOLD_RING_OFF		(1 << 11)
+
+/* PLL1_SYS defines */
+#define ANADIG_PLL_SYS_DIV_SELECT_MASK		(0x7F)
+#define ANADIG_PLL_SYS_DIV_SELECT_OFFSET	(0)
+#define ANADIG_PLL_SYS_BYPASS_MASK		(0x10000)
+#define ANADIG_PLL_SYS_BYPASS_OFFSET	(16)
+
+/* PLL2_528 defines */
+#define ANADIG_PLL_528_DIV_SELECT		(1)
+
+/* PLL3_480 defines. */
+#define ANADIG_PLL_480_EN_USB_CLKS		(1 << 6)
+#define ANADIG_PLL_480_DIV_SELECT_MASK		(0x3)
+#define ANADIG_PLL_480_DIV_SELECT_OFFSET	(0)
+
+/* PLL4_AUDIO PLL5_VIDEO defines. */
+#define ANADIG_PLL_AV_DIV_SELECT_MASK		(0x7F)
+#define ANADIG_PLL_AV_DIV_SELECT_OFFSET		(0)
+#define ANADIG_PLL_AV_TEST_DIV_SEL_MASK		(0x180000)
+#define ANADIG_PLL_AV_TEST_DIV_SEL_OFFSET	(19)
+
+/* PLL6_MLB defines. */
+#define ANADIG_PLL_MLB_LOCK			(1 << 31)
+#define ANADIG_PLL_MLB_FLT_RES_CFG_MASK		(0x7 << 26)
+#define ANADIG_PLL_MLB_FLT_RES_CFG_OFFSET	(26)
+#define ANADIG_PLL_MLB_RX_CLK_DELAY_CFG_MASK	(0x7 << 23)
+#define ANADIG_PLL_MLB_RX_CLK_DELAY_CFG_OFFSET	(23)
+#define ANADIG_PLL_MLB_VDDD_DELAY_CFG_MASK	(0x7 << 20)
+#define ANADIG_PLL_MLB_VDDD_DELAY_CFG_OFFSET	(20)
+#define ANADIG_PLL_MLB_VDDA_DELAY_CFG_MASK	(0x7 << 17)
+#define ANADIG_PLL_MLB_VDDA_DELAY_CFG_OFFSET	(17)
+#define ANADIG_PLL_MLB_BYPASS			(1 << 16)
+
+/* PLL8_ENET defines. */
+#define ANADIG_PLL_ENET_LOCK			(1 << 31)
+#define ANADIG_PLL_ENET_EN_SATA			(1 << 20)
+#define ANADIG_PLL_ENET_EN_PCIE			(1 << 19)
+#define ANADIG_PLL_ENET_BYPASS			(1 << 16)
+#define ANADIG_PLL_ENET_EN			(1 << 13)
+#define ANADIG_PLL_ENET_POWER_DOWN		(1 << 12)
+#define ANADIG_PLL_ENET_DIV_SELECT_MASK		(0x3)
+#define ANADIG_PLL_ENET_DIV_SELECT_OFFSET	(0)
+#define ANATOP_BYPASS_SRC_LVDS1         0x00004000
+
+/* PFD register defines. */
+#define ANADIG_PFD_FRAC_MASK			0x3F
+#define ANADIG_PFD3_CLKGATE			(1 << 31)
+#define ANADIG_PFD3_STABLE			(1 << 30)
+#define ANADIG_PFD3_FRAC_OFFSET			24
+#define ANADIG_PFD2_CLKGATE			(1 << 23)
+#define ANADIG_PFD2_STABLE			(1 << 22)
+#define ANADIG_PFD2_FRAC_OFFSET			16
+#define ANADIG_PFD1_CLKGATE			(1 << 15)
+#define ANADIG_PFD1_STABLE			(1 << 14)
+#define ANADIG_PFD1_FRAC_OFFSET			8
+#define ANADIG_PFD0_CLKGATE			(1 << 7)
+#define ANADIG_PFD0_STABLE			(1 << 6)
+#define ANADIG_PFD0_FRAC_OFFSET			0
+
+/* ANATOP  Regulator/LDO defines */
+#define ANADIG_REG_RAMP_RATE_MASK			0x03
+#define ANADIG_REG_RAMP_RATE_OFFSET			(0x3 << 27)
+#define ANADIG_REG_ADJUST_MASK				0xF
+#define ANADIG_REG_TARGET_MASK				0x1F
+#define ANADIG_REG2_SOC_ADJUST_OFFSET		23
+#define ANADIG_REG2_SOC_TARGET_OFFSET		18
+#define ANADIG_REG1_PU_ADJUST_OFFSET			14
+#define ANADIG_REG1_PU_TARGET_OFFSET			9
+#define ANADIG_REG0_CORE_ADJUST_OFFSET		5
+#define ANADIG_REG0_CORE_TARGET_OFFSET		0
+
+/* ANA MISC2 register defines */
+#define ANADIG_ANA_MISC2_REG1_BO_EN			(1 << 13)
+#define ANADIG_ANA_MISC2_CONTROL3_MASK		0xC0000000
+#define ANADIG_ANA_MISC2_CONTROL3_OFFSET	30
+
+#define MXC_CCM_BASE		MX6_IO_ADDRESS(CCM_BASE_ADDR)
+/* CCM Register Offsets. */
+#define MXC_CCM_CDCR_OFFSET			0x4C
+#define MXC_CCM_CACRR_OFFSET			0x10
+#define MXC_CCM_CDHIPR_OFFSET			0x48
+
+/* Register addresses of CCM*/
+#define MXC_CCM_CCR		(MXC_CCM_BASE + 0x00)
+#define MXC_CCM_CCDR		(MXC_CCM_BASE + 0x04)
+#define MXC_CCM_CSR		(MXC_CCM_BASE + 0x08)
+#define MXC_CCM_CCSR		(MXC_CCM_BASE + 0x0c)
+#define MXC_CCM_CACRR		(MXC_CCM_BASE + 0x10)
+#define MXC_CCM_CBCDR		(MXC_CCM_BASE + 0x14)
+#define MXC_CCM_CBCMR		(MXC_CCM_BASE + 0x18)
+#define MXC_CCM_CSCMR1		(MXC_CCM_BASE + 0x1c)
+#define MXC_CCM_CSCMR2		(MXC_CCM_BASE + 0x20)
+#define MXC_CCM_CSCDR1		(MXC_CCM_BASE + 0x24)
+#define MXC_CCM_CS1CDR		(MXC_CCM_BASE + 0x28)
+#define MXC_CCM_CS2CDR		(MXC_CCM_BASE + 0x2c)
+#define MXC_CCM_CDCDR		(MXC_CCM_BASE + 0x30)
+#define MXC_CCM_CHSCCDR		(MXC_CCM_BASE + 0x34)
+#define MXC_CCM_CSCDR2		(MXC_CCM_BASE + 0x38)
+#define MXC_CCM_CSCDR3		(MXC_CCM_BASE + 0x3c)
+#define MXC_CCM_CSCDR4		(MXC_CCM_BASE + 0x40)
+#define MXC_CCM_CWDR		(MXC_CCM_BASE + 0x44)
+#define MXC_CCM_CDHIPR		(MXC_CCM_BASE + 0x48)
+#define MXC_CCM_CDCR		(MXC_CCM_BASE + 0x4c)
+#define MXC_CCM_CTOR		(MXC_CCM_BASE + 0x50)
+#define MXC_CCM_CLPCR		(MXC_CCM_BASE + 0x54)
+#define MXC_CCM_CISR		(MXC_CCM_BASE + 0x58)
+#define MXC_CCM_CIMR		(MXC_CCM_BASE + 0x5c)
+#define MXC_CCM_CCOSR 		(MXC_CCM_BASE + 0x60)
+#define MXC_CCM_CGPR		(MXC_CCM_BASE + 0x64)
+#define MXC_CCM_CCGR0		(MXC_CCM_BASE + 0x68)
+#define MXC_CCM_CCGR1		(MXC_CCM_BASE + 0x6C)
+#define MXC_CCM_CCGR2		(MXC_CCM_BASE + 0x70)
+#define MXC_CCM_CCGR3		(MXC_CCM_BASE + 0x74)
+#define MXC_CCM_CCGR4		(MXC_CCM_BASE + 0x78)
+#define MXC_CCM_CCGR5		(MXC_CCM_BASE + 0x7C)
+#define MXC_CCM_CCGR6		(MXC_CCM_BASE + 0x80)
+#define MXC_CCM_CCGR7		(MXC_CCM_BASE + 0x84)
+#define MXC_CCM_CMEOR		(MXC_CCM_BASE + 0x88)
+
+/* Define the bits in register CCR */
+#define MXC_CCM_CCR_RBC_EN			(1 << 27)
+#define MXC_CCM_CCR_REG_BYPASS_CNT_MASK		(0x3F << 21)
+#define MXC_CCM_CCR_REG_BYPASS_CNT_OFFSET	(21)
+#define MXC_CCM_CCR_WB_COUNT_MASK		(0x7 << 16)
+#define MXC_CCM_CCR_WB_COUNT_OFFSET		(16)
+#define MXC_CCM_CCR_COSC_EN			(1 << 12)
+#define MXC_CCM_CCR_OSCNT_MASK			(0xFF)
+#define MXC_CCM_CCR_OSCNT_OFFSET		(0)
+
+/* Define the bits in register CCDR */
+#define MXC_CCM_CCDR_MMDC_CH1_HS_MASK		(1 << 16)
+#define MXC_CCM_CCDR_MMDC_CH0_HS_MASK		(1 << 17)
+
+/* Define the bits in register CSR */
+#define MXC_CCM_CSR_COSC_READY			(1 << 5)
+#define MXC_CCM_CSR_REF_EN_B			(1 << 0)
+
+/* Define the bits in register CCSR */
+#define MXC_CCM_CCSR_PDF_540M_AUTO_DIS		(1 << 15)
+#define MXC_CCM_CCSR_PDF_720M_AUTO_DIS		(1 << 14)
+#define MXC_CCM_CCSR_PDF_454M_AUTO_DIS		(1 << 13)
+#define MXC_CCM_CCSR_PDF_508M_AUTO_DIS		(1 << 12)
+#define MXC_CCM_CCSR_PDF_594M_AUTO_DIS		(1 << 11)
+#define MXC_CCM_CCSR_PDF_352M_AUTO_DIS		(1 << 10)
+#define MXC_CCM_CCSR_PDF_400M_AUTO_DIS		(1 << 9)
+#define MXC_CCM_CCSR_STEP_SEL			(1 << 8)
+#define MXC_CCM_CCSR_PLL1_SW_CLK_SEL		(1 << 2)
+#define MXC_CCM_CCSR_PLL2_SW_CLK_SEL		(1 << 1)
+#define MXC_CCM_CCSR_PLL3_SW_CLK_SEL		(1 << 0)
+
+/* Define the bits in register CACRR */
+#define MXC_CCM_CACRR_ARM_PODF_OFFSET		(0)
+#define MXC_CCM_CACRR_ARM_PODF_MASK		(0x7)
+
+/* Define the bits in register CBCDR */
+#define MXC_CCM_CBCDR_PERIPH_CLK2_PODF_MASK	(0x7 << 27)
+#define MXC_CCM_CBCDR_PERIPH_CLK2_PODF_OFFSET	(27)
+#define MXC_CCM_CBCDR_PERIPH2_CLK_SEL		(1 << 26)
+#define MXC_CCM_CBCDR_PERIPH_CLK_SEL		(1 << 25)
+#define MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK	(0x7 << 19)
+#define MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET	(19)
+#define MXC_CCM_CBCDR_AXI_PODF_MASK		(0x7 << 16)
+#define MXC_CCM_CBCDR_AXI_PODF_OFFSET		(16)
+#define MXC_CCM_CBCDR_AHB_PODF_MASK		(0x7 << 10)
+#define MXC_CCM_CBCDR_AHB_PODF_OFFSET		(10)
+#define MXC_CCM_CBCDR_IPG_PODF_MASK		(0x3 << 8)
+#define MXC_CCM_CBCDR_IPG_PODF_OFFSET		(8)
+#define MXC_CCM_CBCDR_AXI_ALT_SEL_MASK		(1 << 7)
+#define MXC_CCM_CBCDR_AXI_ALT_SEL_OFFSET	(7)
+#define MXC_CCM_CBCDR_AXI_SEL			(1 << 6)
+#define MXC_CCM_CBCDR_MMDC_CH1_PODF_MASK	(0x7 << 3)
+#define MXC_CCM_CBCDR_MMDC_CH1_PODF_OFFSET	(3)
+#define MXC_CCM_CBCDR_PERIPH2_CLK2_PODF_MASK	(0x7 << 0)
+#define MXC_CCM_CBCDR_PERIPH2_CLK2_PODF_OFFSET	(0)
+
+/* Define the bits in register CBCMR */
+#define MXC_CCM_CBCMR_GPU3D_SHADER_PODF_MASK		(0x7 << 29)
+#define MXC_CCM_CBCMR_GPU3D_SHADER_PODF_OFFSET		(29)
+#define MXC_CCM_CBCMR_GPU3D_CORE_PODF_MASK		(0x7 << 26)
+#define MXC_CCM_CBCMR_GPU3D_CORE_PODF_OFFSET		(26)
+#define MXC_CCM_CBCMR_GPU2D_CORE_PODF_MASK		(0x7 << 23)
+#define MXC_CCM_CBCMR_GPU2D_CORE_PODF_OFFSET		(23)
+#define MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK		(0x3 << 21)
+#define MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET	(21)
+#define MXC_CCM_CBCMR_PERIPH2_CLK2_SEL			(1 << 20)
+#define MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK		(0x3 << 18)
+#define MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET		(18)
+#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK		(0x3 << 16)
+#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET		(16)
+#define MXC_CCM_CBCMR_MLB_CLK_SEL_MASK			(0x3 << 16)
+#define MXC_CCM_CBCMR_MLB_CLK_SEL_OFFSET		(16)
+#define MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_MASK		(0x3 << 14)
+#define MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_OFFSET		(14)
+#define MXC_CCM_CBCMR_PERIPH_CLK2_SEL_MASK		(0x3 << 12)
+#define MXC_CCM_CBCMR_PERIPH_CLK2_SEL_OFFSET		(12)
+#define MXC_CCM_CBCMR_VDOAXI_CLK_SEL			(1 << 11)
+#define MXC_CCM_CBCMR_PCIE_AXI_CLK_SEL			(1 << 10)
+#define MXC_CCM_CBCMR_GPU3D_SHADER_CLK_SEL_MASK		(0x3 << 8)
+#define MXC_CCM_CBCMR_GPU3D_SHADER_CLK_SEL_OFFSET	(8)
+#define MXC_CCM_CBCMR_GPU3D_CORE_CLK_SEL_MASK		(0x3 << 4)
+#define MXC_CCM_CBCMR_GPU3D_CORE_CLK_SEL_OFFSET		(4)
+#define MXC_CCM_CBCMR_GPU3D_AXI_CLK_SEL			(1 << 1)
+#define MXC_CCM_CBCMR_GPU2D_AXI_CLK_SEL			(1 << 0)
+
+/* Define the bits in register CSCMR1 */
+#define MXC_CCM_CSCMR1_ACLK_EMI_SLOW_MASK		(0x3 << 29)
+#define MXC_CCM_CSCMR1_ACLK_EMI_SLOW_OFFSET		(29)
+#define MXC_CCM_CSCMR1_ACLK_EMI_MASK			(0x3 << 27)
+#define MXC_CCM_CSCMR1_ACLK_EMI_OFFSET			(27)
+#define MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK		(0x7 << 23)
+#define MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_OFFSET	(23)
+#define MXC_CCM_CSCMR1_ACLK_EMI_PODF_MASK		(0x7 << 20)
+#define MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET		(20)
+#define MXC_CCM_CSCMR1_USDHC4_CLK_SEL			(1 << 19)
+#define MXC_CCM_CSCMR1_USDHC3_CLK_SEL			(1 << 18)
+#define MXC_CCM_CSCMR1_USDHC2_CLK_SEL			(1 << 17)
+#define MXC_CCM_CSCMR1_USDHC1_CLK_SEL			(1 << 16)
+#define MXC_CCM_CSCMR1_SSI3_CLK_SEL_MASK		(0x3 << 14)
+#define MXC_CCM_CSCMR1_SSI3_CLK_SEL_OFFSET		(14)
+#define MXC_CCM_CSCMR1_SSI2_CLK_SEL_MASK		(0x3 << 12)
+#define MXC_CCM_CSCMR1_SSI2_CLK_SEL_OFFSET		(12)
+#define MXC_CCM_CSCMR1_SSI1_CLK_SEL_MASK		(0x3 << 10)
+#define MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET		(10)
+#define MXC_CCM_CSCMR1_PERCLK_CLK_SEL_MASK		(0x1 << 6)
+#define MXC_CCM_CSCMR1_PERCLK_CLK_SEL_OFFSET	(6)
+#define MXC_CCM_CSCMR1_PERCLK_PODF_MASK			(0x3F)
+#define MXC_CCM_CSCMR1_PERCLK_PODF_OFFSET		(0)
+
+/* Define the bits in register CSCMR2 */
+#define MXC_CCM_CSCMR2_ESAI_CLK_SEL_MASK		(0x3 << 19)
+#define MXC_CCM_CSCMR2_ESAI_CLK_SEL_OFFSET		(19)
+#define MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV			(1 << 11)
+#define MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV			(1 << 10)
+#define MXC_CCM_CSCMR2_CAN_CLK_PODF_MASK		(0x3F << 2)
+#define MXC_CCM_CSCMR2_CAN_CLK_PODF_OFFSET		(2)
+
+/* Define the bits in register CSCDR1 */
+#define MXC_CCM_CSCDR1_VPU_AXI_PODF_MASK		(0x7 << 25)
+#define MXC_CCM_CSCDR1_VPU_AXI_PODF_OFFSET		(25)
+#define MXC_CCM_CSCDR1_USDHC4_PODF_MASK			(0x7 << 22)
+#define MXC_CCM_CSCDR1_USDHC4_PODF_OFFSET		(22)
+#define MXC_CCM_CSCDR1_USDHC3_PODF_MASK			(0x7 << 19)
+#define MXC_CCM_CSCDR1_USDHC3_PODF_OFFSET		(19)
+#define MXC_CCM_CSCDR1_USDHC2_PODF_MASK			(0x7 << 16)
+#define MXC_CCM_CSCDR1_USDHC2_PODF_OFFSET		(16)
+#define MXC_CCM_CSCDR1_USDHC1_PODF_MASK			(0x7 << 11)
+#define MXC_CCM_CSCDR1_USDHC1_PODF_OFFSET		(11)
+#define MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET		(8)
+#define MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK		(0x7 << 8)
+#define MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET		(6)
+#define MXC_CCM_CSCDR1_UART_CLK_SEL_MASK		(0x1 << 6)
+#define MXC_CCM_CSCDR1_UART_CLK_SEL_OFFSET		(6)
+#define MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK		(0x3 << 6)
+#define MXC_CCM_CSCDR1_UART_CLK_PODF_MASK		(0x3F)
+#define MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET		(0)
+
+/* Define the bits in register CS1CDR */
+#define MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK		(0x7 << 25)
+#define MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET		(25)
+#define MXC_CCM_CS1CDR_SSI3_CLK_PRED_MASK		(0x7 << 22)
+#define MXC_CCM_CS1CDR_SSI3_CLK_PRED_OFFSET		(22)
+#define MXC_CCM_CS1CDR_SSI3_CLK_PODF_MASK		(0x3F << 16)
+#define MXC_CCM_CS1CDR_SSI3_CLK_PODF_OFFSET		(16)
+#define MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK		(0x7 << 9)
+#define MXC_CCM_CS1CDR_ESAI_CLK_PRED_OFFSET		(9)
+#define MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK		(0x7 << 6)
+#define MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET		(6)
+#define MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK		(0x3F)
+#define MXC_CCM_CS1CDR_SSI1_CLK_PODF_OFFSET		(0)
+
+/* Define the bits in register CS2CDR */
+#define MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK		(0x3F << 21)
+#define MXC_CCM_CS2CDR_ENFC_CLK_PODF_OFFSET		(21)
+#define MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK		(0x7 << 18)
+#define MXC_CCM_CS2CDR_ENFC_CLK_PRED_OFFSET		(18)
+#define MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK		(0x3 << 16)
+#define MXC_CCM_CS2CDR_ENFC_CLK_SEL_OFFSET		(16)
+#define MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK		(0x7 << 12)
+#define MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET		(12)
+#define MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK		(0x7 << 9)
+#define MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET		(9)
+#define MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK		(0x7 << 6)
+#define MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET		(6)
+#define MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK		(0x3F)
+#define MXC_CCM_CS2CDR_SSI2_CLK_PODF_OFFSET		(0)
+
+/* Define the bits in register CDCDR */
+#define MXC_CCM_CDCDR_HSI_TX_PODF_MASK			(0x7 << 29)
+#define MXC_CCM_CDCDR_HSI_TX_PODF_OFFSET		(29)
+#define MXC_CCM_CDCDR_HSI_TX_CLK_SEL			(1 << 28)
+#define MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK		(0x7 << 25)
+#define MXC_CCM_CDCDR_SPDIF0_CLK_PRED_OFFSET		(25)
+#define MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK		(0x7 << 22)
+#define MXC_CCM_CDCDR_SPDIF0_CLK_PODF_OFFSET		(22)
+#define MXC_CCM_CDCDR_SPDIF0_CLK_SEL_MASK		(0x3 << 20)
+#define MXC_CCM_CDCDR_SPDIF0_CLK_SEL_OFFSET		(20)
+#define MXC_CCM_CDCDR_SPDIF1_CLK_PRED_MASK		(0x7 << 12)
+#define MXC_CCM_CDCDR_SPDIF1_CLK_PRED_OFFSET		(12)
+#define MXC_CCM_CDCDR_SPDIF1_CLK_PODF_MASK		(0x7 << 9)
+#define MXC_CCM_CDCDR_SPDIF1_CLK_PODF_OFFSET		(9)
+#define MXC_CCM_CDCDR_SPDIF1_CLK_SEL_MASK		(0x3 << 7)
+#define MXC_CCM_CDCDR_SPDIF1_CLK_SEL_OFFSET		(7)
+
+/* Define the bits in register CHSCCDR */
+#define MXC_CCM_CHSCCDR_IPU1_DI1_PRE_CLK_SEL_MASK	(0x7 << 15)
+#define MXC_CCM_CHSCCDR_IPU1_DI1_PRE_CLK_SEL_OFFSET	(15)
+#define MXC_CCM_CHSCCDR_IPU1_DI1_PODF_MASK		(0x7 << 12)
+#define MXC_CCM_CHSCCDR_IPU1_DI1_PODF_OFFSET		(12)
+#define MXC_CCM_CHSCCDR_IPU1_DI1_CLK_SEL_MASK		(0x7 << 9)
+#define MXC_CCM_CHSCCDR_IPU1_DI1_CLK_SEL_OFFSET		(9)
+#define MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK	(0x7 << 6)
+#define MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_OFFSET	(6)
+#define MXC_CCM_CHSCCDR_IPU1_DI0_PODF_MASK		(0x7 << 3)
+#define MXC_CCM_CHSCCDR_IPU1_DI0_PODF_OFFSET		(3)
+#define MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK		(0x7)
+#define MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET		(0)
+
+/* Define the bits in register CSCDR2 */
+#define MXC_CCM_CSCDR2_ECSPI_CLK_PODF_MASK		(0x3F << 19)
+#define MXC_CCM_CSCDR2_ECSPI_CLK_PODF_OFFSET		(19)
+#define MXC_CCM_CSCDR2_ECSPI_CLK_SEL_MASK		(0x1 << 18)
+#define MXC_CCM_CSCDR2_ECSPI_CLK_SEL_OFFSET		(18)
+#define MXC_CCM_CSCDR2_IPU2_DI1_PRE_CLK_SEL_MASK	(0x7 << 15)
+#define MXC_CCM_CSCDR2_IPU2_DI1_PRE_CLK_SEL_OFFSET	(15)
+#define MXC_CCM_CSCDR2_IPU2_DI1_PODF_MASK		(0x7 << 12)
+#define MXC_CCM_CSCDR2_IPU2_DI1_PODF_OFFSET		(12)
+#define MXC_CCM_CSCDR2_IPU2_DI1_CLK_SEL_MASK		(0x7 << 9)
+#define MXC_CCM_CSCDR2_IPU2_DI1_CLK_SEL_OFFSET		(9)
+#define MXC_CCM_CSCDR2_IPU2_DI0_PRE_CLK_SEL_MASK	(0x7 << 6)
+#define MXC_CCM_CSCDR2_IPU2_DI0_PRE_CLK_SEL_OFFSET	(6)
+#define MXC_CCM_CSCDR2_IPU2_DI0_PODF_MASK		(0x7 << 3)
+#define MXC_CCM_CSCDR2_IPU2_DI0_PODF_OFFSET		(3)
+#define MXC_CCM_CSCDR2_IPU2_DI0_CLK_SEL_MASK		(0x7)
+#define MXC_CCM_CSCDR2_IPU2_DI0_CLK_SEL_OFFSET		(0)
+
+/* Define the bits in register CSCDR3 */
+#define MXC_CCM_CSCDR3_IPU2_HSP_PODF_MASK		(0x7 << 16)
+#define MXC_CCM_CSCDR3_IPU2_HSP_PODF_OFFSET		(16)
+#define MXC_CCM_CSCDR3_IPU2_HSP_CLK_SEL_MASK		(0x3 << 14)
+#define MXC_CCM_CSCDR3_IPU2_HSP_CLK_SEL_OFFSET		(14)
+#define MXC_CCM_CSCDR3_IPU1_HSP_PODF_MASK		(0x7 << 11)
+#define MXC_CCM_CSCDR3_IPU1_HSP_PODF_OFFSET		(11)
+#define MXC_CCM_CSCDR3_IPU1_HSP_CLK_SEL_MASK		(0x3 << 9)
+#define MXC_CCM_CSCDR3_IPU1_HSP_CLK_SEL_OFFSET		(9)
+
+/* Define the bits in register CDHIPR */
+#define MXC_CCM_CDHIPR_ARM_PODF_BUSY			(1 << 16)
+#define MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY		(1 << 5)
+#define MXC_CCM_CDHIPR_MMDC_CH0_PODF_BUSY		(1 << 4)
+#define MXC_CCM_CDHIPR_PERIPH2_CLK_SEL_BUSY		(1 << 3)
+#define MXC_CCM_CDHIPR_MMDC_CH1_PODF_BUSY		(1 << 2)
+#define MXC_CCM_CDHIPR_AHB_PODF_BUSY			(1 << 1)
+#define MXC_CCM_CDHIPR_AXI_PODF_BUSY			(1)
+
+/* Define the bits in register CLPCR */
+#define MXC_CCM_CLPCR_MASK_L2CC_IDLE			(1 << 27)
+#define MXC_CCM_CLPCR_MASK_SCU_IDLE			(1 << 26)
+#define MXC_CCM_CLPCR_MASK_CORE3_WFI			(1 << 25)
+#define MXC_CCM_CLPCR_MASK_CORE2_WFI			(1 << 24)
+#define MXC_CCM_CLPCR_MASK_CORE1_WFI			(1 << 23)
+#define MXC_CCM_CLPCR_MASK_CORE0_WFI			(1 << 22)
+#define MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS		(1 << 21)
+#define MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS		(1 << 19)
+#define MXC_CCM_CLPCR_WB_CORE_AT_LPM			(1 << 17)
+#define MXC_CCM_CLPCR_WB_PER_AT_LPM			(1 << 16)
+#define MXC_CCM_CLPCR_COSC_PWRDOWN			(1 << 11)
+#define MXC_CCM_CLPCR_STBY_COUNT_MASK			(0x3 << 9)
+#define MXC_CCM_CLPCR_STBY_COUNT_OFFSET			(9)
+#define MXC_CCM_CLPCR_VSTBY				(1 << 8)
+#define MXC_CCM_CLPCR_DIS_REF_OSC			(1 << 7)
+#define MXC_CCM_CLPCR_SBYOS				(1 << 6)
+#define MXC_CCM_CLPCR_ARM_CLK_DIS_ON_LPM		(1 << 5)
+#define MXC_CCM_CLPCR_LPSR_CLK_SEL_MASK			(0x3 << 3)
+#define MXC_CCM_CLPCR_LPSR_CLK_SEL_OFFSET		(3)
+#define MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY		(1 << 2)
+#define MXC_CCM_CLPCR_LPM_MASK				(0x3)
+#define MXC_CCM_CLPCR_LPM_OFFSET			(0)
+
+/* Define the bits in register CISR */
+#define MXC_CCM_CISR_ARM_PODF_LOADED			(1 << 26)
+#define MXC_CCM_CISR_MMDC_CH0_PODF_LOADED		(1 << 23)
+#define MXC_CCM_CISR_PERIPH_CLK_SEL_LOADED		(1 << 22)
+#define MXC_CCM_CISR_MMDC_CH1_PODF_LOADED		(1 << 21)
+#define MXC_CCM_CISR_AHB_PODF_LOADED			(1 << 20)
+#define MXC_CCM_CISR_PERIPH2_CLK_SEL_LOADED		(1 << 19)
+#define MXC_CCM_CISR_AXI_PODF_LOADED			(1 << 17)
+#define MXC_CCM_CISR_COSC_READY				(1 << 6)
+#define MXC_CCM_CISR_LRF_PLL				(1)
+
+/* Define the bits in register CIMR */
+#define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED		(1 << 26)
+#define MXC_CCM_CIMR_MASK_MMDC_CH0_PODF_LOADED		(1 << 23)
+#define MXC_CCM_CIMR_MASK_PERIPH_CLK_SEL_LOADED		(1 << 22)
+#define MXC_CCM_CIMR_MASK_MMDC_CH1_PODF_LOADED		(1 << 21)
+#define MXC_CCM_CIMR_MASK_AHB_PODF_LOADED		(1 << 20)
+#define MXC_CCM_CIMR_MASK_PERIPH2_CLK_SEL_LOADED	(1 << 22)
+#define MXC_CCM_CIMR_MASK_AXI_PODF_LOADED		(1 << 17)
+#define MXC_CCM_CIMR_MASK_COSC_READY			(1 << 6)
+#define MXC_CCM_CIMR_MASK_LRF_PLL			(1)
+
+/* Define the bits in register CCOSR */
+#define MXC_CCM_CCOSR_CKO2_EN_OFFSET		(24)
+#define MXC_CCM_CCOSR_CKO2_DIV_MASK		(0x7 << 21)
+#define MXC_CCM_CCOSR_CKO2_DIV_OFFSET		(21)
+#define MXC_CCM_CCOSR_CKO2_SEL_OFFSET		(16)
+#define MXC_CCM_CCOSR_CKO2_SEL_MASK		(0x1F << 16)
+#define MXC_CCM_CCOSR_CKOL_MIRROR_CKO2_MASK	(1 << 8)
+#define MXC_CCM_CCOSR_CKOL_EN_OFFSET		7
+#define MXC_CCM_CCOSR_CKOL_EN			(0x1 << 7)
+#define MXC_CCM_CCOSR_CKOL_DIV_MASK		(0x7 << 4)
+#define MXC_CCM_CCOSR_CKOL_DIV_OFFSET		(4)
+#define MXC_CCM_CCOSR_CKOL_SEL_MASK		(0xF)
+#define MXC_CCM_CCOSR_CKOL_SEL_OFFSET		(0)
+
+/* Define the bits in registers CGPR */
+#define MXC_CCM_CGPR_EFUSE_PROG_SUPPLY_GATE	(1 << 4)
+#define MXC_CCM_CGPR_MMDC_EXT_CLK_DIS		(1 << 2)
+#define MXC_CCM_CGPR_PMIC_DELAY_SCALER		(1)
+#define MXC_CCM_CGPR_MEM_IPG_STOP_MASK		(1 << 1)
+#define MXC_CCM_CGPR_WAIT_MODE_FIX			(1 << 17)
+
+/* Define the bits in registers CCGRx */
+#define MXC_CCM_CCGRx_CG_MASK			0x3
+#define MXC_CCM_CCGRx_MOD_OFF			0x0
+#define MXC_CCM_CCGRx_MOD_ON			0x3
+#define MXC_CCM_CCGRx_MOD_IDLE			0x1
+
+#define MXC_CCM_CCGRx_CG15_MASK			(0x3 << 30)
+#define MXC_CCM_CCGRx_CG14_MASK			(0x3 << 28)
+#define MXC_CCM_CCGRx_CG13_MASK			(0x3 << 26)
+#define MXC_CCM_CCGRx_CG12_MASK			(0x3 << 24)
+#define MXC_CCM_CCGRx_CG11_MASK			(0x3 << 22)
+#define MXC_CCM_CCGRx_CG10_MASK			(0x3 << 20)
+#define MXC_CCM_CCGRx_CG9_MASK			(0x3 << 18)
+#define MXC_CCM_CCGRx_CG8_MASK			(0x3 << 16)
+#define MXC_CCM_CCGRx_CG7_MASK			(0x3 << 14)
+#define MXC_CCM_CCGRx_CG5_MASK			(0x3 << 10)
+#define MXC_CCM_CCGRx_CG4_MASK			(0x3 << 8)
+#define MXC_CCM_CCGRx_CG3_MASK			(0x3 << 6)
+#define MXC_CCM_CCGRx_CG2_MASK			(0x3 << 4)
+#define MXC_CCM_CCGRx_CG1_MASK			(0x3 << 2)
+#define MXC_CCM_CCGRx_CG0_MASK			(0x3 << 0)
+
+#define MXC_CCM_CCGRx_CG15_OFFSET		30
+#define MXC_CCM_CCGRx_CG14_OFFSET		28
+#define MXC_CCM_CCGRx_CG13_OFFSET		26
+#define MXC_CCM_CCGRx_CG12_OFFSET		24
+#define MXC_CCM_CCGRx_CG11_OFFSET		22
+#define MXC_CCM_CCGRx_CG10_OFFSET		20
+#define MXC_CCM_CCGRx_CG9_OFFSET		18
+#define MXC_CCM_CCGRx_CG8_OFFSET		16
+#define MXC_CCM_CCGRx_CG7_OFFSET		14
+#define MXC_CCM_CCGRx_CG6_OFFSET		12
+#define MXC_CCM_CCGRx_CG5_OFFSET		10
+#define MXC_CCM_CCGRx_CG4_OFFSET		8
+#define MXC_CCM_CCGRx_CG3_OFFSET		6
+#define MXC_CCM_CCGRx_CG2_OFFSET		4
+#define MXC_CCM_CCGRx_CG1_OFFSET		2
+#define MXC_CCM_CCGRx_CG0_OFFSET		0
+
+#endif				/* __ARCH_ARM_MACH_MX6_CRM_REGS_H__ */
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 04a02ba..7db6b4d 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -38,6 +38,7 @@
 #include "common.h"
 #include "cpuidle.h"
 #include "hardware.h"
+#include "pcie.h"
 
 #define IMX6Q_ANALOG_DIGPROG	0x260
 
@@ -190,6 +191,139 @@ static void __init imx6q_usb_init(void)
 	}
 }
 
+#define SBC6X_PCIE_PWR                  IMX_GPIO_NR(1, 3)
+#define SBC6X_PCIE_RST                  IMX_GPIO_NR(1, 8)
+
+#include "pcie.h"
+struct imx_pcie_data {
+        int id;
+        resource_size_t iobase;
+        resource_size_t iosize;
+	resource_size_t irq;
+};
+
+struct platform_device *__init imx_add_pcie(
+	const struct imx_pcie_data *data,
+	const struct imx_pcie_platform_data *pdata);
+
+static const struct imx_pcie_platform_data mx6_sbc6x_pcie_data __initconst = {
+        .pcie_pwr_en    =  SBC6X_PCIE_PWR,
+        .pcie_rst       =  SBC6X_PCIE_RST,
+        .pcie_wake_up   = -EINVAL,
+        .pcie_dis       = -EINVAL,
+};
+
+#define imx_pcie_data_entry_single(soc, _id, _hwid, size)               \
+        {                                                               \
+	.id = _id,                                              \
+                .iobase = soc ## _PCIE ## _hwid ## _BASE_ADDR,  \
+                .iosize = size,                                         \
+                .irq    = soc ## _INT_PCIE ## _hwid,                    \
+			}
+
+#define imx_pcie_data_entry(soc, _id, _hwid, _size)                     \
+        [_id] = imx_pcie_data_entry_single(soc, _id, _hwid, _size)
+
+#ifdef CONFIG_SOC_IMX6Q
+#define MX6Q_PCIE_BASE_ADDR (PCIE_ARB_END_ADDR - SZ_16K + 1)
+#define MX6Q_INT_PCIE MXC_INT_PCIE_3
+const struct imx_pcie_data imx6q_pcie_data __initconst =
+	imx_pcie_data_entry_single(MX6Q, 0, , SZ_16K);
+#endif
+
+#define imx6q_add_pcie(pdata) imx_add_pcie(&imx6q_pcie_data, pdata)
+
+
+
+struct platform_device *imx_add_platform_device_dmamask(
+	const char *name, int id,
+	const struct resource *res, unsigned int num_resources,
+	const void *data, size_t size_data, u64 dmamask);
+
+struct platform_device *__init imx_add_platform_device_dmamask(
+		const char *name, int id,
+		const struct resource *res, unsigned int num_resources,
+		const void *data, size_t size_data, u64 dmamask)
+{
+	int ret = -ENOMEM;
+	struct platform_device *pdev;
+
+	pdev = platform_device_alloc(name, id);
+	if (!pdev)
+		goto err;
+
+	if (dmamask) {
+		/*
+		 * This memory isn't freed when the device is put,
+		 * I don't have a nice idea for that though.  Conceptually
+		 * dma_mask in struct device should not be a pointer.
+		 * See http://thread.gmane.org/gmane.linux.kernel.pci/9081
+		 */
+		pdev->dev.dma_mask =
+			kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
+		if (!pdev->dev.dma_mask)
+			/* ret is still -ENOMEM; */
+			goto err;
+
+		*pdev->dev.dma_mask = dmamask;
+		pdev->dev.coherent_dma_mask = dmamask;
+	}
+
+	if (res) {
+		ret = platform_device_add_resources(pdev, res, num_resources);
+		if (ret)
+			goto err;
+	}
+
+	if (data) {
+		ret = platform_device_add_data(pdev, data, size_data);
+		if (ret)
+			goto err;
+	}
+
+	ret = platform_device_add(pdev);
+	if (ret) {
+err:
+		if (dmamask)
+			kfree(pdev->dev.dma_mask);
+		platform_device_put(pdev);
+		return ERR_PTR(ret);
+	}
+
+	return pdev;
+}
+
+static inline struct platform_device *imx_add_platform_device(
+	const char *name, int id,
+	const struct resource *res, unsigned int num_resources,
+	const void *data, size_t size_data)
+{
+        return imx_add_platform_device_dmamask(
+		name, id, res, num_resources, data, size_data, 0);
+}
+
+struct platform_device *__init imx_add_pcie(
+	const struct imx_pcie_data *data,
+	const struct imx_pcie_platform_data *pdata)
+{
+        struct resource res[] = {
+                {
+                        .start = data->iobase,
+                        .end = data->iobase + data->iosize - 1,
+                        .flags = IORESOURCE_MEM,
+                }, {
+                        .start = data->irq,
+                        .end = data->irq,
+                        .flags = IORESOURCE_IRQ,
+                },
+        };
+
+        return imx_add_platform_device("imx-pcie", -1,
+				       res, ARRAY_SIZE(res),
+				       pdata, sizeof(*pdata));
+}
+
+
 static void __init imx6q_init_machine(void)
 {
 	if (of_machine_is_compatible("fsl,imx6q-sabrelite"))
@@ -200,6 +334,10 @@ static void __init imx6q_init_machine(void)
 	imx6q_pm_init();
 	imx6q_usb_init();
 	imx6q_1588_init();
+
+	printk("FIXME: initializing Pcie\n");
+        /* Add PCIe RC interface support */
+        imx6q_add_pcie(&mx6_sbc6x_pcie_data);
 }
 
 #define OCOTP_CFG3			0x440
diff --git a/arch/arm/mach-imx/pcie.c b/arch/arm/mach-imx/pcie.c
new file mode 100644
index 0000000..9d4f6a6
--- /dev/null
+++ b/arch/arm/mach-imx/pcie.c
@@ -0,0 +1,822 @@
+/*
+ * arch/arm/mach-mx6/pcie.c
+ *
+ * PCIe host controller driver for IMX6 SOCs
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Bits taken from arch/arm/mach-dove/pcie.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+
+#include "pcie.h"
+
+#include <asm/sizes.h>
+
+#include "crm_regs.h"
+
+/* Register Definitions */
+#define PRT_LOG_R_BaseAddress 0x700
+
+/* Register DB_R0 */
+/* Debug Register 0 */
+#define DB_R0 (PRT_LOG_R_BaseAddress + 0x28)
+#define DB_R0_RegisterSize 32
+#define DB_R0_RegisterResetValue 0x0
+#define DB_R0_RegisterResetMask 0xFFFFFFFF
+/* End of Register Definition for DB_R0 */
+
+/* Register DB_R1 */
+/* Debug Register 1 */
+#define DB_R1 (PRT_LOG_R_BaseAddress + 0x2c)
+#define DB_R1_RegisterSize 32
+#define DB_R1_RegisterResetValue 0x0
+#define DB_R1_RegisterResetMask 0xFFFFFFFF
+/* End of Register Definition for DB_R1 */
+
+#define ATU_R_BaseAddress 0x900
+#define ATU_VIEWPORT_R (ATU_R_BaseAddress + 0x0)
+#define ATU_REGION_CTRL1_R (ATU_R_BaseAddress + 0x4)
+#define ATU_REGION_CTRL2_R (ATU_R_BaseAddress + 0x8)
+#define ATU_REGION_LOWBASE_R (ATU_R_BaseAddress + 0xC)
+#define ATU_REGION_UPBASE_R (ATU_R_BaseAddress + 0x10)
+#define ATU_REGION_LIMIT_ADDR_R (ATU_R_BaseAddress + 0x14)
+#define ATU_REGION_LOW_TRGT_ADDR_R (ATU_R_BaseAddress + 0x18)
+#define ATU_REGION_UP_TRGT_ADDR_R (ATU_R_BaseAddress + 0x1C)
+
+/* GPR1: iomuxc_gpr1_pcie_ref_clk_en(iomuxc_gpr1[16]) */
+#define iomuxc_gpr1_pcie_ref_clk_en		(1 << 16)
+/* GPR1: iomuxc_gpr1_test_powerdown(iomuxc_gpr1_18) */
+#define iomuxc_gpr1_test_powerdown		(1 << 18)
+
+/* GPR12: iomuxc_gpr12_los_level(iomuxc_gpr12[8:4]) */
+#define iomuxc_gpr12_los_level			(0x1F << 4)
+/* GPR12: iomuxc_gpr12_app_ltssm_enable(iomuxc_gpr12[10]) */
+#define iomuxc_gpr12_app_ltssm_enable		(1 << 10)
+/* GPR12: iomuxc_gpr12_device_type(iomuxc_gpr12[15:12]) */
+#define iomuxc_gpr12_device_type		(0xF << 12)
+
+/* GPR8: iomuxc_gpr8_tx_deemph_gen1(iomuxc_gpr8[5:0]) */
+#define iomuxc_gpr8_tx_deemph_gen1		(0x3F << 0)
+/* GPR8: iomuxc_gpr8_tx_deemph_gen2_3p5db(iomuxc_gpr8[11:6]) */
+#define iomuxc_gpr8_tx_deemph_gen2_3p5db	(0x3F << 6)
+/* GPR8: iomuxc_gpr8_tx_deemph_gen2_6db(iomuxc_gpr8[17:12]) */
+#define iomuxc_gpr8_tx_deemph_gen2_6db		(0x3F << 12)
+/* GPR8: iomuxc_gpr8_tx_swing_full(iomuxc_gpr8[24:18]) */
+#define iomuxc_gpr8_tx_swing_full		(0x7F << 18)
+/* GPR8: iomuxc_gpr8_tx_swing_low(iomuxc_gpr8[31:25]) */
+#define iomuxc_gpr8_tx_swing_low		(0x7F << 25)
+
+/* Registers of PHY */
+/* Register PHY_STS_R */
+/* PHY Status Register */
+#define PHY_STS_R (PRT_LOG_R_BaseAddress + 0x110)
+
+/* Register PHY_CTRL_R */
+/* PHY Control Register */
+#define PHY_CTRL_R (PRT_LOG_R_BaseAddress + 0x114)
+
+#define SSP_CR_SUP_DIG_MPLL_OVRD_IN_LO 0x0011
+/* FIELD: RES_ACK_IN_OVRD [15:15]
+// FIELD: RES_ACK_IN [14:14]
+// FIELD: RES_REQ_IN_OVRD [13:13]
+// FIELD: RES_REQ_IN [12:12]
+// FIELD: RTUNE_REQ_OVRD [11:11]
+// FIELD: RTUNE_REQ [10:10]
+// FIELD: MPLL_MULTIPLIER_OVRD [9:9]
+// FIELD: MPLL_MULTIPLIER [8:2]
+// FIELD: MPLL_EN_OVRD [1:1]
+// FIELD: MPLL_EN [0:0]
+*/
+
+#define SSP_CR_SUP_DIG_ATEOVRD 0x0010
+/* FIELD: ateovrd_en [2:2]
+// FIELD: ref_usb2_en [1:1]
+// FIELD: ref_clkdiv2 [0:0]
+*/
+
+#define SSP_CR_LANE0_DIG_RX_OVRD_IN_LO 0x1005
+/* FIELD: RX_LOS_EN_OVRD [13:13]
+// FIELD: RX_LOS_EN [12:12]
+// FIELD: RX_TERM_EN_OVRD [11:11]
+// FIELD: RX_TERM_EN [10:10]
+// FIELD: RX_BIT_SHIFT_OVRD [9:9]
+// FIELD: RX_BIT_SHIFT [8:8]
+// FIELD: RX_ALIGN_EN_OVRD [7:7]
+// FIELD: RX_ALIGN_EN [6:6]
+// FIELD: RX_DATA_EN_OVRD [5:5]
+// FIELD: RX_DATA_EN [4:4]
+// FIELD: RX_PLL_EN_OVRD [3:3]
+// FIELD: RX_PLL_EN [2:2]
+// FIELD: RX_INVERT_OVRD [1:1]
+// FIELD: RX_INVERT [0:0]
+*/
+
+#define SSP_CR_LANE0_DIG_RX_ASIC_OUT 0x100D
+/* FIELD: LOS [2:2]
+// FIELD: PLL_STATE [1:1]
+// FIELD: VALID [0:0]
+*/
+
+/* control bus bit definition */
+#define PCIE_CR_CTL_DATA_LOC 0
+#define PCIE_CR_CTL_CAP_ADR_LOC 16
+#define PCIE_CR_CTL_CAP_DAT_LOC 17
+#define PCIE_CR_CTL_WR_LOC 18
+#define PCIE_CR_CTL_RD_LOC 19
+#define PCIE_CR_STAT_DATA_LOC 0
+#define PCIE_CR_STAT_ACK_LOC 16
+
+#define PCIE_CAP_STRUC_BaseAddress 0x70
+
+/* Register LNK_CAP */
+/* PCIE Link cap */
+#define LNK_CAP (PCIE_CAP_STRUC_BaseAddress + 0xc)
+#define LNK_CAP_RegisterSize 32
+#define LNK_CAP_RegisterResetValue 0x011cc12
+#define LNK_CAP_RegisterResetMask 0xffffffff
+
+/* End of Register Definitions */
+
+#define PCIE_DBI_BASE_ADDR	(PCIE_ARB_END_ADDR - SZ_16K + 1)
+
+#define  PCIE_CONF_BUS(b)		(((b) & 0xFF) << 16)
+#define  PCIE_CONF_DEV(d)		(((d) & 0x1F) << 11)
+#define  PCIE_CONF_FUNC(f)		(((f) & 0x7) << 8)
+#define  PCIE_CONF_REG(r)		((r) & ~0x3)
+
+
+#define PERIPBASE_VIRT 0xF2000000
+#define MX6_IO_ADDRESS(x) (void __force __iomem *)((x) + PERIPBASE_VIRT)
+
+
+static void __iomem *base;
+static void __iomem *dbi_base;
+
+void *iomux_base;
+
+enum {
+	MemRdWr = 0,
+	MemRdLk = 1,
+	IORdWr = 2,
+	CfgRdWr0 = 4,
+	CfgRdWr1 = 5
+};
+
+struct imx_pcie_port {
+	u8			index;
+	u8			root_bus_nr;
+	void __iomem		*base;
+	void __iomem		*dbi_base;
+	spinlock_t		conf_lock;
+
+	char			io_space_name[16];
+	char			mem_space_name[16];
+
+	struct resource		res[2];
+};
+
+static struct imx_pcie_port imx_pcie_port[1];
+static int num_pcie_ports;
+
+static int pcie_phy_cr_read(int addr, int *data);
+static int pcie_phy_cr_write(int addr, int data);
+static void change_field(int *in, int start, int end, int val);
+
+/* IMX PCIE GPR configure routines */
+static inline void imx_pcie_clrset(u32 mask, u32 val, void __iomem *addr)
+{
+	printk("FIXME: Addr is %lx\n", addr);
+	writel(((readl(addr) & ~mask) | (val & mask)), addr);
+}
+
+static struct imx_pcie_port *bus_to_port(int bus)
+{
+	int i;
+
+	for (i = num_pcie_ports - 1; i >= 0; i--) {
+		int rbus = imx_pcie_port[i].root_bus_nr;
+		if (rbus != -1 && rbus == bus)
+			break;
+	}
+
+	return i >= 0 ? imx_pcie_port + i : NULL;
+}
+
+static int __init imx_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+	struct imx_pcie_port *pp;
+
+	if (nr >= num_pcie_ports)
+		return 0;
+
+	pp = &imx_pcie_port[nr];
+	pp->root_bus_nr = sys->busnr;
+
+	/*
+	 * IORESOURCE_IO
+	 */
+	snprintf(pp->io_space_name, sizeof(pp->io_space_name),
+		 "PCIe %d I/O", pp->index);
+	pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
+	pp->res[0].name = pp->io_space_name;
+	if (pp->index == 0) {
+		pp->res[0].start = PCIE_ARB_BASE_ADDR;
+		pp->res[0].end = pp->res[0].start + SZ_1M - 1;
+	}
+	pp->res[0].flags = IORESOURCE_IO;
+	if (request_resource(&ioport_resource, &pp->res[0]))
+		panic("Request PCIe IO resource failed\n");
+// FIXME
+//	sys->resource[0] = &pp->res[0];
+
+	/*
+	 * IORESOURCE_MEM
+	 */
+	snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
+			"PCIe %d MEM", pp->index);
+	pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
+	pp->res[1].name = pp->mem_space_name;
+	if (pp->index == 0) {
+		pp->res[1].start = PCIE_ARB_BASE_ADDR + SZ_1M;
+		pp->res[1].end = pp->res[1].start + SZ_16M - SZ_2M - 1;
+	}
+	pp->res[1].flags = IORESOURCE_MEM;
+	if (request_resource(&iomem_resource, &pp->res[1]))
+		panic("Request PCIe Memory resource failed\n");
+//	sys->resource[1] = &pp->res[1];
+
+//	sys->resource[2] = NULL;
+
+	return 1;
+}
+
+static int imx_pcie_link_up(void __iomem *dbi_base)
+{
+	/* Check the pcie link up or link down */
+	int iterations = 200;
+	u32 rc, ltssm, rx_valid, temp;
+
+	do {
+		/* link is debug bit 36 debug 1 start in bit 32 */
+		rc = readl(dbi_base + DB_R1) & (0x1 << (36 - 32)) ;
+		iterations--;
+		usleep_range(2000, 3000);
+
+		/* 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_cr_read(SSP_CR_LANE0_DIG_RX_ASIC_OUT, &rx_valid);
+		ltssm = readl(dbi_base + DB_R0) & 0x3F;
+		if ((ltssm == 0x0D) && ((rx_valid & 0x01) == 0)) {
+			pr_info("Transition to gen2 is stuck, reset PHY!\n");
+			pcie_phy_cr_read(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO, &temp);
+			change_field(&temp, 3, 3, 0x1);
+			change_field(&temp, 5, 5, 0x1);
+			pcie_phy_cr_write(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO,
+					0x0028);
+			usleep_range(2000, 3000);
+			pcie_phy_cr_read(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO, &temp);
+			change_field(&temp, 3, 3, 0x0);
+			change_field(&temp, 5, 5, 0x0);
+			pcie_phy_cr_write(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO,
+					0x0000);
+		}
+
+		if ((iterations < 0))
+			pr_info("link up failed, DB_R0:0x%08x, DB_R1:0x%08x!\n"
+					, readl(dbi_base + DB_R0)
+					, readl(dbi_base + DB_R1));
+	} while (!rc && iterations);
+
+	if (!rc)
+		return 0;
+	return 1;
+}
+
+static void imx_pcie_regions_setup(void __iomem *dbi_base)
+{
+	/*
+	 * i.MX6 defines 16MB in the AXI address map for PCIe.
+	 *
+	 * That address space excepted the pcie registers is
+	 * split and defined into different regions by iATU,
+	 * with sizes and offsets as follows:
+	 *
+	 * 0x0100_0000 --- 0x010F_FFFF 1MB IORESOURCE_IO
+	 * 0x0110_0000 --- 0x01EF_FFFF 14MB IORESOURCE_MEM
+	 * 0x01F0_0000 --- 0x01FF_FFFF 1MB Cfg + Registers
+	 */
+
+	/* CMD reg:I/O space, MEM space, and Bus Master Enable */
+	writel(readl(dbi_base + PCI_COMMAND)
+			| PCI_COMMAND_IO
+			| PCI_COMMAND_MEMORY
+			| PCI_COMMAND_MASTER,
+			dbi_base + PCI_COMMAND);
+
+	/* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */
+	writel(readl(dbi_base + PCI_CLASS_REVISION)
+			| (PCI_CLASS_BRIDGE_PCI << 16),
+			dbi_base + PCI_CLASS_REVISION);
+
+	/*
+	 * region0 outbound used to access target cfg
+	 */
+	writel(0, dbi_base + ATU_VIEWPORT_R);
+	writel(PCIE_ARB_END_ADDR - SZ_1M + 1, dbi_base + ATU_REGION_LOWBASE_R);
+	writel(PCIE_ARB_END_ADDR, dbi_base + ATU_REGION_LIMIT_ADDR_R);
+	writel(0, dbi_base + ATU_REGION_UPBASE_R);
+
+	writel(0, dbi_base + ATU_REGION_LOW_TRGT_ADDR_R);
+	writel(0, dbi_base + ATU_REGION_UP_TRGT_ADDR_R);
+	writel(CfgRdWr0, dbi_base + ATU_REGION_CTRL1_R);
+	writel((1<<31), dbi_base + ATU_REGION_CTRL2_R);
+}
+
+static int imx_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+			int size, u32 *val)
+{
+	struct imx_pcie_port *pp = bus_to_port(bus->number);
+	u32 va_address;
+
+	if (pp) {
+		if (devfn != 0) {
+			*val = 0xffffffff;
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+
+		va_address = (u32)dbi_base + (where & ~0x3);
+	} else
+		va_address = (u32)base + (PCIE_CONF_BUS(bus->number - 1) +
+					  PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+					  PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+					  PCIE_CONF_REG(where));
+
+	*val = readl(va_address);
+
+	if (size == 1)
+		*val = (*val >> (8 * (where & 3))) & 0xFF;
+	else if (size == 2)
+		*val = (*val >> (8 * (where & 3))) & 0xFFFF;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int imx_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+			int where, int size, u32 val)
+{
+	struct imx_pcie_port *pp = bus_to_port(bus->number);
+	u32 va_address = 0, mask = 0, tmp = 0;
+	int ret = PCIBIOS_SUCCESSFUL;
+
+	if (pp) {
+		if (devfn != 0)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+		va_address = (u32)dbi_base + (where & ~0x3);
+	} else
+		va_address = (u32)base + (PCIE_CONF_BUS(bus->number - 1) +
+					  PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+					  PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+					  PCIE_CONF_REG(where));
+
+	if (size == 4) {
+		writel(val, va_address);
+		goto exit;
+	}
+
+	if (size == 2)
+		mask = ~(0xFFFF << ((where & 0x3) * 8));
+	else if (size == 1)
+		mask = ~(0xFF << ((where & 0x3) * 8));
+	else
+		ret = PCIBIOS_BAD_REGISTER_NUMBER;
+
+	tmp = readl(va_address) & mask;
+	tmp |= val << ((where & 0x3) * 8);
+	writel(tmp, va_address);
+exit:
+
+	return ret;
+}
+
+static struct pci_ops imx_pcie_ops = {
+	.read = imx_pcie_rd_conf,
+	.write = imx_pcie_wr_conf,
+};
+
+static struct pci_bus __init *
+imx_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+{
+	struct pci_bus *bus;
+
+	if (nr < num_pcie_ports) {
+		bus = pci_scan_bus(sys->busnr, &imx_pcie_ops, sys);
+	} else {
+		bus = NULL;
+		BUG();
+	}
+
+	return bus;
+}
+
+static int __init imx_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	return MXC_INT_PCIE_3;
+}
+
+static struct hw_pci imx_pci __initdata = {
+	.nr_controllers	= 1,
+	.swizzle	= pci_std_swizzle,
+	.setup		= imx_pcie_setup,
+	.scan		= imx_pcie_scan_bus,
+	.map_irq	= imx_pcie_map_irq,
+};
+
+/* PHY CR bus acess routines */
+static int pcie_phy_cr_ack_polling(int max_iterations, int exp_val)
+{
+	u32 temp_rd_data, wait_counter = 0;
+
+	do {
+		temp_rd_data = readl(dbi_base + PHY_STS_R);
+		temp_rd_data = (temp_rd_data >> PCIE_CR_STAT_ACK_LOC) & 0x1;
+		wait_counter++;
+	} while ((wait_counter < max_iterations) && (temp_rd_data != exp_val));
+
+	if (temp_rd_data != exp_val)
+		return 0 ;
+	return 1 ;
+}
+
+static int pcie_phy_cr_cap_addr(int addr)
+{
+	u32 temp_wr_data;
+
+	/* write addr */
+	temp_wr_data = addr << PCIE_CR_CTL_DATA_LOC ;
+	writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+	/* capture addr */
+	temp_wr_data |= (0x1 << PCIE_CR_CTL_CAP_ADR_LOC);
+	writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+	/* wait for ack */
+	if (!pcie_phy_cr_ack_polling(100, 1))
+		return 0;
+
+	/* deassert cap addr */
+	temp_wr_data = addr << PCIE_CR_CTL_DATA_LOC;
+	writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+	/* wait for ack de-assetion */
+	if (!pcie_phy_cr_ack_polling(100, 0))
+		return 0 ;
+
+	return 1 ;
+}
+
+static int pcie_phy_cr_read(int addr , int *data)
+{
+	u32 temp_rd_data, temp_wr_data;
+
+	/*  write addr */
+	/* cap addr */
+	if (!pcie_phy_cr_cap_addr(addr))
+		return 0;
+
+	/* assert rd signal */
+	temp_wr_data = 0x1 << PCIE_CR_CTL_RD_LOC;
+	writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+	/* wait for ack */
+	if (!pcie_phy_cr_ack_polling(100, 1))
+		return 0;
+
+	/* after got ack return data */
+	temp_rd_data = readl(dbi_base + PHY_STS_R);
+	*data = (temp_rd_data & (0xffff << PCIE_CR_STAT_DATA_LOC)) ;
+
+	/* deassert rd signal */
+	temp_wr_data = 0x0;
+	writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+	/* wait for ack de-assetion */
+	if (!pcie_phy_cr_ack_polling(100, 0))
+		return 0 ;
+
+	return 1 ;
+
+}
+
+static int pcie_phy_cr_write(int addr, int data)
+{
+	u32 temp_wr_data;
+
+	/* write addr */
+	/* cap addr */
+	if (!pcie_phy_cr_cap_addr(addr))
+		return 0 ;
+
+	temp_wr_data = data << PCIE_CR_CTL_DATA_LOC;
+	writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+	/* capture data */
+	temp_wr_data |= (0x1 << PCIE_CR_CTL_CAP_DAT_LOC);
+	writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+	/* wait for ack */
+	if (!pcie_phy_cr_ack_polling(100, 1))
+		return 0 ;
+
+	/* deassert cap data */
+	temp_wr_data = data << PCIE_CR_CTL_DATA_LOC;
+	writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+	/* wait for ack de-assetion */
+	if (!pcie_phy_cr_ack_polling(100, 0))
+		return 0;
+
+	/* assert wr signal */
+	temp_wr_data = 0x1 << PCIE_CR_CTL_WR_LOC;
+	writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+	/* wait for ack */
+	if (!pcie_phy_cr_ack_polling(100, 1))
+		return 0;
+
+	/* deassert wr signal */
+	temp_wr_data = data << PCIE_CR_CTL_DATA_LOC;
+	writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+	/* wait for ack de-assetion */
+	if (!pcie_phy_cr_ack_polling(100, 0))
+		return 0;
+
+	temp_wr_data = 0x0 ;
+	writel(temp_wr_data, dbi_base + PHY_CTRL_R);
+
+	return 1 ;
+}
+
+static void change_field(int *in, int start, int end, int val)
+{
+	int mask;
+
+	mask = ((0xFFFFFFFF << start) ^ (0xFFFFFFFF << (end + 1))) & 0xFFFFFFFF;
+	*in = (*in & ~mask) | (val << start);
+}
+
+static void imx_pcie_enable_controller(struct device *dev)
+{
+	struct clk *pcie_clk;
+	struct imx_pcie_platform_data *pdata = dev->platform_data;
+
+	/* Enable PCIE power */
+	gpio_request(pdata->pcie_pwr_en, "PCIE POWER_EN");
+
+	/* activate PCIE_PWR_EN */
+	gpio_direction_output(pdata->pcie_pwr_en, 1);
+
+	imx_pcie_clrset(iomuxc_gpr1_test_powerdown, 0 << 18, IOMUXC_GPR1);
+
+/* FIXME */
+#define PCIE_CLK "pcie_ref"
+	/* enable the clks */
+	pcie_clk = clk_get(NULL, PCIE_CLK);
+	if (IS_ERR(pcie_clk)) {
+		pr_err("no pcie (?) clock.\n");
+	} else if (clk_enable(pcie_clk)) {
+		pr_err("can't enable pcie clock.\n");
+		clk_put(pcie_clk);
+	}
+
+	imx_pcie_clrset(iomuxc_gpr1_pcie_ref_clk_en, 1 << 16, IOMUXC_GPR1);
+}
+
+static void card_reset(struct device *dev)
+{
+	struct imx_pcie_platform_data *pdata = dev->platform_data;
+
+	/* PCIE RESET */
+	gpio_request(pdata->pcie_rst, "PCIE RESET");
+
+	/* activate PERST_B */
+	gpio_direction_output(pdata->pcie_rst, 0);
+
+	/* Add one reset to the pcie external device */
+	msleep(100);
+
+	/* deactive PERST_B */
+	gpio_direction_output(pdata->pcie_rst, 1);
+}
+
+static void __init add_pcie_port(void __iomem *base, void __iomem *dbi_base,
+		struct imx_pcie_platform_data *pdata)
+{
+	struct clk *pcie_clk;
+
+	if (imx_pcie_link_up(dbi_base)) {
+		struct imx_pcie_port *pp = &imx_pcie_port[num_pcie_ports++];
+
+		pr_info("IMX PCIe port: link up.\n");
+
+		pp->index = 0;
+		pp->root_bus_nr = -1;
+		pp->base = base;
+		pp->dbi_base = dbi_base;
+		spin_lock_init(&pp->conf_lock);
+		memset(pp->res, 0, sizeof(pp->res));
+	} else {
+		pr_info("IMX PCIe port: link down!\n");
+		/* Release the clocks, and disable the power */
+
+		pcie_clk = clk_get(NULL, PCIE_CLK);
+		if (IS_ERR(pcie_clk))
+			pr_err("no pcie clock.\n");
+
+		clk_disable(pcie_clk);
+		clk_put(pcie_clk);
+
+		imx_pcie_clrset(iomuxc_gpr1_pcie_ref_clk_en, 0 << 16,
+				IOMUXC_GPR1);
+
+		/* Disable PCIE power */
+		gpio_request(pdata->pcie_pwr_en, "PCIE POWER_EN");
+
+		/* activate PCIE_PWR_EN */
+		gpio_direction_output(pdata->pcie_pwr_en, 0);
+
+		imx_pcie_clrset(iomuxc_gpr1_test_powerdown, 1 << 18,
+				IOMUXC_GPR1);
+	}
+}
+
+static int imx_pcie_pltfm_probe(struct platform_device *pdev)
+{
+	struct resource *mem;
+	struct device *dev = &pdev->dev;
+	struct imx_pcie_platform_data *pdata = dev->platform_data;
+
+	printk("imx_pcie_pltfm_probe\n");
+
+	printk("FIXME: preparing for  Pcie\n");
+	{
+		iomux_base = ioremap(MX6Q_IOMUXC_BASE_ADDR, SZ_16K);
+		printk("FIXME: %lx, mapped at %lx\n", MX6Q_IOMUXC_BASE_ADDR, iomux_base);
+		printk("FIXME: sanity check %lx\n", phys_to_virt(MX6Q_IOMUXC_BASE_ADDR));
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(dev, "no mmio space\n");
+		return -EINVAL;
+	}
+
+	base = ioremap_nocache(PCIE_ARB_END_ADDR - SZ_1M + 1, SZ_1M - SZ_16K);
+	if (!base) {
+		pr_err("error with ioremap in function %s\n", __func__);
+		return -EIO;
+	}
+
+	dbi_base = devm_ioremap(dev, mem->start, resource_size(mem));
+	if (!dbi_base) {
+		dev_err(dev, "can't map %pR\n", mem);
+		return -ENOMEM;
+	}
+
+	printk("imx_pcie_pltfm_probe: clrsets\n");
+	/* FIXME the field name should be aligned to RM */
+	imx_pcie_clrset(iomuxc_gpr12_app_ltssm_enable, 0 << 10, IOMUXC_GPR12);
+
+	printk("imx_pcie_pltfm_probe: clrsets1\n");
+
+	/* configure constant input signal to the pcie ctrl and phy */
+	imx_pcie_clrset(iomuxc_gpr12_device_type, PCI_EXP_TYPE_ROOT_PORT << 12,
+			IOMUXC_GPR12);
+	imx_pcie_clrset(iomuxc_gpr12_los_level, 9 << 4, IOMUXC_GPR12);
+
+	printk("imx_pcie_pltfm_probe: clrsets2\n");
+	imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen1, 0 << 0, IOMUXC_GPR8);
+	imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen2_3p5db, 0 << 6, IOMUXC_GPR8);
+	imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen2_6db, 20 << 12, IOMUXC_GPR8);
+	imx_pcie_clrset(iomuxc_gpr8_tx_swing_full, 127 << 18, IOMUXC_GPR8);
+	imx_pcie_clrset(iomuxc_gpr8_tx_swing_low, 127 << 25, IOMUXC_GPR8);
+
+
+	printk("imx_pcie_pltfm_probe: controller\n");
+	/* Enable the pwr, clks and so on */
+	imx_pcie_enable_controller(dev);
+
+	/* togle the external card's reset */
+	card_reset(dev) ;
+
+	usleep_range(3000, 4000);
+	imx_pcie_regions_setup(dbi_base);
+	usleep_range(3000, 4000);
+
+	/* start link up */
+	imx_pcie_clrset(iomuxc_gpr12_app_ltssm_enable, 1 << 10, IOMUXC_GPR12);
+
+	/* add the pcie port */
+	add_pcie_port(base, dbi_base, pdata);
+
+
+	printk("imx_pcie_pltfm_probe: common init\n");
+
+	pci_common_init(&imx_pci);
+	return 0;
+}
+
+static int imx_pcie_pltfm_remove(struct platform_device *pdev)
+{
+	struct clk *pcie_clk;
+	struct device *dev = &pdev->dev;
+	struct imx_pcie_platform_data *pdata = dev->platform_data;
+	struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	/* Release clocks, and disable power  */
+	pcie_clk = clk_get(NULL, PCIE_CLK);
+	if (IS_ERR(pcie_clk))
+		pr_err("no pcie clock.\n");
+
+	if (pcie_clk) {
+		clk_disable(pcie_clk);
+		clk_put(pcie_clk);
+	}
+
+	imx_pcie_clrset(iomuxc_gpr1_pcie_ref_clk_en, 0 << 16, IOMUXC_GPR1);
+
+	/* Disable PCIE power */
+	gpio_request(pdata->pcie_pwr_en, "PCIE POWER_EN");
+
+	/* activate PCIE_PWR_EN */
+	gpio_direction_output(pdata->pcie_pwr_en, 0);
+
+	imx_pcie_clrset(iomuxc_gpr1_test_powerdown, 1 << 18, IOMUXC_GPR1);
+
+	iounmap(base);
+	iounmap(dbi_base);
+	release_mem_region(iomem->start, resource_size(iomem));
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver imx_pcie_pltfm_driver = {
+	.driver = {
+		.name	= "imx-pcie",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= imx_pcie_pltfm_probe,
+	.remove		= imx_pcie_pltfm_remove,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __init imx_pcie_drv_init(void)
+{
+	return platform_driver_register(&imx_pcie_pltfm_driver);
+}
+
+static void __exit imx_pcie_drv_exit(void)
+{
+	platform_driver_unregister(&imx_pcie_pltfm_driver);
+}
+
+module_init(imx_pcie_drv_init);
+module_exit(imx_pcie_drv_exit);
+
+MODULE_DESCRIPTION("i.MX PCIE platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-imx/pcie.h b/arch/arm/mach-imx/pcie.h
new file mode 100644
index 0000000..39efcae
--- /dev/null
+++ b/arch/arm/mach-imx/pcie.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __ASM_ARCH_IMX_PCIE_H
+#define __ASM_ARCH_IMX_PCIE_H
+
+/**
+ * struct imx_pcie_platform_data - optional platform data for pcie on i.MX
+ *
+ * @pcie_pwr_en:	used for enable/disable pcie power (-EINVAL if unused)
+ * @pcie_rst:		used for reset pcie ep (-EINVAL if unused)
+ * @pcie_wake_up:	used for wake up (-EINVAL if unused)
+ * @pcie_dis:		used for disable pcie ep (-EINVAL if unused)
+ */
+
+struct imx_pcie_platform_data {
+	unsigned int pcie_pwr_en;
+	unsigned int pcie_rst;
+	unsigned int pcie_wake_up;
+	unsigned int pcie_dis;
+};
+
+/* FIXME: defines that may not belong here */
+#define PCIE_ARB_BASE_ADDR 0x01000000
+#define PCIE_ARB_END_ADDR 0x01FFFFFF
+#define MXC_INT_PCIE_3 155
+#define MX6Q_IOMUXC_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x60000)
+#define AIPS1_ARB_BASE_ADDR 0x02000000
+#define ATZ1_BASE_ADDR AIPS1_ARB_BASE_ADDR
+#define AIPS1_OFF_BASE_ADDR (ATZ1_BASE_ADDR + 0x80000)
+
+#define pci_std_swizzle pci_common_swizzle
+
+#endif /* __ASM_ARCH_IMX_PCIE_H */

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html



More information about the linux-arm-kernel mailing list