1*5cbc7d3eSVincent Guittot // SPDX-License-Identifier: GPL-2.0 2*5cbc7d3eSVincent Guittot /* 3*5cbc7d3eSVincent Guittot * PCIe host controller driver for NXP S32G SoCs 4*5cbc7d3eSVincent Guittot * 5*5cbc7d3eSVincent Guittot * Copyright 2019-2025 NXP 6*5cbc7d3eSVincent Guittot */ 7*5cbc7d3eSVincent Guittot 8*5cbc7d3eSVincent Guittot #include <linux/interrupt.h> 9*5cbc7d3eSVincent Guittot #include <linux/io.h> 10*5cbc7d3eSVincent Guittot #include <linux/module.h> 11*5cbc7d3eSVincent Guittot #include <linux/of_device.h> 12*5cbc7d3eSVincent Guittot #include <linux/of_address.h> 13*5cbc7d3eSVincent Guittot #include <linux/pci.h> 14*5cbc7d3eSVincent Guittot #include <linux/phy/phy.h> 15*5cbc7d3eSVincent Guittot #include <linux/platform_device.h> 16*5cbc7d3eSVincent Guittot #include <linux/pm_runtime.h> 17*5cbc7d3eSVincent Guittot #include <linux/sizes.h> 18*5cbc7d3eSVincent Guittot #include <linux/types.h> 19*5cbc7d3eSVincent Guittot 20*5cbc7d3eSVincent Guittot #include "pcie-designware.h" 21*5cbc7d3eSVincent Guittot 22*5cbc7d3eSVincent Guittot /* PCIe controller Sub-System */ 23*5cbc7d3eSVincent Guittot 24*5cbc7d3eSVincent Guittot /* PCIe controller 0 General Control 1 */ 25*5cbc7d3eSVincent Guittot #define PCIE_S32G_PE0_GEN_CTRL_1 0x50 26*5cbc7d3eSVincent Guittot #define DEVICE_TYPE_MASK GENMASK(3, 0) 27*5cbc7d3eSVincent Guittot #define SRIS_MODE BIT(8) 28*5cbc7d3eSVincent Guittot 29*5cbc7d3eSVincent Guittot /* PCIe controller 0 General Control 3 */ 30*5cbc7d3eSVincent Guittot #define PCIE_S32G_PE0_GEN_CTRL_3 0x58 31*5cbc7d3eSVincent Guittot #define LTSSM_EN BIT(0) 32*5cbc7d3eSVincent Guittot 33*5cbc7d3eSVincent Guittot /* PCIe Controller 0 Interrupt Status */ 34*5cbc7d3eSVincent Guittot #define PCIE_S32G_PE0_INT_STS 0xE8 35*5cbc7d3eSVincent Guittot #define HP_INT_STS BIT(6) 36*5cbc7d3eSVincent Guittot 37*5cbc7d3eSVincent Guittot /* Boundary between peripheral space and physical memory space */ 38*5cbc7d3eSVincent Guittot #define S32G_MEMORY_BOUNDARY_ADDR 0x80000000 39*5cbc7d3eSVincent Guittot 40*5cbc7d3eSVincent Guittot struct s32g_pcie_port { 41*5cbc7d3eSVincent Guittot struct list_head list; 42*5cbc7d3eSVincent Guittot struct phy *phy; 43*5cbc7d3eSVincent Guittot }; 44*5cbc7d3eSVincent Guittot 45*5cbc7d3eSVincent Guittot struct s32g_pcie { 46*5cbc7d3eSVincent Guittot struct dw_pcie pci; 47*5cbc7d3eSVincent Guittot void __iomem *ctrl_base; 48*5cbc7d3eSVincent Guittot struct list_head ports; 49*5cbc7d3eSVincent Guittot }; 50*5cbc7d3eSVincent Guittot 51*5cbc7d3eSVincent Guittot #define to_s32g_from_dw_pcie(x) \ 52*5cbc7d3eSVincent Guittot container_of(x, struct s32g_pcie, pci) 53*5cbc7d3eSVincent Guittot 54*5cbc7d3eSVincent Guittot static void s32g_pcie_writel_ctrl(struct s32g_pcie *s32g_pp, u32 reg, u32 val) 55*5cbc7d3eSVincent Guittot { 56*5cbc7d3eSVincent Guittot writel(val, s32g_pp->ctrl_base + reg); 57*5cbc7d3eSVincent Guittot } 58*5cbc7d3eSVincent Guittot 59*5cbc7d3eSVincent Guittot static u32 s32g_pcie_readl_ctrl(struct s32g_pcie *s32g_pp, u32 reg) 60*5cbc7d3eSVincent Guittot { 61*5cbc7d3eSVincent Guittot return readl(s32g_pp->ctrl_base + reg); 62*5cbc7d3eSVincent Guittot } 63*5cbc7d3eSVincent Guittot 64*5cbc7d3eSVincent Guittot static void s32g_pcie_enable_ltssm(struct s32g_pcie *s32g_pp) 65*5cbc7d3eSVincent Guittot { 66*5cbc7d3eSVincent Guittot u32 reg; 67*5cbc7d3eSVincent Guittot 68*5cbc7d3eSVincent Guittot reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3); 69*5cbc7d3eSVincent Guittot reg |= LTSSM_EN; 70*5cbc7d3eSVincent Guittot s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg); 71*5cbc7d3eSVincent Guittot } 72*5cbc7d3eSVincent Guittot 73*5cbc7d3eSVincent Guittot static void s32g_pcie_disable_ltssm(struct s32g_pcie *s32g_pp) 74*5cbc7d3eSVincent Guittot { 75*5cbc7d3eSVincent Guittot u32 reg; 76*5cbc7d3eSVincent Guittot 77*5cbc7d3eSVincent Guittot reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3); 78*5cbc7d3eSVincent Guittot reg &= ~LTSSM_EN; 79*5cbc7d3eSVincent Guittot s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg); 80*5cbc7d3eSVincent Guittot } 81*5cbc7d3eSVincent Guittot 82*5cbc7d3eSVincent Guittot static int s32g_pcie_start_link(struct dw_pcie *pci) 83*5cbc7d3eSVincent Guittot { 84*5cbc7d3eSVincent Guittot struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci); 85*5cbc7d3eSVincent Guittot 86*5cbc7d3eSVincent Guittot s32g_pcie_enable_ltssm(s32g_pp); 87*5cbc7d3eSVincent Guittot 88*5cbc7d3eSVincent Guittot return 0; 89*5cbc7d3eSVincent Guittot } 90*5cbc7d3eSVincent Guittot 91*5cbc7d3eSVincent Guittot static void s32g_pcie_stop_link(struct dw_pcie *pci) 92*5cbc7d3eSVincent Guittot { 93*5cbc7d3eSVincent Guittot struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci); 94*5cbc7d3eSVincent Guittot 95*5cbc7d3eSVincent Guittot s32g_pcie_disable_ltssm(s32g_pp); 96*5cbc7d3eSVincent Guittot } 97*5cbc7d3eSVincent Guittot 98*5cbc7d3eSVincent Guittot static struct dw_pcie_ops s32g_pcie_ops = { 99*5cbc7d3eSVincent Guittot .start_link = s32g_pcie_start_link, 100*5cbc7d3eSVincent Guittot .stop_link = s32g_pcie_stop_link, 101*5cbc7d3eSVincent Guittot }; 102*5cbc7d3eSVincent Guittot 103*5cbc7d3eSVincent Guittot /* Configure the AMBA AXI Coherency Extensions (ACE) interface */ 104*5cbc7d3eSVincent Guittot static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci) 105*5cbc7d3eSVincent Guittot { 106*5cbc7d3eSVincent Guittot u32 ddr_base_low = lower_32_bits(S32G_MEMORY_BOUNDARY_ADDR); 107*5cbc7d3eSVincent Guittot u32 ddr_base_high = upper_32_bits(S32G_MEMORY_BOUNDARY_ADDR); 108*5cbc7d3eSVincent Guittot 109*5cbc7d3eSVincent Guittot dw_pcie_dbi_ro_wr_en(pci); 110*5cbc7d3eSVincent Guittot dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, 0x0); 111*5cbc7d3eSVincent Guittot 112*5cbc7d3eSVincent Guittot /* 113*5cbc7d3eSVincent Guittot * Ncore is a cache-coherent interconnect module that enables the 114*5cbc7d3eSVincent Guittot * integration of heterogeneous coherent and non-coherent agents in 115*5cbc7d3eSVincent Guittot * the chip. Ncore transactions to peripheral should be non-coherent 116*5cbc7d3eSVincent Guittot * or it might drop them. 117*5cbc7d3eSVincent Guittot * 118*5cbc7d3eSVincent Guittot * One example where this is needed are PCIe MSIs, which use NoSnoop=0 119*5cbc7d3eSVincent Guittot * and might end up routed to Ncore. PCIe coherent traffic (e.g. MSIs) 120*5cbc7d3eSVincent Guittot * that targets peripheral space will be dropped by Ncore because 121*5cbc7d3eSVincent Guittot * peripherals on S32G are not coherent as slaves. We add a hard 122*5cbc7d3eSVincent Guittot * boundary in the PCIe controller coherency control registers to 123*5cbc7d3eSVincent Guittot * separate physical memory space from peripheral space. 124*5cbc7d3eSVincent Guittot * 125*5cbc7d3eSVincent Guittot * Define the start of DDR as seen by Linux as this boundary between 126*5cbc7d3eSVincent Guittot * "memory" and "peripherals", with peripherals being below. 127*5cbc7d3eSVincent Guittot */ 128*5cbc7d3eSVincent Guittot dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_1_OFF, 129*5cbc7d3eSVincent Guittot (ddr_base_low & CFG_MEMTYPE_BOUNDARY_LOW_ADDR_MASK)); 130*5cbc7d3eSVincent Guittot dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_2_OFF, ddr_base_high); 131*5cbc7d3eSVincent Guittot dw_pcie_dbi_ro_wr_dis(pci); 132*5cbc7d3eSVincent Guittot } 133*5cbc7d3eSVincent Guittot 134*5cbc7d3eSVincent Guittot static int s32g_init_pcie_controller(struct dw_pcie_rp *pp) 135*5cbc7d3eSVincent Guittot { 136*5cbc7d3eSVincent Guittot struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 137*5cbc7d3eSVincent Guittot struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci); 138*5cbc7d3eSVincent Guittot u32 val; 139*5cbc7d3eSVincent Guittot 140*5cbc7d3eSVincent Guittot /* Set RP mode */ 141*5cbc7d3eSVincent Guittot val = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1); 142*5cbc7d3eSVincent Guittot val &= ~DEVICE_TYPE_MASK; 143*5cbc7d3eSVincent Guittot val |= FIELD_PREP(DEVICE_TYPE_MASK, PCI_EXP_TYPE_ROOT_PORT); 144*5cbc7d3eSVincent Guittot 145*5cbc7d3eSVincent Guittot /* Use default CRNS */ 146*5cbc7d3eSVincent Guittot val &= ~SRIS_MODE; 147*5cbc7d3eSVincent Guittot 148*5cbc7d3eSVincent Guittot s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1, val); 149*5cbc7d3eSVincent Guittot 150*5cbc7d3eSVincent Guittot /* 151*5cbc7d3eSVincent Guittot * Make sure we use the coherency defaults (just in case the settings 152*5cbc7d3eSVincent Guittot * have been changed from their reset values) 153*5cbc7d3eSVincent Guittot */ 154*5cbc7d3eSVincent Guittot s32g_pcie_reset_mstr_ace(pci); 155*5cbc7d3eSVincent Guittot 156*5cbc7d3eSVincent Guittot dw_pcie_dbi_ro_wr_en(pci); 157*5cbc7d3eSVincent Guittot 158*5cbc7d3eSVincent Guittot val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE); 159*5cbc7d3eSVincent Guittot val |= PORT_FORCE_DO_DESKEW_FOR_SRIS; 160*5cbc7d3eSVincent Guittot dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val); 161*5cbc7d3eSVincent Guittot 162*5cbc7d3eSVincent Guittot val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); 163*5cbc7d3eSVincent Guittot val |= GEN3_RELATED_OFF_EQ_PHASE_2_3; 164*5cbc7d3eSVincent Guittot dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); 165*5cbc7d3eSVincent Guittot 166*5cbc7d3eSVincent Guittot dw_pcie_dbi_ro_wr_dis(pci); 167*5cbc7d3eSVincent Guittot 168*5cbc7d3eSVincent Guittot return 0; 169*5cbc7d3eSVincent Guittot } 170*5cbc7d3eSVincent Guittot 171*5cbc7d3eSVincent Guittot static const struct dw_pcie_host_ops s32g_pcie_host_ops = { 172*5cbc7d3eSVincent Guittot .init = s32g_init_pcie_controller, 173*5cbc7d3eSVincent Guittot }; 174*5cbc7d3eSVincent Guittot 175*5cbc7d3eSVincent Guittot static int s32g_init_pcie_phy(struct s32g_pcie *s32g_pp) 176*5cbc7d3eSVincent Guittot { 177*5cbc7d3eSVincent Guittot struct dw_pcie *pci = &s32g_pp->pci; 178*5cbc7d3eSVincent Guittot struct device *dev = pci->dev; 179*5cbc7d3eSVincent Guittot struct s32g_pcie_port *port, *tmp; 180*5cbc7d3eSVincent Guittot int ret; 181*5cbc7d3eSVincent Guittot 182*5cbc7d3eSVincent Guittot list_for_each_entry(port, &s32g_pp->ports, list) { 183*5cbc7d3eSVincent Guittot ret = phy_init(port->phy); 184*5cbc7d3eSVincent Guittot if (ret) { 185*5cbc7d3eSVincent Guittot dev_err(dev, "Failed to init serdes PHY\n"); 186*5cbc7d3eSVincent Guittot goto err_phy_revert; 187*5cbc7d3eSVincent Guittot } 188*5cbc7d3eSVincent Guittot 189*5cbc7d3eSVincent Guittot ret = phy_set_mode_ext(port->phy, PHY_MODE_PCIE, 0); 190*5cbc7d3eSVincent Guittot if (ret) { 191*5cbc7d3eSVincent Guittot dev_err(dev, "Failed to set mode on serdes PHY\n"); 192*5cbc7d3eSVincent Guittot goto err_phy_exit; 193*5cbc7d3eSVincent Guittot } 194*5cbc7d3eSVincent Guittot 195*5cbc7d3eSVincent Guittot ret = phy_power_on(port->phy); 196*5cbc7d3eSVincent Guittot if (ret) { 197*5cbc7d3eSVincent Guittot dev_err(dev, "Failed to power on serdes PHY\n"); 198*5cbc7d3eSVincent Guittot goto err_phy_exit; 199*5cbc7d3eSVincent Guittot } 200*5cbc7d3eSVincent Guittot } 201*5cbc7d3eSVincent Guittot 202*5cbc7d3eSVincent Guittot return 0; 203*5cbc7d3eSVincent Guittot 204*5cbc7d3eSVincent Guittot err_phy_exit: 205*5cbc7d3eSVincent Guittot phy_exit(port->phy); 206*5cbc7d3eSVincent Guittot 207*5cbc7d3eSVincent Guittot err_phy_revert: 208*5cbc7d3eSVincent Guittot list_for_each_entry_continue_reverse(port, &s32g_pp->ports, list) { 209*5cbc7d3eSVincent Guittot phy_power_off(port->phy); 210*5cbc7d3eSVincent Guittot phy_exit(port->phy); 211*5cbc7d3eSVincent Guittot } 212*5cbc7d3eSVincent Guittot 213*5cbc7d3eSVincent Guittot list_for_each_entry_safe(port, tmp, &s32g_pp->ports, list) 214*5cbc7d3eSVincent Guittot list_del(&port->list); 215*5cbc7d3eSVincent Guittot 216*5cbc7d3eSVincent Guittot return ret; 217*5cbc7d3eSVincent Guittot } 218*5cbc7d3eSVincent Guittot 219*5cbc7d3eSVincent Guittot static void s32g_deinit_pcie_phy(struct s32g_pcie *s32g_pp) 220*5cbc7d3eSVincent Guittot { 221*5cbc7d3eSVincent Guittot struct s32g_pcie_port *port, *tmp; 222*5cbc7d3eSVincent Guittot 223*5cbc7d3eSVincent Guittot list_for_each_entry_safe(port, tmp, &s32g_pp->ports, list) { 224*5cbc7d3eSVincent Guittot phy_power_off(port->phy); 225*5cbc7d3eSVincent Guittot phy_exit(port->phy); 226*5cbc7d3eSVincent Guittot list_del(&port->list); 227*5cbc7d3eSVincent Guittot } 228*5cbc7d3eSVincent Guittot } 229*5cbc7d3eSVincent Guittot 230*5cbc7d3eSVincent Guittot static int s32g_pcie_init(struct device *dev, struct s32g_pcie *s32g_pp) 231*5cbc7d3eSVincent Guittot { 232*5cbc7d3eSVincent Guittot s32g_pcie_disable_ltssm(s32g_pp); 233*5cbc7d3eSVincent Guittot 234*5cbc7d3eSVincent Guittot return s32g_init_pcie_phy(s32g_pp); 235*5cbc7d3eSVincent Guittot } 236*5cbc7d3eSVincent Guittot 237*5cbc7d3eSVincent Guittot static void s32g_pcie_deinit(struct s32g_pcie *s32g_pp) 238*5cbc7d3eSVincent Guittot { 239*5cbc7d3eSVincent Guittot s32g_pcie_disable_ltssm(s32g_pp); 240*5cbc7d3eSVincent Guittot 241*5cbc7d3eSVincent Guittot s32g_deinit_pcie_phy(s32g_pp); 242*5cbc7d3eSVincent Guittot } 243*5cbc7d3eSVincent Guittot 244*5cbc7d3eSVincent Guittot static int s32g_pcie_parse_port(struct s32g_pcie *s32g_pp, struct device_node *node) 245*5cbc7d3eSVincent Guittot { 246*5cbc7d3eSVincent Guittot struct device *dev = s32g_pp->pci.dev; 247*5cbc7d3eSVincent Guittot struct s32g_pcie_port *port; 248*5cbc7d3eSVincent Guittot int num_lanes; 249*5cbc7d3eSVincent Guittot 250*5cbc7d3eSVincent Guittot port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); 251*5cbc7d3eSVincent Guittot if (!port) 252*5cbc7d3eSVincent Guittot return -ENOMEM; 253*5cbc7d3eSVincent Guittot 254*5cbc7d3eSVincent Guittot port->phy = devm_of_phy_get(dev, node, NULL); 255*5cbc7d3eSVincent Guittot if (IS_ERR(port->phy)) 256*5cbc7d3eSVincent Guittot return dev_err_probe(dev, PTR_ERR(port->phy), 257*5cbc7d3eSVincent Guittot "Failed to get serdes PHY\n"); 258*5cbc7d3eSVincent Guittot 259*5cbc7d3eSVincent Guittot INIT_LIST_HEAD(&port->list); 260*5cbc7d3eSVincent Guittot list_add_tail(&port->list, &s32g_pp->ports); 261*5cbc7d3eSVincent Guittot 262*5cbc7d3eSVincent Guittot /* 263*5cbc7d3eSVincent Guittot * The DWC core initialization code cannot yet parse the num-lanes 264*5cbc7d3eSVincent Guittot * attribute in the Root Port node. The S32G only supports one Root 265*5cbc7d3eSVincent Guittot * Port for now so its driver can parse the node and set the num_lanes 266*5cbc7d3eSVincent Guittot * field of struct dwc_pcie before calling dw_pcie_host_init(). 267*5cbc7d3eSVincent Guittot */ 268*5cbc7d3eSVincent Guittot if (!of_property_read_u32(node, "num-lanes", &num_lanes)) 269*5cbc7d3eSVincent Guittot s32g_pp->pci.num_lanes = num_lanes; 270*5cbc7d3eSVincent Guittot 271*5cbc7d3eSVincent Guittot return 0; 272*5cbc7d3eSVincent Guittot } 273*5cbc7d3eSVincent Guittot 274*5cbc7d3eSVincent Guittot static int s32g_pcie_parse_ports(struct device *dev, struct s32g_pcie *s32g_pp) 275*5cbc7d3eSVincent Guittot { 276*5cbc7d3eSVincent Guittot struct s32g_pcie_port *port, *tmp; 277*5cbc7d3eSVincent Guittot int ret = -ENOENT; 278*5cbc7d3eSVincent Guittot 279*5cbc7d3eSVincent Guittot for_each_available_child_of_node_scoped(dev->of_node, of_port) { 280*5cbc7d3eSVincent Guittot if (!of_node_is_type(of_port, "pci")) 281*5cbc7d3eSVincent Guittot continue; 282*5cbc7d3eSVincent Guittot 283*5cbc7d3eSVincent Guittot ret = s32g_pcie_parse_port(s32g_pp, of_port); 284*5cbc7d3eSVincent Guittot if (ret) 285*5cbc7d3eSVincent Guittot goto err_port; 286*5cbc7d3eSVincent Guittot } 287*5cbc7d3eSVincent Guittot 288*5cbc7d3eSVincent Guittot err_port: 289*5cbc7d3eSVincent Guittot list_for_each_entry_safe(port, tmp, &s32g_pp->ports, list) 290*5cbc7d3eSVincent Guittot list_del(&port->list); 291*5cbc7d3eSVincent Guittot 292*5cbc7d3eSVincent Guittot return ret; 293*5cbc7d3eSVincent Guittot } 294*5cbc7d3eSVincent Guittot 295*5cbc7d3eSVincent Guittot static int s32g_pcie_get_resources(struct platform_device *pdev, 296*5cbc7d3eSVincent Guittot struct s32g_pcie *s32g_pp) 297*5cbc7d3eSVincent Guittot { 298*5cbc7d3eSVincent Guittot struct dw_pcie *pci = &s32g_pp->pci; 299*5cbc7d3eSVincent Guittot struct device *dev = &pdev->dev; 300*5cbc7d3eSVincent Guittot int ret; 301*5cbc7d3eSVincent Guittot 302*5cbc7d3eSVincent Guittot pci->dev = dev; 303*5cbc7d3eSVincent Guittot pci->ops = &s32g_pcie_ops; 304*5cbc7d3eSVincent Guittot 305*5cbc7d3eSVincent Guittot s32g_pp->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "ctrl"); 306*5cbc7d3eSVincent Guittot if (IS_ERR(s32g_pp->ctrl_base)) 307*5cbc7d3eSVincent Guittot return PTR_ERR(s32g_pp->ctrl_base); 308*5cbc7d3eSVincent Guittot 309*5cbc7d3eSVincent Guittot INIT_LIST_HEAD(&s32g_pp->ports); 310*5cbc7d3eSVincent Guittot 311*5cbc7d3eSVincent Guittot ret = s32g_pcie_parse_ports(dev, s32g_pp); 312*5cbc7d3eSVincent Guittot if (ret) 313*5cbc7d3eSVincent Guittot return dev_err_probe(dev, ret, 314*5cbc7d3eSVincent Guittot "Failed to parse Root Port: %d\n", ret); 315*5cbc7d3eSVincent Guittot 316*5cbc7d3eSVincent Guittot platform_set_drvdata(pdev, s32g_pp); 317*5cbc7d3eSVincent Guittot 318*5cbc7d3eSVincent Guittot return 0; 319*5cbc7d3eSVincent Guittot } 320*5cbc7d3eSVincent Guittot 321*5cbc7d3eSVincent Guittot static int s32g_pcie_probe(struct platform_device *pdev) 322*5cbc7d3eSVincent Guittot { 323*5cbc7d3eSVincent Guittot struct device *dev = &pdev->dev; 324*5cbc7d3eSVincent Guittot struct s32g_pcie *s32g_pp; 325*5cbc7d3eSVincent Guittot struct dw_pcie_rp *pp; 326*5cbc7d3eSVincent Guittot int ret; 327*5cbc7d3eSVincent Guittot 328*5cbc7d3eSVincent Guittot s32g_pp = devm_kzalloc(dev, sizeof(*s32g_pp), GFP_KERNEL); 329*5cbc7d3eSVincent Guittot if (!s32g_pp) 330*5cbc7d3eSVincent Guittot return -ENOMEM; 331*5cbc7d3eSVincent Guittot 332*5cbc7d3eSVincent Guittot ret = s32g_pcie_get_resources(pdev, s32g_pp); 333*5cbc7d3eSVincent Guittot if (ret) 334*5cbc7d3eSVincent Guittot return ret; 335*5cbc7d3eSVincent Guittot 336*5cbc7d3eSVincent Guittot pm_runtime_no_callbacks(dev); 337*5cbc7d3eSVincent Guittot devm_pm_runtime_enable(dev); 338*5cbc7d3eSVincent Guittot ret = pm_runtime_get_sync(dev); 339*5cbc7d3eSVincent Guittot if (ret < 0) 340*5cbc7d3eSVincent Guittot goto err_pm_runtime_put; 341*5cbc7d3eSVincent Guittot 342*5cbc7d3eSVincent Guittot ret = s32g_pcie_init(dev, s32g_pp); 343*5cbc7d3eSVincent Guittot if (ret) 344*5cbc7d3eSVincent Guittot goto err_pm_runtime_put; 345*5cbc7d3eSVincent Guittot 346*5cbc7d3eSVincent Guittot pp = &s32g_pp->pci.pp; 347*5cbc7d3eSVincent Guittot pp->ops = &s32g_pcie_host_ops; 348*5cbc7d3eSVincent Guittot pp->use_atu_msg = true; 349*5cbc7d3eSVincent Guittot 350*5cbc7d3eSVincent Guittot ret = dw_pcie_host_init(pp); 351*5cbc7d3eSVincent Guittot if (ret) 352*5cbc7d3eSVincent Guittot goto err_pcie_deinit; 353*5cbc7d3eSVincent Guittot 354*5cbc7d3eSVincent Guittot return 0; 355*5cbc7d3eSVincent Guittot 356*5cbc7d3eSVincent Guittot err_pcie_deinit: 357*5cbc7d3eSVincent Guittot s32g_pcie_deinit(s32g_pp); 358*5cbc7d3eSVincent Guittot err_pm_runtime_put: 359*5cbc7d3eSVincent Guittot pm_runtime_put(dev); 360*5cbc7d3eSVincent Guittot 361*5cbc7d3eSVincent Guittot return ret; 362*5cbc7d3eSVincent Guittot } 363*5cbc7d3eSVincent Guittot 364*5cbc7d3eSVincent Guittot static int s32g_pcie_suspend_noirq(struct device *dev) 365*5cbc7d3eSVincent Guittot { 366*5cbc7d3eSVincent Guittot struct s32g_pcie *s32g_pp = dev_get_drvdata(dev); 367*5cbc7d3eSVincent Guittot struct dw_pcie *pci = &s32g_pp->pci; 368*5cbc7d3eSVincent Guittot 369*5cbc7d3eSVincent Guittot return dw_pcie_suspend_noirq(pci); 370*5cbc7d3eSVincent Guittot } 371*5cbc7d3eSVincent Guittot 372*5cbc7d3eSVincent Guittot static int s32g_pcie_resume_noirq(struct device *dev) 373*5cbc7d3eSVincent Guittot { 374*5cbc7d3eSVincent Guittot struct s32g_pcie *s32g_pp = dev_get_drvdata(dev); 375*5cbc7d3eSVincent Guittot struct dw_pcie *pci = &s32g_pp->pci; 376*5cbc7d3eSVincent Guittot 377*5cbc7d3eSVincent Guittot return dw_pcie_resume_noirq(pci); 378*5cbc7d3eSVincent Guittot } 379*5cbc7d3eSVincent Guittot 380*5cbc7d3eSVincent Guittot static const struct dev_pm_ops s32g_pcie_pm_ops = { 381*5cbc7d3eSVincent Guittot NOIRQ_SYSTEM_SLEEP_PM_OPS(s32g_pcie_suspend_noirq, 382*5cbc7d3eSVincent Guittot s32g_pcie_resume_noirq) 383*5cbc7d3eSVincent Guittot }; 384*5cbc7d3eSVincent Guittot 385*5cbc7d3eSVincent Guittot static const struct of_device_id s32g_pcie_of_match[] = { 386*5cbc7d3eSVincent Guittot { .compatible = "nxp,s32g2-pcie" }, 387*5cbc7d3eSVincent Guittot { /* sentinel */ }, 388*5cbc7d3eSVincent Guittot }; 389*5cbc7d3eSVincent Guittot MODULE_DEVICE_TABLE(of, s32g_pcie_of_match); 390*5cbc7d3eSVincent Guittot 391*5cbc7d3eSVincent Guittot static struct platform_driver s32g_pcie_driver = { 392*5cbc7d3eSVincent Guittot .driver = { 393*5cbc7d3eSVincent Guittot .name = "s32g-pcie", 394*5cbc7d3eSVincent Guittot .of_match_table = s32g_pcie_of_match, 395*5cbc7d3eSVincent Guittot .suppress_bind_attrs = true, 396*5cbc7d3eSVincent Guittot .pm = pm_sleep_ptr(&s32g_pcie_pm_ops), 397*5cbc7d3eSVincent Guittot .probe_type = PROBE_PREFER_ASYNCHRONOUS, 398*5cbc7d3eSVincent Guittot }, 399*5cbc7d3eSVincent Guittot .probe = s32g_pcie_probe, 400*5cbc7d3eSVincent Guittot }; 401*5cbc7d3eSVincent Guittot 402*5cbc7d3eSVincent Guittot builtin_platform_driver(s32g_pcie_driver); 403*5cbc7d3eSVincent Guittot 404*5cbc7d3eSVincent Guittot MODULE_AUTHOR("Ionut Vicovan <Ionut.Vicovan@nxp.com>"); 405*5cbc7d3eSVincent Guittot MODULE_DESCRIPTION("NXP S32G PCIe Host controller driver"); 406*5cbc7d3eSVincent Guittot MODULE_LICENSE("GPL"); 407