|
|
@@ -0,0 +1,113 @@
|
|
|
+From 460f382c278fe66059a773c41cbcd0db86d53983 Mon Sep 17 00:00:00 2001
|
|
|
+From: Mathias Kresin <[email protected]>
|
|
|
+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 <[email protected]>
|
|
|
+---
|
|
|
+ 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/module.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");
|