// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2023 Rockchip Electronics Co., Ltd */ #include #include #include #include #include #include #include #include #include #ifndef CONFIG_SPL_LOAD_FIT_ADDRESS #error "SPL_LOAD_FIT_ADDRESS not defined!" #endif #define printep(fmt, ...) \ do { \ printf("RKEP: %d - ", readl(CONFIG_ROCKCHIP_STIMER_BASE + 0x2c) / 24); \ printf(fmt, ##__VA_ARGS__); \ } while (0) #ifdef CONFIG_ROCKCHIP_RK3588 #define PCIE_SNPS_DBI_BASE 0xf5000000 #define PCIE_SNPS_APB_BASE 0xfe150000 #define PCIE_SNPS_IATU_BASE 0xa40300000 #define PCI_RESBAR 0x2e8 #elif CONFIG_ROCKCHIP_RK3568 #define PCIE_SNPS_DBI_BASE 0xf6000000 #define PCIE_SNPS_APB_BASE 0xfe280000 #define PCIE_SNPS_IATU_BASE 0x3c0b00000 #define PCI_RESBAR 0x2b8 #else #error "this soc is not support pcie ep!" #endif #define RKEP_BAR0_ADDR 0x3c000000 #define RKEP_BAR2_ADDR CONFIG_SPL_LOAD_FIT_ADDRESS #define RKEP_BAR0_CMD_ADDR (RKEP_BAR0_ADDR + 0x400) #define RKEP_BOOT_MAGIC 0x524b4550 /* RKEP */ #define RKEP_CMD_LOADER_RUN 0x524b4501 #define PCI_EXP_LNKCAP 12 /* Link Capabilities */ #define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ #define PCI_EXP_LNKCTL2_TLS 0x000f #define PCI_EXP_LNKCAP_SLS 0x0000000f #define PCI_EXP_LNKCTL2_TLS_2_5GT 0x0001 /* Supported Speed 2.5GT/s */ #define PCI_EXP_LNKCTL2_TLS_5_0GT 0x0002 /* Supported Speed 5GT/s */ #define PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Supported Speed 8GT/s */ /* Synopsys-specific PCIe configuration registers */ #define PCIE_PORT_LINK_CONTROL 0x710 #define PORT_LINK_MODE_MASK (0x3f << 16) #define PORT_LINK_MODE_1_LANES (0x1 << 16) #define PORT_LINK_MODE_2_LANES (0x3 << 16) #define PORT_LINK_MODE_4_LANES (0x7 << 16) #define PORT_LINK_MODE_8_LANES (0xf << 16) #define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C #define PORT_LOGIC_SPEED_CHANGE (0x1 << 17) #define PORT_LOGIC_LINK_WIDTH_MASK (0x1f << 8) #define PORT_LOGIC_LINK_WIDTH_1_LANES (0x1 << 8) #define PORT_LOGIC_LINK_WIDTH_2_LANES (0x2 << 8) #define PORT_LOGIC_LINK_WIDTH_4_LANES (0x4 << 8) #define PORT_LOGIC_LINK_WIDTH_8_LANES (0x8 << 8) #define PCIE_DIRECT_SPEED_CHANGE (0x1 << 17) #define LINK_WAIT_IATU 10000 #define PCIE_ATU_ENABLE (0x1 << 31) #define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30 | 1 << 19) #define PCIE_ATU_UNR_REGION_CTRL1 0x00 #define PCIE_ATU_UNR_REGION_CTRL2 0x04 #define PCIE_ATU_CPU_ADDR_LOW 0x14 #define PCIE_ATU_CPU_ADDR_HIGH 0x18 /* SRNS: Use Separate refclk(internal clock) instead of from RC */ // #define PCIE_ENABLE_SRNS_PLL_REFCLK struct rkpcie_cmd { u32 cmd; u32 size; u32 data[6]; }; /* rkep device mode status definition */ #define RKEP_MODE_BOOTROM 1 #define RKEP_MODE_LOADER 2 #define RKEP_MODE_KERNEL 3 /* Common status */ #define RKEP_SMODE_INIT 0 #define RKEP_SMODE_LNKRDY 1 #define RKEP_SMODE_LNKUP 2 #define RKEP_SMODE_ERR 0xff /* Firmware download status */ #define RKEP_SMODE_FWDLRDY 0x10 #define RKEP_SMODE_FWDLDONE 0x11 /* Application status*/ #define RKEP_SMODE_APPRDY 0x20 struct rkpcie_boot { /* magic: "RKEP" */ u32 magic; u32 version; struct { u16 mode; u16 submode; } devmode; /* Size of ATAGS for cap */ u32 cap_size; struct { u8 cmd; u8 status; /* Error code for current CMD */ u16 opcode; } cmd_status; u32 reserved[2]; /* RK ATAGS, for mem and other info */ struct tag cap; /* offset 0x400 */ struct rkpcie_cmd cmd; }; static void pcie_inbound_config(void) { u64 base = PCIE_SNPS_IATU_BASE + 0x100; u32 val; char i; /* BAR0: RKEP_BAR0_ADDR */ writel(RKEP_BAR0_ADDR, base + PCIE_ATU_CPU_ADDR_LOW); writel(0, base + PCIE_ATU_CPU_ADDR_HIGH); writel(0, base + PCIE_ATU_UNR_REGION_CTRL1); /* PCIE_ATU_UNR_REGION_CTRL2 */ writel(PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE | (0 << 8), base + PCIE_ATU_UNR_REGION_CTRL2); for (i = 0; i < 5; i++) { val = readl(base + PCIE_ATU_UNR_REGION_CTRL2); if (val & PCIE_ATU_ENABLE) break; udelay(LINK_WAIT_IATU); } printep("BAR0: 0x%x\n", RKEP_BAR0_ADDR); /* BAR2: RKEP_BAR2_ADDR */ writel(RKEP_BAR2_ADDR, base + PCIE_ATU_CPU_ADDR_LOW + 0x200); writel(0, base + PCIE_ATU_CPU_ADDR_HIGH + 0x200); writel(0, base + PCIE_ATU_UNR_REGION_CTRL1 + 0x200); writel(PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE | (2 << 8), base + PCIE_ATU_UNR_REGION_CTRL2 + 0x200); for (i = 0; i < 5; i++) { val = readl(base + PCIE_ATU_UNR_REGION_CTRL2 + 0x200); if (val & PCIE_ATU_ENABLE) break; udelay(LINK_WAIT_IATU); } printep("BAR2: 0x%x%x\n", 0, RKEP_BAR2_ADDR); /* BAR4 is wired reg, no need iATU */ } static int rockchip_pcie_ep_set_bar_flag(void *dbi_base, u32 barno, int flags) { u32 reg; reg = PCI_BASE_ADDRESS_0 + (4 * barno); /* Disabled the upper 32bits BAR to make a 64bits bar pair */ if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) writel(0, dbi_base + reg + 0x100000 + 4); writel(flags, dbi_base + reg); if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) writel(0, dbi_base + reg + 4); return 0; } static void pcie_bar_init(void *dbi_base) { void *resbar_base; u32 val; writel(0, dbi_base + 0x10); writel(0, dbi_base + 0x14); writel(0, dbi_base + 0x18); writel(0, dbi_base + 0x1c); writel(0, dbi_base + 0x20); writel(0, dbi_base + 0x24); /* Disable ASPM */ val = readl(dbi_base + 0x7c); val &= ~(3 << 10); writel(val, dbi_base + 0x7c); /* Resize BAR0 to support 4M 32bits */ resbar_base = dbi_base + PCI_RESBAR; writel(0x40, resbar_base + 0x4); writel(0x2c0, resbar_base + 0x8); /* BAR2: 64M 64bits */ writel(0x400, resbar_base + 0x14); writel(0x6c0, resbar_base + 0x18); /* BAR4: Fixed for EP wired register, 1M 32bits */ writel(0x10, resbar_base + 0x24); writel(0xc0, resbar_base + 0x28); /* Set flags */ rockchip_pcie_ep_set_bar_flag(dbi_base, 0, PCI_BASE_ADDRESS_MEM_TYPE_32); rockchip_pcie_ep_set_bar_flag(dbi_base, 2, PCI_BASE_ADDRESS_MEM_PREFETCH | PCI_BASE_ADDRESS_MEM_TYPE_64); rockchip_pcie_ep_set_bar_flag(dbi_base, 4, PCI_BASE_ADDRESS_MEM_TYPE_32); /* Close bar1 bar3 bar5 */ writel(0x0, dbi_base + 0x100000 + 0x14); //writel(0x0, dbi_base + 0x100000 + 0x18); writel(0x0, dbi_base + 0x100000 + 0x1c); //writel(0x0, dbi_base + 0x100000 + 0x20); writel(0x0, dbi_base + 0x100000 + 0x24); /* Close ROM BAR */ writel(0x0, dbi_base + 0x100000 + 0x30); } static void pcie_bar0_header_init(void) { struct rkpcie_boot *bh = (struct rkpcie_boot *)RKEP_BAR0_ADDR; bh->magic = RKEP_BOOT_MAGIC; bh->version = 0x100; bh->devmode.mode = RKEP_MODE_LOADER; bh->devmode.submode = RKEP_SMODE_INIT; bh->cap_size = 0; memset((char *)RKEP_BAR0_CMD_ADDR, 0, sizeof(struct rkpcie_cmd)); } static void pcie_link_set_max_speed(void *dbi_base, u32 link_gen) { u32 cap, ctrl2, link_speed; u8 offset = 0x70; cap = readl(dbi_base + offset + PCI_EXP_LNKCAP); ctrl2 = readl(dbi_base + offset + PCI_EXP_LNKCTL2); ctrl2 &= ~PCI_EXP_LNKCTL2_TLS; link_speed = link_gen; cap &= ~((u32)PCI_EXP_LNKCAP_SLS); writel(ctrl2 | link_speed, dbi_base + offset + PCI_EXP_LNKCTL2); writel(cap | link_speed, dbi_base + offset + PCI_EXP_LNKCAP); } static void pcie_link_set_lanes(void *dbi_base, u32 lanes) { u32 val; /* Set the number of lanes */ val = readl(dbi_base + PCIE_PORT_LINK_CONTROL); val &= ~PORT_LINK_MODE_MASK; switch (lanes) { case 1: val |= PORT_LINK_MODE_1_LANES; break; case 2: val |= PORT_LINK_MODE_2_LANES; break; case 4: val |= PORT_LINK_MODE_4_LANES; break; default: printf("RKEP: num-lanes %u: invalid value\n", lanes); return; } writel(val, dbi_base + PCIE_PORT_LINK_CONTROL); /* Set link width speed control register */ val = readl(dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); val &= ~PORT_LOGIC_LINK_WIDTH_MASK; switch (lanes) { case 1: val |= PORT_LOGIC_LINK_WIDTH_1_LANES; break; case 2: val |= PORT_LOGIC_LINK_WIDTH_2_LANES; break; case 4: val |= PORT_LOGIC_LINK_WIDTH_4_LANES; break; } val |= PCIE_DIRECT_SPEED_CHANGE; writel(val, dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); } static void pcie_devmode_update(int mode, int submode) { struct rkpcie_boot *bh = (struct rkpcie_boot *)RKEP_BAR0_ADDR; bh->devmode.mode = mode; bh->devmode.submode = submode; flush_dcache_range(RKEP_BAR0_ADDR, RKEP_BAR0_ADDR + 64); } #ifdef CONFIG_SPL_RAM_DEVICE static void pcie_wait_for_fw(void) { struct rkpcie_cmd *cmd = (struct rkpcie_cmd *)(RKEP_BAR0_CMD_ADDR); int val; int i = 0; printep("Link ready! Waiting RC to download Firmware:\n"); printep("Download uboot.img to BAR2+0\n"); printep("Download boot.img to BAR2+0x400000\n"); printep("Send CMD_LOADER_RUN to BAR0+0x400\n"); while (1) { invalidate_dcache_range(RKEP_BAR0_CMD_ADDR, RKEP_BAR0_CMD_ADDR + 32); val = readl(&cmd->cmd); if (val == RKEP_CMD_LOADER_RUN) break; i++; if (!(i % 10)) printep("Waiting for FW, CMD: %x\n", val); mdelay(100); } /* Invalidate Cache for firmware area: BAR2, 64MB */ invalidate_dcache_range(RKEP_BAR2_ADDR, RKEP_BAR2_ADDR + 0x4000000); printep("Firmware Download complete!\n"); } static void pcie_update_atags(void) { struct tag_ram_partition t_ram_part; if (!atags_is_available()) { printep("RKEP: No ATAGS data found, create new!\n"); atags_destroy(); } /* ram partition */ memset(&t_ram_part, 0, sizeof(t_ram_part)); t_ram_part.version = 0; t_ram_part.count = 1; strcpy(t_ram_part.part[0].name, "boot"); t_ram_part.part[0].start = RKEP_BAR2_ADDR + 0x400000; /* 4M offset */ t_ram_part.part[0].size = 0x3c00000; /* 60M size */ atags_set_tag(ATAG_RAM_PARTITION, &t_ram_part); } void rockchip_pcie_ep_get_firmware(void) { pcie_devmode_update(RKEP_MODE_LOADER, RKEP_SMODE_FWDLRDY); pcie_wait_for_fw(); pcie_update_atags(); pcie_devmode_update(RKEP_MODE_LOADER, RKEP_SMODE_FWDLDONE); } #endif #ifdef CONFIG_ROCKCHIP_RK3588 #define BUS_IOC_GPIO3D_IOMUX_SEL_H 0xfd5f807c #define GPIO3_BASE 0xfec40000 #define GPIO3_SWPORT_DR_H (GPIO3_BASE + 0x4) #define GPIO3_SWPORT_DDR_H (GPIO3_BASE + 0xc) static void pcie_board_init(void) { /* Enable AU5426 buffer chip on EVB4v10 */ /* Set GPIO3D4 to gpio output HIGH mode PCIE20_CLK_PWREN */ writel(0xf << 16, BUS_IOC_GPIO3D_IOMUX_SEL_H); writel(0x10001000, GPIO3_SWPORT_DDR_H); writel(0x10001000, GPIO3_SWPORT_DR_H); udelay(100); } #define PHY_MODE_PCIE_AGGREGATION 4 /* PCIe3x4 */ #define PHY_MODE_PCIE_NANBNB 0 /* P1:PCIe3x2 + P0:PCIe3x2 */ #define PHY_MODE_PCIE_NANBBI 1 /* P1:PCIe3x2 + P0:PCIe3x1*2 */ #define PHY_MODE_PCIE_NABINB 2 /* P1:PCIe3x1*2 + P0:PCIe3x2 */ #define PHY_MODE_PCIE_NABIBI 3 /* P1:PCIe3x1*2 + P0:PCIe3x1*2 */ #define CRU_BASE_ADDR 0xfd7c0000 #define CRU_SOFTRST_CON32 (CRU_BASE_ADDR + 0x0a80) #define CRU_SOFTRST_CON33 (CRU_BASE_ADDR + 0x0a84) #define CRU_SOFTRST_CON34 (CRU_BASE_ADDR + 0x0a88) #define CRU_GATE_CON32 (CRU_BASE_ADDR + 0x0880) #define CRU_GATE_CON33 (CRU_BASE_ADDR + 0x0884) #define CRU_GATE_CON34 (CRU_BASE_ADDR + 0x0888) #define CRU_GATE_CON38 (CRU_BASE_ADDR + 0x0898) #define CRU_GATE_CON39 (CRU_BASE_ADDR + 0x089c) #define PHPTOPCRU_BASE_ADDR 0xfd7c8000 #define PHPTOPCRU_SOFTRST_CON00 (PHPTOPCRU_BASE_ADDR + 0x0a00) #define PHPTOPCRU_GATE_CON00 (PHPTOPCRU_BASE_ADDR + 0x0800) #define PCIE3PHY_GRF_BASE 0xfd5b8000 #define RK3588_PCIE3PHY_GRF_CMN_CON0 (PCIE3PHY_GRF_BASE + 0x0000) #define PCIE3PHY_GRF_PHY0_CON6 (PCIE3PHY_GRF_BASE + 0x0118) #define PCIE3PHY_GRF_PHY1_CON6 (PCIE3PHY_GRF_BASE + 0x0218) #define PCIE3PHY_GRF_PHY0_LN0_CON1 (PCIE3PHY_GRF_BASE + 0x1004) #define PCIE3PHY_GRF_PHY0_LN1_CON1 (PCIE3PHY_GRF_BASE + 0x1104) #define PCIE3PHY_GRF_PHY1_LN0_CON1 (PCIE3PHY_GRF_BASE + 0x2004) #define PCIE3PHY_GRF_PHY1_LN1_CON1 (PCIE3PHY_GRF_BASE + 0x2104) #define FIREWALL_PCIE_MASTER_SEC 0xfe0300f0 #define FIREWALL_PCIE_ACCESS 0xfe586040 #define CRU_PHYREF_ALT_GATE_CON (CRU_BASE_ADDR + 0x0c38) #define PMU1_GRF_BASE 0xfd58a000 #define PMU_PWR_GATE_SFTCON1 0xfd8d8150 #define PMU1_IOC_BASE 0xfd5F0000 #define CRU_GLB_RST_CON_OFFSET (0xC10U) #define CRU_GLB_SRST_FST_VALUE_OFFSET (0xC08U) void pcie_first_reset(void) { printep("Fst Reset\n"); mdelay(1); writel(0xFFDF, CRU_BASE_ADDR + CRU_GLB_RST_CON_OFFSET); writel(0xffffffff, PMU1_GRF_BASE + 0x4); // reset width writel(0x30003000, PMU1_GRF_BASE + 0x1c); // pmu1_grf pmu1_ioc hiold writel(0x00f00020, PMU1_IOC_BASE + 0x0); //select tsad_shut_m0 iomux writel(0xFDB9, CRU_BASE_ADDR + CRU_GLB_SRST_FST_VALUE_OFFSET); while (1) ; } static void pcie_cru_init(void) { u32 phy0_mplla, phy1_mplla, t0 = 0, t1 = 0; u32 i, timeout = 500; /* Enable power domain: PD_PCIE & PD_PHP */ writel(0x1 << 23 | 0x1 << 21, PMU_PWR_GATE_SFTCON1); /* FixMe init 3.0 PHY */ /* Phy mode: Aggregation NBNB */ writel((0x7 << 16) | PHY_MODE_PCIE_AGGREGATION, RK3588_PCIE3PHY_GRF_CMN_CON0); printep("PHY Mode 0x%x\n", readl(RK3588_PCIE3PHY_GRF_CMN_CON0) & 7); /* Enable clock and sfreset for Controller and PHY */ writel(0xffff0000, CRU_SOFTRST_CON32); writel(0xffff0000, CRU_SOFTRST_CON33); writel(0xffff0000, CRU_SOFTRST_CON34); writel(0xffff0000, CRU_GATE_CON32); writel(0xffff0000, CRU_GATE_CON33); writel(0xffff0000, CRU_GATE_CON34); writel(0xffff0000, CRU_GATE_CON38); writel(0xffff0000, CRU_GATE_CON39); writel((0x1 << 24), PHPTOPCRU_SOFTRST_CON00); writel(0xffff0000, PHPTOPCRU_GATE_CON00); /* PHY Reset */ writel((0x1 << 10) | (0x1 << 26), PHPTOPCRU_SOFTRST_CON00); udelay(1); #ifdef PCIE_ENABLE_SRNS_PLL_REFCLK writel(0x000f0000, CRU_PHYREF_ALT_GATE_CON); /* PHY0 & PHY1 use internal clock */ writel(0x0 | (0x1 << 18), PCIE3PHY_GRF_PHY0_CON6); writel(0x0 | (0x1 << 18), PCIE3PHY_GRF_PHY1_CON6); /* phy0_rx0_cmn_refclk_mod */ writel((0x0) | (0x1 << 23), PCIE3PHY_GRF_PHY0_LN0_CON1); /* phy1_rx0_cmn_refclk_mod */ writel((0x0) | (0x1 << 23), PCIE3PHY_GRF_PHY0_LN1_CON1); /* phy0_rx0_cmn_refclk_mod */ writel((0x0) | (0x1 << 23), PCIE3PHY_GRF_PHY1_LN0_CON1); /* phy1_rx0_cmn_refclk_mod */ writel((0x0) | (0x1 << 23), PCIE3PHY_GRF_PHY1_LN1_CON1); #endif udelay(1000); /* Deassert PCIe PMA output clamp mode */ writel((0x1 << 8) | (0x1 << 24), RK3588_PCIE3PHY_GRF_CMN_CON0); /* Deassert PHY Reset */ writel((0x1 << 26), PHPTOPCRU_SOFTRST_CON00); /* S-Phy: waiting for phy locked */ for (i = 0; i < timeout; i++) { phy0_mplla = readl(PCIE3PHY_GRF_BASE + 0x904); phy1_mplla = readl(PCIE3PHY_GRF_BASE + 0xA04); if (phy0_mplla != t0 || phy1_mplla != t1) { printep("RKEP: GRF:904=%x, a04=%x...\n", phy0_mplla, phy1_mplla); t0 = phy0_mplla; t1 = phy1_mplla; if (phy0_mplla == 0xF && phy1_mplla == 0xF) break; } udelay(10); } if (i >= timeout) { printep("lock fail\n"); mdelay(1); pcie_first_reset(); } /* PHY config: no config need for snps3.0phy */ } static void pcie_firewall_init(void) { /* Enable PCIe Access in firewall and master secure mode */ writel(0xffff0000, FIREWALL_PCIE_MASTER_SEC); writel(0x01800000, FIREWALL_PCIE_ACCESS); } #elif CONFIG_ROCKCHIP_RK3568 static void pcie_board_init(void) { /* to-do */ } static const u16 phy_fw[] = { #include "./../../../drivers/phy/phy-rockchip-snps-pcie3.fw" }; #define GRF_PCIE30PHY_RK3568_CON1 0x4 #define GRF_PCIE30PHY_RK3568_CON3 0xC #define GRF_PCIE30PHY_RK3568_CON4 0x10 #define GRF_PCIE30PHY_RK3568_CON5 0x14 #define GRF_PCIE30PHY_RK3568_CON6 0x18 #define GRF_PCIE30PHY_RK3568_CON9 0x24 #define GRF_PCIE30PHY_RK3568_STATUS0 0x80 #define RK3568_SRAM_INIT_DONE(reg) ((reg) & BIT(14)) #define PMUCRU_BASE 0xFDD00000 #define PMUCRU_PMUGATE_CON02 (PMUCRU_BASE + 0x188) #define CRU_BASE 0xFDD20000 #define CRU_GATE_CON12 (CRU_BASE + 0x330) #define CRU_GATE_CON13 (CRU_BASE + 0x334) #define CRU_GATE_CON33 (CRU_BASE + 0x384) #define CRU_SOFTRST_CON12 (CRU_BASE + 0x430) #define CRU_SOFTRST_CON27 (CRU_BASE + 0x46c) #define CRU_GLB_SRST_FST_OFFSET (0xD4U) #define PCIE30_PHY_GRF 0xFDCB8000 #define SYS_GRF_BASE 0xFDC60000 void pcie_first_reset(void) { printep("Fst Reset\n"); mdelay(1); writel(0x00040004, CRU_BASE + 0x104); writel(0x00700010, CRU_BASE); writel(0x00100010, SYS_GRF_BASE + 0x508); writel(0xFDB9, CRU_BASE + CRU_GLB_SRST_FST_OFFSET); while (1) ; } void pcie_cru_init(void) { u32 i, reg, timeout = 500; void __iomem *mmio = (void __iomem *)0xFE8C0000; u32 phy0_status0, phy0_status1, t0 = 0, t1 = 0; /* Enable phy and controoler clk */ writel(0xffff0000, PMUCRU_PMUGATE_CON02); writel(0xffff0000, CRU_GATE_CON12); writel(0xffff0000, CRU_GATE_CON13); writel(0xffff0000, CRU_GATE_CON33); writel(0xffff0000, CRU_SOFTRST_CON27); writel(0x40004000, CRU_SOFTRST_CON27); writel(0x80008000, PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON9); writel((0x1 << 15) | (0x1 << 31), PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON9); //map to access sram #ifdef PCIE_ENABLE_SRNS_PLL_REFCLK /* use internal clock */ writel(0x0 | (0x1 << 31), PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON3); /* rx0_cmn_refclk_mode disabled */ writel((0x0) | (0x1 << 25), PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON5); /* rx1_cmn_refclk_mode disabled */ writel((0x0) | (0x1 << 25), PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON6); #endif writel((0x0 << 14) | (0x1 << (14 + 16)), PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON4); //sdram_ld_done writel((0x0 << 13) | (0x1 << (13 + 16)), PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON4); //sdram_bypass writel(0x40000000, CRU_SOFTRST_CON27); udelay(5); printep("RKEP: sram initial\n"); while (1) { reg = readl(PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_STATUS0); if (RK3568_SRAM_INIT_DONE(reg)) break; } printep("RKEP: sram init done\n"); writel((0x3 << 8) | (0x3 << (8 + 16)), PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON9); //map to access sram for (i = 0; i < ARRAY_SIZE(phy_fw); i++) writel(phy_fw[i], mmio + (i << 2)); printep("RKEP: snps pcie3phy FW update! size %ld\n", ARRAY_SIZE(phy_fw)); writel((0x0 << 8) | (0x3 << (8 + 16)), PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON9); writel((0x1 << 14) | (0x1 << (14 + 16)), PCIE30_PHY_GRF + GRF_PCIE30PHY_RK3568_CON4); //sdram_ld_done writel(0xffff0000, CRU_SOFTRST_CON12); writel(0x100010, PCIE_SNPS_APB_BASE + 0x180); /* S-Phy: waiting for phy locked */ for (i = 0; i < timeout; i++) { phy0_status0 = readl(PCIE30_PHY_GRF + 0x80); phy0_status1 = readl(PCIE30_PHY_GRF + 0x84); if (phy0_status0 != t0 || phy0_status1 != t1) { printep("RKEP: GRF:0x80=%x, 0x84=%x...\n", phy0_status0, phy0_status1); t0 = phy0_status0; t1 = phy0_status1; if (RK3568_SRAM_INIT_DONE(phy0_status0)) break; } udelay(10); } if (i >= timeout) { printep("lock fail\n"); mdelay(1); pcie_first_reset(); } udelay(1); } static void pcie_firewall_init(void) { } #endif static void pcie_ep_init(void) { u32 val; void *dbi_base = (void *)PCIE_SNPS_DBI_BASE; u64 apb_base = PCIE_SNPS_APB_BASE; int i, retries = 0; #ifdef PCIE_ENABLE_SRNS_PLL_REFCLK printep("RefClock in SRNS clock mode\n"); #else printep("RefClock in common clock_mode\n"); #endif /* * ltssm_enable enhance mode and enable delaying the link training * after Hot Reset */ writel(0x120012, apb_base + 0x180); /* Unmask pm_turnoff_int */ writel(0x04000000, apb_base + 0x18); /* PortLorgic DBI_RO_WR_EN */ val = readl((dbi_base + 0x8bc)); val |= 0x1; writel(val, dbi_base + 0x8bc); reinit: pcie_bar_init(dbi_base); pcie_inbound_config(); /* Device PID, DID */ writel(0x1d87, dbi_base + 0x00); writel(0x356a, dbi_base + 0x02); /* Device Class: Processing accelerators */ writel(0x1200, dbi_base + 0x0a); pcie_link_set_max_speed(dbi_base, PCI_EXP_LNKCTL2_TLS_8_0GT); #ifdef CONFIG_ROCKCHIP_RK3588 pcie_link_set_lanes(dbi_base, 4); #elif CONFIG_ROCKCHIP_RK3568 pcie_link_set_lanes(dbi_base, 2); #endif /* EP mode */ writel(0xf00000, apb_base); udelay(100); /* Enable EP mem/io access */ val = readl(dbi_base + 0x4); writel(val | 0x6, dbi_base + 0x4); val = readl(apb_base + 0x10); if (val & 0x4) { printep("Link is reset, int status misc=%x\n", val); retries++; } if (retries) /* Set app_dly2_done to enable app_ltssm_enable */ writel(0x80008, apb_base + 0x180); else /* Enable LTSSM */ writel(0xc000c, apb_base); printep("init PCIe fast Link up\n"); pcie_devmode_update(RKEP_MODE_LOADER, RKEP_SMODE_LNKRDY); /* Waiting for Link up */ while (1) { val = readl(apb_base + 0x300); if (((val & 0x3ffff) & ((0x3 << 16) | 0x11)) == 0x30011) break; mdelay(1); } printep("Link up %x\n", val); mdelay(3); /* Wait for link stable */ for (i = 0; i < 10000; i++) { val = readl(apb_base + 0x10); if (val & 0x4) { writel(0x4, apb_base + 0x10); printep("Link is reset, int status misc=%x\n", val); if (retries < 3) { retries++; goto reinit; } else { break; } } udelay(1); } printep("Done\n"); pcie_devmode_update(RKEP_MODE_LOADER, RKEP_SMODE_LNKUP); } void rockchip_pcie_ep_init(void) { u32 val; printf("\nRKEP: Init PCIe EP\n"); pcie_bar0_header_init(); #ifdef CONFIG_ROCKCHIP_RK3588 writel(0x1 << 23 | 0x1 << 21, PMU_PWR_GATE_SFTCON1); udelay(10); #endif pcie_firewall_init(); /* Re-in pcie initial */ val = readl(PCIE_SNPS_APB_BASE + 0x300); if (((val & 0x3ffff) & ((0x3 << 16))) == 0x30000) { printf("RKEP: already link up\n"); pcie_devmode_update(RKEP_MODE_LOADER, RKEP_SMODE_LNKUP); return; } pcie_board_init(); /* CRU and PHY Init */ pcie_cru_init(); pcie_ep_init(); }