]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00174033-1 MX6 PCIE: add pcie RC driver
authorRichard Zhu <r65037@freescale.com>
Wed, 8 Feb 2012 06:57:56 +0000 (14:57 +0800)
committerOliver Wendt <ow@karo-electronics.de>
Mon, 30 Sep 2013 12:10:52 +0000 (14:10 +0200)
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>
arch/arm/mach-mx6/Kconfig
arch/arm/mach-mx6/Makefile
arch/arm/mach-mx6/board-mx6q_arm2.c
arch/arm/mach-mx6/clock.c
arch/arm/mach-mx6/crm_regs.h
arch/arm/mach-mx6/pcie.c [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/hardware.h

index 83dfa5c3378359945caf93a167c76981d32a58d5..57959f050b03a10ed458ab018a507f452cb69bd4 100644 (file)
@@ -163,4 +163,8 @@ config MACH_MX6Q_SABREAUTO
 
 comment "MX6 Options:"
 
+config IMX_PCIE
+       bool "PCI Express support"
+       select PCI
+
 endif
index 6fc9646ba8d2b1cc3cab27c98253d4d1a85fddb8..21f776ab598c388a73154c79f40be94b978fabad 100644 (file)
@@ -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
index 5ea5a2ab907eefa406e1df46fc996dbbf50bbefc..17eb522067b55c9bbd031df04c05fd27114c0721 100644 (file)
@@ -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;
 
index 5e703a8c915319a691a232b5a212d04e73b36be6..2315244dd9db6a915a397ddc4d1af6b269dd8348 100644 (file)
@@ -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);
index 0e29ea83f1df894c61dccab54c3f81a0c6525f53..6dbdeafa0dba63e73a8d7187a75563ac0b9c06f6 100644 (file)
 #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 (file)
index 0000000..9959bbc
--- /dev/null
@@ -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);
index ef964551b0ea7c0774edc7eba601e79fd003620e..e1c523443ca8f63fd87053d6f8141c4c6c30265c 100755 (executable)
@@ -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
        .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__ */