mirror of https://github.com/hak5/openwrt.git
114 lines
3.8 KiB
Diff
114 lines
3.8 KiB
Diff
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");
|