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;