1bc58f211SShawn Lin // SPDX-License-Identifier: GPL-2.0+ 2bc58f211SShawn Lin /* 3bc58f211SShawn Lin * Rockchip DesignWare based PCIe host controller driver 4bc58f211SShawn Lin * 5bc58f211SShawn Lin * Copyright (c) 2021 Rockchip, Inc. 6bc58f211SShawn Lin */ 7bc58f211SShawn Lin 8bc58f211SShawn Lin #include <common.h> 9bc58f211SShawn Lin #include <clk.h> 10bc58f211SShawn Lin #include <dm.h> 11bc58f211SShawn Lin #include <generic-phy.h> 12bc58f211SShawn Lin #include <pci.h> 13bc58f211SShawn Lin #include <power-domain.h> 14bc58f211SShawn Lin #include <power/regulator.h> 15bc58f211SShawn Lin #include <reset.h> 16bc58f211SShawn Lin #include <syscon.h> 17bc58f211SShawn Lin #include <asm/io.h> 18bc58f211SShawn Lin #include <asm-generic/gpio.h> 19bc58f211SShawn Lin #include <asm/arch-rockchip/clock.h> 20bc58f211SShawn Lin #include <linux/iopoll.h> 21fbc8ca74SJon Lin #include <linux/ioport.h> 22bc58f211SShawn Lin 23bc58f211SShawn Lin DECLARE_GLOBAL_DATA_PTR; 24bc58f211SShawn Lin 250e16653bSJon Lin #define RK_PCIE_DBG 0 260e16653bSJon Lin 270e16653bSJon Lin #define __pcie_dev_print_emit(fmt, ...) \ 280e16653bSJon Lin ({ \ 290e16653bSJon Lin printf(fmt, ##__VA_ARGS__); \ 300e16653bSJon Lin }) 310e16653bSJon Lin 320e16653bSJon Lin #ifdef dev_err 330e16653bSJon Lin #undef dev_err 340e16653bSJon Lin #define dev_err(dev, fmt, ...) \ 350e16653bSJon Lin ({ \ 360e16653bSJon Lin if (dev) \ 370e16653bSJon Lin __pcie_dev_print_emit("%s: " fmt, dev->name, \ 380e16653bSJon Lin ##__VA_ARGS__); \ 390e16653bSJon Lin }) 400e16653bSJon Lin #endif 410e16653bSJon Lin 420e16653bSJon Lin #ifdef dev_info 430e16653bSJon Lin #undef dev_info 440e16653bSJon Lin #define dev_info dev_err 450e16653bSJon Lin #endif 460e16653bSJon Lin 470e16653bSJon Lin #ifdef DEBUG 480e16653bSJon Lin #define dev_dbg dev_err 490e16653bSJon Lin #else 500e16653bSJon Lin #define dev_dbg(dev, fmt, ...) \ 510e16653bSJon Lin ({ \ 520e16653bSJon Lin if (0) \ 530e16653bSJon Lin __dev_printk(7, dev, fmt, ##__VA_ARGS__); \ 540e16653bSJon Lin }) 550e16653bSJon Lin #endif 560e16653bSJon Lin 57bc58f211SShawn Lin struct rk_pcie { 58bc58f211SShawn Lin struct udevice *dev; 59bc58f211SShawn Lin struct udevice *vpcie3v3; 60bc58f211SShawn Lin void *dbi_base; 61bc58f211SShawn Lin void *apb_base; 62bc58f211SShawn Lin void *cfg_base; 63bc58f211SShawn Lin fdt_size_t cfg_size; 64bc58f211SShawn Lin struct phy phy; 65bc58f211SShawn Lin struct clk_bulk clks; 66bc58f211SShawn Lin int first_busno; 67bc58f211SShawn Lin struct reset_ctl_bulk rsts; 68bc58f211SShawn Lin struct gpio_desc rst_gpio; 69bc58f211SShawn Lin struct pci_region io; 70bc58f211SShawn Lin struct pci_region mem; 71c2482762SShawn Lin bool is_bifurcation; 72abcec002SJon Lin u32 gen; 73bc58f211SShawn Lin }; 74bc58f211SShawn Lin 75bc58f211SShawn Lin enum { 76bc58f211SShawn Lin PCIBIOS_SUCCESSFUL = 0x0000, 77bc58f211SShawn Lin PCIBIOS_UNSUPPORTED = -ENODEV, 78bc58f211SShawn Lin PCIBIOS_NODEV = -ENODEV, 79bc58f211SShawn Lin }; 80bc58f211SShawn Lin 81bc58f211SShawn Lin #define msleep(a) udelay((a) * 1000) 82bc58f211SShawn Lin 83bc58f211SShawn Lin /* Parameters for the waiting for iATU enabled routine */ 84bc58f211SShawn Lin #define PCIE_CLIENT_GENERAL_DEBUG 0x104 85bc58f211SShawn Lin #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 86bc58f211SShawn Lin #define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) 87bc58f211SShawn Lin #define PCIE_CLIENT_LTSSM_STATUS 0x300 88bc58f211SShawn Lin #define SMLH_LINKUP BIT(16) 89bc58f211SShawn Lin #define RDLH_LINKUP BIT(17) 90bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310 91bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320 92bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324 93bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328 94bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c 95bc58f211SShawn Lin #define PCIE_CLIENT_DBG_FIFO_STATUS 0x350 96bc58f211SShawn Lin #define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000 97bc58f211SShawn Lin #define PCIE_CLIENT_DBF_EN 0xffff0003 98bc58f211SShawn Lin 99bc58f211SShawn Lin /* PCI DBICS registers */ 100bc58f211SShawn Lin #define PCIE_LINK_STATUS_REG 0x80 101bc58f211SShawn Lin #define PCIE_LINK_STATUS_SPEED_OFF 16 102bc58f211SShawn Lin #define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF) 103bc58f211SShawn Lin #define PCIE_LINK_STATUS_WIDTH_OFF 20 104bc58f211SShawn Lin #define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF) 105bc58f211SShawn Lin 106bc58f211SShawn Lin #define PCIE_LINK_CAPABILITY 0x7c 107bc58f211SShawn Lin #define PCIE_LINK_CTL_2 0xa0 108bc58f211SShawn Lin #define TARGET_LINK_SPEED_MASK 0xf 109bc58f211SShawn Lin #define LINK_SPEED_GEN_1 0x1 110bc58f211SShawn Lin #define LINK_SPEED_GEN_2 0x2 111bc58f211SShawn Lin #define LINK_SPEED_GEN_3 0x3 112bc58f211SShawn Lin 113bc58f211SShawn Lin #define PCIE_MISC_CONTROL_1_OFF 0x8bc 114bc58f211SShawn Lin #define PCIE_DBI_RO_WR_EN BIT(0) 115bc58f211SShawn Lin 116bc58f211SShawn Lin #define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80c 117bc58f211SShawn Lin #define PORT_LOGIC_SPEED_CHANGE BIT(17) 118bc58f211SShawn Lin 119bc58f211SShawn Lin /* 120bc58f211SShawn Lin * iATU Unroll-specific register definitions 121bc58f211SShawn Lin * From 4.80 core version the address translation will be made by unroll. 122bc58f211SShawn Lin * The registers are offset from atu_base 123bc58f211SShawn Lin */ 124bc58f211SShawn Lin #define PCIE_ATU_UNR_REGION_CTRL1 0x00 125bc58f211SShawn Lin #define PCIE_ATU_UNR_REGION_CTRL2 0x04 126bc58f211SShawn Lin #define PCIE_ATU_UNR_LOWER_BASE 0x08 127bc58f211SShawn Lin #define PCIE_ATU_UNR_UPPER_BASE 0x0c 128bc58f211SShawn Lin #define PCIE_ATU_UNR_LIMIT 0x10 129bc58f211SShawn Lin #define PCIE_ATU_UNR_LOWER_TARGET 0x14 130bc58f211SShawn Lin #define PCIE_ATU_UNR_UPPER_TARGET 0x18 131bc58f211SShawn Lin 132bc58f211SShawn Lin #define PCIE_ATU_REGION_INDEX1 (0x1 << 0) 133bc58f211SShawn Lin #define PCIE_ATU_REGION_INDEX0 (0x0 << 0) 134bc58f211SShawn Lin #define PCIE_ATU_TYPE_MEM (0x0 << 0) 135bc58f211SShawn Lin #define PCIE_ATU_TYPE_IO (0x2 << 0) 136bc58f211SShawn Lin #define PCIE_ATU_TYPE_CFG0 (0x4 << 0) 137bc58f211SShawn Lin #define PCIE_ATU_TYPE_CFG1 (0x5 << 0) 138bc58f211SShawn Lin #define PCIE_ATU_ENABLE (0x1 << 31) 139bc58f211SShawn Lin #define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) 140bc58f211SShawn Lin #define PCIE_ATU_BUS(x) (((x) & 0xff) << 24) 141bc58f211SShawn Lin #define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19) 142bc58f211SShawn Lin #define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16) 143bc58f211SShawn Lin 144bc58f211SShawn Lin /* Register address builder */ 145bc58f211SShawn Lin #define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \ 146bc58f211SShawn Lin ((0x3 << 20) | ((region) << 9)) 147bc58f211SShawn Lin #define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \ 148bc58f211SShawn Lin ((0x3 << 20) | ((region) << 9) | (0x1 << 8)) 149bc58f211SShawn Lin 150bc58f211SShawn Lin /* Parameters for the waiting for iATU enabled routine */ 151bc58f211SShawn Lin #define LINK_WAIT_MAX_IATU_RETRIES 5 152bc58f211SShawn Lin #define LINK_WAIT_IATU 10000 153bc58f211SShawn Lin 1541f452320SJon Lin #define PCIE_TYPE0_HDR_DBI2_OFFSET 0x100000 1551f452320SJon Lin 156bc58f211SShawn Lin static int rk_pcie_read(void __iomem *addr, int size, u32 *val) 157bc58f211SShawn Lin { 158bc58f211SShawn Lin if ((uintptr_t)addr & (size - 1)) { 159bc58f211SShawn Lin *val = 0; 160bc58f211SShawn Lin return PCIBIOS_UNSUPPORTED; 161bc58f211SShawn Lin } 162bc58f211SShawn Lin 163bc58f211SShawn Lin if (size == 4) { 164bc58f211SShawn Lin *val = readl(addr); 165bc58f211SShawn Lin } else if (size == 2) { 166bc58f211SShawn Lin *val = readw(addr); 167bc58f211SShawn Lin } else if (size == 1) { 168bc58f211SShawn Lin *val = readb(addr); 169bc58f211SShawn Lin } else { 170bc58f211SShawn Lin *val = 0; 171bc58f211SShawn Lin return PCIBIOS_NODEV; 172bc58f211SShawn Lin } 173bc58f211SShawn Lin 174bc58f211SShawn Lin return PCIBIOS_SUCCESSFUL; 175bc58f211SShawn Lin } 176bc58f211SShawn Lin 177bc58f211SShawn Lin static int rk_pcie_write(void __iomem *addr, int size, u32 val) 178bc58f211SShawn Lin { 179bc58f211SShawn Lin if ((uintptr_t)addr & (size - 1)) 180bc58f211SShawn Lin return PCIBIOS_UNSUPPORTED; 181bc58f211SShawn Lin 182bc58f211SShawn Lin if (size == 4) 183bc58f211SShawn Lin writel(val, addr); 184bc58f211SShawn Lin else if (size == 2) 185bc58f211SShawn Lin writew(val, addr); 186bc58f211SShawn Lin else if (size == 1) 187bc58f211SShawn Lin writeb(val, addr); 188bc58f211SShawn Lin else 189bc58f211SShawn Lin return PCIBIOS_NODEV; 190bc58f211SShawn Lin 191bc58f211SShawn Lin return PCIBIOS_SUCCESSFUL; 192bc58f211SShawn Lin } 193bc58f211SShawn Lin 194bc58f211SShawn Lin static u32 __rk_pcie_read_apb(struct rk_pcie *rk_pcie, void __iomem *base, 195bc58f211SShawn Lin u32 reg, size_t size) 196bc58f211SShawn Lin { 197bc58f211SShawn Lin int ret; 198bc58f211SShawn Lin u32 val; 199bc58f211SShawn Lin 200bc58f211SShawn Lin ret = rk_pcie_read(base + reg, size, &val); 201bc58f211SShawn Lin if (ret) 2020e16653bSJon Lin dev_err(rk_pcie->dev, "Read APB address failed\n"); 203bc58f211SShawn Lin 204bc58f211SShawn Lin return val; 205bc58f211SShawn Lin } 206bc58f211SShawn Lin 207bc58f211SShawn Lin static void __rk_pcie_write_apb(struct rk_pcie *rk_pcie, void __iomem *base, 208bc58f211SShawn Lin u32 reg, size_t size, u32 val) 209bc58f211SShawn Lin { 210bc58f211SShawn Lin int ret; 211bc58f211SShawn Lin 212bc58f211SShawn Lin ret = rk_pcie_write(base + reg, size, val); 213bc58f211SShawn Lin if (ret) 2140e16653bSJon Lin dev_err(rk_pcie->dev, "Write APB address failed\n"); 215bc58f211SShawn Lin } 216bc58f211SShawn Lin 217bc58f211SShawn Lin static inline u32 rk_pcie_readl_apb(struct rk_pcie *rk_pcie, u32 reg) 218bc58f211SShawn Lin { 219bc58f211SShawn Lin return __rk_pcie_read_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4); 220bc58f211SShawn Lin } 221bc58f211SShawn Lin 222bc58f211SShawn Lin static inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, u32 reg, 223bc58f211SShawn Lin u32 val) 224bc58f211SShawn Lin { 225bc58f211SShawn Lin __rk_pcie_write_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4, val); 226bc58f211SShawn Lin } 227bc58f211SShawn Lin 228bc58f211SShawn Lin static int rk_pcie_get_link_speed(struct rk_pcie *rk_pcie) 229bc58f211SShawn Lin { 230bc58f211SShawn Lin return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) & 231bc58f211SShawn Lin PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF; 232bc58f211SShawn Lin } 233bc58f211SShawn Lin 234bc58f211SShawn Lin static int rk_pcie_get_link_width(struct rk_pcie *rk_pcie) 235bc58f211SShawn Lin { 236bc58f211SShawn Lin return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) & 237bc58f211SShawn Lin PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF; 238bc58f211SShawn Lin } 239bc58f211SShawn Lin 240bc58f211SShawn Lin static void rk_pcie_writel_ob_unroll(struct rk_pcie *rk_pcie, u32 index, 241bc58f211SShawn Lin u32 reg, u32 val) 242bc58f211SShawn Lin { 243bc58f211SShawn Lin u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); 244bc58f211SShawn Lin void __iomem *base = rk_pcie->dbi_base; 245bc58f211SShawn Lin 246bc58f211SShawn Lin writel(val, base + offset + reg); 247bc58f211SShawn Lin } 248bc58f211SShawn Lin 249bc58f211SShawn Lin static u32 rk_pcie_readl_ob_unroll(struct rk_pcie *rk_pcie, u32 index, u32 reg) 250bc58f211SShawn Lin { 251bc58f211SShawn Lin u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); 252bc58f211SShawn Lin void __iomem *base = rk_pcie->dbi_base; 253bc58f211SShawn Lin 254bc58f211SShawn Lin return readl(base + offset + reg); 255bc58f211SShawn Lin } 256bc58f211SShawn Lin 257bc58f211SShawn Lin static inline void rk_pcie_dbi_write_enable(struct rk_pcie *rk_pcie, bool en) 258bc58f211SShawn Lin { 259bc58f211SShawn Lin u32 val; 260bc58f211SShawn Lin 261bc58f211SShawn Lin val = readl(rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF); 262bc58f211SShawn Lin 263bc58f211SShawn Lin if (en) 264bc58f211SShawn Lin val |= PCIE_DBI_RO_WR_EN; 265bc58f211SShawn Lin else 266bc58f211SShawn Lin val &= ~PCIE_DBI_RO_WR_EN; 267bc58f211SShawn Lin writel(val, rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF); 268bc58f211SShawn Lin } 269bc58f211SShawn Lin 270bc58f211SShawn Lin static void rk_pcie_setup_host(struct rk_pcie *rk_pcie) 271bc58f211SShawn Lin { 272bc58f211SShawn Lin u32 val; 273bc58f211SShawn Lin 274bc58f211SShawn Lin rk_pcie_dbi_write_enable(rk_pcie, true); 275bc58f211SShawn Lin 276bc58f211SShawn Lin /* setup RC BARs */ 277bc58f211SShawn Lin writel(PCI_BASE_ADDRESS_MEM_TYPE_64, 278bc58f211SShawn Lin rk_pcie->dbi_base + PCI_BASE_ADDRESS_0); 279bc58f211SShawn Lin writel(0x0, rk_pcie->dbi_base + PCI_BASE_ADDRESS_1); 280bc58f211SShawn Lin 281bc58f211SShawn Lin /* setup interrupt pins */ 282bc58f211SShawn Lin val = readl(rk_pcie->dbi_base + PCI_INTERRUPT_LINE); 283bc58f211SShawn Lin val &= 0xffff00ff; 284bc58f211SShawn Lin val |= 0x00000100; 285bc58f211SShawn Lin writel(val, rk_pcie->dbi_base + PCI_INTERRUPT_LINE); 286bc58f211SShawn Lin 287bc58f211SShawn Lin /* setup bus numbers */ 288bc58f211SShawn Lin val = readl(rk_pcie->dbi_base + PCI_PRIMARY_BUS); 289bc58f211SShawn Lin val &= 0xff000000; 290bc58f211SShawn Lin val |= 0x00ff0100; 291bc58f211SShawn Lin writel(val, rk_pcie->dbi_base + PCI_PRIMARY_BUS); 292bc58f211SShawn Lin 293bc58f211SShawn Lin val = readl(rk_pcie->dbi_base + PCI_PRIMARY_BUS); 294bc58f211SShawn Lin 295bc58f211SShawn Lin /* setup command register */ 296bc58f211SShawn Lin val = readl(rk_pcie->dbi_base + PCI_COMMAND); 297bc58f211SShawn Lin val &= 0xffff0000; 298bc58f211SShawn Lin val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | 299bc58f211SShawn Lin PCI_COMMAND_MASTER | PCI_COMMAND_SERR; 300bc58f211SShawn Lin writel(val, rk_pcie->dbi_base + PCI_COMMAND); 301bc58f211SShawn Lin 302bc58f211SShawn Lin /* program correct class for RC */ 303bc58f211SShawn Lin writew(PCI_CLASS_BRIDGE_PCI, rk_pcie->dbi_base + PCI_CLASS_DEVICE); 304bc58f211SShawn Lin /* Better disable write permission right after the update */ 305bc58f211SShawn Lin 306bc58f211SShawn Lin val = readl(rk_pcie->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); 307bc58f211SShawn Lin val |= PORT_LOGIC_SPEED_CHANGE; 308bc58f211SShawn Lin writel(val, rk_pcie->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); 309bc58f211SShawn Lin 3101f452320SJon Lin /* Disable BAR0 BAR1 */ 3111f452320SJon Lin writel(0, rk_pcie->dbi_base + PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + 0 * 4); 3121f452320SJon Lin writel(0, rk_pcie->dbi_base + PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + 1 * 4); 3131f452320SJon Lin 314bc58f211SShawn Lin rk_pcie_dbi_write_enable(rk_pcie, false); 315bc58f211SShawn Lin } 316bc58f211SShawn Lin 317bc58f211SShawn Lin static void rk_pcie_configure(struct rk_pcie *pci, u32 cap_speed) 318bc58f211SShawn Lin { 319bc58f211SShawn Lin u32 val; 320bc58f211SShawn Lin 321bc58f211SShawn Lin rk_pcie_dbi_write_enable(pci, true); 322bc58f211SShawn Lin 323bc58f211SShawn Lin val = readl(pci->dbi_base + PCIE_LINK_CAPABILITY); 324bc58f211SShawn Lin val &= ~TARGET_LINK_SPEED_MASK; 325bc58f211SShawn Lin val |= cap_speed; 326bc58f211SShawn Lin writel(val, pci->dbi_base + PCIE_LINK_CAPABILITY); 327bc58f211SShawn Lin 328bc58f211SShawn Lin val = readl(pci->dbi_base + PCIE_LINK_CTL_2); 329bc58f211SShawn Lin val &= ~TARGET_LINK_SPEED_MASK; 330bc58f211SShawn Lin val |= cap_speed; 331bc58f211SShawn Lin writel(val, pci->dbi_base + PCIE_LINK_CTL_2); 332bc58f211SShawn Lin 333bc58f211SShawn Lin rk_pcie_dbi_write_enable(pci, false); 334bc58f211SShawn Lin } 335bc58f211SShawn Lin 336bc58f211SShawn Lin static void rk_pcie_prog_outbound_atu_unroll(struct rk_pcie *pci, int index, 337bc58f211SShawn Lin int type, u64 cpu_addr, 338bc58f211SShawn Lin u64 pci_addr, u32 size) 339bc58f211SShawn Lin { 340bc58f211SShawn Lin u32 retries, val; 341bc58f211SShawn Lin 342bc58f211SShawn Lin dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n", 343bc58f211SShawn Lin index, type, cpu_addr, pci_addr, size); 344bc58f211SShawn Lin 345bc58f211SShawn Lin rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, 346bc58f211SShawn Lin lower_32_bits(cpu_addr)); 347bc58f211SShawn Lin rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, 348bc58f211SShawn Lin upper_32_bits(cpu_addr)); 349bc58f211SShawn Lin rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT, 350bc58f211SShawn Lin lower_32_bits(cpu_addr + size - 1)); 351bc58f211SShawn Lin rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, 352bc58f211SShawn Lin lower_32_bits(pci_addr)); 353bc58f211SShawn Lin rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, 354bc58f211SShawn Lin upper_32_bits(pci_addr)); 355bc58f211SShawn Lin rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, 356bc58f211SShawn Lin type); 357bc58f211SShawn Lin rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, 358bc58f211SShawn Lin PCIE_ATU_ENABLE); 359bc58f211SShawn Lin 360bc58f211SShawn Lin /* 361bc58f211SShawn Lin * Make sure ATU enable takes effect before any subsequent config 362bc58f211SShawn Lin * and I/O accesses. 363bc58f211SShawn Lin */ 364bc58f211SShawn Lin for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { 365bc58f211SShawn Lin val = rk_pcie_readl_ob_unroll(pci, index, 366bc58f211SShawn Lin PCIE_ATU_UNR_REGION_CTRL2); 367bc58f211SShawn Lin if (val & PCIE_ATU_ENABLE) 368bc58f211SShawn Lin return; 369bc58f211SShawn Lin 370bc58f211SShawn Lin udelay(LINK_WAIT_IATU); 371bc58f211SShawn Lin } 372bc58f211SShawn Lin dev_err(pci->dev, "outbound iATU is not being enabled\n"); 373bc58f211SShawn Lin } 374bc58f211SShawn Lin 375bc58f211SShawn Lin static int rk_pcie_addr_valid(pci_dev_t d, int first_busno) 376bc58f211SShawn Lin { 377bc58f211SShawn Lin if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0)) 378bc58f211SShawn Lin return 0; 379bc58f211SShawn Lin if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0)) 380bc58f211SShawn Lin return 0; 381bc58f211SShawn Lin 382bc58f211SShawn Lin return 1; 383bc58f211SShawn Lin } 384bc58f211SShawn Lin 385bc58f211SShawn Lin static uintptr_t set_cfg_address(struct rk_pcie *pcie, 386bc58f211SShawn Lin pci_dev_t d, uint where) 387bc58f211SShawn Lin { 388bc58f211SShawn Lin int bus = PCI_BUS(d) - pcie->first_busno; 389bc58f211SShawn Lin uintptr_t va_address; 390bc58f211SShawn Lin u32 atu_type; 391bc58f211SShawn Lin 392bc58f211SShawn Lin /* Use dbi_base for own configuration read and write */ 393bc58f211SShawn Lin if (!bus) { 394bc58f211SShawn Lin va_address = (uintptr_t)pcie->dbi_base; 395bc58f211SShawn Lin goto out; 396bc58f211SShawn Lin } 397bc58f211SShawn Lin 398bc58f211SShawn Lin if (bus == 1) 399bc58f211SShawn Lin /* 400bc58f211SShawn Lin * For local bus whose primary bus number is root bridge, 401bc58f211SShawn Lin * change TLP Type field to 4. 402bc58f211SShawn Lin */ 403bc58f211SShawn Lin atu_type = PCIE_ATU_TYPE_CFG0; 404bc58f211SShawn Lin else 405bc58f211SShawn Lin /* Otherwise, change TLP Type field to 5. */ 406bc58f211SShawn Lin atu_type = PCIE_ATU_TYPE_CFG1; 407bc58f211SShawn Lin 408bc58f211SShawn Lin /* 409bc58f211SShawn Lin * Not accessing root port configuration space? 410bc58f211SShawn Lin * Region #0 is used for Outbound CFG space access. 411bc58f211SShawn Lin * Direction = Outbound 412bc58f211SShawn Lin * Region Index = 0 413bc58f211SShawn Lin */ 414bc58f211SShawn Lin d = PCI_MASK_BUS(d); 415bc58f211SShawn Lin d = PCI_ADD_BUS(bus, d); 416bc58f211SShawn Lin rk_pcie_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1, 417bc58f211SShawn Lin atu_type, (u64)pcie->cfg_base, 418bc58f211SShawn Lin d << 8, pcie->cfg_size); 419bc58f211SShawn Lin 420bc58f211SShawn Lin va_address = (uintptr_t)pcie->cfg_base; 421bc58f211SShawn Lin 422bc58f211SShawn Lin out: 423bc58f211SShawn Lin va_address += where & ~0x3; 424bc58f211SShawn Lin 425bc58f211SShawn Lin return va_address; 426bc58f211SShawn Lin } 427bc58f211SShawn Lin 428bc58f211SShawn Lin static int rockchip_pcie_rd_conf(struct udevice *bus, pci_dev_t bdf, 429bc58f211SShawn Lin uint offset, ulong *valuep, 430bc58f211SShawn Lin enum pci_size_t size) 431bc58f211SShawn Lin { 432bc58f211SShawn Lin struct rk_pcie *pcie = dev_get_priv(bus); 433bc58f211SShawn Lin uintptr_t va_address; 434bc58f211SShawn Lin ulong value; 435bc58f211SShawn Lin 436bc58f211SShawn Lin debug("PCIE CFG read: bdf=%2x:%2x:%2x\n", 437bc58f211SShawn Lin PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); 438bc58f211SShawn Lin 439bc58f211SShawn Lin if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) { 440bc58f211SShawn Lin debug("- out of range\n"); 441bc58f211SShawn Lin *valuep = pci_get_ff(size); 442bc58f211SShawn Lin return 0; 443bc58f211SShawn Lin } 444bc58f211SShawn Lin 445bc58f211SShawn Lin va_address = set_cfg_address(pcie, bdf, offset); 446bc58f211SShawn Lin 447bc58f211SShawn Lin value = readl(va_address); 448bc58f211SShawn Lin 449bc58f211SShawn Lin debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); 450bc58f211SShawn Lin *valuep = pci_conv_32_to_size(value, offset, size); 451bc58f211SShawn Lin 452bc58f211SShawn Lin rk_pcie_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1, 453bc58f211SShawn Lin PCIE_ATU_TYPE_IO, pcie->io.phys_start, 454bc58f211SShawn Lin pcie->io.bus_start, pcie->io.size); 455bc58f211SShawn Lin 456bc58f211SShawn Lin return 0; 457bc58f211SShawn Lin } 458bc58f211SShawn Lin 459bc58f211SShawn Lin static int rockchip_pcie_wr_conf(struct udevice *bus, pci_dev_t bdf, 460bc58f211SShawn Lin uint offset, ulong value, 461bc58f211SShawn Lin enum pci_size_t size) 462bc58f211SShawn Lin { 463bc58f211SShawn Lin struct rk_pcie *pcie = dev_get_priv(bus); 464bc58f211SShawn Lin uintptr_t va_address; 465bc58f211SShawn Lin ulong old; 466bc58f211SShawn Lin 467bc58f211SShawn Lin debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d)\n", 468bc58f211SShawn Lin PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); 469bc58f211SShawn Lin debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value); 470bc58f211SShawn Lin if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) { 471bc58f211SShawn Lin debug("- out of range\n"); 472bc58f211SShawn Lin return 0; 473bc58f211SShawn Lin } 474bc58f211SShawn Lin 475bc58f211SShawn Lin va_address = set_cfg_address(pcie, bdf, offset); 476bc58f211SShawn Lin 477bc58f211SShawn Lin old = readl(va_address); 478bc58f211SShawn Lin value = pci_conv_size_to_32(old, value, offset, size); 479bc58f211SShawn Lin writel(value, va_address); 480bc58f211SShawn Lin 481bc58f211SShawn Lin rk_pcie_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1, 482bc58f211SShawn Lin PCIE_ATU_TYPE_IO, pcie->io.phys_start, 483bc58f211SShawn Lin pcie->io.bus_start, pcie->io.size); 484bc58f211SShawn Lin 485bc58f211SShawn Lin return 0; 486bc58f211SShawn Lin } 487bc58f211SShawn Lin 488bc58f211SShawn Lin static void rk_pcie_enable_debug(struct rk_pcie *rk_pcie) 489bc58f211SShawn Lin { 490bc58f211SShawn Lin #if RK_PCIE_DBG 491bc58f211SShawn Lin rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0, 492bc58f211SShawn Lin PCIE_CLIENT_DBG_TRANSITION_DATA); 493bc58f211SShawn Lin rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1, 494bc58f211SShawn Lin PCIE_CLIENT_DBG_TRANSITION_DATA); 495bc58f211SShawn Lin rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0, 496bc58f211SShawn Lin PCIE_CLIENT_DBG_TRANSITION_DATA); 497bc58f211SShawn Lin rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1, 498bc58f211SShawn Lin PCIE_CLIENT_DBG_TRANSITION_DATA); 499bc58f211SShawn Lin rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_MODE_CON, 500bc58f211SShawn Lin PCIE_CLIENT_DBF_EN); 501bc58f211SShawn Lin #endif 502bc58f211SShawn Lin } 503bc58f211SShawn Lin 504bc58f211SShawn Lin static void rk_pcie_debug_dump(struct rk_pcie *rk_pcie) 505bc58f211SShawn Lin { 506bc58f211SShawn Lin #if RK_PCIE_DBG 507bc58f211SShawn Lin u32 loop; 508bc58f211SShawn Lin 5090e16653bSJon Lin dev_err(rk_pcie->dev, "ltssm = 0x%x\n", 510bc58f211SShawn Lin rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS)); 511bc58f211SShawn Lin for (loop = 0; loop < 64; loop++) 5120e16653bSJon Lin dev_err(rk_pcie->dev, "fifo_status = 0x%x\n", 513bc58f211SShawn Lin rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_STATUS)); 514bc58f211SShawn Lin #endif 515bc58f211SShawn Lin } 516bc58f211SShawn Lin 517bc58f211SShawn Lin static inline void rk_pcie_link_status_clear(struct rk_pcie *rk_pcie) 518bc58f211SShawn Lin { 519bc58f211SShawn Lin rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_GENERAL_DEBUG, 0x0); 520bc58f211SShawn Lin } 521bc58f211SShawn Lin 522bc58f211SShawn Lin static inline void rk_pcie_disable_ltssm(struct rk_pcie *rk_pcie) 523bc58f211SShawn Lin { 524bc58f211SShawn Lin rk_pcie_writel_apb(rk_pcie, 0x0, 0xc0008); 525bc58f211SShawn Lin } 526bc58f211SShawn Lin 527bc58f211SShawn Lin static inline void rk_pcie_enable_ltssm(struct rk_pcie *rk_pcie) 528bc58f211SShawn Lin { 529bc58f211SShawn Lin rk_pcie_writel_apb(rk_pcie, 0x0, 0xc000c); 530bc58f211SShawn Lin } 531bc58f211SShawn Lin 532bc58f211SShawn Lin static int is_link_up(struct rk_pcie *priv) 533bc58f211SShawn Lin { 534bc58f211SShawn Lin u32 val; 535bc58f211SShawn Lin 536bc58f211SShawn Lin val = rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS); 537bc58f211SShawn Lin if ((val & (RDLH_LINKUP | SMLH_LINKUP)) == 0x30000 && 538bc58f211SShawn Lin (val & GENMASK(5, 0)) == 0x11) 539bc58f211SShawn Lin return 1; 540bc58f211SShawn Lin 541bc58f211SShawn Lin return 0; 542bc58f211SShawn Lin } 543bc58f211SShawn Lin 544bc58f211SShawn Lin static int rk_pcie_link_up(struct rk_pcie *priv, u32 cap_speed) 545bc58f211SShawn Lin { 546bc58f211SShawn Lin int retries; 547bc58f211SShawn Lin 548bc58f211SShawn Lin if (is_link_up(priv)) { 549bc58f211SShawn Lin printf("PCI Link already up before configuration!\n"); 550bc58f211SShawn Lin return 1; 551bc58f211SShawn Lin } 552bc58f211SShawn Lin 553bc58f211SShawn Lin /* DW pre link configurations */ 554bc58f211SShawn Lin rk_pcie_configure(priv, cap_speed); 555bc58f211SShawn Lin 55692d35878SJon Lin /* Release the device */ 5576d508927SJon Lin if (dm_gpio_is_valid(&priv->rst_gpio)) { 5586d508927SJon Lin /* 5596d508927SJon Lin * T_PVPERL (Power stable to PERST# inactive) should be a minimum of 100ms. 5606d508927SJon Lin * We add a 200ms by default for sake of hoping everthings 5616d508927SJon Lin * work fine. 5626d508927SJon Lin */ 5636d508927SJon Lin msleep(200); 564bc58f211SShawn Lin dm_gpio_set_value(&priv->rst_gpio, 1); 5656d508927SJon Lin /* 5666d508927SJon Lin * Add this 20ms delay because we observe link is always up stably after it and 5676d508927SJon Lin * could help us save 20ms for scanning devices. 5686d508927SJon Lin */ 5696d508927SJon Lin msleep(20); 5706d508927SJon Lin } 571bc58f211SShawn Lin 572bc58f211SShawn Lin rk_pcie_disable_ltssm(priv); 573bc58f211SShawn Lin rk_pcie_link_status_clear(priv); 574bc58f211SShawn Lin rk_pcie_enable_debug(priv); 575bc58f211SShawn Lin 576bc58f211SShawn Lin /* Enable LTSSM */ 577bc58f211SShawn Lin rk_pcie_enable_ltssm(priv); 578bc58f211SShawn Lin 579beef0f23SShawn Lin for (retries = 0; retries < 50; retries++) { 580bc58f211SShawn Lin if (is_link_up(priv)) { 581bc58f211SShawn Lin dev_info(priv->dev, "PCIe Link up, LTSSM is 0x%x\n", 582bc58f211SShawn Lin rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS)); 583bc58f211SShawn Lin rk_pcie_debug_dump(priv); 584ff2f1e41SShawn Lin /* Link maybe in Gen switch recovery but we need to wait more 1s */ 585ff2f1e41SShawn Lin msleep(1000); 586bc58f211SShawn Lin return 0; 587bc58f211SShawn Lin } 588bc58f211SShawn Lin 589bc58f211SShawn Lin dev_info(priv->dev, "PCIe Linking... LTSSM is 0x%x\n", 590bc58f211SShawn Lin rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS)); 591bc58f211SShawn Lin rk_pcie_debug_dump(priv); 59292d35878SJon Lin msleep(10); 593bc58f211SShawn Lin } 594bc58f211SShawn Lin 595bc58f211SShawn Lin dev_err(priv->dev, "PCIe-%d Link Fail\n", priv->dev->seq); 596*b2a4eeb5SShawn Lin rk_pcie_disable_ltssm(priv); 597bc58f211SShawn Lin return -EINVAL; 598bc58f211SShawn Lin } 599bc58f211SShawn Lin 600bc58f211SShawn Lin static int rockchip_pcie_init_port(struct udevice *dev) 601bc58f211SShawn Lin { 602bc58f211SShawn Lin int ret; 603bc58f211SShawn Lin u32 val; 604bc58f211SShawn Lin struct rk_pcie *priv = dev_get_priv(dev); 605c2482762SShawn Lin union phy_configure_opts phy_cfg; 606bc58f211SShawn Lin 60792d35878SJon Lin /* Rest the device */ 60892d35878SJon Lin if (dm_gpio_is_valid(&priv->rst_gpio)) 60992d35878SJon Lin dm_gpio_set_value(&priv->rst_gpio, 0); 61092d35878SJon Lin 611bc58f211SShawn Lin /* Set power and maybe external ref clk input */ 612bc58f211SShawn Lin if (priv->vpcie3v3) { 61332aabf13SJon Lin ret = regulator_set_enable(priv->vpcie3v3, true); 614bc58f211SShawn Lin if (ret) { 615bc58f211SShawn Lin dev_err(priv->dev, "failed to enable vpcie3v3 (ret=%d)\n", 616bc58f211SShawn Lin ret); 617bc58f211SShawn Lin return ret; 618bc58f211SShawn Lin } 619bc58f211SShawn Lin } 620bc58f211SShawn Lin 621c2482762SShawn Lin if (priv->is_bifurcation) { 622c2482762SShawn Lin phy_cfg.pcie.is_bifurcation = true; 623c2482762SShawn Lin ret = generic_phy_configure(&priv->phy, &phy_cfg); 624c2482762SShawn Lin if (ret) 625c2482762SShawn Lin dev_err(dev, "failed to set bifurcation for phy (ret=%d)\n", ret); 626c2482762SShawn Lin } 627c2482762SShawn Lin 628bc58f211SShawn Lin ret = generic_phy_init(&priv->phy); 629bc58f211SShawn Lin if (ret) { 630bc58f211SShawn Lin dev_err(dev, "failed to init phy (ret=%d)\n", ret); 631*b2a4eeb5SShawn Lin goto err_disable_3v3; 632bc58f211SShawn Lin } 633bc58f211SShawn Lin 634bc58f211SShawn Lin ret = generic_phy_power_on(&priv->phy); 635bc58f211SShawn Lin if (ret) { 636bc58f211SShawn Lin dev_err(dev, "failed to power on phy (ret=%d)\n", ret); 637bc58f211SShawn Lin goto err_exit_phy; 638bc58f211SShawn Lin } 639bc58f211SShawn Lin 640bc58f211SShawn Lin ret = reset_deassert_bulk(&priv->rsts); 641bc58f211SShawn Lin if (ret) { 642bc58f211SShawn Lin dev_err(dev, "failed to deassert resets (ret=%d)\n", ret); 643bc58f211SShawn Lin goto err_power_off_phy; 644bc58f211SShawn Lin } 645bc58f211SShawn Lin 646bc58f211SShawn Lin ret = clk_enable_bulk(&priv->clks); 647bc58f211SShawn Lin if (ret) { 648bc58f211SShawn Lin dev_err(dev, "failed to enable clks (ret=%d)\n", ret); 649bc58f211SShawn Lin goto err_deassert_bulk; 650bc58f211SShawn Lin } 651bc58f211SShawn Lin 652bc58f211SShawn Lin /* LTSSM EN ctrl mode */ 653bc58f211SShawn Lin val = rk_pcie_readl_apb(priv, PCIE_CLIENT_HOT_RESET_CTRL); 654bc58f211SShawn Lin val |= PCIE_LTSSM_ENABLE_ENHANCE | (PCIE_LTSSM_ENABLE_ENHANCE << 16); 655bc58f211SShawn Lin rk_pcie_writel_apb(priv, PCIE_CLIENT_HOT_RESET_CTRL, val); 656bc58f211SShawn Lin 657bc58f211SShawn Lin /* Set RC mode */ 658bc58f211SShawn Lin rk_pcie_writel_apb(priv, 0x0, 0xf00040); 659bc58f211SShawn Lin rk_pcie_setup_host(priv); 660bc58f211SShawn Lin 661abcec002SJon Lin ret = rk_pcie_link_up(priv, priv->gen); 662bc58f211SShawn Lin if (ret < 0) 663bc58f211SShawn Lin goto err_link_up; 664bc58f211SShawn Lin 665bc58f211SShawn Lin return 0; 666bc58f211SShawn Lin err_link_up: 667bc58f211SShawn Lin clk_disable_bulk(&priv->clks); 668bc58f211SShawn Lin err_deassert_bulk: 669bc58f211SShawn Lin reset_assert_bulk(&priv->rsts); 670bc58f211SShawn Lin err_power_off_phy: 671bc58f211SShawn Lin generic_phy_power_off(&priv->phy); 672bc58f211SShawn Lin err_exit_phy: 673bc58f211SShawn Lin generic_phy_exit(&priv->phy); 674*b2a4eeb5SShawn Lin err_disable_3v3: 675*b2a4eeb5SShawn Lin if(priv->vpcie3v3) 676*b2a4eeb5SShawn Lin regulator_set_enable(priv->vpcie3v3, false); 677bc58f211SShawn Lin return ret; 678bc58f211SShawn Lin } 679bc58f211SShawn Lin 680bc58f211SShawn Lin static int rockchip_pcie_parse_dt(struct udevice *dev) 681bc58f211SShawn Lin { 682bc58f211SShawn Lin struct rk_pcie *priv = dev_get_priv(dev); 683abcec002SJon Lin u32 max_link_speed; 684bc58f211SShawn Lin int ret; 685fbc8ca74SJon Lin struct resource res; 686bc58f211SShawn Lin 687fbc8ca74SJon Lin ret = dev_read_resource_byname(dev, "pcie-dbi", &res); 688fbc8ca74SJon Lin if (ret) 689bc58f211SShawn Lin return -ENODEV; 690fbc8ca74SJon Lin priv->dbi_base = (void *)(res.start); 691bc58f211SShawn Lin dev_dbg(dev, "DBI address is 0x%p\n", priv->dbi_base); 692bc58f211SShawn Lin 693fbc8ca74SJon Lin ret = dev_read_resource_byname(dev, "pcie-apb", &res); 694fbc8ca74SJon Lin if (ret) 695bc58f211SShawn Lin return -ENODEV; 696fbc8ca74SJon Lin priv->apb_base = (void *)(res.start); 697bc58f211SShawn Lin dev_dbg(dev, "APB address is 0x%p\n", priv->apb_base); 698bc58f211SShawn Lin 699bc58f211SShawn Lin ret = gpio_request_by_name(dev, "reset-gpios", 0, 700bc58f211SShawn Lin &priv->rst_gpio, GPIOD_IS_OUT); 701bc58f211SShawn Lin if (ret) { 702bc58f211SShawn Lin dev_err(dev, "failed to find reset-gpios property\n"); 703bc58f211SShawn Lin return ret; 704bc58f211SShawn Lin } 705bc58f211SShawn Lin 706bc58f211SShawn Lin ret = reset_get_bulk(dev, &priv->rsts); 707bc58f211SShawn Lin if (ret) { 708bc58f211SShawn Lin dev_err(dev, "Can't get reset: %d\n", ret); 709bc58f211SShawn Lin return ret; 710bc58f211SShawn Lin } 711bc58f211SShawn Lin 712bc58f211SShawn Lin ret = clk_get_bulk(dev, &priv->clks); 713bc58f211SShawn Lin if (ret) { 714bc58f211SShawn Lin dev_err(dev, "Can't get clock: %d\n", ret); 715bc58f211SShawn Lin return ret; 716bc58f211SShawn Lin } 717bc58f211SShawn Lin 718bc58f211SShawn Lin ret = device_get_supply_regulator(dev, "vpcie3v3-supply", 719bc58f211SShawn Lin &priv->vpcie3v3); 720bc58f211SShawn Lin if (ret && ret != -ENOENT) { 721bc58f211SShawn Lin dev_err(dev, "failed to get vpcie3v3 supply (ret=%d)\n", ret); 722bc58f211SShawn Lin return ret; 723bc58f211SShawn Lin } 724bc58f211SShawn Lin 725bc58f211SShawn Lin ret = generic_phy_get_by_index(dev, 0, &priv->phy); 726bc58f211SShawn Lin if (ret) { 727bc58f211SShawn Lin dev_err(dev, "failed to get pcie phy (ret=%d)\n", ret); 728bc58f211SShawn Lin return ret; 729bc58f211SShawn Lin } 730bc58f211SShawn Lin 731c2482762SShawn Lin if (dev_read_bool(dev, "rockchip,bifurcation")) 732c2482762SShawn Lin priv->is_bifurcation = true; 733c2482762SShawn Lin 734abcec002SJon Lin ret = ofnode_read_u32(dev->node, "max-link-speed", &max_link_speed); 735abcec002SJon Lin if (ret < 0 || max_link_speed > 4) 736abcec002SJon Lin priv->gen = 0; 737abcec002SJon Lin else 738abcec002SJon Lin priv->gen = max_link_speed; 739abcec002SJon Lin 740bc58f211SShawn Lin return 0; 741bc58f211SShawn Lin } 742bc58f211SShawn Lin 743bc58f211SShawn Lin static int rockchip_pcie_probe(struct udevice *dev) 744bc58f211SShawn Lin { 745bc58f211SShawn Lin struct rk_pcie *priv = dev_get_priv(dev); 746bc58f211SShawn Lin struct udevice *ctlr = pci_get_controller(dev); 747bc58f211SShawn Lin struct pci_controller *hose = dev_get_uclass_priv(ctlr); 748bc58f211SShawn Lin int ret; 749bc58f211SShawn Lin 750bc58f211SShawn Lin priv->first_busno = dev->seq; 751bc58f211SShawn Lin priv->dev = dev; 752bc58f211SShawn Lin 753bc58f211SShawn Lin ret = rockchip_pcie_parse_dt(dev); 754bc58f211SShawn Lin if (ret) 755bc58f211SShawn Lin return ret; 756bc58f211SShawn Lin 757bc58f211SShawn Lin ret = rockchip_pcie_init_port(dev); 758bc58f211SShawn Lin if (ret) 759*b2a4eeb5SShawn Lin goto free_rst; 760bc58f211SShawn Lin 761bc58f211SShawn Lin dev_info(dev, "PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", 762bc58f211SShawn Lin dev->seq, rk_pcie_get_link_speed(priv), 763bc58f211SShawn Lin rk_pcie_get_link_width(priv), 764bc58f211SShawn Lin hose->first_busno); 765bc58f211SShawn Lin 766bc58f211SShawn Lin for (ret = 0; ret < hose->region_count; ret++) { 767bc58f211SShawn Lin if (hose->regions[ret].flags == PCI_REGION_IO) { 768bc58f211SShawn Lin priv->io.phys_start = hose->regions[ret].phys_start; /* IO base */ 769bc58f211SShawn Lin priv->io.bus_start = hose->regions[ret].bus_start; /* IO_bus_addr */ 770bc58f211SShawn Lin priv->io.size = hose->regions[ret].size; /* IO size */ 771bc58f211SShawn Lin } else if (hose->regions[ret].flags == PCI_REGION_MEM) { 772bc58f211SShawn Lin priv->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */ 773bc58f211SShawn Lin priv->mem.bus_start = hose->regions[ret].bus_start; /* MEM_bus_addr */ 774bc58f211SShawn Lin priv->mem.size = hose->regions[ret].size; /* MEM size */ 775bc58f211SShawn Lin } else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) { 776bc58f211SShawn Lin priv->cfg_base = (void *)(priv->io.phys_start - priv->io.size); 777bc58f211SShawn Lin priv->cfg_size = priv->io.size; 778bc58f211SShawn Lin } else { 779bc58f211SShawn Lin dev_err(dev, "invalid flags type!\n"); 780bc58f211SShawn Lin } 781bc58f211SShawn Lin } 782bc58f211SShawn Lin 783bc58f211SShawn Lin dev_dbg(dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n", 784bc58f211SShawn Lin priv->cfg_base, priv->cfg_base + priv->cfg_size, 785bc58f211SShawn Lin priv->cfg_size); 786bc58f211SShawn Lin 787bc58f211SShawn Lin dev_dbg(dev, "IO space: [0x%llx - 0x%llx, size 0x%x]\n", 788bc58f211SShawn Lin priv->io.phys_start, priv->io.phys_start + priv->io.size, 789bc58f211SShawn Lin priv->io.size); 790bc58f211SShawn Lin 791bc58f211SShawn Lin dev_dbg(dev, "IO bus: [0x%x - 0x%x, size 0x%x]\n", 792bc58f211SShawn Lin priv->io.bus_start, priv->io.bus_start + priv->io.size, 793bc58f211SShawn Lin priv->io.size); 794bc58f211SShawn Lin 795bc58f211SShawn Lin dev_dbg(dev, "MEM space: [0x%llx - 0x%llx, size 0x%x]\n", 796bc58f211SShawn Lin priv->mem.phys_start, priv->mem.phys_start + priv->mem.size, 797bc58f211SShawn Lin priv->mem.size); 798bc58f211SShawn Lin 799bc58f211SShawn Lin dev_dbg(dev, "MEM bus: [0x%x - 0x%x, size 0x%x]\n", 800bc58f211SShawn Lin priv->mem.bus_start, priv->mem.bus_start + priv->mem.size, 801bc58f211SShawn Lin priv->mem.size); 802bc58f211SShawn Lin 803bc58f211SShawn Lin rk_pcie_prog_outbound_atu_unroll(priv, PCIE_ATU_REGION_INDEX0, 804bc58f211SShawn Lin PCIE_ATU_TYPE_MEM, 805bc58f211SShawn Lin priv->mem.phys_start, 806bc58f211SShawn Lin priv->mem.bus_start, priv->mem.size); 807bc58f211SShawn Lin return 0; 808*b2a4eeb5SShawn Lin free_rst: 809*b2a4eeb5SShawn Lin dm_gpio_free(dev, &priv->rst_gpio); 810*b2a4eeb5SShawn Lin return ret; 811bc58f211SShawn Lin } 812bc58f211SShawn Lin 813bc58f211SShawn Lin static const struct dm_pci_ops rockchip_pcie_ops = { 814bc58f211SShawn Lin .read_config = rockchip_pcie_rd_conf, 815bc58f211SShawn Lin .write_config = rockchip_pcie_wr_conf, 816bc58f211SShawn Lin }; 817bc58f211SShawn Lin 818bc58f211SShawn Lin static const struct udevice_id rockchip_pcie_ids[] = { 819793cb46eSJon Lin { .compatible = "rockchip,rk3528-pcie" }, 820e751b113SJon Lin { .compatible = "rockchip,rk3562-pcie" }, 821bc58f211SShawn Lin { .compatible = "rockchip,rk3568-pcie" }, 82243ede60cSJon Lin { .compatible = "rockchip,rk3588-pcie" }, 82353314ce8SJon Lin { .compatible = "rockchip,rk3576-pcie" }, 824bc58f211SShawn Lin { } 825bc58f211SShawn Lin }; 826bc58f211SShawn Lin 827bc58f211SShawn Lin U_BOOT_DRIVER(rockchip_pcie) = { 828bc58f211SShawn Lin .name = "pcie_dw_rockchip", 829bc58f211SShawn Lin .id = UCLASS_PCI, 830bc58f211SShawn Lin .of_match = rockchip_pcie_ids, 831bc58f211SShawn Lin .ops = &rockchip_pcie_ops, 832bc58f211SShawn Lin .probe = rockchip_pcie_probe, 833bc58f211SShawn Lin .priv_auto_alloc_size = sizeof(struct rk_pcie), 834bc58f211SShawn Lin }; 835