summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2012-02-08 14:57:56 +0800
committerRichard Zhu <r65037@freescale.com>2012-02-10 14:00:01 +0800
commiteeefe04ae2dbe4d336d721ae38019fe9cd282aa0 (patch)
tree2f7111db4e63435a7d71dc5587e628b0d9c85bb5
parent3dbc85ad1da25dfdbd33af34219dda2014477636 (diff)
ENGR00174033-1 MX6 PCIE: add pcie RC driver
Add PCIE RC driver on MX6 platforms. Based on iwl4965agn pcie wifi device, verified the following features. * Link up is stable * map the CFG, IO and MEM spaces, and CFG/MEM spaces can be accessed Signed-off-by: Richard Zhu <r65037@freescale.com>
-rw-r--r--arch/arm/mach-mx6/Kconfig4
-rw-r--r--arch/arm/mach-mx6/Makefile1
-rw-r--r--arch/arm/mach-mx6/board-mx6q_arm2.c2
-rw-r--r--arch/arm/mach-mx6/clock.c43
-rw-r--r--arch/arm/mach-mx6/crm_regs.h4
-rw-r--r--arch/arm/mach-mx6/pcie.c484
-rwxr-xr-xarch/arm/plat-mxc/include/mach/hardware.h7
7 files changed, 542 insertions, 3 deletions
diff --git a/arch/arm/mach-mx6/Kconfig b/arch/arm/mach-mx6/Kconfig
index 83dfa5c33783..57959f050b03 100644
--- a/arch/arm/mach-mx6/Kconfig
+++ b/arch/arm/mach-mx6/Kconfig
@@ -163,4 +163,8 @@ config MACH_MX6Q_SABREAUTO
comment "MX6 Options:"
+config IMX_PCIE
+ bool "PCI Express support"
+ select PCI
+
endif
diff --git a/arch/arm/mach-mx6/Makefile b/arch/arm/mach-mx6/Makefile
index 6fc9646ba8d2..21f776ab598c 100644
--- a/arch/arm/mach-mx6/Makefile
+++ b/arch/arm/mach-mx6/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_MACH_MX6Q_SABRESD) += board-mx6q_sabresd.o mx6q_sabresd_pmic_pfuze1
obj-$(CONFIG_MACH_MX6Q_SABREAUTO) += board-mx6q_sabreauto.o mx6q_sabreauto_pmic_pfuze100.o
obj-$(CONFIG_SMP) += plat_hotplug.o platsmp.o headsmp.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
+obj-$(CONFIG_IMX_PCIE) += pcie.o
diff --git a/arch/arm/mach-mx6/board-mx6q_arm2.c b/arch/arm/mach-mx6/board-mx6q_arm2.c
index 5ea5a2ab907e..17eb522067b5 100644
--- a/arch/arm/mach-mx6/board-mx6q_arm2.c
+++ b/arch/arm/mach-mx6/board-mx6q_arm2.c
@@ -394,7 +394,7 @@ static int max7310_1_setup(struct i2c_client *client,
unsigned gpio_base, unsigned ngpio,
void *context)
{
- int max7310_gpio_value[] = { 0, 1, 0, 1, 0, 0, 0, 0 };
+ int max7310_gpio_value[] = { 0, 1, 1, 1, 0, 0, 0, 0 };
int n;
diff --git a/arch/arm/mach-mx6/clock.c b/arch/arm/mach-mx6/clock.c
index 5e703a8c9153..2315244dd9db 100644
--- a/arch/arm/mach-mx6/clock.c
+++ b/arch/arm/mach-mx6/clock.c
@@ -4565,7 +4565,48 @@ static int _clk_pcie_enable(struct clk *clk)
{
unsigned int reg;
- /* Enable SATA ref clock */
+ /* Clear Power Down and Enable PLLs */
+ reg = __raw_readl(PLL8_ENET_BASE_ADDR);
+ reg &= ~ANADIG_PLL_ENET_POWER_DOWN;
+ __raw_writel(reg, PLL8_ENET_BASE_ADDR);
+
+ reg = __raw_readl(PLL8_ENET_BASE_ADDR);
+ reg |= ANADIG_PLL_ENET_EN;
+ __raw_writel(reg, PLL8_ENET_BASE_ADDR);
+
+ /* Waiting for the PLL is locked */
+ if (!WAIT(ANADIG_PLL_ENET_LOCK & __raw_readl(PLL8_ENET_BASE_ADDR),
+ SPIN_DELAY))
+ panic("pll8 lock failed\n");
+
+ /* Disable the bypass */
+ reg = __raw_readl(PLL8_ENET_BASE_ADDR);
+ reg &= ~ANADIG_PLL_ENET_BYPASS;
+ __raw_writel(reg, PLL8_ENET_BASE_ADDR);
+
+ /*
+ * Enable SATA ref clock.
+ * PCIe needs both sides to have the same source of refernce clock,
+ * The SATA reference clock is taken out on clk out
+ */
+ reg = __raw_readl(PLL8_ENET_BASE_ADDR);
+ reg |= ANADIG_PLL_ENET_EN_SATA;
+ __raw_writel(reg, PLL8_ENET_BASE_ADDR);
+
+ /* Activate LVDS CLK1 (the MiniPCIe slot clock input) */
+ reg = __raw_readl(ANADIG_MISC1_REG);
+ reg &= ~ANATOP_LVDS_CLK1_IBEN_MASK;
+ __raw_writel(reg, ANADIG_MISC1_REG);
+
+ reg = __raw_readl(ANADIG_MISC1_REG);
+ reg |= ANATOP_LVDS_CLK1_SRC_SATA;
+ __raw_writel(reg, ANADIG_MISC1_REG);
+
+ reg = __raw_readl(ANADIG_MISC1_REG);
+ reg |= ANATOP_LVDS_CLK1_OBEN_MASK;
+ __raw_writel(reg, ANADIG_MISC1_REG);
+
+ /* Enable PCIE ref clock */
reg = __raw_readl(PLL8_ENET_BASE_ADDR);
reg |= ANADIG_PLL_ENET_EN_PCIE;
__raw_writel(reg, PLL8_ENET_BASE_ADDR);
diff --git a/arch/arm/mach-mx6/crm_regs.h b/arch/arm/mach-mx6/crm_regs.h
index 0e29ea83f1df..6dbdeafa0dba 100644
--- a/arch/arm/mach-mx6/crm_regs.h
+++ b/arch/arm/mach-mx6/crm_regs.h
@@ -47,6 +47,10 @@
#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 ANA_MISC2_BASE_ADDR (MXC_PLL_BASE + 0x170)
#define PLL_SETREG_OFFSET 0x4
diff --git a/arch/arm/mach-mx6/pcie.c b/arch/arm/mach-mx6/pcie.c
new file mode 100644
index 000000000000..9959bbceaa4d
--- /dev/null
+++ b/arch/arm/mach-mx6/pcie.c
@@ -0,0 +1,484 @@
+/*
+ * 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 <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)
+
+/* 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)
+
+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;
+
+/* IMX PCIE GPR configure routines */
+static inline void imx_pcie_clrset(u32 mask, u32 val, void __iomem *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_64K - 1;
+ }
+ pp->res[0].flags = IORESOURCE_IO;
+ if (request_resource(&ioport_resource, &pp->res[0]))
+ panic("Request PCIe IO resource failed\n");
+ 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_64K;
+ pp->res[1].end = pp->res[1].start + SZ_16M - SZ_128K - 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 void __init imx_pcie_preinit(void)
+{
+ pcibios_setup("debug");
+}
+
+static int imx_pcie_link_up(void __iomem *dbi_base)
+{
+ /* Check the pcie link up or link down */
+ u32 rc, iterations = 0x100000;
+
+ do {
+ /* link is debug bit 36 debug 1 start in bit 32 */
+ rc = readl(dbi_base + DB_R1) & (0x1 << (36-32)) ;
+ iterations--;
+ if ((iterations % 0x100000) == 0)
+ pr_info("link up failed!\n");
+ } while (!rc && iterations);
+
+ if (!rc)
+ return 0;
+ return 1;
+}
+
+static int pcie_valid_config(struct imx_pcie_port *pp, int bus_num, int dev)
+{
+ /*If there is no link, then there is no device*/
+ if (bus_num != pp->root_bus_nr) {
+ if (!imx_pcie_link_up(pp->dbi_base))
+ return 0;
+ }
+
+ /*
+ * Don't go out when trying to access nonexisting devices
+ * on the local bus.
+ * We have only one slot on the root port.
+ */
+ if (bus_num == pp->root_bus_nr && dev > 0)
+ 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 --- 0x0100_FFFF 64KB IORESOURCE_IO
+ * 0x0101_0000 --- 0x01FE_FFFF 16MB - 128KB IORESOURCE_MEM
+ * 0x01FF_0000 --- 0x01FF_FFFF 64KB 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);
+ /*
+ * region0 outbound used to access target cfg
+ */
+ writel(0, dbi_base + ATU_VIEWPORT_R);
+ writel(PCIE_ARB_END_ADDR - SZ_64K + 1, dbi_base + ATU_REGION_LOWBASE_R);
+ writel(0, dbi_base + ATU_REGION_UPBASE_R);
+ writel(PCIE_ARB_END_ADDR, dbi_base + ATU_REGION_LIMIT_ADDR_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);
+
+ /*
+ * region1 outbound used to as IORESOURCE_IO
+ */
+ writel(1, dbi_base + ATU_VIEWPORT_R);
+ writel(0, dbi_base + ATU_REGION_LOWBASE_R);
+ writel(0, dbi_base + ATU_REGION_UPBASE_R);
+ writel(SZ_64K - 1, dbi_base + ATU_REGION_LIMIT_ADDR_R);
+ writel(0, dbi_base + ATU_REGION_LOW_TRGT_ADDR_R);
+ writel(0, dbi_base + ATU_REGION_UP_TRGT_ADDR_R);
+ writel(IORdWr, dbi_base + ATU_REGION_CTRL1_R);
+ writel((1<<31), dbi_base + ATU_REGION_CTRL2_R);
+
+ /*
+ * region2 outbound used to as IORESOURCE_MEM
+ */
+ writel(2, dbi_base + ATU_VIEWPORT_R);
+ writel(0, dbi_base + ATU_REGION_LOWBASE_R);
+ writel(0, dbi_base + ATU_REGION_UPBASE_R);
+ writel(SZ_16M - SZ_128K - 1, dbi_base + ATU_REGION_LIMIT_ADDR_R);
+ writel(0, dbi_base + ATU_REGION_LOW_TRGT_ADDR_R);
+ writel(0, dbi_base + ATU_REGION_UP_TRGT_ADDR_R);
+ writel(MemRdWr, 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);
+ unsigned long flags;
+ u32 va_address;
+
+ if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) {
+ *val = 0xFFFFFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+
+ spin_lock_irqsave(&pp->conf_lock, flags);
+
+ va_address = (u32)pp->base +
+ PCIE_CONF_BUS(bus->number) +
+ PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+ PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+ (where & ~0x3);
+
+ *val = readl(va_address);
+
+ if (size == 1)
+ *val = (*val >> (8 * (where & 3))) & 0xFF;
+ else if (size == 2)
+ *val = (*val >> (8 * (where & 3))) & 0xFFFF;
+
+ spin_unlock_irqrestore(&pp->conf_lock, flags);
+
+ 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);
+ unsigned long flags;
+ u32 va_address = 0, mask = 0, tmp = 0;
+ int ret = PCIBIOS_SUCCESSFUL;
+
+ if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ spin_lock_irqsave(&pp->conf_lock, flags);
+
+ va_address = (u32)pp->base +
+ PCIE_CONF_BUS(bus->number) +
+ PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+ PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+ (where & ~0x3);
+
+ 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:
+ spin_unlock_irqrestore(&pp->conf_lock, flags);
+
+ 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_0;
+}
+
+static struct hw_pci imx_pci __initdata = {
+ .nr_controllers = 1,
+ .swizzle = pci_std_swizzle,
+ .setup = imx_pcie_setup,
+ .preinit = imx_pcie_preinit,
+ .scan = imx_pcie_scan_bus,
+ .map_irq = imx_pcie_map_irq,
+};
+
+static void imx_pcie_enable_controller(void)
+{
+ struct clk *pcie_clk;
+
+ imx_pcie_clrset(iomuxc_gpr1_test_powerdown, 0 << 18, IOMUXC_GPR1);
+
+ /* enable the clks */
+ pcie_clk = clk_get(NULL, "pcie_clk");
+ if (IS_ERR(pcie_clk))
+ pr_err("no pcie clock.\n");
+
+ if (clk_enable(pcie_clk)) {
+ pr_err("can't enable pcie clock.\n");
+ clk_put(pcie_clk);
+ }
+}
+
+static void card_reset(void)
+{
+ /* Add one reset to the pcie external device */
+}
+
+static void __init add_pcie_port(void __iomem *base, void __iomem *dbi_base)
+{
+ 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");
+}
+
+static int __init imx_pcie_init(void)
+{
+ void __iomem *base, *dbi_base;
+
+ base = ioremap_nocache(PCIE_ARB_END_ADDR - SZ_64K + 1, SZ_32K);
+ if (!base) {
+ pr_err("error with ioremap in function %s\n", __func__);
+ return -EIO;
+ }
+
+ dbi_base = ioremap_nocache(PCIE_DBI_BASE_ADDR, SZ_16K);
+ if (!dbi_base) {
+ pr_err("error with ioremap in function %s\n", __func__);
+ iounmap(base);
+ return -EIO;
+ }
+
+ /* FIXME the field name should be aligned to RM */
+ imx_pcie_clrset(iomuxc_gpr12_app_ltssm_enable, 0 << 10, IOMUXC_GPR12);
+
+ /* 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);
+ imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen1, 21 << 0, IOMUXC_GPR8);
+ imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen2_3p5db, 21 << 6, IOMUXC_GPR8);
+ imx_pcie_clrset(iomuxc_gpr8_tx_deemph_gen2_6db, 32 << 12, IOMUXC_GPR8);
+ imx_pcie_clrset(iomuxc_gpr8_tx_swing_full, 115 << 18, IOMUXC_GPR8);
+ imx_pcie_clrset(iomuxc_gpr8_tx_swing_low, 115 << 25, IOMUXC_GPR8);
+
+ /* Enable the pwr, clks and so on */
+ imx_pcie_enable_controller();
+
+ imx_pcie_clrset(iomuxc_gpr1_pcie_ref_clk_en, 1 << 16, IOMUXC_GPR1);
+
+ /* togle the external card's reset */
+ card_reset() ;
+
+ 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);
+
+ pci_common_init(&imx_pci);
+ pr_info("pcie init successful\n");
+ return 0;
+}
+subsys_initcall(imx_pcie_init);
diff --git a/arch/arm/plat-mxc/include/mach/hardware.h b/arch/arm/plat-mxc/include/mach/hardware.h
index ef964551b0ea..e1c523443ca8 100755
--- a/arch/arm/plat-mxc/include/mach/hardware.h
+++ b/arch/arm/plat-mxc/include/mach/hardware.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2011 Freescale Semiconductor, Inc.
+ * Copyright 2004-2012 Freescale Semiconductor, Inc.
* Copyright 2008 Juergen Beisert, kernel@pengutronix.de
*
* This program is free software; you can redistribute it and/or
@@ -138,4 +138,9 @@
.type = _type, \
}
+/* macro to get at IO space when running virtually */
+#define PCIBIOS_MIN_IO 0x00000000
+#define PCIBIOS_MIN_MEM 0x00000000
+#define pcibios_assign_all_busses() 0
+
#endif /* __ASM_ARCH_MXC_HARDWARE_H__ */