18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PCIe host controller driver for Intel Gateway SoCs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2019 Intel Corporation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 118c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 128c2ecf20Sopenharmony_ci#include <linux/pci_regs.h> 138c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/reset.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "../../pci.h" 188c2ecf20Sopenharmony_ci#include "pcie-designware.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define PORT_AFR_N_FTS_GEN12_DFT (SZ_128 - 1) 218c2ecf20Sopenharmony_ci#define PORT_AFR_N_FTS_GEN3 180 228c2ecf20Sopenharmony_ci#define PORT_AFR_N_FTS_GEN4 196 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* PCIe Application logic Registers */ 258c2ecf20Sopenharmony_ci#define PCIE_APP_CCR 0x10 268c2ecf20Sopenharmony_ci#define PCIE_APP_CCR_LTSSM_ENABLE BIT(0) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define PCIE_APP_MSG_CR 0x30 298c2ecf20Sopenharmony_ci#define PCIE_APP_MSG_XMT_PM_TURNOFF BIT(0) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define PCIE_APP_PMC 0x44 328c2ecf20Sopenharmony_ci#define PCIE_APP_PMC_IN_L2 BIT(20) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define PCIE_APP_IRNEN 0xF4 358c2ecf20Sopenharmony_ci#define PCIE_APP_IRNCR 0xF8 368c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_AER_REPORT BIT(0) 378c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_PME BIT(2) 388c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_RX_VDM_MSG BIT(4) 398c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_PM_TO_ACK BIT(9) 408c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_LINK_AUTO_BW_STAT BIT(11) 418c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_BW_MGT BIT(12) 428c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_INTA BIT(13) 438c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_INTB BIT(14) 448c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_INTC BIT(15) 458c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_INTD BIT(16) 468c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_MSG_LTR BIT(18) 478c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_SYS_ERR_RC BIT(29) 488c2ecf20Sopenharmony_ci#define PCIE_APP_INTX_OFST 12 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define PCIE_APP_IRN_INT \ 518c2ecf20Sopenharmony_ci (PCIE_APP_IRN_AER_REPORT | PCIE_APP_IRN_PME | \ 528c2ecf20Sopenharmony_ci PCIE_APP_IRN_RX_VDM_MSG | PCIE_APP_IRN_SYS_ERR_RC | \ 538c2ecf20Sopenharmony_ci PCIE_APP_IRN_PM_TO_ACK | PCIE_APP_IRN_MSG_LTR | \ 548c2ecf20Sopenharmony_ci PCIE_APP_IRN_BW_MGT | PCIE_APP_IRN_LINK_AUTO_BW_STAT | \ 558c2ecf20Sopenharmony_ci PCIE_APP_IRN_INTA | PCIE_APP_IRN_INTB | \ 568c2ecf20Sopenharmony_ci PCIE_APP_IRN_INTC | PCIE_APP_IRN_INTD) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define BUS_IATU_OFFSET SZ_256M 598c2ecf20Sopenharmony_ci#define RESET_INTERVAL_MS 100 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistruct intel_pcie_soc { 628c2ecf20Sopenharmony_ci unsigned int pcie_ver; 638c2ecf20Sopenharmony_ci unsigned int pcie_atu_offset; 648c2ecf20Sopenharmony_ci u32 num_viewport; 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistruct intel_pcie_port { 688c2ecf20Sopenharmony_ci struct dw_pcie pci; 698c2ecf20Sopenharmony_ci void __iomem *app_base; 708c2ecf20Sopenharmony_ci struct gpio_desc *reset_gpio; 718c2ecf20Sopenharmony_ci u32 rst_intrvl; 728c2ecf20Sopenharmony_ci struct clk *core_clk; 738c2ecf20Sopenharmony_ci struct reset_control *core_rst; 748c2ecf20Sopenharmony_ci struct phy *phy; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void pcie_update_bits(void __iomem *base, u32 ofs, u32 mask, u32 val) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci u32 old; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci old = readl(base + ofs); 828c2ecf20Sopenharmony_ci val = (old & ~mask) | (val & mask); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (val != old) 858c2ecf20Sopenharmony_ci writel(val, base + ofs); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic inline u32 pcie_app_rd(struct intel_pcie_port *lpp, u32 ofs) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci return readl(lpp->app_base + ofs); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic inline void pcie_app_wr(struct intel_pcie_port *lpp, u32 ofs, u32 val) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci writel(val, lpp->app_base + ofs); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic void pcie_app_wr_mask(struct intel_pcie_port *lpp, u32 ofs, 998c2ecf20Sopenharmony_ci u32 mask, u32 val) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci pcie_update_bits(lpp->app_base, ofs, mask, val); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic inline u32 pcie_rc_cfg_rd(struct intel_pcie_port *lpp, u32 ofs) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci return dw_pcie_readl_dbi(&lpp->pci, ofs); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic inline void pcie_rc_cfg_wr(struct intel_pcie_port *lpp, u32 ofs, u32 val) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci dw_pcie_writel_dbi(&lpp->pci, ofs, val); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void pcie_rc_cfg_wr_mask(struct intel_pcie_port *lpp, u32 ofs, 1158c2ecf20Sopenharmony_ci u32 mask, u32 val) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci pcie_update_bits(lpp->pci.dbi_base, ofs, mask, val); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void intel_pcie_ltssm_enable(struct intel_pcie_port *lpp) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci pcie_app_wr_mask(lpp, PCIE_APP_CCR, PCIE_APP_CCR_LTSSM_ENABLE, 1238c2ecf20Sopenharmony_ci PCIE_APP_CCR_LTSSM_ENABLE); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void intel_pcie_ltssm_disable(struct intel_pcie_port *lpp) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci pcie_app_wr_mask(lpp, PCIE_APP_CCR, PCIE_APP_CCR_LTSSM_ENABLE, 0); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void intel_pcie_link_setup(struct intel_pcie_port *lpp) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci u32 val; 1348c2ecf20Sopenharmony_ci u8 offset = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCTL); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci val &= ~(PCI_EXP_LNKCTL_LD | PCI_EXP_LNKCTL_ASPMC); 1398c2ecf20Sopenharmony_ci pcie_rc_cfg_wr(lpp, offset + PCI_EXP_LNKCTL, val); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void intel_pcie_init_n_fts(struct dw_pcie *pci) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci switch (pci->link_gen) { 1458c2ecf20Sopenharmony_ci case 3: 1468c2ecf20Sopenharmony_ci pci->n_fts[1] = PORT_AFR_N_FTS_GEN3; 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci case 4: 1498c2ecf20Sopenharmony_ci pci->n_fts[1] = PORT_AFR_N_FTS_GEN4; 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci default: 1528c2ecf20Sopenharmony_ci pci->n_fts[1] = PORT_AFR_N_FTS_GEN12_DFT; 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci pci->n_fts[0] = PORT_AFR_N_FTS_GEN12_DFT; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void intel_pcie_rc_setup(struct intel_pcie_port *lpp) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci intel_pcie_ltssm_disable(lpp); 1618c2ecf20Sopenharmony_ci intel_pcie_link_setup(lpp); 1628c2ecf20Sopenharmony_ci intel_pcie_init_n_fts(&lpp->pci); 1638c2ecf20Sopenharmony_ci dw_pcie_setup_rc(&lpp->pci.pp); 1648c2ecf20Sopenharmony_ci dw_pcie_upconfig_setup(&lpp->pci); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct device *dev = lpp->pci.dev; 1708c2ecf20Sopenharmony_ci int ret; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci lpp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 1738c2ecf20Sopenharmony_ci if (IS_ERR(lpp->reset_gpio)) { 1748c2ecf20Sopenharmony_ci ret = PTR_ERR(lpp->reset_gpio); 1758c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 1768c2ecf20Sopenharmony_ci dev_err(dev, "Failed to request PCIe GPIO: %d\n", ret); 1778c2ecf20Sopenharmony_ci return ret; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* Make initial reset last for 100us */ 1818c2ecf20Sopenharmony_ci usleep_range(100, 200); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic void intel_pcie_core_rst_assert(struct intel_pcie_port *lpp) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci reset_control_assert(lpp->core_rst); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic void intel_pcie_core_rst_deassert(struct intel_pcie_port *lpp) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * One micro-second delay to make sure the reset pulse 1958c2ecf20Sopenharmony_ci * wide enough so that core reset is clean. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci udelay(1); 1988c2ecf20Sopenharmony_ci reset_control_deassert(lpp->core_rst); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* 2018c2ecf20Sopenharmony_ci * Some SoC core reset also reset PHY, more delay needed 2028c2ecf20Sopenharmony_ci * to make sure the reset process is done. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic void intel_pcie_device_rst_assert(struct intel_pcie_port *lpp) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(lpp->reset_gpio, 1); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic void intel_pcie_device_rst_deassert(struct intel_pcie_port *lpp) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci msleep(lpp->rst_intrvl); 2158c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(lpp->reset_gpio, 0); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int intel_pcie_app_logic_setup(struct intel_pcie_port *lpp) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci intel_pcie_device_rst_deassert(lpp); 2218c2ecf20Sopenharmony_ci intel_pcie_ltssm_enable(lpp); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return dw_pcie_wait_for_link(&lpp->pci); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic void intel_pcie_core_irq_disable(struct intel_pcie_port *lpp) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci pcie_app_wr(lpp, PCIE_APP_IRNEN, 0); 2298c2ecf20Sopenharmony_ci pcie_app_wr(lpp, PCIE_APP_IRNCR, PCIE_APP_IRN_INT); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int intel_pcie_get_resources(struct platform_device *pdev) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct intel_pcie_port *lpp = platform_get_drvdata(pdev); 2358c2ecf20Sopenharmony_ci struct dw_pcie *pci = &lpp->pci; 2368c2ecf20Sopenharmony_ci struct device *dev = pci->dev; 2378c2ecf20Sopenharmony_ci int ret; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi"); 2408c2ecf20Sopenharmony_ci if (IS_ERR(pci->dbi_base)) 2418c2ecf20Sopenharmony_ci return PTR_ERR(pci->dbi_base); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci lpp->core_clk = devm_clk_get(dev, NULL); 2448c2ecf20Sopenharmony_ci if (IS_ERR(lpp->core_clk)) { 2458c2ecf20Sopenharmony_ci ret = PTR_ERR(lpp->core_clk); 2468c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 2478c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get clks: %d\n", ret); 2488c2ecf20Sopenharmony_ci return ret; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci lpp->core_rst = devm_reset_control_get(dev, NULL); 2528c2ecf20Sopenharmony_ci if (IS_ERR(lpp->core_rst)) { 2538c2ecf20Sopenharmony_ci ret = PTR_ERR(lpp->core_rst); 2548c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 2558c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get resets: %d\n", ret); 2568c2ecf20Sopenharmony_ci return ret; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci ret = device_property_read_u32(dev, "reset-assert-ms", 2608c2ecf20Sopenharmony_ci &lpp->rst_intrvl); 2618c2ecf20Sopenharmony_ci if (ret) 2628c2ecf20Sopenharmony_ci lpp->rst_intrvl = RESET_INTERVAL_MS; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci lpp->app_base = devm_platform_ioremap_resource_byname(pdev, "app"); 2658c2ecf20Sopenharmony_ci if (IS_ERR(lpp->app_base)) 2668c2ecf20Sopenharmony_ci return PTR_ERR(lpp->app_base); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci lpp->phy = devm_phy_get(dev, "pcie"); 2698c2ecf20Sopenharmony_ci if (IS_ERR(lpp->phy)) { 2708c2ecf20Sopenharmony_ci ret = PTR_ERR(lpp->phy); 2718c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 2728c2ecf20Sopenharmony_ci dev_err(dev, "Couldn't get pcie-phy: %d\n", ret); 2738c2ecf20Sopenharmony_ci return ret; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic void intel_pcie_deinit_phy(struct intel_pcie_port *lpp) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci phy_exit(lpp->phy); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int intel_pcie_wait_l2(struct intel_pcie_port *lpp) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci u32 value; 2878c2ecf20Sopenharmony_ci int ret; 2888c2ecf20Sopenharmony_ci struct dw_pcie *pci = &lpp->pci; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (pci->link_gen < 3) 2918c2ecf20Sopenharmony_ci return 0; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* Send PME_TURN_OFF message */ 2948c2ecf20Sopenharmony_ci pcie_app_wr_mask(lpp, PCIE_APP_MSG_CR, PCIE_APP_MSG_XMT_PM_TURNOFF, 2958c2ecf20Sopenharmony_ci PCIE_APP_MSG_XMT_PM_TURNOFF); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Read PMC status and wait for falling into L2 link state */ 2988c2ecf20Sopenharmony_ci ret = readl_poll_timeout(lpp->app_base + PCIE_APP_PMC, value, 2998c2ecf20Sopenharmony_ci value & PCIE_APP_PMC_IN_L2, 20, 3008c2ecf20Sopenharmony_ci jiffies_to_usecs(5 * HZ)); 3018c2ecf20Sopenharmony_ci if (ret) 3028c2ecf20Sopenharmony_ci dev_err(lpp->pci.dev, "PCIe link enter L2 timeout!\n"); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return ret; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void intel_pcie_turn_off(struct intel_pcie_port *lpp) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci if (dw_pcie_link_up(&lpp->pci)) 3108c2ecf20Sopenharmony_ci intel_pcie_wait_l2(lpp); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* Put endpoint device in reset state */ 3138c2ecf20Sopenharmony_ci intel_pcie_device_rst_assert(lpp); 3148c2ecf20Sopenharmony_ci pcie_rc_cfg_wr_mask(lpp, PCI_COMMAND, PCI_COMMAND_MEMORY, 0); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int intel_pcie_host_setup(struct intel_pcie_port *lpp) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci int ret; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci intel_pcie_core_rst_assert(lpp); 3228c2ecf20Sopenharmony_ci intel_pcie_device_rst_assert(lpp); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci ret = phy_init(lpp->phy); 3258c2ecf20Sopenharmony_ci if (ret) 3268c2ecf20Sopenharmony_ci return ret; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci intel_pcie_core_rst_deassert(lpp); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ret = clk_prepare_enable(lpp->core_clk); 3318c2ecf20Sopenharmony_ci if (ret) { 3328c2ecf20Sopenharmony_ci dev_err(lpp->pci.dev, "Core clock enable failed: %d\n", ret); 3338c2ecf20Sopenharmony_ci goto clk_err; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci intel_pcie_rc_setup(lpp); 3378c2ecf20Sopenharmony_ci ret = intel_pcie_app_logic_setup(lpp); 3388c2ecf20Sopenharmony_ci if (ret) 3398c2ecf20Sopenharmony_ci goto app_init_err; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* Enable integrated interrupts */ 3428c2ecf20Sopenharmony_ci pcie_app_wr_mask(lpp, PCIE_APP_IRNEN, PCIE_APP_IRN_INT, 3438c2ecf20Sopenharmony_ci PCIE_APP_IRN_INT); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ciapp_init_err: 3488c2ecf20Sopenharmony_ci clk_disable_unprepare(lpp->core_clk); 3498c2ecf20Sopenharmony_ciclk_err: 3508c2ecf20Sopenharmony_ci intel_pcie_core_rst_assert(lpp); 3518c2ecf20Sopenharmony_ci intel_pcie_deinit_phy(lpp); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return ret; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void __intel_pcie_remove(struct intel_pcie_port *lpp) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci intel_pcie_core_irq_disable(lpp); 3598c2ecf20Sopenharmony_ci intel_pcie_turn_off(lpp); 3608c2ecf20Sopenharmony_ci clk_disable_unprepare(lpp->core_clk); 3618c2ecf20Sopenharmony_ci intel_pcie_core_rst_assert(lpp); 3628c2ecf20Sopenharmony_ci intel_pcie_deinit_phy(lpp); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int intel_pcie_remove(struct platform_device *pdev) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct intel_pcie_port *lpp = platform_get_drvdata(pdev); 3688c2ecf20Sopenharmony_ci struct pcie_port *pp = &lpp->pci.pp; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci dw_pcie_host_deinit(pp); 3718c2ecf20Sopenharmony_ci __intel_pcie_remove(lpp); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int __maybe_unused intel_pcie_suspend_noirq(struct device *dev) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct intel_pcie_port *lpp = dev_get_drvdata(dev); 3798c2ecf20Sopenharmony_ci int ret; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci intel_pcie_core_irq_disable(lpp); 3828c2ecf20Sopenharmony_ci ret = intel_pcie_wait_l2(lpp); 3838c2ecf20Sopenharmony_ci if (ret) 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci intel_pcie_deinit_phy(lpp); 3878c2ecf20Sopenharmony_ci clk_disable_unprepare(lpp->core_clk); 3888c2ecf20Sopenharmony_ci return ret; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic int __maybe_unused intel_pcie_resume_noirq(struct device *dev) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct intel_pcie_port *lpp = dev_get_drvdata(dev); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci return intel_pcie_host_setup(lpp); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic int intel_pcie_rc_init(struct pcie_port *pp) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 4018c2ecf20Sopenharmony_ci struct intel_pcie_port *lpp = dev_get_drvdata(pci->dev); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return intel_pcie_host_setup(lpp); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci/* 4078c2ecf20Sopenharmony_ci * Dummy function so that DW core doesn't configure MSI 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_cistatic int intel_pcie_msi_init(struct pcie_port *pp) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic u64 intel_pcie_cpu_addr(struct dw_pcie *pcie, u64 cpu_addr) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci return cpu_addr + BUS_IATU_OFFSET; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic const struct dw_pcie_ops intel_pcie_ops = { 4208c2ecf20Sopenharmony_ci .cpu_addr_fixup = intel_pcie_cpu_addr, 4218c2ecf20Sopenharmony_ci}; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic const struct dw_pcie_host_ops intel_pcie_dw_ops = { 4248c2ecf20Sopenharmony_ci .host_init = intel_pcie_rc_init, 4258c2ecf20Sopenharmony_ci .msi_host_init = intel_pcie_msi_init, 4268c2ecf20Sopenharmony_ci}; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic const struct intel_pcie_soc pcie_data = { 4298c2ecf20Sopenharmony_ci .pcie_ver = 0x520A, 4308c2ecf20Sopenharmony_ci .pcie_atu_offset = 0xC0000, 4318c2ecf20Sopenharmony_ci .num_viewport = 3, 4328c2ecf20Sopenharmony_ci}; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic int intel_pcie_probe(struct platform_device *pdev) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci const struct intel_pcie_soc *data; 4378c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4388c2ecf20Sopenharmony_ci struct intel_pcie_port *lpp; 4398c2ecf20Sopenharmony_ci struct pcie_port *pp; 4408c2ecf20Sopenharmony_ci struct dw_pcie *pci; 4418c2ecf20Sopenharmony_ci int ret; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci lpp = devm_kzalloc(dev, sizeof(*lpp), GFP_KERNEL); 4448c2ecf20Sopenharmony_ci if (!lpp) 4458c2ecf20Sopenharmony_ci return -ENOMEM; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, lpp); 4488c2ecf20Sopenharmony_ci pci = &lpp->pci; 4498c2ecf20Sopenharmony_ci pci->dev = dev; 4508c2ecf20Sopenharmony_ci pp = &pci->pp; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci ret = intel_pcie_get_resources(pdev); 4538c2ecf20Sopenharmony_ci if (ret) 4548c2ecf20Sopenharmony_ci return ret; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci ret = intel_pcie_ep_rst_init(lpp); 4578c2ecf20Sopenharmony_ci if (ret) 4588c2ecf20Sopenharmony_ci return ret; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci data = device_get_match_data(dev); 4618c2ecf20Sopenharmony_ci if (!data) 4628c2ecf20Sopenharmony_ci return -ENODEV; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci pci->ops = &intel_pcie_ops; 4658c2ecf20Sopenharmony_ci pci->version = data->pcie_ver; 4668c2ecf20Sopenharmony_ci pci->atu_base = pci->dbi_base + data->pcie_atu_offset; 4678c2ecf20Sopenharmony_ci pp->ops = &intel_pcie_dw_ops; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci ret = dw_pcie_host_init(pp); 4708c2ecf20Sopenharmony_ci if (ret) { 4718c2ecf20Sopenharmony_ci dev_err(dev, "Cannot initialize host\n"); 4728c2ecf20Sopenharmony_ci return ret; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* 4768c2ecf20Sopenharmony_ci * Intel PCIe doesn't configure IO region, so set viewport 4778c2ecf20Sopenharmony_ci * to not perform IO region access. 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci pci->num_viewport = data->num_viewport; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci return 0; 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic const struct dev_pm_ops intel_pcie_pm_ops = { 4858c2ecf20Sopenharmony_ci SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(intel_pcie_suspend_noirq, 4868c2ecf20Sopenharmony_ci intel_pcie_resume_noirq) 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic const struct of_device_id of_intel_pcie_match[] = { 4908c2ecf20Sopenharmony_ci { .compatible = "intel,lgm-pcie", .data = &pcie_data }, 4918c2ecf20Sopenharmony_ci {} 4928c2ecf20Sopenharmony_ci}; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic struct platform_driver intel_pcie_driver = { 4958c2ecf20Sopenharmony_ci .probe = intel_pcie_probe, 4968c2ecf20Sopenharmony_ci .remove = intel_pcie_remove, 4978c2ecf20Sopenharmony_ci .driver = { 4988c2ecf20Sopenharmony_ci .name = "intel-gw-pcie", 4998c2ecf20Sopenharmony_ci .of_match_table = of_intel_pcie_match, 5008c2ecf20Sopenharmony_ci .pm = &intel_pcie_pm_ops, 5018c2ecf20Sopenharmony_ci }, 5028c2ecf20Sopenharmony_ci}; 5038c2ecf20Sopenharmony_cibuiltin_platform_driver(intel_pcie_driver); 504