[U-Boot] [PATCH 1/4] arm/ls102xa: create TLB to map PCIe region

LS1021A's PCIe1 region begins 0x40_00000000; PCIe2 begins 0x48_00000000. In order to access PCIe device, we must create TLB to map the 40bit physical address to 32bit virtual address. This patch will enable MMU after DDR is available and creates MMU table in DRAM to map all 4G space; then, re-use the reserved space to map PCIe region. The following the mapping layout.
VA mapping: ------- <---- 0GB | | | | |-------| <---- 0x24000000 |///////| ===> 192MB VA map for PCIe1 with offset 0x40_0000_0000 |-------| <---- 0x300000000 | | |-------| <---- 0x34000000 |///////| ===> 192MB VA map for PCIe2 with offset 0x48_0000_0000 |-------| <---- 0x40000000 | | |-------| <---- 0x80000000 DDR0 space start |\\\| |\\\| ===> 2GB VA map for 2GB DDR0 Memory space |\\\| ------- <---- 4GB DDR0 space end
Signed-off-by: Minghuan Lian Minghuan.Lian@freescale.com --- arch/arm/cpu/armv7/ls102xa/cpu.c | 203 +++++++++++++++++++++++++++-- arch/arm/include/asm/arch-ls102xa/config.h | 14 ++ 2 files changed, 207 insertions(+), 10 deletions(-)
diff --git a/arch/arm/cpu/armv7/ls102xa/cpu.c b/arch/arm/cpu/armv7/ls102xa/cpu.c index ce2d92f..18665a3 100644 --- a/arch/arm/cpu/armv7/ls102xa/cpu.c +++ b/arch/arm/cpu/armv7/ls102xa/cpu.c @@ -8,6 +8,8 @@ #include <asm/arch/clock.h> #include <asm/io.h> #include <asm/arch/immap_ls102xa.h> +#include <asm/cache.h> +#include <asm/system.h> #include <tsec.h> #include <netdev.h> #include <fsl_esdhc.h> @@ -16,6 +18,197 @@
DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_SYS_DCACHE_OFF + +/* + * Bit[1] of the descriptor indicates the descriptor type, + * and bit[0] indicates whether the descriptor is valid. + */ +#define PMD_TYPE_TABLE 0x3 +#define PMD_TYPE_SECT 0x1 + +/* AttrIndx[2:0] */ +#define PMD_ATTRINDX(t) ((t) << 2) + +/* Section */ +#define PMD_SECT_AF (1 << 10) + +#define BLOCK_SIZE_L1 (1UL << 30) +#define BLOCK_SIZE_L2 (1UL << 21) + +/* TTBCR flags */ +#define TTBCR_EAE (1 << 31) +#define TTBCR_T0SZ(x) ((x) << 0) +#define TTBCR_T1SZ(x) ((x) << 16) +#define TTBCR_USING_TTBR0 (TTBCR_T0SZ(0) | TTBCR_T1SZ(0)) +#define TTBCR_IRGN0_NC (0 << 8) +#define TTBCR_IRGN0_WBWA (1 << 8) +#define TTBCR_IRGN0_WT (2 << 8) +#define TTBCR_IRGN0_WBNWA (3 << 8) +#define TTBCR_IRGN0_MASK (3 << 8) +#define TTBCR_ORGN0_NC (0 << 10) +#define TTBCR_ORGN0_WBWA (1 << 10) +#define TTBCR_ORGN0_WT (2 << 10) +#define TTBCR_ORGN0_WBNWA (3 << 10) +#define TTBCR_ORGN0_MASK (3 << 10) +#define TTBCR_SHARED_NON (0 << 12) +#define TTBCR_SHARED_OUTER (2 << 12) +#define TTBCR_SHARED_INNER (3 << 12) +#define TTBCR_EPD0 (0 << 7) +#define TTBCR (TTBCR_SHARED_NON | \ + TTBCR_ORGN0_NC | \ + TTBCR_IRGN0_NC | \ + TTBCR_USING_TTBR0 | \ + TTBCR_EAE) + +/* + * Memory region attributes for LPAE (defined in pgtable): + * + * n = AttrIndx[2:0] + * + * n MAIR + * UNCACHED 000 00000000 + * BUFFERABLE 001 01000100 + * DEV_WC 001 01000100 + * WRITETHROUGH 010 10101010 + * WRITEBACK 011 11101110 + * DEV_CACHED 011 11101110 + * DEV_SHARED 100 00000100 + * DEV_NONSHARED 100 00000100 + * unused 101 + * unused 110 + * WRITEALLOC 111 11111111 + */ +#define MT_MAIR0 0xeeaa4400 +#define MT_MAIR1 0xff000004 +#define MT_STRONLY_ORDER 0 +#define MT_NORMAL_NC 1 +#define MT_DEVICE_MEM 4 +#define MT_NORMAL 7 + +/* The phy_addr must be aligned to 4KB */ +static inline void set_pgtable(u32 *page_table, u32 index, u32 phy_addr) +{ + u32 value = phy_addr | PMD_TYPE_TABLE; + + page_table[2 * index] = value; + page_table[2 * index + 1] = 0; +} + +/* The phy_addr must be aligned to 4KB */ +static inline void set_pgsection(u32 *page_table, u32 index, u64 phy_addr, + u32 memory_type) +{ + u64 value; + + value = phy_addr | PMD_TYPE_SECT | PMD_SECT_AF; + value |= PMD_ATTRINDX(memory_type); + page_table[2 * index] = value & 0xFFFFFFFF; + page_table[2 * index + 1] = (value >> 32) & 0xFFFFFFFF; +} + +/* + * Start MMU after DDR is available, we create MMU table in DRAM. + * The base address of TTLB is gd->arch.tlb_addr. We use two + * levels of translation tables here to cover 40-bit address space. + * + * The TTLBs are located at PHY 2G~4G. + * + * VA mapping: + * + * ------- <---- 0GB + * | | + * | | + * |-------| <---- 0x24000000 + * |///////| ===> 192MB VA map for PCIe1 with offset 0x40_0000_0000 + * |-------| <---- 0x300000000 + * | | + * |-------| <---- 0x34000000 + * |///////| ===> 192MB VA map for PCIe2 with offset 0x48_0000_0000 + * |-------| <---- 0x40000000 + * | | + * |-------| <---- 0x80000000 DDR0 space start + * |\\\| + *.|\\\| ===> 2GB VA map for 2GB DDR0 Memory space + * |\\\| + * ------- <---- 4GB DDR0 space end + */ +static void mmu_setup(void) +{ + u32 *level0_table = (u32 *)gd->arch.tlb_addr; + u32 *level1_table = (u32 *)(gd->arch.tlb_addr + 0x1000); + u64 va_start = 0; + u32 reg; + int i; + + /* Level 0 Table 2-3 are used to map DDR */ + set_pgsection(level0_table, 3, 3 * BLOCK_SIZE_L1, MT_NORMAL); + set_pgsection(level0_table, 2, 2 * BLOCK_SIZE_L1, MT_NORMAL); + /* Level 0 Table 1 is used to map device */ + set_pgsection(level0_table, 1, 1 * BLOCK_SIZE_L1, MT_DEVICE_MEM); + /* Level 0 Table 0 is used to map device including PCIe MEM */ + set_pgtable(level0_table, 0, (u32)level1_table); + + /* Level 1 has 512 entries */ + for (i = 0; i < 512; i++) { + /* Mapping for PCIe 1 */ + if (va_start >= CONFIG_SYS_PCIE1_VIRT_ADDR && + va_start < (CONFIG_SYS_PCIE1_VIRT_ADDR + + CONFIG_SYS_PCIE_MMAP_SIZE)) + set_pgsection(level1_table, i, + CONFIG_SYS_PCIE1_PHYS_BASE + va_start, + MT_DEVICE_MEM); + /* Mapping for PCIe 2 */ + else if (va_start >= CONFIG_SYS_PCIE2_VIRT_ADDR && + va_start < (CONFIG_SYS_PCIE2_VIRT_ADDR + + CONFIG_SYS_PCIE_MMAP_SIZE)) + set_pgsection(level1_table, i, + CONFIG_SYS_PCIE2_PHYS_BASE + va_start, + MT_DEVICE_MEM); + else + set_pgsection(level1_table, i, + va_start, + MT_DEVICE_MEM); + va_start += BLOCK_SIZE_L2; + } + + asm volatile("dsb sy;isb"); + asm volatile("mcr p15, 0, %0, c2, c0, 2" /* Write RT to TTBCR */ + : : "r" (TTBCR) : "memory"); + asm volatile("mcrr p15, 0, %0, %1, c2" /* TTBR 0 */ + : : "r" ((u32)level0_table), "r" (0) : "memory"); + asm volatile("mcr p15, 0, %0, c10, c2, 0" /* write MAIR 0 */ + : : "r" (MT_MAIR0) : "memory"); + asm volatile("mcr p15, 0, %0, c10, c2, 1" /* write MAIR 1 */ + : : "r" (MT_MAIR1) : "memory"); + + /* Set the access control to all-supervisor */ + asm volatile("mcr p15, 0, %0, c3, c0, 0" + : : "r" (~0)); + + /* Enable the mmu */ + reg = get_cr(); + set_cr(reg | CR_M); +} + +/* + * This function is called from lib/board.c. It recreates MMU + * table in main memory. MMU and i/d-cache are enabled here. + */ +void enable_caches(void) +{ + /* Invalidate all TLB */ + mmu_page_table_flush(gd->arch.tlb_addr, + gd->arch.tlb_addr + gd->arch.tlb_size); + /* Set up and enable mmu */ + mmu_setup(); + + /* Invalidate & Enable d-cache */ + invalidate_dcache_all(); + set_cr(get_cr() | CR_C); +} +#endif /* #ifndef CONFIG_SYS_DCACHE_OFF */ + #if defined(CONFIG_DISPLAY_CPUINFO) int print_cpuinfo(void) { @@ -78,16 +271,6 @@ int print_cpuinfo(void) } #endif
-void enable_caches(void) -{ -#ifndef CONFIG_SYS_ICACHE_OFF - icache_enable(); -#endif -#ifndef CONFIG_SYS_DCACHE_OFF - dcache_enable(); -#endif -} - #ifdef CONFIG_FSL_ESDHC int cpu_mmc_init(bd_t *bis) { diff --git a/arch/arm/include/asm/arch-ls102xa/config.h b/arch/arm/include/asm/arch-ls102xa/config.h index 5e934da..1c32f2e 100644 --- a/arch/arm/include/asm/arch-ls102xa/config.h +++ b/arch/arm/include/asm/arch-ls102xa/config.h @@ -61,6 +61,20 @@ #define CONFIG_SYS_PCIE1_ADDR (CONFIG_SYS_IMMR + 0x2400000) #define CONFIG_SYS_PCIE2_ADDR (CONFIG_SYS_IMMR + 0x2500000)
+#define CONFIG_SYS_PCIE1_PHYS_BASE 0x4000000000ULL +#define CONFIG_SYS_PCIE2_PHYS_BASE 0x4800000000ULL +#define CONFIG_SYS_PCIE1_VIRT_ADDR 0x24000000UL +#define CONFIG_SYS_PCIE2_VIRT_ADDR 0x34000000UL +#define CONFIG_SYS_PCIE_MMAP_SIZE (192 * 1024 * 1024) /* 192M */ +/* + * TLB will map VIRT_ADDR to (PHYS_BASE + VIRT_ADDR) + * So 40bit PCIe PHY addr can directly be converted to a 32bit virtual addr. + */ +#define CONFIG_SYS_PCIE1_PHYS_ADDR (CONFIG_SYS_PCIE1_PHYS_BASE + \ + CONFIG_SYS_PCIE1_VIRT_ADDR) +#define CONFIG_SYS_PCIE2_PHYS_ADDR (CONFIG_SYS_PCIE2_PHYS_BASE + \ + CONFIG_SYS_PCIE2_VIRT_ADDR) + #ifdef CONFIG_DDR_SPD #define CONFIG_SYS_FSL_DDR_BE #define CONFIG_VERY_BIG_RAM

Signed-off-by: Minghuan Lian Minghuan.Lian@freescale.com --- arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h b/arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h index 697d4ca..440a5b4 100644 --- a/arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h +++ b/arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h @@ -131,8 +131,7 @@ struct ccsr_scfg { u32 pex1rdmmsgrqsr; u32 pex2rdmmsgrqsr; u32 spimsiclrcr; - u32 pex1mscportsr; - u32 pex2mscportsr; + u32 pexmscportsr[2]; u32 pex2pmwrcr; u32 resv5[24]; u32 mac1_streamid;

On 01/21/2015 01:29 AM, Minghuan Lian wrote:
Signed-off-by: Minghuan Lian Minghuan.Lian@freescale.com
This set is applied to u-boot-fsl-qoriq master branch, awaiting upstream.
York

The patch enables and adds PCIe settings for boards LS1021AQDS and LS1021ATWR.
Signed-off-by: Minghuan Lian Minghuan.Lian@freescale.com --- include/configs/ls1021aqds.h | 24 ++++++++++++++++++++++++ include/configs/ls1021atwr.h | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+)
diff --git a/include/configs/ls1021aqds.h b/include/configs/ls1021aqds.h index 8dc04f2..0e6ae50 100644 --- a/include/configs/ls1021aqds.h +++ b/include/configs/ls1021aqds.h @@ -479,6 +479,30 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_PCIE_LAYERSCAPE /* Use common FSL Layerscape PCIe code */ #define FSL_PCIE_COMPAT "fsl,ls1021a-pcie"
+#define CONFIG_SYS_PCI_64BIT + +#define CONFIG_SYS_PCIE_CFG0_PHYS_OFF 0x00000000 +#define CONFIG_SYS_PCIE_CFG0_SIZE 0x00001000 /* 4k */ +#define CONFIG_SYS_PCIE_CFG1_PHYS_OFF 0x00001000 +#define CONFIG_SYS_PCIE_CFG1_SIZE 0x00001000 /* 4k */ + +#define CONFIG_SYS_PCIE_IO_BUS 0x00000000 +#define CONFIG_SYS_PCIE_IO_PHYS_OFF 0x00010000 +#define CONFIG_SYS_PCIE_IO_SIZE 0x00010000 /* 64k */ + +#define CONFIG_SYS_PCIE_MEM_BUS 0x08000000 +#define CONFIG_SYS_PCIE_MEM_PHYS_OFF 0x04000000 +#define CONFIG_SYS_PCIE_MEM_SIZE 0x08000000 /* 128M */ + +#ifdef CONFIG_PCI +#define CONFIG_NET_MULTI +#define CONFIG_PCI_PNP +#define CONFIG_E1000 +#define CONFIG_PCI_SCAN_SHOW +#define CONFIG_CMD_PCI +#define CONFIG_CMD_NET +#endif + #define CONFIG_CMD_PING #define CONFIG_CMD_DHCP #define CONFIG_CMD_MII diff --git a/include/configs/ls1021atwr.h b/include/configs/ls1021atwr.h index 66954d0..748635c 100644 --- a/include/configs/ls1021atwr.h +++ b/include/configs/ls1021atwr.h @@ -298,6 +298,30 @@ #define CONFIG_PCIE_LAYERSCAPE /* Use common FSL Layerscape PCIe code */ #define FSL_PCIE_COMPAT "fsl,ls1021a-pcie"
+#define CONFIG_SYS_PCI_64BIT + +#define CONFIG_SYS_PCIE_CFG0_PHYS_OFF 0x00000000 +#define CONFIG_SYS_PCIE_CFG0_SIZE 0x00001000 /* 4k */ +#define CONFIG_SYS_PCIE_CFG1_PHYS_OFF 0x00001000 +#define CONFIG_SYS_PCIE_CFG1_SIZE 0x00001000 /* 4k */ + +#define CONFIG_SYS_PCIE_IO_BUS 0x00000000 +#define CONFIG_SYS_PCIE_IO_PHYS_OFF 0x00010000 +#define CONFIG_SYS_PCIE_IO_SIZE 0x00010000 /* 64k */ + +#define CONFIG_SYS_PCIE_MEM_BUS 0x08000000 +#define CONFIG_SYS_PCIE_MEM_PHYS_OFF 0x04000000 +#define CONFIG_SYS_PCIE_MEM_SIZE 0x08000000 /* 128M */ + +#ifdef CONFIG_PCI +#define CONFIG_NET_MULTI +#define CONFIG_PCI_PNP +#define CONFIG_E1000 +#define CONFIG_PCI_SCAN_SHOW +#define CONFIG_CMD_PCI +#define CONFIG_CMD_NET +#endif + #define CONFIG_CMD_PING #define CONFIG_CMD_DHCP #define CONFIG_CMD_MII

The patch adds Freescale Layerscape PCIe driver and provides up to 4 controllers support.
Signed-off-by: Minghuan Lian Minghuan.Lian@freescale.com --- drivers/pci/pcie_layerscape.c | 471 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 466 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index 291c249..bcad8f2 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -1,5 +1,5 @@ /* - * Copyright 2014 Freescale Semiconductor, Inc. + * Copyright 2014-2015 Freescale Semiconductor, Inc. * Layerscape PCIe driver * * SPDX-License-Identifier: GPL-2.0+ @@ -9,8 +9,465 @@ #include <asm/arch/fsl_serdes.h> #include <pci.h> #include <asm/io.h> +#include <errno.h> +#include <malloc.h> #include <asm/pcie_layerscape.h>
+#ifndef CONFIG_SYS_PCI_MEMORY_BUS +#define CONFIG_SYS_PCI_MEMORY_BUS CONFIG_SYS_SDRAM_BASE +#endif + +#ifndef CONFIG_SYS_PCI_MEMORY_PHYS +#define CONFIG_SYS_PCI_MEMORY_PHYS CONFIG_SYS_SDRAM_BASE +#endif + +#ifndef CONFIG_SYS_PCI_MEMORY_SIZE +#define CONFIG_SYS_PCI_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) /* 2G */ +#endif + +/* iATU registers */ +#define PCIE_ATU_VIEWPORT 0x900 +#define PCIE_ATU_REGION_INBOUND (0x1 << 31) +#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31) +#define PCIE_ATU_REGION_INDEX0 (0x0 << 0) +#define PCIE_ATU_REGION_INDEX1 (0x1 << 0) +#define PCIE_ATU_REGION_INDEX2 (0x2 << 0) +#define PCIE_ATU_REGION_INDEX3 (0x3 << 0) +#define PCIE_ATU_CR1 0x904 +#define PCIE_ATU_TYPE_MEM (0x0 << 0) +#define PCIE_ATU_TYPE_IO (0x2 << 0) +#define PCIE_ATU_TYPE_CFG0 (0x4 << 0) +#define PCIE_ATU_TYPE_CFG1 (0x5 << 0) +#define PCIE_ATU_CR2 0x908 +#define PCIE_ATU_ENABLE (0x1 << 31) +#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) +#define PCIE_ATU_LOWER_BASE 0x90C +#define PCIE_ATU_UPPER_BASE 0x910 +#define PCIE_ATU_LIMIT 0x914 +#define PCIE_ATU_LOWER_TARGET 0x918 +#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24) +#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19) +#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16) +#define PCIE_ATU_UPPER_TARGET 0x91C + +#define PCIE_LINK_CAP 0x7c +#define PCIE_LINK_SPEED_MASK 0xf +#define PCIE_LINK_STA 0x82 + +#define PCIE_DBI_SIZE (4 * 1024) /* 4K */ + +struct ls_pcie { + int idx; + void __iomem *dbi; + void __iomem *va_cfg0; + void __iomem *va_cfg1; + struct pci_controller hose; +}; + +struct ls_pcie_info { + unsigned long regs; + int pci_num; + u64 cfg0_phys; + u64 cfg0_size; + u64 cfg1_phys; + u64 cfg1_size; + u64 mem_bus; + u64 mem_phys; + u64 mem_size; + u64 io_bus; + u64 io_phys; + u64 io_size; +}; + +#define SET_LS_PCIE_INFO(x, num) \ +{ \ + x.regs = CONFIG_SYS_PCIE##num##_ADDR; \ + x.cfg0_phys = CONFIG_SYS_PCIE_CFG0_PHYS_OFF + \ + CONFIG_SYS_PCIE##num##_PHYS_ADDR; \ + x.cfg0_size = CONFIG_SYS_PCIE_CFG0_SIZE; \ + x.cfg1_phys = CONFIG_SYS_PCIE_CFG1_PHYS_OFF + \ + CONFIG_SYS_PCIE##num##_PHYS_ADDR; \ + x.cfg1_size = CONFIG_SYS_PCIE_CFG1_SIZE; \ + x.mem_bus = CONFIG_SYS_PCIE_MEM_BUS; \ + x.mem_phys = CONFIG_SYS_PCIE_MEM_PHYS_OFF + \ + CONFIG_SYS_PCIE##num##_PHYS_ADDR; \ + x.mem_size = CONFIG_SYS_PCIE_MEM_SIZE; \ + x.io_bus = CONFIG_SYS_PCIE_IO_BUS; \ + x.io_phys = CONFIG_SYS_PCIE_IO_PHYS_OFF + \ + CONFIG_SYS_PCIE##num##_PHYS_ADDR; \ + x.io_size = CONFIG_SYS_PCIE_IO_SIZE; \ + x.pci_num = num; \ +} + +#ifdef CONFIG_LS102XA +#include <asm/arch/immap_ls102xa.h> + +/* PEX1/2 Misc Ports Status Register */ +#define LTSSM_STATE_SHIFT 20 +#define LTSSM_STATE_MASK 0x3f +#define LTSSM_PCIE_L0 0x11 /* L0 state */ + +static int ls_pcie_link_state(struct ls_pcie *pcie) +{ + u32 state; + struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR; + + state = in_be32(&scfg->pexmscportsr[pcie->idx]); + state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; + if (state < LTSSM_PCIE_L0) { + debug("....PCIe link error. LTSSM=0x%02x.\n", state); + return 0; + } + + return 1; +} +#else +#define PCIE_LDBG 0x7FC + +static int ls_pcie_link_state(struct ls_pcie *pcie) +{ + u32 state; + + state = readl(pcie->dbi + PCIE_LDBG); + if (state) + return 1; + + debug("....PCIe link error.\n"); + return 0; +} +#endif + +static int ls_pcie_link_up(struct ls_pcie *pcie) +{ + int state; + u32 cap; + + state = ls_pcie_link_state(pcie); + if (state) + return state; + + /* Try to download speed to gen1 */ + cap = readl(pcie->dbi + PCIE_LINK_CAP); + writel((cap & (~PCIE_LINK_SPEED_MASK)) | 1, pcie->dbi + PCIE_LINK_CAP); + udelay(2000); + state = ls_pcie_link_state(pcie); + if (state) + return state; + + writel(cap, pcie->dbi + PCIE_LINK_CAP); + + return 0; +} + +static void ls_pcie_cfg0_set_busdev(struct ls_pcie *pcie, u32 busdev) +{ + writel(PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, + pcie->dbi + PCIE_ATU_VIEWPORT); + writel(busdev, pcie->dbi + PCIE_ATU_LOWER_TARGET); +} + +static void ls_pcie_cfg1_set_busdev(struct ls_pcie *pcie, u32 busdev) +{ + writel(PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, + pcie->dbi + PCIE_ATU_VIEWPORT); + writel(busdev, pcie->dbi + PCIE_ATU_LOWER_TARGET); +} + +static void ls_pcie_iatu_outbound_set(struct ls_pcie *pcie, int idx, int type, + u64 phys, u64 bus_addr, pci_size_t size) +{ + writel(PCIE_ATU_REGION_OUTBOUND | idx, pcie->dbi + PCIE_ATU_VIEWPORT); + writel((u32)phys, pcie->dbi + PCIE_ATU_LOWER_BASE); + writel(phys >> 32, pcie->dbi + PCIE_ATU_UPPER_BASE); + writel(phys + size - 1, pcie->dbi + PCIE_ATU_LIMIT); + writel((u32)bus_addr, pcie->dbi + PCIE_ATU_LOWER_TARGET); + writel(bus_addr >> 32, pcie->dbi + PCIE_ATU_UPPER_TARGET); + writel(type, pcie->dbi + PCIE_ATU_CR1); + writel(PCIE_ATU_ENABLE, pcie->dbi + PCIE_ATU_CR2); +} + +static void ls_pcie_setup_atu(struct ls_pcie *pcie, struct ls_pcie_info *info) +{ +#ifdef DEBUG + int i; +#endif + + /* ATU 0 : OUTBOUND : CFG0 */ + ls_pcie_iatu_outbound_set(pcie, PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_CFG0, + info->cfg0_phys, + 0, + info->cfg0_size); + /* ATU 1 : OUTBOUND : CFG1 */ + ls_pcie_iatu_outbound_set(pcie, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_CFG1, + info->cfg1_phys, + 0, + info->cfg1_size); + /* ATU 2 : OUTBOUND : MEM */ + ls_pcie_iatu_outbound_set(pcie, PCIE_ATU_REGION_INDEX2, + PCIE_ATU_TYPE_MEM, + info->mem_phys, + info->mem_bus, + info->mem_size); + /* ATU 3 : OUTBOUND : IO */ + ls_pcie_iatu_outbound_set(pcie, PCIE_ATU_REGION_INDEX3, + PCIE_ATU_TYPE_IO, + info->io_phys, + info->io_bus, + info->io_size); + +#ifdef DEBUG + for (i = 0; i <= PCIE_ATU_REGION_INDEX3; i++) { + writel(PCIE_ATU_REGION_OUTBOUND | i, + pcie->dbi + PCIE_ATU_VIEWPORT); + debug("iATU%d:\n", i); + debug("\tLOWER PHYS 0x%08x\n", + readl(pcie->dbi + PCIE_ATU_LOWER_BASE)); + debug("\tUPPER PHYS 0x%08x\n", + readl(pcie->dbi + PCIE_ATU_UPPER_BASE)); + debug("\tLOWER BUS 0x%08x\n", + readl(pcie->dbi + PCIE_ATU_LOWER_TARGET)); + debug("\tUPPER BUS 0x%08x\n", + readl(pcie->dbi + PCIE_ATU_UPPER_TARGET)); + debug("\tLIMIT 0x%08x\n", + readl(pcie->dbi + PCIE_ATU_LIMIT)); + debug("\tCR1 0x%08x\n", + readl(pcie->dbi + PCIE_ATU_CR1)); + debug("\tCR2 0x%08x\n", + readl(pcie->dbi + PCIE_ATU_CR2)); + } +#endif +} + +int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev) +{ + /* Do not skip controller */ + return 0; +} + +static int ls_pcie_addr_valid(struct pci_controller *hose, pci_dev_t d) +{ + if (PCI_DEV(d) > 0) + return -EINVAL; + + return 0; +} + +static int ls_pcie_read_config(struct pci_controller *hose, pci_dev_t d, + int where, u32 *val) +{ + struct ls_pcie *pcie = hose->priv_data; + u32 busdev, *addr; + + if (ls_pcie_addr_valid(hose, d)) { + *val = 0xffffffff; + return -EINVAL; + } + + if (PCI_BUS(d) == hose->first_busno) { + addr = pcie->dbi + (where & ~0x3); + } else { + busdev = PCIE_ATU_BUS(PCI_BUS(d)) | + PCIE_ATU_DEV(PCI_DEV(d)) | + PCIE_ATU_FUNC(PCI_FUNC(d)); + + if (PCI_BUS(d) == hose->first_busno + 1) { + ls_pcie_cfg0_set_busdev(pcie, busdev); + addr = pcie->va_cfg0 + (where & ~0x3); + } else { + ls_pcie_cfg1_set_busdev(pcie, busdev); + addr = pcie->va_cfg1 + (where & ~0x3); + } + } + + *val = readl(addr); + + return 0; +} + +static int ls_pcie_write_config(struct pci_controller *hose, pci_dev_t d, + int where, u32 val) +{ + struct ls_pcie *pcie = hose->priv_data; + u32 busdev, *addr; + + if (ls_pcie_addr_valid(hose, d)) + return -EINVAL; + + if (PCI_BUS(d) == hose->first_busno) { + addr = pcie->dbi + (where & ~0x3); + } else { + busdev = PCIE_ATU_BUS(PCI_BUS(d)) | + PCIE_ATU_DEV(PCI_DEV(d)) | + PCIE_ATU_FUNC(PCI_FUNC(d)); + + if (PCI_BUS(d) == hose->first_busno + 1) { + ls_pcie_cfg0_set_busdev(pcie, busdev); + addr = pcie->va_cfg0 + (where & ~0x3); + } else { + ls_pcie_cfg1_set_busdev(pcie, busdev); + addr = pcie->va_cfg1 + (where & ~0x3); + } + } + + writel(val, addr); + + return 0; +} + +static void ls_pcie_setup_ctrl(struct ls_pcie *pcie, + struct ls_pcie_info *info) +{ + struct pci_controller *hose = &pcie->hose; + pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0); + + ls_pcie_setup_atu(pcie, info); + + pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0); + + /* program correct class for RC */ + pci_hose_write_config_word(hose, dev, PCI_CLASS_DEVICE, + PCI_CLASS_BRIDGE_PCI); +} + +int ls_pcie_init_ctrl(int busno, enum srds_prtcl dev, struct ls_pcie_info *info) +{ + struct ls_pcie *pcie; + struct pci_controller *hose; + int num = dev - PCIE1; + pci_dev_t pdev = PCI_BDF(busno, 0, 0); + int i, linkup, ep_mode; + u8 header_type; + u16 temp16; + + if (!is_serdes_configured(dev)) { + printf("PCIe%d: disabled\n", num + 1); + return busno; + } + + pcie = malloc(sizeof(*pcie)); + if (!pcie) + return busno; + memset(pcie, 0, sizeof(*pcie)); + + hose = &pcie->hose; + hose->priv_data = pcie; + hose->first_busno = busno; + pcie->idx = num; + pcie->dbi = map_physmem(info->regs, PCIE_DBI_SIZE, MAP_NOCACHE); + pcie->va_cfg0 = map_physmem(info->cfg0_phys, + info->cfg0_size, + MAP_NOCACHE); + pcie->va_cfg1 = map_physmem(info->cfg1_phys, + info->cfg1_size, + MAP_NOCACHE); + + /* outbound memory */ + pci_set_region(&hose->regions[0], + (pci_size_t)info->mem_bus, + (phys_size_t)info->mem_phys, + (pci_size_t)info->mem_size, + PCI_REGION_MEM); + + /* outbound io */ + pci_set_region(&hose->regions[1], + (pci_size_t)info->io_bus, + (phys_size_t)info->io_phys, + (pci_size_t)info->io_size, + PCI_REGION_IO); + + /* System memory space */ + pci_set_region(&hose->regions[2], + CONFIG_SYS_PCI_MEMORY_BUS, + CONFIG_SYS_PCI_MEMORY_PHYS, + CONFIG_SYS_PCI_MEMORY_SIZE, + PCI_REGION_SYS_MEMORY); + + hose->region_count = 3; + + for (i = 0; i < hose->region_count; i++) + debug("PCI reg:%d %016llx:%016llx %016llx %08lx\n", + i, + (u64)hose->regions[i].phys_start, + (u64)hose->regions[i].bus_start, + (u64)hose->regions[i].size, + hose->regions[i].flags); + + pci_set_ops(hose, + pci_hose_read_config_byte_via_dword, + pci_hose_read_config_word_via_dword, + ls_pcie_read_config, + pci_hose_write_config_byte_via_dword, + pci_hose_write_config_word_via_dword, + ls_pcie_write_config); + + pci_hose_read_config_byte(hose, pdev, PCI_HEADER_TYPE, &header_type); + ep_mode = (header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL; + printf("PCIe%u: %s ", info->pci_num, + ep_mode ? "Endpoint" : "Root Complex"); + + linkup = ls_pcie_link_up(pcie); + + if (!linkup) { + /* Let the user know there's no PCIe link */ + printf("no link, regs @ 0x%lx\n", info->regs); + hose->last_busno = hose->first_busno; + return busno; + } + + /* Print the negotiated PCIe link width */ + pci_hose_read_config_word(hose, dev, PCIE_LINK_STA, &temp16); + printf("x%d gen%d, regs @ 0x%lx\n", (temp16 & 0x3f0) >> 4, + (temp16 & 0xf), info->regs); + + if (ep_mode) + return busno; + + ls_pcie_setup_ctrl(pcie, info); + + pci_register_hose(hose); + + hose->last_busno = pci_hose_scan(hose); + + printf("PCIe%x: Bus %02x - %02x\n", + info->pci_num, hose->first_busno, hose->last_busno); + + return hose->last_busno + 1; +} + +int ls_pcie_init_board(int busno) +{ + struct ls_pcie_info info; + +#ifdef CONFIG_PCIE1 + SET_LS_PCIE_INFO(info, 1); + busno = ls_pcie_init_ctrl(busno, PCIE1, &info); +#endif + +#ifdef CONFIG_PCIE2 + SET_LS_PCIE_INFO(info, 2); + busno = ls_pcie_init_ctrl(busno, PCIE2, &info); +#endif + +#ifdef CONFIG_PCIE3 + SET_LS_PCIE_INFO(info, 3); + busno = ls_pcie_init_ctrl(busno, PCIE3, &info); +#endif + +#ifdef CONFIG_PCIE4 + SET_LS_PCIE_INFO(info, 4); + busno = ls_pcie_init_ctrl(busno, PCIE4, &info); +#endif + + return busno; +} + +void pci_init_board(void) +{ + ls_pcie_init_board(0); +} + #ifdef CONFIG_OF_BOARD_SETUP #include <libfdt.h> #include <fdt_support.h> @@ -38,6 +495,14 @@ void ft_pcie_setup(void *blob, bd_t *bd) #ifdef CONFIG_PCIE2 ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE2_ADDR, PCIE2); #endif + + #ifdef CONFIG_PCIE3 + ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE3_ADDR, PCIE3); + #endif + + #ifdef CONFIG_PCIE4 + ft_pcie_ls_setup(blob, FSL_PCIE_COMPAT, CONFIG_SYS_PCIE4_ADDR, PCIE4); + #endif }
#else @@ -45,7 +510,3 @@ void ft_pcie_setup(void *blob, bd_t *bd) { } #endif - -void pci_init_board(void) -{ -}

On 01/21/2015 01:29 AM, Minghuan Lian wrote:
LS1021A's PCIe1 region begins 0x40_00000000; PCIe2 begins 0x48_00000000. In order to access PCIe device, we must create TLB to map the 40bit physical address to 32bit virtual address. This patch will enable MMU after DDR is available and creates MMU table in DRAM to map all 4G space; then, re-use the reserved space to map PCIe region. The following the mapping layout.
VA mapping: ------- <---- 0GB | | | | |-------| <---- 0x24000000 |///////| ===> 192MB VA map for PCIe1 with offset 0x40_0000_0000 |-------| <---- 0x300000000 | | |-------| <---- 0x34000000 |///////| ===> 192MB VA map for PCIe2 with offset 0x48_0000_0000 |-------| <---- 0x40000000 | | |-------| <---- 0x80000000 DDR0 space start |\\\| |\\\| ===> 2GB VA map for 2GB DDR0 Memory space |\\\| ------- <---- 4GB DDR0 space end
Signed-off-by: Minghuan Lian Minghuan.Lian@freescale.com
Applied to u-boot-fsl-qoriq master branch, awaiting upstream.
York
participants (2)
-
Minghuan Lian
-
York Sun