Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.6-rc5 563 lines 13 kB view raw
1/* 2 * pcie-dra7xx - PCIe controller driver for TI DRA7xx SoCs 3 * 4 * Copyright (C) 2013-2014 Texas Instruments Incorporated - http://www.ti.com 5 * 6 * Authors: Kishon Vijay Abraham I <kishon@ti.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13#include <linux/err.h> 14#include <linux/interrupt.h> 15#include <linux/irq.h> 16#include <linux/irqdomain.h> 17#include <linux/kernel.h> 18#include <linux/module.h> 19#include <linux/of_gpio.h> 20#include <linux/pci.h> 21#include <linux/phy/phy.h> 22#include <linux/platform_device.h> 23#include <linux/pm_runtime.h> 24#include <linux/resource.h> 25#include <linux/types.h> 26 27#include "pcie-designware.h" 28 29/* PCIe controller wrapper DRA7XX configuration registers */ 30 31#define PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN 0x0024 32#define PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN 0x0028 33#define ERR_SYS BIT(0) 34#define ERR_FATAL BIT(1) 35#define ERR_NONFATAL BIT(2) 36#define ERR_COR BIT(3) 37#define ERR_AXI BIT(4) 38#define ERR_ECRC BIT(5) 39#define PME_TURN_OFF BIT(8) 40#define PME_TO_ACK BIT(9) 41#define PM_PME BIT(10) 42#define LINK_REQ_RST BIT(11) 43#define LINK_UP_EVT BIT(12) 44#define CFG_BME_EVT BIT(13) 45#define CFG_MSE_EVT BIT(14) 46#define INTERRUPTS (ERR_SYS | ERR_FATAL | ERR_NONFATAL | ERR_COR | ERR_AXI | \ 47 ERR_ECRC | PME_TURN_OFF | PME_TO_ACK | PM_PME | \ 48 LINK_REQ_RST | LINK_UP_EVT | CFG_BME_EVT | CFG_MSE_EVT) 49 50#define PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI 0x0034 51#define PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI 0x0038 52#define INTA BIT(0) 53#define INTB BIT(1) 54#define INTC BIT(2) 55#define INTD BIT(3) 56#define MSI BIT(4) 57#define LEG_EP_INTERRUPTS (INTA | INTB | INTC | INTD) 58 59#define PCIECTRL_DRA7XX_CONF_DEVICE_CMD 0x0104 60#define LTSSM_EN 0x1 61 62#define PCIECTRL_DRA7XX_CONF_PHY_CS 0x010C 63#define LINK_UP BIT(16) 64#define DRA7XX_CPU_TO_BUS_ADDR 0x0FFFFFFF 65 66struct dra7xx_pcie { 67 void __iomem *base; 68 struct phy **phy; 69 int phy_count; 70 struct device *dev; 71 struct pcie_port pp; 72}; 73 74#define to_dra7xx_pcie(x) container_of((x), struct dra7xx_pcie, pp) 75 76static inline u32 dra7xx_pcie_readl(struct dra7xx_pcie *pcie, u32 offset) 77{ 78 return readl(pcie->base + offset); 79} 80 81static inline void dra7xx_pcie_writel(struct dra7xx_pcie *pcie, u32 offset, 82 u32 value) 83{ 84 writel(value, pcie->base + offset); 85} 86 87static inline u32 dra7xx_pcie_readl_rc(struct pcie_port *pp, u32 offset) 88{ 89 return readl(pp->dbi_base + offset); 90} 91 92static inline void dra7xx_pcie_writel_rc(struct pcie_port *pp, u32 offset, 93 u32 value) 94{ 95 writel(value, pp->dbi_base + offset); 96} 97 98static int dra7xx_pcie_link_up(struct pcie_port *pp) 99{ 100 struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); 101 u32 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS); 102 103 return !!(reg & LINK_UP); 104} 105 106static int dra7xx_pcie_establish_link(struct pcie_port *pp) 107{ 108 struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); 109 u32 reg; 110 111 if (dw_pcie_link_up(pp)) { 112 dev_err(pp->dev, "link is already up\n"); 113 return 0; 114 } 115 116 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD); 117 reg |= LTSSM_EN; 118 dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); 119 120 return dw_pcie_wait_for_link(pp); 121} 122 123static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp) 124{ 125 struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); 126 127 dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, 128 ~INTERRUPTS); 129 dra7xx_pcie_writel(dra7xx, 130 PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN, INTERRUPTS); 131 dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, 132 ~LEG_EP_INTERRUPTS & ~MSI); 133 134 if (IS_ENABLED(CONFIG_PCI_MSI)) 135 dra7xx_pcie_writel(dra7xx, 136 PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI, MSI); 137 else 138 dra7xx_pcie_writel(dra7xx, 139 PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI, 140 LEG_EP_INTERRUPTS); 141} 142 143static void dra7xx_pcie_host_init(struct pcie_port *pp) 144{ 145 dw_pcie_setup_rc(pp); 146 147 pp->io_base &= DRA7XX_CPU_TO_BUS_ADDR; 148 pp->mem_base &= DRA7XX_CPU_TO_BUS_ADDR; 149 pp->cfg0_base &= DRA7XX_CPU_TO_BUS_ADDR; 150 pp->cfg1_base &= DRA7XX_CPU_TO_BUS_ADDR; 151 152 dra7xx_pcie_establish_link(pp); 153 if (IS_ENABLED(CONFIG_PCI_MSI)) 154 dw_pcie_msi_init(pp); 155 dra7xx_pcie_enable_interrupts(pp); 156} 157 158static struct pcie_host_ops dra7xx_pcie_host_ops = { 159 .link_up = dra7xx_pcie_link_up, 160 .host_init = dra7xx_pcie_host_init, 161}; 162 163static int dra7xx_pcie_intx_map(struct irq_domain *domain, unsigned int irq, 164 irq_hw_number_t hwirq) 165{ 166 irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); 167 irq_set_chip_data(irq, domain->host_data); 168 169 return 0; 170} 171 172static const struct irq_domain_ops intx_domain_ops = { 173 .map = dra7xx_pcie_intx_map, 174}; 175 176static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp) 177{ 178 struct device *dev = pp->dev; 179 struct device_node *node = dev->of_node; 180 struct device_node *pcie_intc_node = of_get_next_child(node, NULL); 181 182 if (!pcie_intc_node) { 183 dev_err(dev, "No PCIe Intc node found\n"); 184 return PTR_ERR(pcie_intc_node); 185 } 186 187 pp->irq_domain = irq_domain_add_linear(pcie_intc_node, 4, 188 &intx_domain_ops, pp); 189 if (!pp->irq_domain) { 190 dev_err(dev, "Failed to get a INTx IRQ domain\n"); 191 return PTR_ERR(pp->irq_domain); 192 } 193 194 return 0; 195} 196 197static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg) 198{ 199 struct pcie_port *pp = arg; 200 struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); 201 u32 reg; 202 203 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI); 204 205 switch (reg) { 206 case MSI: 207 dw_handle_msi_irq(pp); 208 break; 209 case INTA: 210 case INTB: 211 case INTC: 212 case INTD: 213 generic_handle_irq(irq_find_mapping(pp->irq_domain, ffs(reg))); 214 break; 215 } 216 217 dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, reg); 218 219 return IRQ_HANDLED; 220} 221 222 223static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg) 224{ 225 struct dra7xx_pcie *dra7xx = arg; 226 u32 reg; 227 228 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN); 229 230 if (reg & ERR_SYS) 231 dev_dbg(dra7xx->dev, "System Error\n"); 232 233 if (reg & ERR_FATAL) 234 dev_dbg(dra7xx->dev, "Fatal Error\n"); 235 236 if (reg & ERR_NONFATAL) 237 dev_dbg(dra7xx->dev, "Non Fatal Error\n"); 238 239 if (reg & ERR_COR) 240 dev_dbg(dra7xx->dev, "Correctable Error\n"); 241 242 if (reg & ERR_AXI) 243 dev_dbg(dra7xx->dev, "AXI tag lookup fatal Error\n"); 244 245 if (reg & ERR_ECRC) 246 dev_dbg(dra7xx->dev, "ECRC Error\n"); 247 248 if (reg & PME_TURN_OFF) 249 dev_dbg(dra7xx->dev, 250 "Power Management Event Turn-Off message received\n"); 251 252 if (reg & PME_TO_ACK) 253 dev_dbg(dra7xx->dev, 254 "Power Management Turn-Off Ack message received\n"); 255 256 if (reg & PM_PME) 257 dev_dbg(dra7xx->dev, 258 "PM Power Management Event message received\n"); 259 260 if (reg & LINK_REQ_RST) 261 dev_dbg(dra7xx->dev, "Link Request Reset\n"); 262 263 if (reg & LINK_UP_EVT) 264 dev_dbg(dra7xx->dev, "Link-up state change\n"); 265 266 if (reg & CFG_BME_EVT) 267 dev_dbg(dra7xx->dev, "CFG 'Bus Master Enable' change\n"); 268 269 if (reg & CFG_MSE_EVT) 270 dev_dbg(dra7xx->dev, "CFG 'Memory Space Enable' change\n"); 271 272 dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, reg); 273 274 return IRQ_HANDLED; 275} 276 277static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, 278 struct platform_device *pdev) 279{ 280 int ret; 281 struct pcie_port *pp; 282 struct resource *res; 283 struct device *dev = &pdev->dev; 284 285 pp = &dra7xx->pp; 286 pp->dev = dev; 287 pp->ops = &dra7xx_pcie_host_ops; 288 289 pp->irq = platform_get_irq(pdev, 1); 290 if (pp->irq < 0) { 291 dev_err(dev, "missing IRQ resource\n"); 292 return -EINVAL; 293 } 294 295 ret = devm_request_irq(&pdev->dev, pp->irq, 296 dra7xx_pcie_msi_irq_handler, 297 IRQF_SHARED | IRQF_NO_THREAD, 298 "dra7-pcie-msi", pp); 299 if (ret) { 300 dev_err(&pdev->dev, "failed to request irq\n"); 301 return ret; 302 } 303 304 if (!IS_ENABLED(CONFIG_PCI_MSI)) { 305 ret = dra7xx_pcie_init_irq_domain(pp); 306 if (ret < 0) 307 return ret; 308 } 309 310 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbics"); 311 pp->dbi_base = devm_ioremap(dev, res->start, resource_size(res)); 312 if (!pp->dbi_base) 313 return -ENOMEM; 314 315 ret = dw_pcie_host_init(pp); 316 if (ret) { 317 dev_err(dra7xx->dev, "failed to initialize host\n"); 318 return ret; 319 } 320 321 return 0; 322} 323 324static int __init dra7xx_pcie_probe(struct platform_device *pdev) 325{ 326 u32 reg; 327 int ret; 328 int irq; 329 int i; 330 int phy_count; 331 struct phy **phy; 332 void __iomem *base; 333 struct resource *res; 334 struct dra7xx_pcie *dra7xx; 335 struct device *dev = &pdev->dev; 336 struct device_node *np = dev->of_node; 337 char name[10]; 338 int gpio_sel; 339 enum of_gpio_flags flags; 340 unsigned long gpio_flags; 341 342 dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL); 343 if (!dra7xx) 344 return -ENOMEM; 345 346 irq = platform_get_irq(pdev, 0); 347 if (irq < 0) { 348 dev_err(dev, "missing IRQ resource\n"); 349 return -EINVAL; 350 } 351 352 ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler, 353 IRQF_SHARED, "dra7xx-pcie-main", dra7xx); 354 if (ret) { 355 dev_err(dev, "failed to request irq\n"); 356 return ret; 357 } 358 359 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ti_conf"); 360 base = devm_ioremap_nocache(dev, res->start, resource_size(res)); 361 if (!base) 362 return -ENOMEM; 363 364 phy_count = of_property_count_strings(np, "phy-names"); 365 if (phy_count < 0) { 366 dev_err(dev, "unable to find the strings\n"); 367 return phy_count; 368 } 369 370 phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL); 371 if (!phy) 372 return -ENOMEM; 373 374 for (i = 0; i < phy_count; i++) { 375 snprintf(name, sizeof(name), "pcie-phy%d", i); 376 phy[i] = devm_phy_get(dev, name); 377 if (IS_ERR(phy[i])) 378 return PTR_ERR(phy[i]); 379 380 ret = phy_init(phy[i]); 381 if (ret < 0) 382 goto err_phy; 383 384 ret = phy_power_on(phy[i]); 385 if (ret < 0) { 386 phy_exit(phy[i]); 387 goto err_phy; 388 } 389 } 390 391 dra7xx->base = base; 392 dra7xx->phy = phy; 393 dra7xx->dev = dev; 394 dra7xx->phy_count = phy_count; 395 396 pm_runtime_enable(dev); 397 ret = pm_runtime_get_sync(dev); 398 if (ret < 0) { 399 dev_err(dev, "pm_runtime_get_sync failed\n"); 400 goto err_get_sync; 401 } 402 403 gpio_sel = of_get_gpio_flags(dev->of_node, 0, &flags); 404 if (gpio_is_valid(gpio_sel)) { 405 gpio_flags = (flags & OF_GPIO_ACTIVE_LOW) ? 406 GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH; 407 ret = devm_gpio_request_one(dev, gpio_sel, gpio_flags, 408 "pcie_reset"); 409 if (ret) { 410 dev_err(&pdev->dev, "gpio%d request failed, ret %d\n", 411 gpio_sel, ret); 412 goto err_gpio; 413 } 414 } else if (gpio_sel == -EPROBE_DEFER) { 415 ret = -EPROBE_DEFER; 416 goto err_gpio; 417 } 418 419 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD); 420 reg &= ~LTSSM_EN; 421 dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); 422 423 platform_set_drvdata(pdev, dra7xx); 424 425 ret = dra7xx_add_pcie_port(dra7xx, pdev); 426 if (ret < 0) 427 goto err_gpio; 428 429 return 0; 430 431err_gpio: 432 pm_runtime_put(dev); 433 434err_get_sync: 435 pm_runtime_disable(dev); 436 437err_phy: 438 while (--i >= 0) { 439 phy_power_off(phy[i]); 440 phy_exit(phy[i]); 441 } 442 443 return ret; 444} 445 446static int __exit dra7xx_pcie_remove(struct platform_device *pdev) 447{ 448 struct dra7xx_pcie *dra7xx = platform_get_drvdata(pdev); 449 struct pcie_port *pp = &dra7xx->pp; 450 struct device *dev = &pdev->dev; 451 int count = dra7xx->phy_count; 452 453 if (pp->irq_domain) 454 irq_domain_remove(pp->irq_domain); 455 pm_runtime_put(dev); 456 pm_runtime_disable(dev); 457 while (count--) { 458 phy_power_off(dra7xx->phy[count]); 459 phy_exit(dra7xx->phy[count]); 460 } 461 462 return 0; 463} 464 465#ifdef CONFIG_PM_SLEEP 466static int dra7xx_pcie_suspend(struct device *dev) 467{ 468 struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev); 469 struct pcie_port *pp = &dra7xx->pp; 470 u32 val; 471 472 /* clear MSE */ 473 val = dra7xx_pcie_readl_rc(pp, PCI_COMMAND); 474 val &= ~PCI_COMMAND_MEMORY; 475 dra7xx_pcie_writel_rc(pp, PCI_COMMAND, val); 476 477 return 0; 478} 479 480static int dra7xx_pcie_resume(struct device *dev) 481{ 482 struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev); 483 struct pcie_port *pp = &dra7xx->pp; 484 u32 val; 485 486 /* set MSE */ 487 val = dra7xx_pcie_readl_rc(pp, PCI_COMMAND); 488 val |= PCI_COMMAND_MEMORY; 489 dra7xx_pcie_writel_rc(pp, PCI_COMMAND, val); 490 491 return 0; 492} 493 494static int dra7xx_pcie_suspend_noirq(struct device *dev) 495{ 496 struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev); 497 int count = dra7xx->phy_count; 498 499 while (count--) { 500 phy_power_off(dra7xx->phy[count]); 501 phy_exit(dra7xx->phy[count]); 502 } 503 504 return 0; 505} 506 507static int dra7xx_pcie_resume_noirq(struct device *dev) 508{ 509 struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev); 510 int phy_count = dra7xx->phy_count; 511 int ret; 512 int i; 513 514 for (i = 0; i < phy_count; i++) { 515 ret = phy_init(dra7xx->phy[i]); 516 if (ret < 0) 517 goto err_phy; 518 519 ret = phy_power_on(dra7xx->phy[i]); 520 if (ret < 0) { 521 phy_exit(dra7xx->phy[i]); 522 goto err_phy; 523 } 524 } 525 526 return 0; 527 528err_phy: 529 while (--i >= 0) { 530 phy_power_off(dra7xx->phy[i]); 531 phy_exit(dra7xx->phy[i]); 532 } 533 534 return ret; 535} 536#endif 537 538static const struct dev_pm_ops dra7xx_pcie_pm_ops = { 539 SET_SYSTEM_SLEEP_PM_OPS(dra7xx_pcie_suspend, dra7xx_pcie_resume) 540 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dra7xx_pcie_suspend_noirq, 541 dra7xx_pcie_resume_noirq) 542}; 543 544static const struct of_device_id of_dra7xx_pcie_match[] = { 545 { .compatible = "ti,dra7-pcie", }, 546 {}, 547}; 548MODULE_DEVICE_TABLE(of, of_dra7xx_pcie_match); 549 550static struct platform_driver dra7xx_pcie_driver = { 551 .remove = __exit_p(dra7xx_pcie_remove), 552 .driver = { 553 .name = "dra7-pcie", 554 .of_match_table = of_dra7xx_pcie_match, 555 .pm = &dra7xx_pcie_pm_ops, 556 }, 557}; 558 559module_platform_driver_probe(dra7xx_pcie_driver, dra7xx_pcie_probe); 560 561MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); 562MODULE_DESCRIPTION("TI PCIe controller driver"); 563MODULE_LICENSE("GPL v2");