123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- From 460f382c278fe66059a773c41cbcd0db86d53983 Mon Sep 17 00:00:00 2001
- From: Mathias Kresin <dev@kresin.me>
- Date: Thu, 13 Apr 2017 09:47:42 +0200
- Subject: [PATCH] MIPS: pci-ar724x: get PCIe controller out of reset
- The ar724x pci driver expects the PCIe controller to be brought out of
- reset by the bootloader.
- At least the AVM Fritz 300E bootloader doesn't take care of releasing
- the different PCIe controller related resets which causes an endless
- hang as soon as either the PCIE Reset register (0x180f0018) or the PCI
- Application Control register (0x180f0000) is read from.
- Do the full "PCIE Root Complex Initialization Sequence" if the PCIe
- host controller is still in reset during probing.
- The QCA u-boot sleeps 10ms after the PCIE Application Control bit is
- set to ready. It has been shown that 10ms might not be enough time if
- PCIe should be used right after setting the bit. During my tests it
- took up to 20ms till the link was up. Giving the link up to 100ms
- should work for all cases.
- Signed-off-by: Mathias Kresin <dev@kresin.me>
- ---
- arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 3 ++
- arch/mips/pci/pci-ar724x.c | 42 ++++++++++++++++++++++++++
- 2 files changed, 45 insertions(+)
- --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
- +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
- @@ -169,6 +169,9 @@
- #define AR724X_PLL_REG_CPU_CONFIG 0x00
- #define AR724X_PLL_REG_PCIE_CONFIG 0x10
-
- +#define AR724X_PLL_REG_PCIE_CONFIG_PPL_BYPASS BIT(16)
- +#define AR724X_PLL_REG_PCIE_CONFIG_PPL_RESET BIT(25)
- +
- #define AR724X_PLL_FB_SHIFT 0
- #define AR724X_PLL_FB_MASK 0x3ff
- #define AR724X_PLL_REF_DIV_SHIFT 10
- --- a/arch/mips/pci/pci-ar724x.c
- +++ b/arch/mips/pci/pci-ar724x.c
- @@ -12,14 +12,18 @@
- #include <linux/irq.h>
- #include <linux/pci.h>
- #include <linux/init.h>
- +#include <linux/delay.h>
- #include <linux/platform_device.h>
- #include <asm/mach-ath79/ath79.h>
- #include <asm/mach-ath79/ar71xx_regs.h>
-
- +#define AR724X_PCI_REG_APP 0x0
- #define AR724X_PCI_REG_RESET 0x18
- #define AR724X_PCI_REG_INT_STATUS 0x4c
- #define AR724X_PCI_REG_INT_MASK 0x50
-
- +#define AR724X_PCI_APP_LTSSM_ENABLE BIT(0)
- +
- #define AR724X_PCI_RESET_LINK_UP BIT(0)
-
- #define AR724X_PCI_INT_DEV0 BIT(14)
- @@ -325,6 +329,37 @@ static void ar724x_pci_irq_init(struct a
- apc);
- }
-
- +static void ar724x_pci_hw_init(struct ar724x_pci_controller *apc)
- +{
- + u32 ppl, app;
- + int wait = 0;
- +
- + /* deassert PCIe host controller and PCIe PHY reset */
- + ath79_device_reset_clear(AR724X_RESET_PCIE);
- + ath79_device_reset_clear(AR724X_RESET_PCIE_PHY);
- +
- + /* remove the reset of the PCIE PLL */
- + ppl = ath79_pll_rr(AR724X_PLL_REG_PCIE_CONFIG);
- + ppl &= ~AR724X_PLL_REG_PCIE_CONFIG_PPL_RESET;
- + ath79_pll_wr(AR724X_PLL_REG_PCIE_CONFIG, ppl);
- +
- + /* deassert bypass for the PCIE PLL */
- + ppl = ath79_pll_rr(AR724X_PLL_REG_PCIE_CONFIG);
- + ppl &= ~AR724X_PLL_REG_PCIE_CONFIG_PPL_BYPASS;
- + ath79_pll_wr(AR724X_PLL_REG_PCIE_CONFIG, ppl);
- +
- + /* set PCIE Application Control to ready */
- + app = __raw_readl(apc->ctrl_base + AR724X_PCI_REG_APP);
- + app |= AR724X_PCI_APP_LTSSM_ENABLE;
- + __raw_writel(app, apc->ctrl_base + AR724X_PCI_REG_APP);
- +
- + /* wait up to 100ms for PHY link up */
- + do {
- + mdelay(10);
- + wait++;
- + } while (wait < 10 && !ar724x_pci_check_link(apc));
- +}
- +
- static int ar724x_pci_probe(struct platform_device *pdev)
- {
- struct ar724x_pci_controller *apc;
- @@ -383,6 +418,13 @@ static int ar724x_pci_probe(struct platf
- apc->pci_controller.io_resource = &apc->io_res;
- apc->pci_controller.mem_resource = &apc->mem_res;
-
- + /*
- + * Do the full PCIE Root Complex Initialization Sequence if the PCIe
- + * host controller is in reset.
- + */
- + if (ath79_reset_rr(AR724X_RESET_REG_RESET_MODULE) & AR724X_RESET_PCIE)
- + ar724x_pci_hw_init(apc);
- +
- apc->link_up = ar724x_pci_check_link(apc);
- if (!apc->link_up)
- dev_warn(&pdev->dev, "PCIe link is down\n");
|