Blob Blame History Raw
From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
Date: Thu, 24 Dec 2020 13:59:03 +0100
Subject: reset: raspberrypi: Don't reset USB if already up
Patch-mainline: Never, see note below
References: bsc#1180336

We discovered that RPi4's firmware doesn't support receiving two USB
reset signals in a row. Leaving the xHCI in a broken state. Since some
boot-loaders (mainly u-boot) now perform this operation, check if
the controller is up before performing the operation.

NOTE: This is a temporary fix while we wait for a firmware update. It's pretty
hacky due to the call to pci_get_device(). It modifies an RPi specific driver,
so it's unlikely to affect other platforms, while making life easier to RPi TW
users.

Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
 drivers/reset/reset-raspberrypi.c | 37 ++++++++++++++++++++++++++++++++++---
 1 file changed, 34 insertions(+), 3 deletions(-)

diff --git a/drivers/reset/reset-raspberrypi.c b/drivers/reset/reset-raspberrypi.c
index 02f59c06f69b..0dbae63fc202 100644
--- a/drivers/reset/reset-raspberrypi.c
+++ b/drivers/reset/reset-raspberrypi.c
@@ -8,11 +8,14 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/reset-controller.h>
 #include <soc/bcm2835/raspberrypi-firmware.h>
 #include <dt-bindings/reset/raspberrypi,firmware-reset.h>
 
+#define VL805_PCI_CONFIG_VERSION_OFFSET		0x50
+
 struct rpi_reset {
 	struct reset_controller_dev rcdev;
 	struct rpi_firmware *fw;
@@ -26,11 +29,34 @@ static inline struct rpi_reset *to_rpi(struct reset_controller_dev *rcdev)
 static int rpi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
 {
 	struct rpi_reset *priv = to_rpi(rcdev);
-	u32 dev_addr;
+	u32 dev_addr, version;
 	int ret;
 
 	switch (id) {
-	case RASPBERRYPI_FIRMWARE_RESET_ID_USB:
+	case RASPBERRYPI_FIRMWARE_RESET_ID_USB: {
+		struct pci_dev *pdev;
+
+		pdev = pci_get_device(0x1106, 0x3483, NULL);
+		if (!pdev) {
+			dev_err(rcdev->dev, "Failed to get pci device\n");
+			break;
+		}
+
+		/*
+		 * Make sure we don't trigger a firmware load unnecessarily.
+		 *
+		 * If something went wrong with PCI, this whole exercise would
+		 * be futile as VideoCore expects from us a configured PCI bus.
+		 * Just take the faulty version (likely ~0) and let xHCI's
+		 * registration fail further down the line.
+		 */
+		pci_read_config_dword(pdev, VL805_PCI_CONFIG_VERSION_OFFSET,
+				      &version);
+		if (version) {
+			pci_info(pdev, "VL805 firmware version %08x\n", version);
+			break;
+		}
+
 		/*
 		 * The Raspberry Pi 4 gets its USB functionality from VL805, a
 		 * PCIe chip that implements xHCI. After a PCI reset, VL805's
@@ -56,7 +82,12 @@ static int rpi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
 
 		/* Wait for vl805 to startup */
 		usleep_range(200, 1000);
-		break;
+
+		pci_read_config_dword(pdev, VL805_PCI_CONFIG_VERSION_OFFSET,
+				      &version);
+
+		pci_info(pdev, "VL805 firmware version %08x\n", version);
+		break; }
 
 	default:
 		return -EINVAL;