|
84 | 84 | #define IDSETR1 0x011004 |
85 | 85 | #define TLCTLR 0x011048 |
86 | 86 | #define MACSR 0x011054 |
| 87 | +#define SPCHGFIN (1 << 4) |
| 88 | +#define SPCHGFAIL (1 << 6) |
| 89 | +#define SPCHGSUC (1 << 7) |
| 90 | +#define LINK_SPEED (0xf << 16) |
| 91 | +#define LINK_SPEED_2_5GTS (1 << 16) |
| 92 | +#define LINK_SPEED_5_0GTS (2 << 16) |
87 | 93 | #define MACCTLR 0x011058 |
| 94 | +#define SPEED_CHANGE (1 << 24) |
88 | 95 | #define SCRAMBLE_DISABLE (1 << 27) |
| 96 | +#define MACS2R 0x011078 |
| 97 | +#define MACCGSPSETR 0x011084 |
| 98 | +#define SPCNGRSN (1 << 31) |
89 | 99 |
|
90 | 100 | /* R-Car H1 PHY */ |
91 | 101 | #define H1_PCIEPHYADRR 0x04000c |
@@ -385,11 +395,67 @@ static int rcar_pcie_setup(struct list_head *resource, struct rcar_pcie *pci) |
385 | 395 | return 1; |
386 | 396 | } |
387 | 397 |
|
| 398 | +static void rcar_pcie_force_speedup(struct rcar_pcie *pcie) |
| 399 | +{ |
| 400 | + unsigned int timeout = 1000; |
| 401 | + u32 macsr; |
| 402 | + |
| 403 | + if ((rcar_pci_read_reg(pcie, MACS2R) & LINK_SPEED) != LINK_SPEED_5_0GTS) |
| 404 | + return; |
| 405 | + |
| 406 | + if (rcar_pci_read_reg(pcie, MACCTLR) & SPEED_CHANGE) { |
| 407 | + dev_err(pcie->dev, "Speed change already in progress\n"); |
| 408 | + return; |
| 409 | + } |
| 410 | + |
| 411 | + macsr = rcar_pci_read_reg(pcie, MACSR); |
| 412 | + if ((macsr & LINK_SPEED) == LINK_SPEED_5_0GTS) |
| 413 | + goto done; |
| 414 | + |
| 415 | + /* Set target link speed to 5.0 GT/s */ |
| 416 | + rcar_rmw32(pcie, EXPCAP(12), PCI_EXP_LNKSTA_CLS, |
| 417 | + PCI_EXP_LNKSTA_CLS_5_0GB); |
| 418 | + |
| 419 | + /* Set speed change reason as intentional factor */ |
| 420 | + rcar_rmw32(pcie, MACCGSPSETR, SPCNGRSN, 0); |
| 421 | + |
| 422 | + /* Clear SPCHGFIN, SPCHGSUC, and SPCHGFAIL */ |
| 423 | + if (macsr & (SPCHGFIN | SPCHGSUC | SPCHGFAIL)) |
| 424 | + rcar_pci_write_reg(pcie, macsr, MACSR); |
| 425 | + |
| 426 | + /* Start link speed change */ |
| 427 | + rcar_rmw32(pcie, MACCTLR, SPEED_CHANGE, SPEED_CHANGE); |
| 428 | + |
| 429 | + while (timeout--) { |
| 430 | + macsr = rcar_pci_read_reg(pcie, MACSR); |
| 431 | + if (macsr & SPCHGFIN) { |
| 432 | + /* Clear the interrupt bits */ |
| 433 | + rcar_pci_write_reg(pcie, macsr, MACSR); |
| 434 | + |
| 435 | + if (macsr & SPCHGFAIL) |
| 436 | + dev_err(pcie->dev, "Speed change failed\n"); |
| 437 | + |
| 438 | + goto done; |
| 439 | + } |
| 440 | + |
| 441 | + msleep(1); |
| 442 | + }; |
| 443 | + |
| 444 | + dev_err(pcie->dev, "Speed change timed out\n"); |
| 445 | + |
| 446 | +done: |
| 447 | + dev_info(pcie->dev, "Current link speed is %s GT/s\n", |
| 448 | + (macsr & LINK_SPEED) == LINK_SPEED_5_0GTS ? "5" : "2.5"); |
| 449 | +} |
| 450 | + |
388 | 451 | static int rcar_pcie_enable(struct rcar_pcie *pcie) |
389 | 452 | { |
390 | 453 | struct pci_bus *bus, *child; |
391 | 454 | LIST_HEAD(res); |
392 | 455 |
|
| 456 | + /* Try setting 5 GT/s link speed */ |
| 457 | + rcar_pcie_force_speedup(pcie); |
| 458 | + |
393 | 459 | rcar_pcie_setup(&res, pcie); |
394 | 460 |
|
395 | 461 | pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); |
|
0 commit comments