/** @file * * Copyright (c) 2022, Rockchips Inc. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause-Patent * **/ #include "PcieInit.h" #include #include #include #include #include #include #include #include #include #include #include #include extern VOID PcieRegWrite(UINT32 Port, UINTN Offset, UINT32 Value); extern EFI_STATUS PciePortReset(UINT32 HostBridgeNum, UINT32 Port); static UINTN rk_pcie_read(UINTN addr, UINTN size, UINT32 *val) { if ((UINTN)addr & (size - 1)) { *val = 0; return PCIBIOS_UNSUPPORTED; } if (size == 4) { *val = MmioRead32(addr); } else if (size == 2) { *val = MmioRead16(addr); } else if (size == 1) { *val = MmioRead8(addr); } else { *val = 0; return PCIBIOS_NODEV; } return PCIBIOS_SUCCESSFUL; } static UINTN rk_pcie_write(UINTN addr, UINTN size, UINT32 val) { if ((UINTN)addr & (size - 1)) return PCIBIOS_UNSUPPORTED; if (size == 4) MmioWrite32(addr, val); else if (size == 2) MmioWrite16(addr, val); else if (size == 1) MmioWrite8(addr, val); else return PCIBIOS_NODEV; return PCIBIOS_SUCCESSFUL; } static UINTN __rk_pcie_read_apb(struct rk_pcie *rk_pcie, UINTN base, UINT32 reg, UINTN size) { int ret; UINT32 val; ret = rk_pcie_read(base + reg, size, &val); if (ret) DEBUG((EFI_D_ERROR, "Read APB address failed\n")); return val; } static void __rk_pcie_write_apb(struct rk_pcie *rk_pcie, UINTN base, UINT32 reg, UINTN size, UINT32 val) { int ret; ret = rk_pcie_write(base + reg, size, val); if (ret) DEBUG((EFI_D_ERROR, "Write APB address failed\n")); } static inline UINT32 rk_pcie_readl_apb(struct rk_pcie *rk_pcie, UINT32 reg) { return __rk_pcie_read_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4); } static inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, UINT32 reg, UINT32 val) { __rk_pcie_write_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4, val); } static int rk_pcie_get_link_speed(struct rk_pcie *rk_pcie) { return (MmioRead32(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) & PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF; } static int rk_pcie_get_link_width(struct rk_pcie *rk_pcie) { return (MmioRead32(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) & PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF; } static inline void rk_pcie_dbi_write_enable(struct rk_pcie *rk_pcie, BOOLEAN en) { UINT32 val; val = MmioRead32(rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF); if (en) val |= PCIE_DBI_RO_WR_EN; else val &= ~PCIE_DBI_RO_WR_EN; MmioWrite32(rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF, val); } static void rk_pcie_setup_host(struct rk_pcie *rk_pcie) { UINT32 val; rk_pcie_dbi_write_enable(rk_pcie, TRUE); /* setup RC BARs */ MmioWrite32(rk_pcie->dbi_base + PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_MEM_TYPE_64); MmioWrite32(rk_pcie->dbi_base + PCI_BASE_ADDRESS_1, 0x0); /* setup interrupt pins */ val = MmioRead32(rk_pcie->dbi_base + PCI_INTERRUPT_LINE); val &= 0xffff00ff; val |= 0x00000100; //val |= 0x00000000; MmioWrite32(rk_pcie->dbi_base + PCI_INTERRUPT_LINE,val); /* setup bus numbers */ val = MmioRead32(rk_pcie->dbi_base + PCI_PRIMARY_BUS); val &= 0xff000000; val |= 0x00ff0100; MmioWrite32(rk_pcie->dbi_base + PCI_PRIMARY_BUS, val); /* setup command register */ val = MmioRead32(rk_pcie->dbi_base + PCI_COMMAND); val &= 0xffff0000; val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR; MmioWrite32(rk_pcie->dbi_base + PCI_COMMAND, val); /* program correct class for RC */ MmioWrite16(rk_pcie->dbi_base + PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI); //test hACK MmioWrite16(rk_pcie->dbi_base + PCI_CLASS_DEVICE, 0x0600); /* Better disable write permission right after the update */ val = MmioRead32(rk_pcie->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); val |= PORT_LOGIC_SPEED_CHANGE; MmioWrite32(rk_pcie->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL, val); rk_pcie_dbi_write_enable(rk_pcie, FALSE); } static void rk_pcie_configure(struct rk_pcie *pci, UINT32 cap_speed) { UINT32 val; rk_pcie_dbi_write_enable(pci, TRUE); val = MmioRead32(pci->dbi_base + PCIE_LINK_CAPABILITY); val &= ~TARGET_LINK_SPEED_MASK; val |= cap_speed; MmioWrite32(pci->dbi_base + PCIE_LINK_CAPABILITY, val); val = MmioRead32(pci->dbi_base + PCIE_LINK_CTL_2); val &= ~TARGET_LINK_SPEED_MASK; val |= cap_speed; MmioWrite32(pci->dbi_base + PCIE_LINK_CTL_2, val); rk_pcie_dbi_write_enable(pci, FALSE); } static void rk_pcie_enable_debug(struct rk_pcie *rk_pcie) { #if RK_PCIE_DBG rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0, PCIE_CLIENT_DBG_TRANSITION_DATA); rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1, PCIE_CLIENT_DBG_TRANSITION_DATA); rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0, PCIE_CLIENT_DBG_TRANSITION_DATA); rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1, PCIE_CLIENT_DBG_TRANSITION_DATA); rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_MODE_CON, PCIE_CLIENT_DBF_EN); #endif } static void rk_pcie_debug_dump(struct rk_pcie *rk_pcie) { #if RK_PCIE_DBG UINT32 loop; DEBUG((EFI_D_ERROR, "ltssm = 0x%x\n", rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS))); for (loop = 0; loop < 64; loop++) DEBUG((EFI_D_ERROR, "fifo_status = 0x%x\n", rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_STATUS))); #endif } static inline void rk_pcie_link_status_clear(struct rk_pcie *rk_pcie) { rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_GENERAL_DEBUG, 0x0); } static inline void rk_pcie_disable_ltssm(struct rk_pcie *rk_pcie) { rk_pcie_writel_apb(rk_pcie, 0x0, 0xc0008); } static inline void rk_pcie_enable_ltssm(struct rk_pcie *rk_pcie) { rk_pcie_writel_apb(rk_pcie, 0x0, 0xc000c); } static int is_link_up(struct rk_pcie *priv) { UINT32 val; val = rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS); if ((val & (RDLH_LINKUP | SMLH_LINKUP)) == 0x30000) return 1; return 0; } static int rk_pcie_link_up(struct rk_pcie *priv, UINT32 cap_speed) { int retries; if (is_link_up(priv)) { DEBUG((EFI_D_ERROR, "PCI Link already up before configuration!\n")); return 1; } /* DW pre link configurations */ rk_pcie_configure(priv, cap_speed); /* Release the device */ Pcie30PeReset(FALSE); rk_pcie_disable_ltssm(priv); rk_pcie_link_status_clear(priv); rk_pcie_enable_debug(priv); /* Enable LTSSM */ rk_pcie_enable_ltssm(priv); for (retries = 0; retries < 500; retries++) { if (is_link_up(priv)) { DEBUG((EFI_D_ERROR, "PCIe Link up, LTSSM is 0x%x\n", rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS))); rk_pcie_debug_dump(priv); /* Link maybe in Gen switch recovery but we need to wait more 1s */ msleep(1000); return 0; } DEBUG((EFI_D_ERROR, "PCIe Linking... LTSSM is 0x%x\n", rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS))); rk_pcie_debug_dump(priv); msleep(1000); } DEBUG((EFI_D_ERROR, "PCIe-%d Link Fail\n", 0)); return -22; } static int rockchip_pcie_init_port(struct rk_pcie *priv) { int ret; UINT32 val; /* RK3588 EVB1 PCIe3L4*/ Pcie30IoInit(); /* Rest the device */ Pcie30PeReset(TRUE); /* Set power and maybe external ref clk input */ Pcie30PowerEn(); msleep(100000); //DEBUG((EFI_D_ERROR, "0xFD5F8070 = 0x%x, 0xFEC4000c = 0x%x, 0xFEC50004 = 0x%x\n", 0)); /* Disable power domain */ MmioWrite32(0xFD8D8150, 0x1 << 23 | 0x1 << 21); //PD_PCIE & PD_PHP /* FixMe init 3.0 PHY */ /* Phy mode: Aggregation NBNB */ MmioWrite32(0xfd5b8000 + RK3588_PCIE3PHY_GRF_CMN_CON0, (0x7 << 16) | PHY_MODE_PCIE_AGGREGATION); /* 开控制器和phy时钟,撤销复位 */ MmioWrite32(0xFD7C0A80, 0xffff0000); //CRU_SOFTRST_CON32 MmioWrite32(0xFD7C0A84, 0xffff0000); //CRU_SOFTRST_CON33 MmioWrite32(0xFD7C0A88, 0xffff0000); //CRU_SOFTRST_CON34 MmioWrite32(0xFD7C0880, 0xffff0000); //CRU_GATE_CON32 MmioWrite32(0xFD7C0884, 0xffff0000); //CRU_GATE_CON33 MmioWrite32(0xFD7C0888, 0xffff0000); //CRU_GATE_CON34 MmioWrite32(0xFD7C0898, 0xffff0000); //CRU_GATE_CON38 MmioWrite32(0xFD7C089c, 0xffff0000); //CRU_GATE_CON39 MmioWrite32(0xFD7C8A00, (0x1 << 24)); //PHPTOPCRU_SOFTRST_CON00 MmioWrite32(0xFD7C8800, 0xffff0000); //PHPTOPCRU_GATE_CON00 /* PHY复位 */ MmioWrite32(0xFD7C8A00, (0x1 << 10) | (0x1 << 26)); msleep(10); /* Deassert PCIe PMA output clamp mode */ MmioWrite32(0xfd5b8000 + RK3588_PCIE3PHY_GRF_CMN_CON0, (0x1 << 8) | (0x1 << 24)); /* 撤销PHY复位 */ MmioWrite32(0xFD7C8A00, (0x1 << 26)); /* 配置PHY: 3.0 PHY不用配置 */ /* LTSSM EN ctrl mode */ val = rk_pcie_readl_apb(priv, PCIE_CLIENT_HOT_RESET_CTRL); val |= PCIE_LTSSM_ENABLE_ENHANCE | (PCIE_LTSSM_ENABLE_ENHANCE << 16); rk_pcie_writel_apb(priv, PCIE_CLIENT_HOT_RESET_CTRL, val); /* Set RC mode */ rk_pcie_dbi_write_enable(priv, TRUE); rk_pcie_writel_apb(priv, 0x0, 0xf00000); MmioWrite32(0xf50002ec, 0xfffff0); MmioWrite32(0xf50002f0, 0x13c0); //BAR0 resize 512G //io -4 0xa400008bc 0x77f41 rk_pcie_writel_apb(priv, 0x0, 0xf00040); rk_pcie_setup_host(priv); ret = rk_pcie_link_up(priv, priv->gen); if (ret < 0) return ret; DEBUG((EFI_D_ERROR, "PCIe Init sucessfully (Gen%d-x%d, Bus%d)\n", rk_pcie_get_link_speed(priv),rk_pcie_get_link_width(priv))); rk_pcie_dbi_write_enable(priv, TRUE); msleep(10000); return 0; } EFI_STATUS PcieInitEntry ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status = EFI_SUCCESS; struct rk_pcie *priv; int ret; priv = (struct rk_pcie *)AllocatePool (sizeof (struct rk_pcie)); if (priv == NULL) { DEBUG((EFI_D_ERROR, "Failed to allocate priv memory!\n")); return EFI_OUT_OF_RESOURCES; } memset(priv, 0, sizeof(struct rk_pcie)); /* 先调试3L4,配置Gen 3 */ priv->gen = 3; priv->lane = 4; priv->dbi_base = PcdGet64(PcdPcieRootPortDbiBaseAddress); priv->apb_base = PcdGet64(PcdPcieRootPortApbBaseAddress); priv->cfg_base = PcdGet64(PcdPcieRootPortCfgBaseAddress); DEBUG((EFI_D_ERROR, "dbi_base = 0x%lx apb_base = 0x%lx cfg_base = 0x%lx\n", priv->dbi_base, priv->apb_base, priv->cfg_base)); ret = rockchip_pcie_init_port(priv); if (ret < 0) return EFI_NO_MEDIA; return Status; }