Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137678416
D25261.id75291.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D25261.id75291.diff
View Options
Index: head/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
===================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
+++ head/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
@@ -397,10 +397,10 @@
bcm2835_mbox_property(void *msg, size_t msg_size)
{
struct bcm_mbox_softc *sc;
- struct msg_set_power_state *buf;
bus_dma_tag_t msg_tag;
bus_dmamap_t msg_map;
bus_addr_t msg_phys;
+ char *buf;
uint32_t reg;
device_t mbox;
int err;
@@ -468,6 +468,26 @@
}
int
+bcm2835_mbox_notify_xhci_reset(uint32_t pci_dev_addr)
+{
+ struct msg_notify_xhci_reset msg;
+ int err;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.hdr.buf_size = sizeof(msg);
+ msg.hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg.tag_hdr.tag = BCM2835_MBOX_TAG_NOTIFY_XHCI_RESET;
+ msg.tag_hdr.val_buf_size = sizeof(msg.body);
+ msg.tag_hdr.val_len = sizeof(msg.body.req);
+ msg.body.req.pci_device_addr = pci_dev_addr;
+ msg.end_tag = 0;
+
+ err = bcm2835_mbox_property(&msg, sizeof(msg));
+
+ return (err);
+}
+
+int
bcm2835_mbox_get_clock_rate(uint32_t clock_id, uint32_t *hz)
{
struct msg_get_clock_rate msg;
@@ -572,3 +592,4 @@
return (err);
}
+
Index: head/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h
===================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h
+++ head/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h
@@ -112,6 +112,24 @@
/* Sets the power state for a given device */
int bcm2835_mbox_set_power_state(uint32_t, boolean_t);
+#define BCM2835_MBOX_TAG_NOTIFY_XHCI_RESET 0x00030058
+
+struct msg_notify_xhci_reset {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_hdr tag_hdr;
+ union {
+ struct {
+ uint32_t pci_device_addr;
+ } req;
+ struct {
+ } resp;
+ } body;
+ uint32_t end_tag;
+};
+
+/* Prompts the VideoCore processor to reload the xhci firmware. */
+int bcm2835_mbox_notify_xhci_reset(uint32_t);
+
#define BCM2835_MBOX_CLOCK_ID_EMMC 0x00000001
#define BCM2838_MBOX_CLOCK_ID_EMMC2 0x0000000c
Index: head/sys/arm/broadcom/bcm2835/bcm2838_xhci.c
===================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2838_xhci.c
+++ head/sys/arm/broadcom/bcm2835/bcm2838_xhci.c
@@ -0,0 +1,217 @@
+/*-
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 2020 Dr Robert Harvey Crowston <crowston@protonmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * $FreeBSD$
+ *
+ */
+
+/*
+ * VIA VL805 controller on the Raspberry Pi 4.
+ * The VL805 is a generic xhci controller. However, in the newer hardware
+ * revisions of the Raspberry Pi 4, it is incapable of loading its own firmware.
+ * Instead, the VideoCore GPU must load the firmware into the controller at the
+ * appropriate time. This driver is a shim that pre-loads the firmware before
+ * handing control to the xhci generic driver.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_util.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/usb_pci.h>
+#include <dev/usb/controller/xhci.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h>
+
+#define VL805_FIRMWARE_REG 0x50
+#define PCIE_BUS_SHIFT 20
+#define PCIE_SLOT_SHIFT 15
+#define PCIE_FUNC_SHIFT 12
+
+static int
+bcm_xhci_probe(device_t dev)
+{
+ phandle_t root;
+ uint32_t device_id;
+
+ device_id = pci_get_devid(dev);
+ if (device_id != 0x34831106) /* VIA VL805 USB 3.0 controller. */
+ return (ENXIO);
+
+ /*
+ * The VIA chip is not unique to the Pi, but we only want to use this
+ * driver if the SoC is a Raspberry Pi 4. Walk the device tree to
+ * discover if the system is a Pi 4.
+ */
+ root = OF_finddevice("/");
+ if (root == -1)
+ return (ENXIO);
+ if (!ofw_bus_node_is_compatible(root, "raspberrypi,4-model-b"))
+ return (ENXIO);
+
+ /*
+ * On the Pi 4, the VIA chip with the firmware-loading limitation is
+ * soldered-on to a particular bus/slot/function. But, it's possible a
+ * user could desolder the VIA chip, replace it with a pci-pci bridge,
+ * then plug in a commodity VIA PCI-e card on the new bridge. In that
+ * case we don't want to try to load the firmware to a commodity
+ * expansion card.
+ */
+ if (pci_get_bus(dev) != 1 || pci_get_slot(dev) != 0 ||
+ pci_get_function(dev) != 0 )
+ return (ENXIO);
+
+ device_set_desc(dev,
+ "VL805 USB 3.0 controller (on the Raspberry Pi 4b)");
+
+ return (BUS_PROBE_SPECIFIC);
+}
+
+static uint32_t
+bcm_xhci_check_firmware(device_t dev, bool expect_loaded)
+{
+ uint32_t revision;
+ bool loaded;
+
+ revision = pci_read_config(dev, VL805_FIRMWARE_REG, 4);
+ loaded = !(revision == 0 || revision == 0xffffffff);
+
+ if (expect_loaded && !loaded)
+ device_printf(dev, "warning: xhci firmware not found.\n");
+ else if (bootverbose && !loaded)
+ device_printf(dev, "note: xhci firmware not found.\n");
+ else if (bootverbose)
+ device_printf(dev,
+ "note: xhci firmware detected; firmware is revision %x.\n",
+ revision);
+
+ if (!loaded)
+ return 0;
+
+ return (revision);
+}
+
+static void
+bcm_xhci_install_xhci_firmware(device_t dev)
+{
+ uint32_t revision, dev_addr;
+ int error;
+
+ revision = bcm_xhci_check_firmware(dev, false);
+ if (revision > 0) {
+ /*
+ * With the pre-June 2020 boot firmware, it does not seem
+ * possible to reload already-installed xhci firmware.
+ */
+ return;
+ }
+
+ /*
+ * Notify the VideoCore gpu processor that it needs to reload the xhci
+ * firmware into the xhci controller. This needs to happen after the pci
+ * bridge topology is registered with the controller.
+ */
+ if (bootverbose)
+ device_printf(dev, "note: installing xhci firmware.\n");
+
+ dev_addr =
+ pci_get_bus(dev) << PCIE_BUS_SHIFT |
+ pci_get_slot(dev) << PCIE_SLOT_SHIFT |
+ pci_get_function(dev) << PCIE_FUNC_SHIFT;
+
+ error = bcm2835_mbox_notify_xhci_reset(dev_addr);
+ if (error)
+ device_printf(dev,
+ "warning: xhci firmware install failed (error %d).\n",
+ error);
+
+ DELAY(1000);
+ bcm_xhci_check_firmware(dev, true);
+
+ return;
+}
+
+static int
+bcm_xhci_attach(device_t dev)
+{
+ struct xhci_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ bcm_xhci_install_xhci_firmware(dev);
+
+ error = xhci_pci_attach(dev);
+ if (error)
+ return (error);
+
+ /* 32 bit DMA is a limitation of the PCI-e controller, not the VL805. */
+ sc->sc_bus.dma_bits = 32;
+ if (bootverbose)
+ device_printf(dev, "note: switched to 32-bit DMA.\n");
+
+ return (0);
+}
+
+/*
+ * Device method table.
+ */
+static device_method_t bcm_xhci_methods[] = {
+ /* Device interface. */
+ DEVMETHOD(device_probe, bcm_xhci_probe),
+ DEVMETHOD(device_attach, bcm_xhci_attach),
+};
+
+DEFINE_CLASS_1(bcm_xhci, bcm_xhci_driver, bcm_xhci_methods,
+ sizeof(struct xhci_softc), xhci_pci_driver);
+
+static devclass_t xhci_devclass;
+DRIVER_MODULE(bcm_xhci, pci, bcm_xhci_driver, xhci_devclass, 0, 0); MODULE_DEPEND(bcm_xhci, usb, 1, 1, 1);
+
Index: head/sys/arm/broadcom/bcm2835/files.bcm283x
===================================================================
--- head/sys/arm/broadcom/bcm2835/files.bcm283x
+++ head/sys/arm/broadcom/bcm2835/files.bcm283x
@@ -19,6 +19,7 @@
arm/broadcom/bcm2835/bcm2835_vcio.c standard
arm/broadcom/bcm2835/bcm2835_wdog.c standard
arm/broadcom/bcm2835/bcm2838_pci.c optional pci
+arm/broadcom/bcm2835/bcm2838_xhci.c optional xhci
arm/broadcom/bcm2835/bcm283x_dwc_fdt.c optional dwcotg fdt
dev/mbox/mbox_if.m standard
Index: head/sys/conf/files.arm64
===================================================================
--- head/sys/conf/files.arm64
+++ head/sys/conf/files.arm64
@@ -107,6 +107,7 @@
arm/broadcom/bcm2835/bcm2836.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt
arm/broadcom/bcm2835/bcm283x_dwc_fdt.c optional dwcotg fdt soc_brcm_bcm2837 | dwcotg fdt soc_brcm_bcm2838
arm/broadcom/bcm2835/bcm2838_pci.c optional soc_brcm_bcm2838 fdt pci
+arm/broadcom/bcm2835/bcm2838_xhci.c optional soc_brcm_bcm2838 fdt pci xhci
arm/freescale/vybrid/vf_i2c.c optional vf_i2c iicbus SOC_NXP_LS
arm/mv/a37x0_gpio.c optional a37x0_gpio gpio fdt
arm/mv/a37x0_iic.c optional a37x0_iic iicbus fdt
Index: head/sys/dev/usb/controller/xhci.h
===================================================================
--- head/sys/dev/usb/controller/xhci.h
+++ head/sys/dev/usb/controller/xhci.h
@@ -544,5 +544,8 @@
usb_error_t xhci_start_controller(struct xhci_softc *);
void xhci_interrupt(struct xhci_softc *);
void xhci_uninit(struct xhci_softc *);
+int xhci_pci_attach(device_t);
+
+DECLARE_CLASS(xhci_pci_driver);
#endif /* _XHCI_H_ */
Index: head/sys/dev/usb/controller/xhci_pci.c
===================================================================
--- head/sys/dev/usb/controller/xhci_pci.c
+++ head/sys/dev/usb/controller/xhci_pci.c
@@ -63,7 +63,6 @@
#include "usb_if.h"
static device_probe_t xhci_pci_probe;
-static device_attach_t xhci_pci_attach;
static device_detach_t xhci_pci_detach;
static usb_take_controller_t xhci_pci_take_controller;
@@ -80,15 +79,12 @@
DEVMETHOD_END
};
-static driver_t xhci_driver = {
- .name = "xhci",
- .methods = xhci_device_methods,
- .size = sizeof(struct xhci_softc),
-};
+DEFINE_CLASS_0(xhci, xhci_pci_driver, xhci_device_methods,
+ sizeof(struct xhci_softc));
static devclass_t xhci_devclass;
-DRIVER_MODULE(xhci, pci, xhci_driver, xhci_devclass, NULL, NULL);
+DRIVER_MODULE(xhci, pci, xhci_pci_driver, xhci_devclass, NULL, NULL);
MODULE_DEPEND(xhci, usb, 1, 1, 1);
static const char *
@@ -223,7 +219,7 @@
return (0);
}
-static int
+int
xhci_pci_attach(device_t self)
{
struct xhci_softc *sc = device_get_softc(self);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Nov 25, 9:26 PM (18 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26180372
Default Alt Text
D25261.id75291.diff (10 KB)
Attached To
Mode
D25261: Handle Raspberry Pi 4 xhci firmware loading.
Attached
Detach File
Event Timeline
Log In to Comment