1*b593c26dSSenchuan Zhang // SPDX-License-Identifier: GPL-2.0 2*b593c26dSSenchuan Zhang /* 3*b593c26dSSenchuan Zhang * ESWIN PCIe Root Complex driver 4*b593c26dSSenchuan Zhang * 5*b593c26dSSenchuan Zhang * Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd. 6*b593c26dSSenchuan Zhang * 7*b593c26dSSenchuan Zhang * Authors: Yu Ning <ningyu@eswincomputing.com> 8*b593c26dSSenchuan Zhang * Senchuan Zhang <zhangsenchuan@eswincomputing.com> 9*b593c26dSSenchuan Zhang * Yanghui Ou <ouyanghui@eswincomputing.com> 10*b593c26dSSenchuan Zhang */ 11*b593c26dSSenchuan Zhang 12*b593c26dSSenchuan Zhang #include <linux/interrupt.h> 13*b593c26dSSenchuan Zhang #include <linux/iopoll.h> 14*b593c26dSSenchuan Zhang #include <linux/module.h> 15*b593c26dSSenchuan Zhang #include <linux/of.h> 16*b593c26dSSenchuan Zhang #include <linux/pci.h> 17*b593c26dSSenchuan Zhang #include <linux/platform_device.h> 18*b593c26dSSenchuan Zhang #include <linux/pm_runtime.h> 19*b593c26dSSenchuan Zhang #include <linux/resource.h> 20*b593c26dSSenchuan Zhang #include <linux/reset.h> 21*b593c26dSSenchuan Zhang #include <linux/types.h> 22*b593c26dSSenchuan Zhang 23*b593c26dSSenchuan Zhang #include "pcie-designware.h" 24*b593c26dSSenchuan Zhang 25*b593c26dSSenchuan Zhang /* ELBI registers */ 26*b593c26dSSenchuan Zhang #define PCIEELBI_CTRL0_OFFSET 0x0 27*b593c26dSSenchuan Zhang #define PCIEELBI_STATUS0_OFFSET 0x100 28*b593c26dSSenchuan Zhang 29*b593c26dSSenchuan Zhang /* LTSSM register fields */ 30*b593c26dSSenchuan Zhang #define PCIEELBI_APP_LTSSM_ENABLE BIT(5) 31*b593c26dSSenchuan Zhang 32*b593c26dSSenchuan Zhang /* APP_HOLD_PHY_RST register fields */ 33*b593c26dSSenchuan Zhang #define PCIEELBI_APP_HOLD_PHY_RST BIT(6) 34*b593c26dSSenchuan Zhang 35*b593c26dSSenchuan Zhang /* PM_SEL_AUX_CLK register fields */ 36*b593c26dSSenchuan Zhang #define PCIEELBI_PM_SEL_AUX_CLK BIT(16) 37*b593c26dSSenchuan Zhang 38*b593c26dSSenchuan Zhang /* DEV_TYPE register fields */ 39*b593c26dSSenchuan Zhang #define PCIEELBI_CTRL0_DEV_TYPE GENMASK(3, 0) 40*b593c26dSSenchuan Zhang 41*b593c26dSSenchuan Zhang /* Vendor and device ID value */ 42*b593c26dSSenchuan Zhang #define PCI_VENDOR_ID_ESWIN 0x1fe1 43*b593c26dSSenchuan Zhang #define PCI_DEVICE_ID_ESWIN_EIC7700 0x2030 44*b593c26dSSenchuan Zhang 45*b593c26dSSenchuan Zhang #define ESWIN_NUM_RSTS ARRAY_SIZE(eswin_pcie_rsts) 46*b593c26dSSenchuan Zhang 47*b593c26dSSenchuan Zhang static const char * const eswin_pcie_rsts[] = { 48*b593c26dSSenchuan Zhang "pwr", 49*b593c26dSSenchuan Zhang "dbi", 50*b593c26dSSenchuan Zhang }; 51*b593c26dSSenchuan Zhang 52*b593c26dSSenchuan Zhang struct eswin_pcie_data { 53*b593c26dSSenchuan Zhang bool skip_l23; 54*b593c26dSSenchuan Zhang }; 55*b593c26dSSenchuan Zhang 56*b593c26dSSenchuan Zhang struct eswin_pcie_port { 57*b593c26dSSenchuan Zhang struct list_head list; 58*b593c26dSSenchuan Zhang struct reset_control *perst; 59*b593c26dSSenchuan Zhang int num_lanes; 60*b593c26dSSenchuan Zhang }; 61*b593c26dSSenchuan Zhang 62*b593c26dSSenchuan Zhang struct eswin_pcie { 63*b593c26dSSenchuan Zhang struct dw_pcie pci; 64*b593c26dSSenchuan Zhang struct clk_bulk_data *clks; 65*b593c26dSSenchuan Zhang struct reset_control_bulk_data resets[ESWIN_NUM_RSTS]; 66*b593c26dSSenchuan Zhang struct list_head ports; 67*b593c26dSSenchuan Zhang const struct eswin_pcie_data *data; 68*b593c26dSSenchuan Zhang int num_clks; 69*b593c26dSSenchuan Zhang }; 70*b593c26dSSenchuan Zhang 71*b593c26dSSenchuan Zhang #define to_eswin_pcie(x) dev_get_drvdata((x)->dev) 72*b593c26dSSenchuan Zhang 73*b593c26dSSenchuan Zhang static int eswin_pcie_start_link(struct dw_pcie *pci) 74*b593c26dSSenchuan Zhang { 75*b593c26dSSenchuan Zhang u32 val; 76*b593c26dSSenchuan Zhang 77*b593c26dSSenchuan Zhang /* Enable LTSSM */ 78*b593c26dSSenchuan Zhang val = readl_relaxed(pci->elbi_base + PCIEELBI_CTRL0_OFFSET); 79*b593c26dSSenchuan Zhang val |= PCIEELBI_APP_LTSSM_ENABLE; 80*b593c26dSSenchuan Zhang writel_relaxed(val, pci->elbi_base + PCIEELBI_CTRL0_OFFSET); 81*b593c26dSSenchuan Zhang 82*b593c26dSSenchuan Zhang return 0; 83*b593c26dSSenchuan Zhang } 84*b593c26dSSenchuan Zhang 85*b593c26dSSenchuan Zhang static bool eswin_pcie_link_up(struct dw_pcie *pci) 86*b593c26dSSenchuan Zhang { 87*b593c26dSSenchuan Zhang u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); 88*b593c26dSSenchuan Zhang u16 val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA); 89*b593c26dSSenchuan Zhang 90*b593c26dSSenchuan Zhang return val & PCI_EXP_LNKSTA_DLLLA; 91*b593c26dSSenchuan Zhang } 92*b593c26dSSenchuan Zhang 93*b593c26dSSenchuan Zhang static int eswin_pcie_perst_reset(struct eswin_pcie_port *port, 94*b593c26dSSenchuan Zhang struct eswin_pcie *pcie) 95*b593c26dSSenchuan Zhang { 96*b593c26dSSenchuan Zhang int ret; 97*b593c26dSSenchuan Zhang 98*b593c26dSSenchuan Zhang ret = reset_control_assert(port->perst); 99*b593c26dSSenchuan Zhang if (ret) { 100*b593c26dSSenchuan Zhang dev_err(pcie->pci.dev, "Failed to assert PERST#\n"); 101*b593c26dSSenchuan Zhang return ret; 102*b593c26dSSenchuan Zhang } 103*b593c26dSSenchuan Zhang 104*b593c26dSSenchuan Zhang /* Ensure that PERST# has been asserted for at least 100 ms */ 105*b593c26dSSenchuan Zhang msleep(PCIE_T_PVPERL_MS); 106*b593c26dSSenchuan Zhang 107*b593c26dSSenchuan Zhang ret = reset_control_deassert(port->perst); 108*b593c26dSSenchuan Zhang if (ret) { 109*b593c26dSSenchuan Zhang dev_err(pcie->pci.dev, "Failed to deassert PERST#\n"); 110*b593c26dSSenchuan Zhang return ret; 111*b593c26dSSenchuan Zhang } 112*b593c26dSSenchuan Zhang 113*b593c26dSSenchuan Zhang return 0; 114*b593c26dSSenchuan Zhang } 115*b593c26dSSenchuan Zhang 116*b593c26dSSenchuan Zhang static void eswin_pcie_assert(struct eswin_pcie *pcie) 117*b593c26dSSenchuan Zhang { 118*b593c26dSSenchuan Zhang struct eswin_pcie_port *port; 119*b593c26dSSenchuan Zhang 120*b593c26dSSenchuan Zhang list_for_each_entry(port, &pcie->ports, list) 121*b593c26dSSenchuan Zhang reset_control_assert(port->perst); 122*b593c26dSSenchuan Zhang reset_control_bulk_assert(ESWIN_NUM_RSTS, pcie->resets); 123*b593c26dSSenchuan Zhang } 124*b593c26dSSenchuan Zhang 125*b593c26dSSenchuan Zhang static int eswin_pcie_parse_port(struct eswin_pcie *pcie, 126*b593c26dSSenchuan Zhang struct device_node *node) 127*b593c26dSSenchuan Zhang { 128*b593c26dSSenchuan Zhang struct device *dev = pcie->pci.dev; 129*b593c26dSSenchuan Zhang struct eswin_pcie_port *port; 130*b593c26dSSenchuan Zhang 131*b593c26dSSenchuan Zhang port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); 132*b593c26dSSenchuan Zhang if (!port) 133*b593c26dSSenchuan Zhang return -ENOMEM; 134*b593c26dSSenchuan Zhang 135*b593c26dSSenchuan Zhang port->perst = of_reset_control_get_exclusive(node, "perst"); 136*b593c26dSSenchuan Zhang if (IS_ERR(port->perst)) { 137*b593c26dSSenchuan Zhang dev_err(dev, "Failed to get PERST# reset\n"); 138*b593c26dSSenchuan Zhang return PTR_ERR(port->perst); 139*b593c26dSSenchuan Zhang } 140*b593c26dSSenchuan Zhang 141*b593c26dSSenchuan Zhang /* 142*b593c26dSSenchuan Zhang * TODO: Since the Root Port node is separated out by pcie devicetree, 143*b593c26dSSenchuan Zhang * the DWC core initialization code can't parse the num-lanes attribute 144*b593c26dSSenchuan Zhang * in the Root Port. Before entering the DWC core initialization code, 145*b593c26dSSenchuan Zhang * the platform driver code parses the Root Port node. The ESWIN only 146*b593c26dSSenchuan Zhang * supports one Root Port node, and the num-lanes attribute is suitable 147*b593c26dSSenchuan Zhang * for the case of one Root Port. 148*b593c26dSSenchuan Zhang */ 149*b593c26dSSenchuan Zhang if (!of_property_read_u32(node, "num-lanes", &port->num_lanes)) 150*b593c26dSSenchuan Zhang pcie->pci.num_lanes = port->num_lanes; 151*b593c26dSSenchuan Zhang 152*b593c26dSSenchuan Zhang INIT_LIST_HEAD(&port->list); 153*b593c26dSSenchuan Zhang list_add_tail(&port->list, &pcie->ports); 154*b593c26dSSenchuan Zhang 155*b593c26dSSenchuan Zhang return 0; 156*b593c26dSSenchuan Zhang } 157*b593c26dSSenchuan Zhang 158*b593c26dSSenchuan Zhang static int eswin_pcie_parse_ports(struct eswin_pcie *pcie) 159*b593c26dSSenchuan Zhang { 160*b593c26dSSenchuan Zhang struct eswin_pcie_port *port, *tmp; 161*b593c26dSSenchuan Zhang struct device *dev = pcie->pci.dev; 162*b593c26dSSenchuan Zhang int ret; 163*b593c26dSSenchuan Zhang 164*b593c26dSSenchuan Zhang for_each_available_child_of_node_scoped(dev->of_node, of_port) { 165*b593c26dSSenchuan Zhang ret = eswin_pcie_parse_port(pcie, of_port); 166*b593c26dSSenchuan Zhang if (ret) 167*b593c26dSSenchuan Zhang goto err_port; 168*b593c26dSSenchuan Zhang } 169*b593c26dSSenchuan Zhang 170*b593c26dSSenchuan Zhang return 0; 171*b593c26dSSenchuan Zhang 172*b593c26dSSenchuan Zhang err_port: 173*b593c26dSSenchuan Zhang list_for_each_entry_safe(port, tmp, &pcie->ports, list) { 174*b593c26dSSenchuan Zhang reset_control_put(port->perst); 175*b593c26dSSenchuan Zhang list_del(&port->list); 176*b593c26dSSenchuan Zhang } 177*b593c26dSSenchuan Zhang 178*b593c26dSSenchuan Zhang return ret; 179*b593c26dSSenchuan Zhang } 180*b593c26dSSenchuan Zhang 181*b593c26dSSenchuan Zhang static int eswin_pcie_host_init(struct dw_pcie_rp *pp) 182*b593c26dSSenchuan Zhang { 183*b593c26dSSenchuan Zhang struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 184*b593c26dSSenchuan Zhang struct eswin_pcie *pcie = to_eswin_pcie(pci); 185*b593c26dSSenchuan Zhang struct eswin_pcie_port *port, *tmp; 186*b593c26dSSenchuan Zhang u32 val; 187*b593c26dSSenchuan Zhang int ret; 188*b593c26dSSenchuan Zhang 189*b593c26dSSenchuan Zhang ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks); 190*b593c26dSSenchuan Zhang if (ret) 191*b593c26dSSenchuan Zhang return ret; 192*b593c26dSSenchuan Zhang 193*b593c26dSSenchuan Zhang /* 194*b593c26dSSenchuan Zhang * The PWR and DBI reset signals are respectively used to reset the 195*b593c26dSSenchuan Zhang * PCIe controller and the DBI register. 196*b593c26dSSenchuan Zhang * 197*b593c26dSSenchuan Zhang * The PERST# signal is a reset signal that simultaneously controls the 198*b593c26dSSenchuan Zhang * PCIe controller, PHY, and Endpoint. Before configuring the PHY, the 199*b593c26dSSenchuan Zhang * PERST# signal must first be deasserted. 200*b593c26dSSenchuan Zhang * 201*b593c26dSSenchuan Zhang * The external reference clock is supplied simultaneously to the PHY 202*b593c26dSSenchuan Zhang * and EP. When the PHY is configurable, the entire chip already has 203*b593c26dSSenchuan Zhang * stable power and reference clock. The PHY will be ready within 20ms 204*b593c26dSSenchuan Zhang * after writing app_hold_phy_rst register bit of ELBI register space. 205*b593c26dSSenchuan Zhang */ 206*b593c26dSSenchuan Zhang ret = reset_control_bulk_deassert(ESWIN_NUM_RSTS, pcie->resets); 207*b593c26dSSenchuan Zhang if (ret) { 208*b593c26dSSenchuan Zhang dev_err(pcie->pci.dev, "Failed to deassert resets\n"); 209*b593c26dSSenchuan Zhang goto err_deassert; 210*b593c26dSSenchuan Zhang } 211*b593c26dSSenchuan Zhang 212*b593c26dSSenchuan Zhang /* Configure Root Port type */ 213*b593c26dSSenchuan Zhang val = readl_relaxed(pci->elbi_base + PCIEELBI_CTRL0_OFFSET); 214*b593c26dSSenchuan Zhang val &= ~PCIEELBI_CTRL0_DEV_TYPE; 215*b593c26dSSenchuan Zhang val |= FIELD_PREP(PCIEELBI_CTRL0_DEV_TYPE, PCI_EXP_TYPE_ROOT_PORT); 216*b593c26dSSenchuan Zhang writel_relaxed(val, pci->elbi_base + PCIEELBI_CTRL0_OFFSET); 217*b593c26dSSenchuan Zhang 218*b593c26dSSenchuan Zhang list_for_each_entry(port, &pcie->ports, list) { 219*b593c26dSSenchuan Zhang ret = eswin_pcie_perst_reset(port, pcie); 220*b593c26dSSenchuan Zhang if (ret) 221*b593c26dSSenchuan Zhang goto err_perst; 222*b593c26dSSenchuan Zhang } 223*b593c26dSSenchuan Zhang 224*b593c26dSSenchuan Zhang /* Configure app_hold_phy_rst */ 225*b593c26dSSenchuan Zhang val = readl_relaxed(pci->elbi_base + PCIEELBI_CTRL0_OFFSET); 226*b593c26dSSenchuan Zhang val &= ~PCIEELBI_APP_HOLD_PHY_RST; 227*b593c26dSSenchuan Zhang writel_relaxed(val, pci->elbi_base + PCIEELBI_CTRL0_OFFSET); 228*b593c26dSSenchuan Zhang 229*b593c26dSSenchuan Zhang /* The maximum waiting time for the clock switch lock is 20ms */ 230*b593c26dSSenchuan Zhang ret = readl_poll_timeout(pci->elbi_base + PCIEELBI_STATUS0_OFFSET, val, 231*b593c26dSSenchuan Zhang !(val & PCIEELBI_PM_SEL_AUX_CLK), 1000, 232*b593c26dSSenchuan Zhang 20000); 233*b593c26dSSenchuan Zhang if (ret) { 234*b593c26dSSenchuan Zhang dev_err(pci->dev, "Timeout waiting for PM_SEL_AUX_CLK ready\n"); 235*b593c26dSSenchuan Zhang goto err_phy_init; 236*b593c26dSSenchuan Zhang } 237*b593c26dSSenchuan Zhang 238*b593c26dSSenchuan Zhang /* 239*b593c26dSSenchuan Zhang * Configure ESWIN VID:DID for Root Port as the default values are 240*b593c26dSSenchuan Zhang * invalid. 241*b593c26dSSenchuan Zhang */ 242*b593c26dSSenchuan Zhang dw_pcie_dbi_ro_wr_en(pci); 243*b593c26dSSenchuan Zhang dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, PCI_VENDOR_ID_ESWIN); 244*b593c26dSSenchuan Zhang dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, PCI_DEVICE_ID_ESWIN_EIC7700); 245*b593c26dSSenchuan Zhang dw_pcie_dbi_ro_wr_dis(pci); 246*b593c26dSSenchuan Zhang 247*b593c26dSSenchuan Zhang return 0; 248*b593c26dSSenchuan Zhang 249*b593c26dSSenchuan Zhang err_phy_init: 250*b593c26dSSenchuan Zhang list_for_each_entry(port, &pcie->ports, list) 251*b593c26dSSenchuan Zhang reset_control_assert(port->perst); 252*b593c26dSSenchuan Zhang err_perst: 253*b593c26dSSenchuan Zhang reset_control_bulk_assert(ESWIN_NUM_RSTS, pcie->resets); 254*b593c26dSSenchuan Zhang err_deassert: 255*b593c26dSSenchuan Zhang clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); 256*b593c26dSSenchuan Zhang list_for_each_entry_safe(port, tmp, &pcie->ports, list) { 257*b593c26dSSenchuan Zhang reset_control_put(port->perst); 258*b593c26dSSenchuan Zhang list_del(&port->list); 259*b593c26dSSenchuan Zhang } 260*b593c26dSSenchuan Zhang 261*b593c26dSSenchuan Zhang return ret; 262*b593c26dSSenchuan Zhang } 263*b593c26dSSenchuan Zhang 264*b593c26dSSenchuan Zhang static void eswin_pcie_host_deinit(struct dw_pcie_rp *pp) 265*b593c26dSSenchuan Zhang { 266*b593c26dSSenchuan Zhang struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 267*b593c26dSSenchuan Zhang struct eswin_pcie *pcie = to_eswin_pcie(pci); 268*b593c26dSSenchuan Zhang 269*b593c26dSSenchuan Zhang eswin_pcie_assert(pcie); 270*b593c26dSSenchuan Zhang clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); 271*b593c26dSSenchuan Zhang } 272*b593c26dSSenchuan Zhang 273*b593c26dSSenchuan Zhang static void eswin_pcie_pme_turn_off(struct dw_pcie_rp *pp) 274*b593c26dSSenchuan Zhang { 275*b593c26dSSenchuan Zhang struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 276*b593c26dSSenchuan Zhang struct eswin_pcie *pcie = to_eswin_pcie(pci); 277*b593c26dSSenchuan Zhang 278*b593c26dSSenchuan Zhang /* 279*b593c26dSSenchuan Zhang * The ESWIN EIC7700 SoC lacks hardware support for the L2/L3 low-power 280*b593c26dSSenchuan Zhang * link states. It cannot enter the L2/L3 Ready state through the 281*b593c26dSSenchuan Zhang * PME_Turn_Off/PME_To_Ack handshake protocol. To avoid this problem, 282*b593c26dSSenchuan Zhang * the skip_l23_ready has been set. 283*b593c26dSSenchuan Zhang */ 284*b593c26dSSenchuan Zhang pp->skip_l23_ready = pcie->data->skip_l23; 285*b593c26dSSenchuan Zhang } 286*b593c26dSSenchuan Zhang 287*b593c26dSSenchuan Zhang static const struct dw_pcie_host_ops eswin_pcie_host_ops = { 288*b593c26dSSenchuan Zhang .init = eswin_pcie_host_init, 289*b593c26dSSenchuan Zhang .deinit = eswin_pcie_host_deinit, 290*b593c26dSSenchuan Zhang .pme_turn_off = eswin_pcie_pme_turn_off, 291*b593c26dSSenchuan Zhang }; 292*b593c26dSSenchuan Zhang 293*b593c26dSSenchuan Zhang static const struct dw_pcie_ops dw_pcie_ops = { 294*b593c26dSSenchuan Zhang .start_link = eswin_pcie_start_link, 295*b593c26dSSenchuan Zhang .link_up = eswin_pcie_link_up, 296*b593c26dSSenchuan Zhang }; 297*b593c26dSSenchuan Zhang 298*b593c26dSSenchuan Zhang static int eswin_pcie_probe(struct platform_device *pdev) 299*b593c26dSSenchuan Zhang { 300*b593c26dSSenchuan Zhang const struct eswin_pcie_data *data; 301*b593c26dSSenchuan Zhang struct eswin_pcie_port *port, *tmp; 302*b593c26dSSenchuan Zhang struct device *dev = &pdev->dev; 303*b593c26dSSenchuan Zhang struct eswin_pcie *pcie; 304*b593c26dSSenchuan Zhang struct dw_pcie *pci; 305*b593c26dSSenchuan Zhang int ret, i; 306*b593c26dSSenchuan Zhang 307*b593c26dSSenchuan Zhang data = of_device_get_match_data(dev); 308*b593c26dSSenchuan Zhang if (!data) 309*b593c26dSSenchuan Zhang return dev_err_probe(dev, -ENODATA, "No platform data\n"); 310*b593c26dSSenchuan Zhang 311*b593c26dSSenchuan Zhang pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); 312*b593c26dSSenchuan Zhang if (!pcie) 313*b593c26dSSenchuan Zhang return -ENOMEM; 314*b593c26dSSenchuan Zhang 315*b593c26dSSenchuan Zhang INIT_LIST_HEAD(&pcie->ports); 316*b593c26dSSenchuan Zhang 317*b593c26dSSenchuan Zhang pci = &pcie->pci; 318*b593c26dSSenchuan Zhang pci->dev = dev; 319*b593c26dSSenchuan Zhang pci->ops = &dw_pcie_ops; 320*b593c26dSSenchuan Zhang pci->pp.ops = &eswin_pcie_host_ops; 321*b593c26dSSenchuan Zhang pcie->data = data; 322*b593c26dSSenchuan Zhang 323*b593c26dSSenchuan Zhang pcie->num_clks = devm_clk_bulk_get_all(dev, &pcie->clks); 324*b593c26dSSenchuan Zhang if (pcie->num_clks < 0) 325*b593c26dSSenchuan Zhang return dev_err_probe(dev, pcie->num_clks, 326*b593c26dSSenchuan Zhang "Failed to get pcie clocks\n"); 327*b593c26dSSenchuan Zhang 328*b593c26dSSenchuan Zhang for (i = 0; i < ESWIN_NUM_RSTS; i++) 329*b593c26dSSenchuan Zhang pcie->resets[i].id = eswin_pcie_rsts[i]; 330*b593c26dSSenchuan Zhang 331*b593c26dSSenchuan Zhang ret = devm_reset_control_bulk_get_exclusive(dev, ESWIN_NUM_RSTS, 332*b593c26dSSenchuan Zhang pcie->resets); 333*b593c26dSSenchuan Zhang if (ret) 334*b593c26dSSenchuan Zhang return dev_err_probe(dev, ret, "Failed to get resets\n"); 335*b593c26dSSenchuan Zhang 336*b593c26dSSenchuan Zhang ret = eswin_pcie_parse_ports(pcie); 337*b593c26dSSenchuan Zhang if (ret) 338*b593c26dSSenchuan Zhang return dev_err_probe(dev, ret, "Failed to parse Root Port\n"); 339*b593c26dSSenchuan Zhang 340*b593c26dSSenchuan Zhang platform_set_drvdata(pdev, pcie); 341*b593c26dSSenchuan Zhang 342*b593c26dSSenchuan Zhang pm_runtime_no_callbacks(dev); 343*b593c26dSSenchuan Zhang devm_pm_runtime_enable(dev); 344*b593c26dSSenchuan Zhang ret = pm_runtime_get_sync(dev); 345*b593c26dSSenchuan Zhang if (ret < 0) 346*b593c26dSSenchuan Zhang goto err_pm_runtime_put; 347*b593c26dSSenchuan Zhang 348*b593c26dSSenchuan Zhang ret = dw_pcie_host_init(&pci->pp); 349*b593c26dSSenchuan Zhang if (ret) { 350*b593c26dSSenchuan Zhang dev_err(dev, "Failed to init host\n"); 351*b593c26dSSenchuan Zhang goto err_init; 352*b593c26dSSenchuan Zhang } 353*b593c26dSSenchuan Zhang 354*b593c26dSSenchuan Zhang return 0; 355*b593c26dSSenchuan Zhang 356*b593c26dSSenchuan Zhang err_pm_runtime_put: 357*b593c26dSSenchuan Zhang list_for_each_entry_safe(port, tmp, &pcie->ports, list) { 358*b593c26dSSenchuan Zhang reset_control_put(port->perst); 359*b593c26dSSenchuan Zhang list_del(&port->list); 360*b593c26dSSenchuan Zhang } 361*b593c26dSSenchuan Zhang err_init: 362*b593c26dSSenchuan Zhang pm_runtime_put(dev); 363*b593c26dSSenchuan Zhang 364*b593c26dSSenchuan Zhang return ret; 365*b593c26dSSenchuan Zhang } 366*b593c26dSSenchuan Zhang 367*b593c26dSSenchuan Zhang static int eswin_pcie_suspend_noirq(struct device *dev) 368*b593c26dSSenchuan Zhang { 369*b593c26dSSenchuan Zhang struct eswin_pcie *pcie = dev_get_drvdata(dev); 370*b593c26dSSenchuan Zhang 371*b593c26dSSenchuan Zhang return dw_pcie_suspend_noirq(&pcie->pci); 372*b593c26dSSenchuan Zhang } 373*b593c26dSSenchuan Zhang 374*b593c26dSSenchuan Zhang static int eswin_pcie_resume_noirq(struct device *dev) 375*b593c26dSSenchuan Zhang { 376*b593c26dSSenchuan Zhang struct eswin_pcie *pcie = dev_get_drvdata(dev); 377*b593c26dSSenchuan Zhang 378*b593c26dSSenchuan Zhang return dw_pcie_resume_noirq(&pcie->pci); 379*b593c26dSSenchuan Zhang } 380*b593c26dSSenchuan Zhang 381*b593c26dSSenchuan Zhang static DEFINE_NOIRQ_DEV_PM_OPS(eswin_pcie_pm, eswin_pcie_suspend_noirq, 382*b593c26dSSenchuan Zhang eswin_pcie_resume_noirq); 383*b593c26dSSenchuan Zhang 384*b593c26dSSenchuan Zhang static const struct eswin_pcie_data eswin_eic7700_data = { 385*b593c26dSSenchuan Zhang .skip_l23 = true, 386*b593c26dSSenchuan Zhang }; 387*b593c26dSSenchuan Zhang 388*b593c26dSSenchuan Zhang static const struct of_device_id eswin_pcie_of_match[] = { 389*b593c26dSSenchuan Zhang { .compatible = "eswin,eic7700-pcie", .data = &eswin_eic7700_data }, 390*b593c26dSSenchuan Zhang {} 391*b593c26dSSenchuan Zhang }; 392*b593c26dSSenchuan Zhang 393*b593c26dSSenchuan Zhang static struct platform_driver eswin_pcie_driver = { 394*b593c26dSSenchuan Zhang .probe = eswin_pcie_probe, 395*b593c26dSSenchuan Zhang .driver = { 396*b593c26dSSenchuan Zhang .name = "eswin-pcie", 397*b593c26dSSenchuan Zhang .of_match_table = eswin_pcie_of_match, 398*b593c26dSSenchuan Zhang .suppress_bind_attrs = true, 399*b593c26dSSenchuan Zhang .pm = &eswin_pcie_pm, 400*b593c26dSSenchuan Zhang }, 401*b593c26dSSenchuan Zhang }; 402*b593c26dSSenchuan Zhang builtin_platform_driver(eswin_pcie_driver); 403*b593c26dSSenchuan Zhang 404*b593c26dSSenchuan Zhang MODULE_DESCRIPTION("ESWIN PCIe Root Complex driver"); 405*b593c26dSSenchuan Zhang MODULE_AUTHOR("Yu Ning <ningyu@eswincomputing.com>"); 406*b593c26dSSenchuan Zhang MODULE_AUTHOR("Senchuan Zhang <zhangsenchuan@eswincomputing.com>"); 407*b593c26dSSenchuan Zhang MODULE_AUTHOR("Yanghui Ou <ouyanghui@eswincomputing.com>"); 408*b593c26dSSenchuan Zhang MODULE_LICENSE("GPL"); 409