| @@ -0,0 +1,545 @@ |
| | 1 | // SPDX-License-Identifier: GPL-2.0 |
| | 2 | /* |
| | 3 | * PCIe host controller driver for Intel Gateway SoCs |
| | 4 | * |
| | 5 | * Copyright (c) 2019 Intel Corporation. |
| | 6 | */ |
| | 7 | |
| | 8 | #include <linux/bitfield.h> |
| | 9 | #include <linux/clk.h> |
| | 10 | #include <linux/gpio/consumer.h> |
| | 11 | #include <linux/iopoll.h> |
| | 12 | #include <linux/pci_regs.h> |
| | 13 | #include <linux/phy/phy.h> |
| | 14 | #include <linux/platform_device.h> |
| | 15 | #include <linux/reset.h> |
| | 16 | |
| | 17 | #include "../../pci.h" |
| | 18 | #include "pcie-designware.h" |
| | 19 | |
| | 20 | #define PORT_AFR_N_FTS_GEN12_DFT (SZ_128 - 1) |
| | 21 | #define PORT_AFR_N_FTS_GEN3 180 |
| | 22 | #define PORT_AFR_N_FTS_GEN4 196 |
| | 23 | |
| | 24 | /* PCIe Application logic Registers */ |
| | 25 | #define PCIE_APP_CCR 0x10 |
| | 26 | #define PCIE_APP_CCR_LTSSM_ENABLE BIT(0) |
| | 27 | |
| | 28 | #define PCIE_APP_MSG_CR 0x30 |
| | 29 | #define PCIE_APP_MSG_XMT_PM_TURNOFF BIT(0) |
| | 30 | |
| | 31 | #define PCIE_APP_PMC 0x44 |
| | 32 | #define PCIE_APP_PMC_IN_L2 BIT(20) |
| | 33 | |
| | 34 | #define PCIE_APP_IRNEN 0xF4 |
| | 35 | #define PCIE_APP_IRNCR 0xF8 |
| | 36 | #define PCIE_APP_IRN_AER_REPORT BIT(0) |
| | 37 | #define PCIE_APP_IRN_PME BIT(2) |
| | 38 | #define PCIE_APP_IRN_RX_VDM_MSG BIT(4) |
| | 39 | #define PCIE_APP_IRN_PM_TO_ACK BIT(9) |
| | 40 | #define PCIE_APP_IRN_LINK_AUTO_BW_STAT BIT(11) |
| | 41 | #define PCIE_APP_IRN_BW_MGT BIT(12) |
| | 42 | #define PCIE_APP_IRN_MSG_LTR BIT(18) |
| | 43 | #define PCIE_APP_IRN_SYS_ERR_RC BIT(29) |
| | 44 | #define PCIE_APP_INTX_OFST 12 |
| | 45 | |
| | 46 | #define PCIE_APP_IRN_INT \ |
| | 47 | (PCIE_APP_IRN_AER_REPORT | PCIE_APP_IRN_PME | \ |
| | 48 | PCIE_APP_IRN_RX_VDM_MSG | PCIE_APP_IRN_SYS_ERR_RC | \ |
| | 49 | PCIE_APP_IRN_PM_TO_ACK | PCIE_APP_IRN_MSG_LTR | \ |
| | 50 | PCIE_APP_IRN_BW_MGT | PCIE_APP_IRN_LINK_AUTO_BW_STAT | \ |
| | 51 | (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTA) | \ |
| | 52 | (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTB) | \ |
| | 53 | (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTC) | \ |
| | 54 | (PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTD)) |
| | 55 | |
| | 56 | #define BUS_IATU_OFFSET SZ_256M |
| | 57 | #define RESET_INTERVAL_MS 100 |
| | 58 | |
| | 59 | struct intel_pcie_soc { |
| | 60 | unsigned int pcie_ver; |
| | 61 | unsigned int pcie_atu_offset; |
| | 62 | u32 num_viewport; |
| | 63 | }; |
| | 64 | |
| | 65 | struct intel_pcie_port { |
| | 66 | struct dw_pcie pci; |
| | 67 | void __iomem *app_base; |
| | 68 | struct gpio_desc *reset_gpio; |
| | 69 | u32 rst_intrvl; |
| | 70 | u32 max_speed; |
| | 71 | u32 link_gen; |
| | 72 | u32 max_width; |
| | 73 | u32 n_fts; |
| | 74 | struct clk *core_clk; |
| | 75 | struct reset_control *core_rst; |
| | 76 | struct phy *phy; |
| | 77 | u8 pcie_cap_ofst; |
| | 78 | }; |
| | 79 | |
| | 80 | static void pcie_update_bits(void __iomem *base, u32 ofs, u32 mask, u32 val) |
| | 81 | { |
| | 82 | u32 old; |
| | 83 | |
| | 84 | old = readl(base + ofs); |
| | 85 | val = (old & ~mask) | (val & mask); |
| | 86 | |
| | 87 | if (val != old) |
| | 88 | writel(val, base + ofs); |
| | 89 | } |
| | 90 | |
| | 91 | static inline u32 pcie_app_rd(struct intel_pcie_port *lpp, u32 ofs) |
| | 92 | { |
| | 93 | return readl(lpp->app_base + ofs); |
| | 94 | } |
| | 95 | |
| | 96 | static inline void pcie_app_wr(struct intel_pcie_port *lpp, u32 ofs, u32 val) |
| | 97 | { |
| | 98 | writel(val, lpp->app_base + ofs); |
| | 99 | } |
| | 100 | |
| | 101 | static void pcie_app_wr_mask(struct intel_pcie_port *lpp, u32 ofs, |
| | 102 | u32 mask, u32 val) |
| | 103 | { |
| | 104 | pcie_update_bits(lpp->app_base, ofs, mask, val); |
| | 105 | } |
| | 106 | |
| | 107 | static inline u32 pcie_rc_cfg_rd(struct intel_pcie_port *lpp, u32 ofs) |
| | 108 | { |
| | 109 | return dw_pcie_readl_dbi(&lpp->pci, ofs); |
| | 110 | } |
| | 111 | |
| | 112 | static inline void pcie_rc_cfg_wr(struct intel_pcie_port *lpp, u32 ofs, u32 val) |
| | 113 | { |
| | 114 | dw_pcie_writel_dbi(&lpp->pci, ofs, val); |
| | 115 | } |
| | 116 | |
| | 117 | static void pcie_rc_cfg_wr_mask(struct intel_pcie_port *lpp, u32 ofs, |
| | 118 | u32 mask, u32 val) |
| | 119 | { |
| | 120 | pcie_update_bits(lpp->pci.dbi_base, ofs, mask, val); |
| | 121 | } |
| | 122 | |
| | 123 | static void intel_pcie_ltssm_enable(struct intel_pcie_port *lpp) |
| | 124 | { |
| | 125 | pcie_app_wr_mask(lpp, PCIE_APP_CCR, PCIE_APP_CCR_LTSSM_ENABLE, |
| | 126 | PCIE_APP_CCR_LTSSM_ENABLE); |
| | 127 | } |
| | 128 | |
| | 129 | static void intel_pcie_ltssm_disable(struct intel_pcie_port *lpp) |
| | 130 | { |
| | 131 | pcie_app_wr_mask(lpp, PCIE_APP_CCR, PCIE_APP_CCR_LTSSM_ENABLE, 0); |
| | 132 | } |
| | 133 | |
| | 134 | static void intel_pcie_link_setup(struct intel_pcie_port *lpp) |
| | 135 | { |
| | 136 | u32 val; |
| | 137 | u8 offset = lpp->pcie_cap_ofst; |
| | 138 | |
| | 139 | val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCAP); |
| | 140 | lpp->max_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, val); |
| | 141 | lpp->max_width = FIELD_GET(PCI_EXP_LNKCAP_MLW, val); |
| | 142 | |
| | 143 | val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCTL); |
| | 144 | |
| | 145 | val &= ~(PCI_EXP_LNKCTL_LD | PCI_EXP_LNKCTL_ASPMC); |
| | 146 | pcie_rc_cfg_wr(lpp, offset + PCI_EXP_LNKCTL, val); |
| | 147 | } |
| | 148 | |
| | 149 | static void intel_pcie_port_logic_setup(struct intel_pcie_port *lpp) |
| | 150 | { |
| | 151 | u32 val, mask; |
| | 152 | |
| | 153 | switch (pcie_link_speed[lpp->max_speed]) { |
| | 154 | case PCIE_SPEED_8_0GT: |
| | 155 | lpp->n_fts = PORT_AFR_N_FTS_GEN3; |
| | 156 | break; |
| | 157 | case PCIE_SPEED_16_0GT: |
| | 158 | lpp->n_fts = PORT_AFR_N_FTS_GEN4; |
| | 159 | break; |
| | 160 | default: |
| | 161 | lpp->n_fts = PORT_AFR_N_FTS_GEN12_DFT; |
| | 162 | break; |
| | 163 | } |
| | 164 | |
| | 165 | mask = PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK; |
| | 166 | val = FIELD_PREP(PORT_AFR_N_FTS_MASK, lpp->n_fts) | |
| | 167 | FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, lpp->n_fts); |
| | 168 | pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_AFR, mask, val); |
| | 169 | |
| | 170 | /* Port Link Control Register */ |
| | 171 | pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_LINK_CONTROL, PORT_LINK_DLL_LINK_EN, |
| | 172 | PORT_LINK_DLL_LINK_EN); |
| | 173 | } |
| | 174 | |
| | 175 | static void intel_pcie_rc_setup(struct intel_pcie_port *lpp) |
| | 176 | { |
| | 177 | intel_pcie_ltssm_disable(lpp); |
| | 178 | intel_pcie_link_setup(lpp); |
| | 179 | dw_pcie_setup_rc(&lpp->pci.pp); |
| | 180 | dw_pcie_upconfig_setup(&lpp->pci); |
| | 181 | intel_pcie_port_logic_setup(lpp); |
| | 182 | dw_pcie_link_set_max_speed(&lpp->pci, lpp->link_gen); |
| | 183 | dw_pcie_link_set_n_fts(&lpp->pci, lpp->n_fts); |
| | 184 | } |
| | 185 | |
| | 186 | static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp) |
| | 187 | { |
| | 188 | struct device *dev = lpp->pci.dev; |
| | 189 | int ret; |
| | 190 | |
| | 191 | lpp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
| | 192 | if (IS_ERR(lpp->reset_gpio)) { |
| | 193 | ret = PTR_ERR(lpp->reset_gpio); |
| | 194 | if (ret != -EPROBE_DEFER) |
| | 195 | dev_err(dev, "Failed to request PCIe GPIO: %d\n", ret); |
| | 196 | return ret; |
| | 197 | } |
| | 198 | |
| | 199 | /* Make initial reset last for 100us */ |
| | 200 | usleep_range(100, 200); |
| | 201 | |
| | 202 | return 0; |
| | 203 | } |
| | 204 | |
| | 205 | static void intel_pcie_core_rst_assert(struct intel_pcie_port *lpp) |
| | 206 | { |
| | 207 | reset_control_assert(lpp->core_rst); |
| | 208 | } |
| | 209 | |
| | 210 | static void intel_pcie_core_rst_deassert(struct intel_pcie_port *lpp) |
| | 211 | { |
| | 212 | /* |
| | 213 | * One micro-second delay to make sure the reset pulse |
| | 214 | * wide enough so that core reset is clean. |
| | 215 | */ |
| | 216 | udelay(1); |
| | 217 | reset_control_deassert(lpp->core_rst); |
| | 218 | |
| | 219 | /* |
| | 220 | * Some SoC core reset also reset PHY, more delay needed |
| | 221 | * to make sure the reset process is done. |
| | 222 | */ |
| | 223 | usleep_range(1000, 2000); |
| | 224 | } |
| | 225 | |
| | 226 | static void intel_pcie_device_rst_assert(struct intel_pcie_port *lpp) |
| | 227 | { |
| | 228 | gpiod_set_value_cansleep(lpp->reset_gpio, 1); |
| | 229 | } |
| | 230 | |
| | 231 | static void intel_pcie_device_rst_deassert(struct intel_pcie_port *lpp) |
| | 232 | { |
| | 233 | msleep(lpp->rst_intrvl); |
| | 234 | gpiod_set_value_cansleep(lpp->reset_gpio, 0); |
| | 235 | } |
| | 236 | |
| | 237 | static int intel_pcie_app_logic_setup(struct intel_pcie_port *lpp) |
| | 238 | { |
| | 239 | intel_pcie_device_rst_deassert(lpp); |
| | 240 | intel_pcie_ltssm_enable(lpp); |
| | 241 | |
| | 242 | return dw_pcie_wait_for_link(&lpp->pci); |
| | 243 | } |
| | 244 | |
| | 245 | static void intel_pcie_core_irq_disable(struct intel_pcie_port *lpp) |
| | 246 | { |
| | 247 | pcie_app_wr(lpp, PCIE_APP_IRNEN, 0); |
| | 248 | pcie_app_wr(lpp, PCIE_APP_IRNCR, PCIE_APP_IRN_INT); |
| | 249 | } |
| | 250 | |
| | 251 | static int intel_pcie_get_resources(struct platform_device *pdev) |
| | 252 | { |
| | 253 | struct intel_pcie_port *lpp = platform_get_drvdata(pdev); |
| | 254 | struct dw_pcie *pci = &lpp->pci; |
| | 255 | struct device *dev = pci->dev; |
| | 256 | struct resource *res; |
| | 257 | int ret; |
| | 258 | |
| | 259 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); |
| | 260 | pci->dbi_base = devm_ioremap_resource(dev, res); |
| | 261 | if (IS_ERR(pci->dbi_base)) |
| | 262 | return PTR_ERR(pci->dbi_base); |
| | 263 | |
| | 264 | lpp->core_clk = devm_clk_get(dev, NULL); |
| | 265 | if (IS_ERR(lpp->core_clk)) { |
| | 266 | ret = PTR_ERR(lpp->core_clk); |
| | 267 | if (ret != -EPROBE_DEFER) |
| | 268 | dev_err(dev, "Failed to get clks: %d\n", ret); |
| | 269 | return ret; |
| | 270 | } |
| | 271 | |
| | 272 | lpp->core_rst = devm_reset_control_get(dev, NULL); |
| | 273 | if (IS_ERR(lpp->core_rst)) { |
| | 274 | ret = PTR_ERR(lpp->core_rst); |
| | 275 | if (ret != -EPROBE_DEFER) |
| | 276 | dev_err(dev, "Failed to get resets: %d\n", ret); |
| | 277 | return ret; |
| | 278 | } |
| | 279 | |
| | 280 | ret = device_property_match_string(dev, "device_type", "pci"); |
| | 281 | if (ret) { |
| | 282 | dev_err(dev, "Failed to find pci device type: %d\n", ret); |
| | 283 | return ret; |
| | 284 | } |
| | 285 | |
| | 286 | ret = device_property_read_u32(dev, "reset-assert-ms", |
| | 287 | &lpp->rst_intrvl); |
| | 288 | if (ret) |
| | 289 | lpp->rst_intrvl = RESET_INTERVAL_MS; |
| | 290 | |
| | 291 | ret = of_pci_get_max_link_speed(dev->of_node); |
| | 292 | lpp->link_gen = ret < 0 ? 0 : ret; |
| | 293 | |
| | 294 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "app"); |
| | 295 | lpp->app_base = devm_ioremap_resource(dev, res); |
| | 296 | if (IS_ERR(lpp->app_base)) |
| | 297 | return PTR_ERR(lpp->app_base); |
| | 298 | |
| | 299 | lpp->phy = devm_phy_get(dev, "pcie"); |
| | 300 | if (IS_ERR(lpp->phy)) { |
| | 301 | ret = PTR_ERR(lpp->phy); |
| | 302 | if (ret != -EPROBE_DEFER) |
| | 303 | dev_err(dev, "Couldn't get pcie-phy: %d\n", ret); |
| | 304 | return ret; |
| | 305 | } |
| | 306 | |
| | 307 | return 0; |
| | 308 | } |
| | 309 | |
| | 310 | static void intel_pcie_deinit_phy(struct intel_pcie_port *lpp) |
| | 311 | { |
| | 312 | phy_exit(lpp->phy); |
| | 313 | } |
| | 314 | |
| | 315 | static int intel_pcie_wait_l2(struct intel_pcie_port *lpp) |
| | 316 | { |
| | 317 | u32 value; |
| | 318 | int ret; |
| | 319 | |
| | 320 | if (pcie_link_speed[lpp->max_speed] < PCIE_SPEED_8_0GT) |
| | 321 | return 0; |
| | 322 | |
| | 323 | /* Send PME_TURN_OFF message */ |
| | 324 | pcie_app_wr_mask(lpp, PCIE_APP_MSG_CR, PCIE_APP_MSG_XMT_PM_TURNOFF, |
| | 325 | PCIE_APP_MSG_XMT_PM_TURNOFF); |
| | 326 | |
| | 327 | /* Read PMC status and wait for falling into L2 link state */ |
| | 328 | ret = readl_poll_timeout(lpp->app_base + PCIE_APP_PMC, value, |
| | 329 | value & PCIE_APP_PMC_IN_L2, 20, |
| | 330 | jiffies_to_usecs(5 * HZ)); |
| | 331 | if (ret) |
| | 332 | dev_err(lpp->pci.dev, "PCIe link enter L2 timeout!\n"); |
| | 333 | |
| | 334 | return ret; |
| | 335 | } |
| | 336 | |
| | 337 | static void intel_pcie_turn_off(struct intel_pcie_port *lpp) |
| | 338 | { |
| | 339 | if (dw_pcie_link_up(&lpp->pci)) |
| | 340 | intel_pcie_wait_l2(lpp); |
| | 341 | |
| | 342 | /* Put endpoint device in reset state */ |
| | 343 | intel_pcie_device_rst_assert(lpp); |
| | 344 | pcie_rc_cfg_wr_mask(lpp, PCI_COMMAND, PCI_COMMAND_MEMORY, 0); |
| | 345 | } |
| | 346 | |
| | 347 | static int intel_pcie_host_setup(struct intel_pcie_port *lpp) |
| | 348 | { |
| | 349 | struct device *dev = lpp->pci.dev; |
| | 350 | int ret; |
| | 351 | |
| | 352 | intel_pcie_core_rst_assert(lpp); |
| | 353 | intel_pcie_device_rst_assert(lpp); |
| | 354 | |
| | 355 | ret = phy_init(lpp->phy); |
| | 356 | if (ret) |
| | 357 | return ret; |
| | 358 | |
| | 359 | intel_pcie_core_rst_deassert(lpp); |
| | 360 | |
| | 361 | ret = clk_prepare_enable(lpp->core_clk); |
| | 362 | if (ret) { |
| | 363 | dev_err(lpp->pci.dev, "Core clock enable failed: %d\n", ret); |
| | 364 | goto clk_err; |
| | 365 | } |
| | 366 | |
| | 367 | if (!lpp->pcie_cap_ofst) { |
| | 368 | ret = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP); |
| | 369 | if (!ret) { |
| | 370 | ret = -ENXIO; |
| | 371 | dev_err(dev, "Invalid PCIe capability offset\n"); |
| | 372 | goto app_init_err; |
| | 373 | } |
| | 374 | |
| | 375 | lpp->pcie_cap_ofst = ret; |
| | 376 | } |
| | 377 | |
| | 378 | intel_pcie_rc_setup(lpp); |
| | 379 | ret = intel_pcie_app_logic_setup(lpp); |
| | 380 | if (ret) |
| | 381 | goto app_init_err; |
| | 382 | |
| | 383 | /* Enable integrated interrupts */ |
| | 384 | pcie_app_wr_mask(lpp, PCIE_APP_IRNEN, PCIE_APP_IRN_INT, |
| | 385 | PCIE_APP_IRN_INT); |
| | 386 | |
| | 387 | return 0; |
| | 388 | |
| | 389 | app_init_err: |
| | 390 | clk_disable_unprepare(lpp->core_clk); |
| | 391 | clk_err: |
| | 392 | intel_pcie_core_rst_assert(lpp); |
| | 393 | intel_pcie_deinit_phy(lpp); |
| | 394 | |
| | 395 | return ret; |
| | 396 | } |
| | 397 | |
| | 398 | static void __intel_pcie_remove(struct intel_pcie_port *lpp) |
| | 399 | { |
| | 400 | intel_pcie_core_irq_disable(lpp); |
| | 401 | intel_pcie_turn_off(lpp); |
| | 402 | clk_disable_unprepare(lpp->core_clk); |
| | 403 | intel_pcie_core_rst_assert(lpp); |
| | 404 | intel_pcie_deinit_phy(lpp); |
| | 405 | } |
| | 406 | |
| | 407 | static int intel_pcie_remove(struct platform_device *pdev) |
| | 408 | { |
| | 409 | struct intel_pcie_port *lpp = platform_get_drvdata(pdev); |
| | 410 | struct pcie_port *pp = &lpp->pci.pp; |
| | 411 | |
| | 412 | dw_pcie_host_deinit(pp); |
| | 413 | __intel_pcie_remove(lpp); |
| | 414 | |
| | 415 | return 0; |
| | 416 | } |
| | 417 | |
| | 418 | static int __maybe_unused intel_pcie_suspend_noirq(struct device *dev) |
| | 419 | { |
| | 420 | struct intel_pcie_port *lpp = dev_get_drvdata(dev); |
| | 421 | int ret; |
| | 422 | |
| | 423 | intel_pcie_core_irq_disable(lpp); |
| | 424 | ret = intel_pcie_wait_l2(lpp); |
| | 425 | if (ret) |
| | 426 | return ret; |
| | 427 | |
| | 428 | intel_pcie_deinit_phy(lpp); |
| | 429 | clk_disable_unprepare(lpp->core_clk); |
| | 430 | return ret; |
| | 431 | } |
| | 432 | |
| | 433 | static int __maybe_unused intel_pcie_resume_noirq(struct device *dev) |
| | 434 | { |
| | 435 | struct intel_pcie_port *lpp = dev_get_drvdata(dev); |
| | 436 | |
| | 437 | return intel_pcie_host_setup(lpp); |
| | 438 | } |
| | 439 | |
| | 440 | static int intel_pcie_rc_init(struct pcie_port *pp) |
| | 441 | { |
| | 442 | struct dw_pcie *pci = to_dw_pcie_from_pp(pp); |
| | 443 | struct intel_pcie_port *lpp = dev_get_drvdata(pci->dev); |
| | 444 | |
| | 445 | return intel_pcie_host_setup(lpp); |
| | 446 | } |
| | 447 | |
| | 448 | /* |
| | 449 | * Dummy function so that DW core doesn't configure MSI |
| | 450 | */ |
| | 451 | static int intel_pcie_msi_init(struct pcie_port *pp) |
| | 452 | { |
| | 453 | return 0; |
| | 454 | } |
| | 455 | |
| | 456 | u64 intel_pcie_cpu_addr(struct dw_pcie *pcie, u64 cpu_addr) |
| | 457 | { |
| | 458 | return cpu_addr + BUS_IATU_OFFSET; |
| | 459 | } |
| | 460 | |
| | 461 | static const struct dw_pcie_ops intel_pcie_ops = { |
| | 462 | .cpu_addr_fixup = intel_pcie_cpu_addr, |
| | 463 | }; |
| | 464 | |
| | 465 | static const struct dw_pcie_host_ops intel_pcie_dw_ops = { |
| | 466 | .host_init = intel_pcie_rc_init, |
| | 467 | .msi_host_init = intel_pcie_msi_init, |
| | 468 | }; |
| | 469 | |
| | 470 | static const struct intel_pcie_soc pcie_data = { |
| | 471 | .pcie_ver = 0x520A, |
| | 472 | .pcie_atu_offset = 0xC0000, |
| | 473 | .num_viewport = 3, |
| | 474 | }; |
| | 475 | |
| | 476 | static int intel_pcie_probe(struct platform_device *pdev) |
| | 477 | { |
| | 478 | const struct intel_pcie_soc *data; |
| | 479 | struct device *dev = &pdev->dev; |
| | 480 | struct intel_pcie_port *lpp; |
| | 481 | struct pcie_port *pp; |
| | 482 | struct dw_pcie *pci; |
| | 483 | int ret; |
| | 484 | |
| | 485 | lpp = devm_kzalloc(dev, sizeof(*lpp), GFP_KERNEL); |
| | 486 | if (!lpp) |
| | 487 | return -ENOMEM; |
| | 488 | |
| | 489 | platform_set_drvdata(pdev, lpp); |
| | 490 | pci = &lpp->pci; |
| | 491 | pci->dev = dev; |
| | 492 | pp = &pci->pp; |
| | 493 | |
| | 494 | ret = intel_pcie_get_resources(pdev); |
| | 495 | if (ret) |
| | 496 | return ret; |
| | 497 | |
| | 498 | ret = intel_pcie_ep_rst_init(lpp); |
| | 499 | if (ret) |
| | 500 | return ret; |
| | 501 | |
| | 502 | data = device_get_match_data(dev); |
| | 503 | if (!data) |
| | 504 | return -ENODEV; |
| | 505 | |
| | 506 | pci->ops = &intel_pcie_ops; |
| | 507 | pci->version = data->pcie_ver; |
| | 508 | pci->atu_base = pci->dbi_base + data->pcie_atu_offset; |
| | 509 | pp->ops = &intel_pcie_dw_ops; |
| | 510 | |
| | 511 | ret = dw_pcie_host_init(pp); |
| | 512 | if (ret) { |
| | 513 | dev_err(dev, "Cannot initialize host\n"); |
| | 514 | return ret; |
| | 515 | } |
| | 516 | |
| | 517 | /* |
| | 518 | * Intel PCIe doesn't configure IO region, so set viewport |
| | 519 | * to not perform IO region access. |
| | 520 | */ |
| | 521 | pci->num_viewport = data->num_viewport; |
| | 522 | |
| | 523 | return 0; |
| | 524 | } |
| | 525 | |
| | 526 | static const struct dev_pm_ops intel_pcie_pm_ops = { |
| | 527 | SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(intel_pcie_suspend_noirq, |
| | 528 | intel_pcie_resume_noirq) |
| | 529 | }; |
| | 530 | |
| | 531 | static const struct of_device_id of_intel_pcie_match[] = { |
| | 532 | { .compatible = "intel,lgm-pcie", .data = &pcie_data }, |
| | 533 | {} |
| | 534 | }; |
| | 535 | |
| | 536 | static struct platform_driver intel_pcie_driver = { |
| | 537 | .probe = intel_pcie_probe, |
| | 538 | .remove = intel_pcie_remove, |
| | 539 | .driver = { |
| | 540 | .name = "intel-gw-pcie", |
| | 541 | .of_match_table = of_intel_pcie_match, |
| | 542 | .pm = &intel_pcie_pm_ops, |
| | 543 | }, |
| | 544 | }; |
| | 545 | builtin_platform_driver(intel_pcie_driver); |