diff options
author | Richard Zhu <r65037@freescale.com> | 2012-02-08 14:57:56 +0800 |
---|---|---|
committer | Richard Zhu <r65037@freescale.com> | 2012-02-10 14:00:01 +0800 |
commit | eeefe04ae2dbe4d336d721ae38019fe9cd282aa0 (patch) | |
tree | 2f7111db4e63435a7d71dc5587e628b0d9c85bb5 /arch/arm/mach-mx6 | |
parent | 3dbc85ad1da25dfdbd33af34219dda2014477636 (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>
Diffstat (limited to 'arch/arm/mach-mx6')
-rw-r--r-- | arch/arm/mach-mx6/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/mach-mx6/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-mx6/board-mx6q_arm2.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-mx6/clock.c | 43 | ||||
-rw-r--r-- | arch/arm/mach-mx6/crm_regs.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-mx6/pcie.c | 484 |
6 files changed, 536 insertions, 2 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); |