18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Rockchip AXI PCIe host controller driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 Rockchip, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Shawn Lin <shawn.lin@rock-chips.com> 88c2ecf20Sopenharmony_ci * Wenrui Li <wenrui.li@rock-chips.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Bits taken from Synopsys DesignWare Host controller driver and 118c2ecf20Sopenharmony_ci * ARM PCI Host generic driver. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/bitrev.h> 158c2ecf20Sopenharmony_ci#include <linux/clk.h> 168c2ecf20Sopenharmony_ci#include <linux/delay.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 188c2ecf20Sopenharmony_ci#include <linux/init.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 218c2ecf20Sopenharmony_ci#include <linux/irq.h> 228c2ecf20Sopenharmony_ci#include <linux/irqchip/chained_irq.h> 238c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 248c2ecf20Sopenharmony_ci#include <linux/kernel.h> 258c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 268c2ecf20Sopenharmony_ci#include <linux/module.h> 278c2ecf20Sopenharmony_ci#include <linux/of_address.h> 288c2ecf20Sopenharmony_ci#include <linux/of_device.h> 298c2ecf20Sopenharmony_ci#include <linux/of_pci.h> 308c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 318c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 328c2ecf20Sopenharmony_ci#include <linux/pci.h> 338c2ecf20Sopenharmony_ci#include <linux/pci_ids.h> 348c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 358c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 368c2ecf20Sopenharmony_ci#include <linux/reset.h> 378c2ecf20Sopenharmony_ci#include <linux/regmap.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "../pci.h" 408c2ecf20Sopenharmony_ci#include "pcie-rockchip.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void rockchip_pcie_enable_bw_int(struct rockchip_pcie *rockchip) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci u32 status; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); 478c2ecf20Sopenharmony_ci status |= (PCI_EXP_LNKCTL_LBMIE | PCI_EXP_LNKCTL_LABIE); 488c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void rockchip_pcie_clr_bw_int(struct rockchip_pcie *rockchip) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci u32 status; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); 568c2ecf20Sopenharmony_ci status |= (PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_LABS) << 16; 578c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void rockchip_pcie_update_txcredit_mui(struct rockchip_pcie *rockchip) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci u32 val; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* Update Tx credit maximum update interval */ 658c2ecf20Sopenharmony_ci val = rockchip_pcie_read(rockchip, PCIE_CORE_TXCREDIT_CFG1); 668c2ecf20Sopenharmony_ci val &= ~PCIE_CORE_TXCREDIT_CFG1_MUI_MASK; 678c2ecf20Sopenharmony_ci val |= PCIE_CORE_TXCREDIT_CFG1_MUI_ENCODE(24000); /* ns */ 688c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, val, PCIE_CORE_TXCREDIT_CFG1); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int rockchip_pcie_valid_device(struct rockchip_pcie *rockchip, 728c2ecf20Sopenharmony_ci struct pci_bus *bus, int dev) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci /* 758c2ecf20Sopenharmony_ci * Access only one slot on each root port. 768c2ecf20Sopenharmony_ci * Do not read more than one device on the bus directly attached 778c2ecf20Sopenharmony_ci * to RC's downstream side. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ci if (pci_is_root_bus(bus) || pci_is_root_bus(bus->parent)) 808c2ecf20Sopenharmony_ci return dev == 0; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return 1; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic u8 rockchip_pcie_lane_map(struct rockchip_pcie *rockchip) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci u32 val; 888c2ecf20Sopenharmony_ci u8 map; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (rockchip->legacy_phy) 918c2ecf20Sopenharmony_ci return GENMASK(MAX_LANE_NUM - 1, 0); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci val = rockchip_pcie_read(rockchip, PCIE_CORE_LANE_MAP); 948c2ecf20Sopenharmony_ci map = val & PCIE_CORE_LANE_MAP_MASK; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* The link may be using a reverse-indexed mapping. */ 978c2ecf20Sopenharmony_ci if (val & PCIE_CORE_LANE_MAP_REVERSE) 988c2ecf20Sopenharmony_ci map = bitrev8(map) >> 4; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return map; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int rockchip_pcie_rd_own_conf(struct rockchip_pcie *rockchip, 1048c2ecf20Sopenharmony_ci int where, int size, u32 *val) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci void __iomem *addr; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci addr = rockchip->apb_base + PCIE_RC_CONFIG_NORMAL_BASE + where; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (!IS_ALIGNED((uintptr_t)addr, size)) { 1118c2ecf20Sopenharmony_ci *val = 0; 1128c2ecf20Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (size == 4) { 1168c2ecf20Sopenharmony_ci *val = readl(addr); 1178c2ecf20Sopenharmony_ci } else if (size == 2) { 1188c2ecf20Sopenharmony_ci *val = readw(addr); 1198c2ecf20Sopenharmony_ci } else if (size == 1) { 1208c2ecf20Sopenharmony_ci *val = readb(addr); 1218c2ecf20Sopenharmony_ci } else { 1228c2ecf20Sopenharmony_ci *val = 0; 1238c2ecf20Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int rockchip_pcie_wr_own_conf(struct rockchip_pcie *rockchip, 1298c2ecf20Sopenharmony_ci int where, int size, u32 val) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci u32 mask, tmp, offset; 1328c2ecf20Sopenharmony_ci void __iomem *addr; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci offset = where & ~0x3; 1358c2ecf20Sopenharmony_ci addr = rockchip->apb_base + PCIE_RC_CONFIG_NORMAL_BASE + offset; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (size == 4) { 1388c2ecf20Sopenharmony_ci writel(val, addr); 1398c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* 1458c2ecf20Sopenharmony_ci * N.B. This read/modify/write isn't safe in general because it can 1468c2ecf20Sopenharmony_ci * corrupt RW1C bits in adjacent registers. But the hardware 1478c2ecf20Sopenharmony_ci * doesn't support smaller writes. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci tmp = readl(addr) & mask; 1508c2ecf20Sopenharmony_ci tmp |= val << ((where & 0x3) * 8); 1518c2ecf20Sopenharmony_ci writel(tmp, addr); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip, 1578c2ecf20Sopenharmony_ci struct pci_bus *bus, u32 devfn, 1588c2ecf20Sopenharmony_ci int where, int size, u32 *val) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci u32 busdev; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn), 1638c2ecf20Sopenharmony_ci PCI_FUNC(devfn), where); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (!IS_ALIGNED(busdev, size)) { 1668c2ecf20Sopenharmony_ci *val = 0; 1678c2ecf20Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (pci_is_root_bus(bus->parent)) 1718c2ecf20Sopenharmony_ci rockchip_pcie_cfg_configuration_accesses(rockchip, 1728c2ecf20Sopenharmony_ci AXI_WRAPPER_TYPE0_CFG); 1738c2ecf20Sopenharmony_ci else 1748c2ecf20Sopenharmony_ci rockchip_pcie_cfg_configuration_accesses(rockchip, 1758c2ecf20Sopenharmony_ci AXI_WRAPPER_TYPE1_CFG); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (size == 4) { 1788c2ecf20Sopenharmony_ci *val = readl(rockchip->reg_base + busdev); 1798c2ecf20Sopenharmony_ci } else if (size == 2) { 1808c2ecf20Sopenharmony_ci *val = readw(rockchip->reg_base + busdev); 1818c2ecf20Sopenharmony_ci } else if (size == 1) { 1828c2ecf20Sopenharmony_ci *val = readb(rockchip->reg_base + busdev); 1838c2ecf20Sopenharmony_ci } else { 1848c2ecf20Sopenharmony_ci *val = 0; 1858c2ecf20Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip, 1918c2ecf20Sopenharmony_ci struct pci_bus *bus, u32 devfn, 1928c2ecf20Sopenharmony_ci int where, int size, u32 val) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci u32 busdev; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn), 1978c2ecf20Sopenharmony_ci PCI_FUNC(devfn), where); 1988c2ecf20Sopenharmony_ci if (!IS_ALIGNED(busdev, size)) 1998c2ecf20Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (pci_is_root_bus(bus->parent)) 2028c2ecf20Sopenharmony_ci rockchip_pcie_cfg_configuration_accesses(rockchip, 2038c2ecf20Sopenharmony_ci AXI_WRAPPER_TYPE0_CFG); 2048c2ecf20Sopenharmony_ci else 2058c2ecf20Sopenharmony_ci rockchip_pcie_cfg_configuration_accesses(rockchip, 2068c2ecf20Sopenharmony_ci AXI_WRAPPER_TYPE1_CFG); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (size == 4) 2098c2ecf20Sopenharmony_ci writel(val, rockchip->reg_base + busdev); 2108c2ecf20Sopenharmony_ci else if (size == 2) 2118c2ecf20Sopenharmony_ci writew(val, rockchip->reg_base + busdev); 2128c2ecf20Sopenharmony_ci else if (size == 1) 2138c2ecf20Sopenharmony_ci writeb(val, rockchip->reg_base + busdev); 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int rockchip_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, 2218c2ecf20Sopenharmony_ci int size, u32 *val) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct rockchip_pcie *rockchip = bus->sysdata; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (!rockchip_pcie_valid_device(rockchip, bus, PCI_SLOT(devfn))) { 2268c2ecf20Sopenharmony_ci *val = 0xffffffff; 2278c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (pci_is_root_bus(bus)) 2318c2ecf20Sopenharmony_ci return rockchip_pcie_rd_own_conf(rockchip, where, size, val); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return rockchip_pcie_rd_other_conf(rockchip, bus, devfn, where, size, 2348c2ecf20Sopenharmony_ci val); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int rockchip_pcie_wr_conf(struct pci_bus *bus, u32 devfn, 2388c2ecf20Sopenharmony_ci int where, int size, u32 val) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct rockchip_pcie *rockchip = bus->sysdata; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (!rockchip_pcie_valid_device(rockchip, bus, PCI_SLOT(devfn))) 2438c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (pci_is_root_bus(bus)) 2468c2ecf20Sopenharmony_ci return rockchip_pcie_wr_own_conf(rockchip, where, size, val); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return rockchip_pcie_wr_other_conf(rockchip, bus, devfn, where, size, 2498c2ecf20Sopenharmony_ci val); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic struct pci_ops rockchip_pcie_ops = { 2538c2ecf20Sopenharmony_ci .read = rockchip_pcie_rd_conf, 2548c2ecf20Sopenharmony_ci .write = rockchip_pcie_wr_conf, 2558c2ecf20Sopenharmony_ci}; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void rockchip_pcie_set_power_limit(struct rockchip_pcie *rockchip) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci int curr; 2608c2ecf20Sopenharmony_ci u32 status, scale, power; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->vpcie3v3)) 2638c2ecf20Sopenharmony_ci return; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* 2668c2ecf20Sopenharmony_ci * Set RC's captured slot power limit and scale if 2678c2ecf20Sopenharmony_ci * vpcie3v3 available. The default values are both zero 2688c2ecf20Sopenharmony_ci * which means the software should set these two according 2698c2ecf20Sopenharmony_ci * to the actual power supply. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci curr = regulator_get_current_limit(rockchip->vpcie3v3); 2728c2ecf20Sopenharmony_ci if (curr <= 0) 2738c2ecf20Sopenharmony_ci return; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci scale = 3; /* 0.001x */ 2768c2ecf20Sopenharmony_ci curr = curr / 1000; /* convert to mA */ 2778c2ecf20Sopenharmony_ci power = (curr * 3300) / 1000; /* milliwatt */ 2788c2ecf20Sopenharmony_ci while (power > PCIE_RC_CONFIG_DCR_CSPL_LIMIT) { 2798c2ecf20Sopenharmony_ci if (!scale) { 2808c2ecf20Sopenharmony_ci dev_warn(rockchip->dev, "invalid power supply\n"); 2818c2ecf20Sopenharmony_ci return; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci scale--; 2848c2ecf20Sopenharmony_ci power = power / 10; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_DCR); 2888c2ecf20Sopenharmony_ci status |= (power << PCIE_RC_CONFIG_DCR_CSPL_SHIFT) | 2898c2ecf20Sopenharmony_ci (scale << PCIE_RC_CONFIG_DCR_CPLS_SHIFT); 2908c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_DCR); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/** 2948c2ecf20Sopenharmony_ci * rockchip_pcie_host_init_port - Initialize hardware 2958c2ecf20Sopenharmony_ci * @rockchip: PCIe port information 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_cistatic int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 3008c2ecf20Sopenharmony_ci int err, i = MAX_LANE_NUM; 3018c2ecf20Sopenharmony_ci u32 status; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(rockchip->ep_gpio, 0); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci err = rockchip_pcie_init_port(rockchip); 3068c2ecf20Sopenharmony_ci if (err) 3078c2ecf20Sopenharmony_ci return err; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* Fix the transmitted FTS count desired to exit from L0s. */ 3108c2ecf20Sopenharmony_ci status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL_PLC1); 3118c2ecf20Sopenharmony_ci status = (status & ~PCIE_CORE_CTRL_PLC1_FTS_MASK) | 3128c2ecf20Sopenharmony_ci (PCIE_CORE_CTRL_PLC1_FTS_CNT << PCIE_CORE_CTRL_PLC1_FTS_SHIFT); 3138c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, status, PCIE_CORE_CTRL_PLC1); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci rockchip_pcie_set_power_limit(rockchip); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Set RC's clock architecture as common clock */ 3188c2ecf20Sopenharmony_ci status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); 3198c2ecf20Sopenharmony_ci status |= PCI_EXP_LNKSTA_SLC << 16; 3208c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* Set RC's RCB to 128 */ 3238c2ecf20Sopenharmony_ci status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); 3248c2ecf20Sopenharmony_ci status |= PCI_EXP_LNKCTL_RCB; 3258c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* Enable Gen1 training */ 3288c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_ENABLE, 3298c2ecf20Sopenharmony_ci PCIE_CLIENT_CONFIG); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(rockchip->ep_gpio, 1); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* 500ms timeout value should be enough for Gen1/2 training */ 3348c2ecf20Sopenharmony_ci err = readl_poll_timeout(rockchip->apb_base + PCIE_CLIENT_BASIC_STATUS1, 3358c2ecf20Sopenharmony_ci status, PCIE_LINK_UP(status), 20, 3368c2ecf20Sopenharmony_ci 500 * USEC_PER_MSEC); 3378c2ecf20Sopenharmony_ci if (err) { 3388c2ecf20Sopenharmony_ci dev_err(dev, "PCIe link training gen1 timeout!\n"); 3398c2ecf20Sopenharmony_ci goto err_power_off_phy; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (rockchip->link_gen == 2) { 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * Enable retrain for gen2. This should be configured only after 3458c2ecf20Sopenharmony_ci * gen1 finished. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); 3488c2ecf20Sopenharmony_ci status |= PCI_EXP_LNKCTL_RL; 3498c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci err = readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL, 3528c2ecf20Sopenharmony_ci status, PCIE_LINK_IS_GEN2(status), 20, 3538c2ecf20Sopenharmony_ci 500 * USEC_PER_MSEC); 3548c2ecf20Sopenharmony_ci if (err) 3558c2ecf20Sopenharmony_ci dev_dbg(dev, "PCIe link training gen2 timeout, fall back to gen1!\n"); 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Check the final link width from negotiated lane counter from MGMT */ 3598c2ecf20Sopenharmony_ci status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL); 3608c2ecf20Sopenharmony_ci status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >> 3618c2ecf20Sopenharmony_ci PCIE_CORE_PL_CONF_LANE_SHIFT); 3628c2ecf20Sopenharmony_ci dev_dbg(dev, "current link width is x%d\n", status); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* Power off unused lane(s) */ 3658c2ecf20Sopenharmony_ci rockchip->lanes_map = rockchip_pcie_lane_map(rockchip); 3668c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LANE_NUM; i++) { 3678c2ecf20Sopenharmony_ci if (!(rockchip->lanes_map & BIT(i))) { 3688c2ecf20Sopenharmony_ci dev_dbg(dev, "idling lane %d\n", i); 3698c2ecf20Sopenharmony_ci phy_power_off(rockchip->phys[i]); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, ROCKCHIP_VENDOR_ID, 3748c2ecf20Sopenharmony_ci PCIE_CORE_CONFIG_VENDOR); 3758c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, 3768c2ecf20Sopenharmony_ci PCI_CLASS_BRIDGE_PCI << PCIE_RC_CONFIG_SCC_SHIFT, 3778c2ecf20Sopenharmony_ci PCIE_RC_CONFIG_RID_CCR); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Clear THP cap's next cap pointer to remove L1 substate cap */ 3808c2ecf20Sopenharmony_ci status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_THP_CAP); 3818c2ecf20Sopenharmony_ci status &= ~PCIE_RC_CONFIG_THP_CAP_NEXT_MASK; 3828c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_THP_CAP); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* Clear L0s from RC's link cap */ 3858c2ecf20Sopenharmony_ci if (of_property_read_bool(dev->of_node, "aspm-no-l0s")) { 3868c2ecf20Sopenharmony_ci status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LINK_CAP); 3878c2ecf20Sopenharmony_ci status &= ~PCIE_RC_CONFIG_LINK_CAP_L0S; 3888c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LINK_CAP); 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_DCSR); 3928c2ecf20Sopenharmony_ci status &= ~PCIE_RC_CONFIG_DCSR_MPS_MASK; 3938c2ecf20Sopenharmony_ci status |= PCIE_RC_CONFIG_DCSR_MPS_256; 3948c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_DCSR); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_cierr_power_off_phy: 3988c2ecf20Sopenharmony_ci while (i--) 3998c2ecf20Sopenharmony_ci phy_power_off(rockchip->phys[i]); 4008c2ecf20Sopenharmony_ci i = MAX_LANE_NUM; 4018c2ecf20Sopenharmony_ci while (i--) 4028c2ecf20Sopenharmony_ci phy_exit(rockchip->phys[i]); 4038c2ecf20Sopenharmony_ci return err; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic irqreturn_t rockchip_pcie_subsys_irq_handler(int irq, void *arg) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct rockchip_pcie *rockchip = arg; 4098c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 4108c2ecf20Sopenharmony_ci u32 reg; 4118c2ecf20Sopenharmony_ci u32 sub_reg; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci reg = rockchip_pcie_read(rockchip, PCIE_CLIENT_INT_STATUS); 4148c2ecf20Sopenharmony_ci if (reg & PCIE_CLIENT_INT_LOCAL) { 4158c2ecf20Sopenharmony_ci dev_dbg(dev, "local interrupt received\n"); 4168c2ecf20Sopenharmony_ci sub_reg = rockchip_pcie_read(rockchip, PCIE_CORE_INT_STATUS); 4178c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_PRFPE) 4188c2ecf20Sopenharmony_ci dev_dbg(dev, "parity error detected while reading from the PNP receive FIFO RAM\n"); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_CRFPE) 4218c2ecf20Sopenharmony_ci dev_dbg(dev, "parity error detected while reading from the Completion Receive FIFO RAM\n"); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_RRPE) 4248c2ecf20Sopenharmony_ci dev_dbg(dev, "parity error detected while reading from replay buffer RAM\n"); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_PRFO) 4278c2ecf20Sopenharmony_ci dev_dbg(dev, "overflow occurred in the PNP receive FIFO\n"); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_CRFO) 4308c2ecf20Sopenharmony_ci dev_dbg(dev, "overflow occurred in the completion receive FIFO\n"); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_RT) 4338c2ecf20Sopenharmony_ci dev_dbg(dev, "replay timer timed out\n"); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_RTR) 4368c2ecf20Sopenharmony_ci dev_dbg(dev, "replay timer rolled over after 4 transmissions of the same TLP\n"); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_PE) 4398c2ecf20Sopenharmony_ci dev_dbg(dev, "phy error detected on receive side\n"); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_MTR) 4428c2ecf20Sopenharmony_ci dev_dbg(dev, "malformed TLP received from the link\n"); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_UCR) 4458c2ecf20Sopenharmony_ci dev_dbg(dev, "malformed TLP received from the link\n"); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_FCE) 4488c2ecf20Sopenharmony_ci dev_dbg(dev, "an error was observed in the flow control advertisements from the other side\n"); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_CT) 4518c2ecf20Sopenharmony_ci dev_dbg(dev, "a request timed out waiting for completion\n"); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_UTC) 4548c2ecf20Sopenharmony_ci dev_dbg(dev, "unmapped TC error\n"); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (sub_reg & PCIE_CORE_INT_MMVC) 4578c2ecf20Sopenharmony_ci dev_dbg(dev, "MSI mask register changes\n"); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, sub_reg, PCIE_CORE_INT_STATUS); 4608c2ecf20Sopenharmony_ci } else if (reg & PCIE_CLIENT_INT_PHY) { 4618c2ecf20Sopenharmony_ci dev_dbg(dev, "phy link changes\n"); 4628c2ecf20Sopenharmony_ci rockchip_pcie_update_txcredit_mui(rockchip); 4638c2ecf20Sopenharmony_ci rockchip_pcie_clr_bw_int(rockchip); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, reg & PCIE_CLIENT_INT_LOCAL, 4678c2ecf20Sopenharmony_ci PCIE_CLIENT_INT_STATUS); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic irqreturn_t rockchip_pcie_client_irq_handler(int irq, void *arg) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct rockchip_pcie *rockchip = arg; 4758c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 4768c2ecf20Sopenharmony_ci u32 reg; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci reg = rockchip_pcie_read(rockchip, PCIE_CLIENT_INT_STATUS); 4798c2ecf20Sopenharmony_ci if (reg & PCIE_CLIENT_INT_LEGACY_DONE) 4808c2ecf20Sopenharmony_ci dev_dbg(dev, "legacy done interrupt received\n"); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (reg & PCIE_CLIENT_INT_MSG) 4838c2ecf20Sopenharmony_ci dev_dbg(dev, "message done interrupt received\n"); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (reg & PCIE_CLIENT_INT_HOT_RST) 4868c2ecf20Sopenharmony_ci dev_dbg(dev, "hot reset interrupt received\n"); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (reg & PCIE_CLIENT_INT_DPA) 4898c2ecf20Sopenharmony_ci dev_dbg(dev, "dpa interrupt received\n"); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (reg & PCIE_CLIENT_INT_FATAL_ERR) 4928c2ecf20Sopenharmony_ci dev_dbg(dev, "fatal error interrupt received\n"); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (reg & PCIE_CLIENT_INT_NFATAL_ERR) 4958c2ecf20Sopenharmony_ci dev_dbg(dev, "no fatal error interrupt received\n"); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (reg & PCIE_CLIENT_INT_CORR_ERR) 4988c2ecf20Sopenharmony_ci dev_dbg(dev, "correctable error interrupt received\n"); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (reg & PCIE_CLIENT_INT_PHY) 5018c2ecf20Sopenharmony_ci dev_dbg(dev, "phy interrupt received\n"); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, reg & (PCIE_CLIENT_INT_LEGACY_DONE | 5048c2ecf20Sopenharmony_ci PCIE_CLIENT_INT_MSG | PCIE_CLIENT_INT_HOT_RST | 5058c2ecf20Sopenharmony_ci PCIE_CLIENT_INT_DPA | PCIE_CLIENT_INT_FATAL_ERR | 5068c2ecf20Sopenharmony_ci PCIE_CLIENT_INT_NFATAL_ERR | 5078c2ecf20Sopenharmony_ci PCIE_CLIENT_INT_CORR_ERR | 5088c2ecf20Sopenharmony_ci PCIE_CLIENT_INT_PHY), 5098c2ecf20Sopenharmony_ci PCIE_CLIENT_INT_STATUS); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic void rockchip_pcie_legacy_int_handler(struct irq_desc *desc) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 5178c2ecf20Sopenharmony_ci struct rockchip_pcie *rockchip = irq_desc_get_handler_data(desc); 5188c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 5198c2ecf20Sopenharmony_ci u32 reg; 5208c2ecf20Sopenharmony_ci u32 hwirq; 5218c2ecf20Sopenharmony_ci u32 virq; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci chained_irq_enter(chip, desc); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci reg = rockchip_pcie_read(rockchip, PCIE_CLIENT_INT_STATUS); 5268c2ecf20Sopenharmony_ci reg = (reg & PCIE_CLIENT_INTR_MASK) >> PCIE_CLIENT_INTR_SHIFT; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci while (reg) { 5298c2ecf20Sopenharmony_ci hwirq = ffs(reg) - 1; 5308c2ecf20Sopenharmony_ci reg &= ~BIT(hwirq); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci virq = irq_find_mapping(rockchip->irq_domain, hwirq); 5338c2ecf20Sopenharmony_ci if (virq) 5348c2ecf20Sopenharmony_ci generic_handle_irq(virq); 5358c2ecf20Sopenharmony_ci else 5368c2ecf20Sopenharmony_ci dev_err(dev, "unexpected IRQ, INT%d\n", hwirq); 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci chained_irq_exit(chip, desc); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci int irq, err; 5458c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 5468c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(pdev, "sys"); 5498c2ecf20Sopenharmony_ci if (irq < 0) 5508c2ecf20Sopenharmony_ci return irq; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler, 5538c2ecf20Sopenharmony_ci IRQF_SHARED, "pcie-sys", rockchip); 5548c2ecf20Sopenharmony_ci if (err) { 5558c2ecf20Sopenharmony_ci dev_err(dev, "failed to request PCIe subsystem IRQ\n"); 5568c2ecf20Sopenharmony_ci return err; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(pdev, "legacy"); 5608c2ecf20Sopenharmony_ci if (irq < 0) 5618c2ecf20Sopenharmony_ci return irq; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(irq, 5648c2ecf20Sopenharmony_ci rockchip_pcie_legacy_int_handler, 5658c2ecf20Sopenharmony_ci rockchip); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(pdev, "client"); 5688c2ecf20Sopenharmony_ci if (irq < 0) 5698c2ecf20Sopenharmony_ci return irq; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler, 5728c2ecf20Sopenharmony_ci IRQF_SHARED, "pcie-client", rockchip); 5738c2ecf20Sopenharmony_ci if (err) { 5748c2ecf20Sopenharmony_ci dev_err(dev, "failed to request PCIe client IRQ\n"); 5758c2ecf20Sopenharmony_ci return err; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return 0; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci/** 5828c2ecf20Sopenharmony_ci * rockchip_pcie_parse_host_dt - Parse Device Tree 5838c2ecf20Sopenharmony_ci * @rockchip: PCIe port information 5848c2ecf20Sopenharmony_ci * 5858c2ecf20Sopenharmony_ci * Return: '0' on success and error value on failure 5868c2ecf20Sopenharmony_ci */ 5878c2ecf20Sopenharmony_cistatic int rockchip_pcie_parse_host_dt(struct rockchip_pcie *rockchip) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 5908c2ecf20Sopenharmony_ci int err; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci err = rockchip_pcie_parse_dt(rockchip); 5938c2ecf20Sopenharmony_ci if (err) 5948c2ecf20Sopenharmony_ci return err; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci rockchip->vpcie12v = devm_regulator_get_optional(dev, "vpcie12v"); 5978c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->vpcie12v)) { 5988c2ecf20Sopenharmony_ci if (PTR_ERR(rockchip->vpcie12v) != -ENODEV) 5998c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->vpcie12v); 6008c2ecf20Sopenharmony_ci dev_info(dev, "no vpcie12v regulator found\n"); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci rockchip->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3"); 6048c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->vpcie3v3)) { 6058c2ecf20Sopenharmony_ci if (PTR_ERR(rockchip->vpcie3v3) != -ENODEV) 6068c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->vpcie3v3); 6078c2ecf20Sopenharmony_ci dev_info(dev, "no vpcie3v3 regulator found\n"); 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci rockchip->vpcie1v8 = devm_regulator_get(dev, "vpcie1v8"); 6118c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->vpcie1v8)) 6128c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->vpcie1v8); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci rockchip->vpcie0v9 = devm_regulator_get(dev, "vpcie0v9"); 6158c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->vpcie0v9)) 6168c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->vpcie0v9); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci return 0; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic int rockchip_pcie_set_vpcie(struct rockchip_pcie *rockchip) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 6248c2ecf20Sopenharmony_ci int err; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (!IS_ERR(rockchip->vpcie12v)) { 6278c2ecf20Sopenharmony_ci err = regulator_enable(rockchip->vpcie12v); 6288c2ecf20Sopenharmony_ci if (err) { 6298c2ecf20Sopenharmony_ci dev_err(dev, "fail to enable vpcie12v regulator\n"); 6308c2ecf20Sopenharmony_ci goto err_out; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (!IS_ERR(rockchip->vpcie3v3)) { 6358c2ecf20Sopenharmony_ci err = regulator_enable(rockchip->vpcie3v3); 6368c2ecf20Sopenharmony_ci if (err) { 6378c2ecf20Sopenharmony_ci dev_err(dev, "fail to enable vpcie3v3 regulator\n"); 6388c2ecf20Sopenharmony_ci goto err_disable_12v; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci err = regulator_enable(rockchip->vpcie1v8); 6438c2ecf20Sopenharmony_ci if (err) { 6448c2ecf20Sopenharmony_ci dev_err(dev, "fail to enable vpcie1v8 regulator\n"); 6458c2ecf20Sopenharmony_ci goto err_disable_3v3; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci err = regulator_enable(rockchip->vpcie0v9); 6498c2ecf20Sopenharmony_ci if (err) { 6508c2ecf20Sopenharmony_ci dev_err(dev, "fail to enable vpcie0v9 regulator\n"); 6518c2ecf20Sopenharmony_ci goto err_disable_1v8; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci return 0; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cierr_disable_1v8: 6578c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie1v8); 6588c2ecf20Sopenharmony_cierr_disable_3v3: 6598c2ecf20Sopenharmony_ci if (!IS_ERR(rockchip->vpcie3v3)) 6608c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie3v3); 6618c2ecf20Sopenharmony_cierr_disable_12v: 6628c2ecf20Sopenharmony_ci if (!IS_ERR(rockchip->vpcie12v)) 6638c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie12v); 6648c2ecf20Sopenharmony_cierr_out: 6658c2ecf20Sopenharmony_ci return err; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic void rockchip_pcie_enable_interrupts(struct rockchip_pcie *rockchip) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, (PCIE_CLIENT_INT_CLI << 16) & 6718c2ecf20Sopenharmony_ci (~PCIE_CLIENT_INT_CLI), PCIE_CLIENT_INT_MASK); 6728c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, (u32)(~PCIE_CORE_INT), 6738c2ecf20Sopenharmony_ci PCIE_CORE_INT_MASK); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci rockchip_pcie_enable_bw_int(rockchip); 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic int rockchip_pcie_intx_map(struct irq_domain *domain, unsigned int irq, 6798c2ecf20Sopenharmony_ci irq_hw_number_t hwirq) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); 6828c2ecf20Sopenharmony_ci irq_set_chip_data(irq, domain->host_data); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci return 0; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic const struct irq_domain_ops intx_domain_ops = { 6888c2ecf20Sopenharmony_ci .map = rockchip_pcie_intx_map, 6898c2ecf20Sopenharmony_ci}; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 6948c2ecf20Sopenharmony_ci struct device_node *intc = of_get_next_child(dev->of_node, NULL); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (!intc) { 6978c2ecf20Sopenharmony_ci dev_err(dev, "missing child interrupt-controller node\n"); 6988c2ecf20Sopenharmony_ci return -EINVAL; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX, 7028c2ecf20Sopenharmony_ci &intx_domain_ops, rockchip); 7038c2ecf20Sopenharmony_ci of_node_put(intc); 7048c2ecf20Sopenharmony_ci if (!rockchip->irq_domain) { 7058c2ecf20Sopenharmony_ci dev_err(dev, "failed to get a INTx IRQ domain\n"); 7068c2ecf20Sopenharmony_ci return -EINVAL; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic int rockchip_pcie_prog_ob_atu(struct rockchip_pcie *rockchip, 7138c2ecf20Sopenharmony_ci int region_no, int type, u8 num_pass_bits, 7148c2ecf20Sopenharmony_ci u32 lower_addr, u32 upper_addr) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci u32 ob_addr_0; 7178c2ecf20Sopenharmony_ci u32 ob_addr_1; 7188c2ecf20Sopenharmony_ci u32 ob_desc_0; 7198c2ecf20Sopenharmony_ci u32 aw_offset; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (region_no >= MAX_AXI_WRAPPER_REGION_NUM) 7228c2ecf20Sopenharmony_ci return -EINVAL; 7238c2ecf20Sopenharmony_ci if (num_pass_bits + 1 < 8) 7248c2ecf20Sopenharmony_ci return -EINVAL; 7258c2ecf20Sopenharmony_ci if (num_pass_bits > 63) 7268c2ecf20Sopenharmony_ci return -EINVAL; 7278c2ecf20Sopenharmony_ci if (region_no == 0) { 7288c2ecf20Sopenharmony_ci if (AXI_REGION_0_SIZE < (2ULL << num_pass_bits)) 7298c2ecf20Sopenharmony_ci return -EINVAL; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci if (region_no != 0) { 7328c2ecf20Sopenharmony_ci if (AXI_REGION_SIZE < (2ULL << num_pass_bits)) 7338c2ecf20Sopenharmony_ci return -EINVAL; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci aw_offset = (region_no << OB_REG_SIZE_SHIFT); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci ob_addr_0 = num_pass_bits & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS; 7398c2ecf20Sopenharmony_ci ob_addr_0 |= lower_addr & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR; 7408c2ecf20Sopenharmony_ci ob_addr_1 = upper_addr; 7418c2ecf20Sopenharmony_ci ob_desc_0 = (1 << 23 | type); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, ob_addr_0, 7448c2ecf20Sopenharmony_ci PCIE_CORE_OB_REGION_ADDR0 + aw_offset); 7458c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, ob_addr_1, 7468c2ecf20Sopenharmony_ci PCIE_CORE_OB_REGION_ADDR1 + aw_offset); 7478c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, ob_desc_0, 7488c2ecf20Sopenharmony_ci PCIE_CORE_OB_REGION_DESC0 + aw_offset); 7498c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, 0, 7508c2ecf20Sopenharmony_ci PCIE_CORE_OB_REGION_DESC1 + aw_offset); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci return 0; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic int rockchip_pcie_prog_ib_atu(struct rockchip_pcie *rockchip, 7568c2ecf20Sopenharmony_ci int region_no, u8 num_pass_bits, 7578c2ecf20Sopenharmony_ci u32 lower_addr, u32 upper_addr) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci u32 ib_addr_0; 7608c2ecf20Sopenharmony_ci u32 ib_addr_1; 7618c2ecf20Sopenharmony_ci u32 aw_offset; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (region_no > MAX_AXI_IB_ROOTPORT_REGION_NUM) 7648c2ecf20Sopenharmony_ci return -EINVAL; 7658c2ecf20Sopenharmony_ci if (num_pass_bits + 1 < MIN_AXI_ADDR_BITS_PASSED) 7668c2ecf20Sopenharmony_ci return -EINVAL; 7678c2ecf20Sopenharmony_ci if (num_pass_bits > 63) 7688c2ecf20Sopenharmony_ci return -EINVAL; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci aw_offset = (region_no << IB_ROOT_PORT_REG_SIZE_SHIFT); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci ib_addr_0 = num_pass_bits & PCIE_CORE_IB_REGION_ADDR0_NUM_BITS; 7738c2ecf20Sopenharmony_ci ib_addr_0 |= (lower_addr << 8) & PCIE_CORE_IB_REGION_ADDR0_LO_ADDR; 7748c2ecf20Sopenharmony_ci ib_addr_1 = upper_addr; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, ib_addr_0, PCIE_RP_IB_ADDR0 + aw_offset); 7778c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, ib_addr_1, PCIE_RP_IB_ADDR1 + aw_offset); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return 0; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic int rockchip_pcie_cfg_atu(struct rockchip_pcie *rockchip) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 7858c2ecf20Sopenharmony_ci struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rockchip); 7868c2ecf20Sopenharmony_ci struct resource_entry *entry; 7878c2ecf20Sopenharmony_ci u64 pci_addr, size; 7888c2ecf20Sopenharmony_ci int offset; 7898c2ecf20Sopenharmony_ci int err; 7908c2ecf20Sopenharmony_ci int reg_no; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci rockchip_pcie_cfg_configuration_accesses(rockchip, 7938c2ecf20Sopenharmony_ci AXI_WRAPPER_TYPE0_CFG); 7948c2ecf20Sopenharmony_ci entry = resource_list_first_type(&bridge->windows, IORESOURCE_MEM); 7958c2ecf20Sopenharmony_ci if (!entry) 7968c2ecf20Sopenharmony_ci return -ENODEV; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci size = resource_size(entry->res); 7998c2ecf20Sopenharmony_ci pci_addr = entry->res->start - entry->offset; 8008c2ecf20Sopenharmony_ci rockchip->msg_bus_addr = pci_addr; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci for (reg_no = 0; reg_no < (size >> 20); reg_no++) { 8038c2ecf20Sopenharmony_ci err = rockchip_pcie_prog_ob_atu(rockchip, reg_no + 1, 8048c2ecf20Sopenharmony_ci AXI_WRAPPER_MEM_WRITE, 8058c2ecf20Sopenharmony_ci 20 - 1, 8068c2ecf20Sopenharmony_ci pci_addr + (reg_no << 20), 8078c2ecf20Sopenharmony_ci 0); 8088c2ecf20Sopenharmony_ci if (err) { 8098c2ecf20Sopenharmony_ci dev_err(dev, "program RC mem outbound ATU failed\n"); 8108c2ecf20Sopenharmony_ci return err; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci err = rockchip_pcie_prog_ib_atu(rockchip, 2, 32 - 1, 0x0, 0); 8158c2ecf20Sopenharmony_ci if (err) { 8168c2ecf20Sopenharmony_ci dev_err(dev, "program RC mem inbound ATU failed\n"); 8178c2ecf20Sopenharmony_ci return err; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci entry = resource_list_first_type(&bridge->windows, IORESOURCE_IO); 8218c2ecf20Sopenharmony_ci if (!entry) 8228c2ecf20Sopenharmony_ci return -ENODEV; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* store the register number offset to program RC io outbound ATU */ 8258c2ecf20Sopenharmony_ci offset = size >> 20; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci size = resource_size(entry->res); 8288c2ecf20Sopenharmony_ci pci_addr = entry->res->start - entry->offset; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci for (reg_no = 0; reg_no < (size >> 20); reg_no++) { 8318c2ecf20Sopenharmony_ci err = rockchip_pcie_prog_ob_atu(rockchip, 8328c2ecf20Sopenharmony_ci reg_no + 1 + offset, 8338c2ecf20Sopenharmony_ci AXI_WRAPPER_IO_WRITE, 8348c2ecf20Sopenharmony_ci 20 - 1, 8358c2ecf20Sopenharmony_ci pci_addr + (reg_no << 20), 8368c2ecf20Sopenharmony_ci 0); 8378c2ecf20Sopenharmony_ci if (err) { 8388c2ecf20Sopenharmony_ci dev_err(dev, "program RC io outbound ATU failed\n"); 8398c2ecf20Sopenharmony_ci return err; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci /* assign message regions */ 8448c2ecf20Sopenharmony_ci rockchip_pcie_prog_ob_atu(rockchip, reg_no + 1 + offset, 8458c2ecf20Sopenharmony_ci AXI_WRAPPER_NOR_MSG, 8468c2ecf20Sopenharmony_ci 20 - 1, 0, 0); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci rockchip->msg_bus_addr += ((reg_no + offset) << 20); 8498c2ecf20Sopenharmony_ci return err; 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cistatic int rockchip_pcie_wait_l2(struct rockchip_pcie *rockchip) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci u32 value; 8558c2ecf20Sopenharmony_ci int err; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* send PME_TURN_OFF message */ 8588c2ecf20Sopenharmony_ci writel(0x0, rockchip->msg_region + PCIE_RC_SEND_PME_OFF); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* read LTSSM and wait for falling into L2 link state */ 8618c2ecf20Sopenharmony_ci err = readl_poll_timeout(rockchip->apb_base + PCIE_CLIENT_DEBUG_OUT_0, 8628c2ecf20Sopenharmony_ci value, PCIE_LINK_IS_L2(value), 20, 8638c2ecf20Sopenharmony_ci jiffies_to_usecs(5 * HZ)); 8648c2ecf20Sopenharmony_ci if (err) { 8658c2ecf20Sopenharmony_ci dev_err(rockchip->dev, "PCIe link enter L2 timeout!\n"); 8668c2ecf20Sopenharmony_ci return err; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci return 0; 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci struct rockchip_pcie *rockchip = dev_get_drvdata(dev); 8758c2ecf20Sopenharmony_ci int ret; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* disable core and cli int since we don't need to ack PME_ACK */ 8788c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, (PCIE_CLIENT_INT_CLI << 16) | 8798c2ecf20Sopenharmony_ci PCIE_CLIENT_INT_CLI, PCIE_CLIENT_INT_MASK); 8808c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, (u32)PCIE_CORE_INT, PCIE_CORE_INT_MASK); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci ret = rockchip_pcie_wait_l2(rockchip); 8838c2ecf20Sopenharmony_ci if (ret) { 8848c2ecf20Sopenharmony_ci rockchip_pcie_enable_interrupts(rockchip); 8858c2ecf20Sopenharmony_ci return ret; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci rockchip_pcie_deinit_phys(rockchip); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci rockchip_pcie_disable_clocks(rockchip); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie0v9); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return ret; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int __maybe_unused rockchip_pcie_resume_noirq(struct device *dev) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci struct rockchip_pcie *rockchip = dev_get_drvdata(dev); 9008c2ecf20Sopenharmony_ci int err; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci err = regulator_enable(rockchip->vpcie0v9); 9038c2ecf20Sopenharmony_ci if (err) { 9048c2ecf20Sopenharmony_ci dev_err(dev, "fail to enable vpcie0v9 regulator\n"); 9058c2ecf20Sopenharmony_ci return err; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci err = rockchip_pcie_enable_clocks(rockchip); 9098c2ecf20Sopenharmony_ci if (err) 9108c2ecf20Sopenharmony_ci goto err_disable_0v9; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci err = rockchip_pcie_host_init_port(rockchip); 9138c2ecf20Sopenharmony_ci if (err) 9148c2ecf20Sopenharmony_ci goto err_pcie_resume; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci err = rockchip_pcie_cfg_atu(rockchip); 9178c2ecf20Sopenharmony_ci if (err) 9188c2ecf20Sopenharmony_ci goto err_err_deinit_port; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* Need this to enter L1 again */ 9218c2ecf20Sopenharmony_ci rockchip_pcie_update_txcredit_mui(rockchip); 9228c2ecf20Sopenharmony_ci rockchip_pcie_enable_interrupts(rockchip); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci return 0; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cierr_err_deinit_port: 9278c2ecf20Sopenharmony_ci rockchip_pcie_deinit_phys(rockchip); 9288c2ecf20Sopenharmony_cierr_pcie_resume: 9298c2ecf20Sopenharmony_ci rockchip_pcie_disable_clocks(rockchip); 9308c2ecf20Sopenharmony_cierr_disable_0v9: 9318c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie0v9); 9328c2ecf20Sopenharmony_ci return err; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic int rockchip_pcie_probe(struct platform_device *pdev) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci struct rockchip_pcie *rockchip; 9388c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 9398c2ecf20Sopenharmony_ci struct pci_host_bridge *bridge; 9408c2ecf20Sopenharmony_ci int err; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (!dev->of_node) 9438c2ecf20Sopenharmony_ci return -ENODEV; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rockchip)); 9468c2ecf20Sopenharmony_ci if (!bridge) 9478c2ecf20Sopenharmony_ci return -ENOMEM; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci rockchip = pci_host_bridge_priv(bridge); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, rockchip); 9528c2ecf20Sopenharmony_ci rockchip->dev = dev; 9538c2ecf20Sopenharmony_ci rockchip->is_rc = true; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci err = rockchip_pcie_parse_host_dt(rockchip); 9568c2ecf20Sopenharmony_ci if (err) 9578c2ecf20Sopenharmony_ci return err; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci err = rockchip_pcie_enable_clocks(rockchip); 9608c2ecf20Sopenharmony_ci if (err) 9618c2ecf20Sopenharmony_ci return err; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci err = rockchip_pcie_set_vpcie(rockchip); 9648c2ecf20Sopenharmony_ci if (err) { 9658c2ecf20Sopenharmony_ci dev_err(dev, "failed to set vpcie regulator\n"); 9668c2ecf20Sopenharmony_ci goto err_set_vpcie; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci err = rockchip_pcie_host_init_port(rockchip); 9708c2ecf20Sopenharmony_ci if (err) 9718c2ecf20Sopenharmony_ci goto err_vpcie; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci err = rockchip_pcie_init_irq_domain(rockchip); 9748c2ecf20Sopenharmony_ci if (err < 0) 9758c2ecf20Sopenharmony_ci goto err_deinit_port; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci err = rockchip_pcie_cfg_atu(rockchip); 9788c2ecf20Sopenharmony_ci if (err) 9798c2ecf20Sopenharmony_ci goto err_remove_irq_domain; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci rockchip->msg_region = devm_ioremap(dev, rockchip->msg_bus_addr, SZ_1M); 9828c2ecf20Sopenharmony_ci if (!rockchip->msg_region) { 9838c2ecf20Sopenharmony_ci err = -ENOMEM; 9848c2ecf20Sopenharmony_ci goto err_remove_irq_domain; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci bridge->sysdata = rockchip; 9888c2ecf20Sopenharmony_ci bridge->ops = &rockchip_pcie_ops; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci err = rockchip_pcie_setup_irq(rockchip); 9918c2ecf20Sopenharmony_ci if (err) 9928c2ecf20Sopenharmony_ci goto err_remove_irq_domain; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci rockchip_pcie_enable_interrupts(rockchip); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci err = pci_host_probe(bridge); 9978c2ecf20Sopenharmony_ci if (err < 0) 9988c2ecf20Sopenharmony_ci goto err_remove_irq_domain; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci return 0; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cierr_remove_irq_domain: 10038c2ecf20Sopenharmony_ci irq_domain_remove(rockchip->irq_domain); 10048c2ecf20Sopenharmony_cierr_deinit_port: 10058c2ecf20Sopenharmony_ci rockchip_pcie_deinit_phys(rockchip); 10068c2ecf20Sopenharmony_cierr_vpcie: 10078c2ecf20Sopenharmony_ci if (!IS_ERR(rockchip->vpcie12v)) 10088c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie12v); 10098c2ecf20Sopenharmony_ci if (!IS_ERR(rockchip->vpcie3v3)) 10108c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie3v3); 10118c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie1v8); 10128c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie0v9); 10138c2ecf20Sopenharmony_cierr_set_vpcie: 10148c2ecf20Sopenharmony_ci rockchip_pcie_disable_clocks(rockchip); 10158c2ecf20Sopenharmony_ci return err; 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic int rockchip_pcie_remove(struct platform_device *pdev) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 10218c2ecf20Sopenharmony_ci struct rockchip_pcie *rockchip = dev_get_drvdata(dev); 10228c2ecf20Sopenharmony_ci struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rockchip); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci pci_stop_root_bus(bridge->bus); 10258c2ecf20Sopenharmony_ci pci_remove_root_bus(bridge->bus); 10268c2ecf20Sopenharmony_ci irq_domain_remove(rockchip->irq_domain); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci rockchip_pcie_deinit_phys(rockchip); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci rockchip_pcie_disable_clocks(rockchip); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (!IS_ERR(rockchip->vpcie12v)) 10338c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie12v); 10348c2ecf20Sopenharmony_ci if (!IS_ERR(rockchip->vpcie3v3)) 10358c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie3v3); 10368c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie1v8); 10378c2ecf20Sopenharmony_ci regulator_disable(rockchip->vpcie0v9); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci return 0; 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cistatic const struct dev_pm_ops rockchip_pcie_pm_ops = { 10438c2ecf20Sopenharmony_ci SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_pcie_suspend_noirq, 10448c2ecf20Sopenharmony_ci rockchip_pcie_resume_noirq) 10458c2ecf20Sopenharmony_ci}; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic const struct of_device_id rockchip_pcie_of_match[] = { 10488c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3399-pcie", }, 10498c2ecf20Sopenharmony_ci {} 10508c2ecf20Sopenharmony_ci}; 10518c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_pcie_of_match); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic struct platform_driver rockchip_pcie_driver = { 10548c2ecf20Sopenharmony_ci .driver = { 10558c2ecf20Sopenharmony_ci .name = "rockchip-pcie", 10568c2ecf20Sopenharmony_ci .of_match_table = rockchip_pcie_of_match, 10578c2ecf20Sopenharmony_ci .pm = &rockchip_pcie_pm_ops, 10588c2ecf20Sopenharmony_ci }, 10598c2ecf20Sopenharmony_ci .probe = rockchip_pcie_probe, 10608c2ecf20Sopenharmony_ci .remove = rockchip_pcie_remove, 10618c2ecf20Sopenharmony_ci}; 10628c2ecf20Sopenharmony_cimodule_platform_driver(rockchip_pcie_driver); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ciMODULE_AUTHOR("Rockchip Inc"); 10658c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Rockchip AXI PCIe driver"); 10668c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1067