Merge branch 'remotes/lorenzo/pci/brcmstb'
- Assert fundamental reset on initialization (Nicolas Saenz Julienne) - Remove unnecessary clk_put(); devm_clk_get() handles this automatically (Jim Quinlan) - Fix outbound memory window register stride offset (Jim Quinlan) - Add "aspm-no-l0s" property for brcmstb and disable ASPM L0s when present (Jim Quinlan) - Add property to notify Raspberry Pi firmware of xHCI reset (Nicolas Saenz Julienne) - Add Raspberry Pi VL805 xHCI init function to trigger VL805 firmware load (Nicolas Saenz Julienne) - Wait in brcmstb probe for Raspberry Pi VL805 firmware initialization (Nicolas Saenz Julienne) - Load Raspberry Pi VL805 firmware in USB early handoff quirk (Nicolas Saenz Julienne) * remotes/lorenzo/pci/brcmstb: USB: pci-quirks: Add Raspberry Pi 4 quirk PCI: brcmstb: Wait for Raspberry Pi's firmware when present firmware: raspberrypi: Introduce vl805 init routine soc: bcm2835: Add notify xHCI reset property PCI: brcmstb: Disable L0s component of ASPM if requested dt-bindings: PCI: brcmstb: New prop 'aspm-no-l0s' PCI: brcmstb: Fix window register offset from 4 to 8 PCI: brcmstb: Don't clk_put() a managed clock PCI: brcmstb: Assert fundamental reset on initialization
This commit is contained in:
Коммит
a1dcc1aa6f
|
@ -56,6 +56,8 @@ properties:
|
|||
description: Indicates usage of spread-spectrum clocking.
|
||||
type: boolean
|
||||
|
||||
aspm-no-l0s: true
|
||||
|
||||
required:
|
||||
- reg
|
||||
- dma-ranges
|
||||
|
|
|
@ -178,8 +178,9 @@ config ISCSI_IBFT
|
|||
Otherwise, say N.
|
||||
|
||||
config RASPBERRYPI_FIRMWARE
|
||||
tristate "Raspberry Pi Firmware Driver"
|
||||
bool "Raspberry Pi Firmware Driver"
|
||||
depends on BCM2835_MBOX
|
||||
default USB_PCI
|
||||
help
|
||||
This option enables support for communicating with the firmware on the
|
||||
Raspberry Pi.
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
|
||||
#define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf))
|
||||
|
@ -19,6 +21,8 @@
|
|||
#define MBOX_DATA28(msg) ((msg) & ~0xf)
|
||||
#define MBOX_CHAN_PROPERTY 8
|
||||
|
||||
#define VL805_PCI_CONFIG_VERSION_OFFSET 0x50
|
||||
|
||||
static struct platform_device *rpi_hwmon;
|
||||
static struct platform_device *rpi_clk;
|
||||
|
||||
|
@ -286,6 +290,63 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(rpi_firmware_get);
|
||||
|
||||
/*
|
||||
* The Raspberry Pi 4 gets its USB functionality from VL805, a PCIe chip that
|
||||
* implements xHCI. After a PCI reset, VL805's firmware may either be loaded
|
||||
* directly from an EEPROM or, if not present, by the SoC's co-processor,
|
||||
* VideoCore. RPi4's VideoCore OS contains both the non public firmware load
|
||||
* logic and the VL805 firmware blob. This function triggers the aforementioned
|
||||
* process.
|
||||
*/
|
||||
int rpi_firmware_init_vl805(struct pci_dev *pdev)
|
||||
{
|
||||
struct device_node *fw_np;
|
||||
struct rpi_firmware *fw;
|
||||
u32 dev_addr, version;
|
||||
int ret;
|
||||
|
||||
fw_np = of_find_compatible_node(NULL, NULL,
|
||||
"raspberrypi,bcm2835-firmware");
|
||||
if (!fw_np)
|
||||
return 0;
|
||||
|
||||
fw = rpi_firmware_get(fw_np);
|
||||
of_node_put(fw_np);
|
||||
if (!fw)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
goto exit;
|
||||
|
||||
dev_addr = pdev->bus->number << 20 | PCI_SLOT(pdev->devfn) << 15 |
|
||||
PCI_FUNC(pdev->devfn) << 12;
|
||||
|
||||
ret = rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET,
|
||||
&dev_addr, sizeof(dev_addr));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Wait for vl805 to startup */
|
||||
usleep_range(200, 1000);
|
||||
|
||||
pci_read_config_dword(pdev, VL805_PCI_CONFIG_VERSION_OFFSET,
|
||||
&version);
|
||||
exit:
|
||||
pci_info(pdev, "VL805 firmware version %08x\n", version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpi_firmware_init_vl805);
|
||||
|
||||
static const struct of_device_id rpi_firmware_of_match[] = {
|
||||
{ .compatible = "raspberrypi,bcm2835-firmware", },
|
||||
{},
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
|
||||
#include "../pci.h"
|
||||
|
||||
/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
|
||||
|
@ -41,6 +43,9 @@
|
|||
#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c
|
||||
#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff
|
||||
|
||||
#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc
|
||||
#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00
|
||||
|
||||
#define PCIE_RC_DL_MDIO_ADDR 0x1100
|
||||
#define PCIE_RC_DL_MDIO_WR_DATA 0x1104
|
||||
#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
|
||||
|
@ -54,11 +59,11 @@
|
|||
|
||||
#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c
|
||||
#define PCIE_MEM_WIN0_LO(win) \
|
||||
PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 4)
|
||||
PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 8)
|
||||
|
||||
#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010
|
||||
#define PCIE_MEM_WIN0_HI(win) \
|
||||
PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 4)
|
||||
PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 8)
|
||||
|
||||
#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c
|
||||
#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f
|
||||
|
@ -693,10 +698,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
|||
int num_out_wins = 0;
|
||||
u16 nlw, cls, lnksta;
|
||||
int i, ret;
|
||||
u32 tmp;
|
||||
u32 tmp, aspm_support;
|
||||
|
||||
/* Reset the bridge */
|
||||
brcm_pcie_bridge_sw_init_set(pcie, 1);
|
||||
brcm_pcie_perst_set(pcie, 1);
|
||||
|
||||
usleep_range(100, 200);
|
||||
|
||||
|
@ -803,6 +809,15 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
|||
num_out_wins++;
|
||||
}
|
||||
|
||||
/* Don't advertise L0s capability if 'aspm-no-l0s' */
|
||||
aspm_support = PCIE_LINK_STATE_L1;
|
||||
if (!of_property_read_bool(pcie->np, "aspm-no-l0s"))
|
||||
aspm_support |= PCIE_LINK_STATE_L0S;
|
||||
tmp = readl(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY);
|
||||
u32p_replace_bits(&tmp, aspm_support,
|
||||
PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK);
|
||||
writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY);
|
||||
|
||||
/*
|
||||
* For config space accesses on the RC, show the right class for
|
||||
* a PCIe-PCIe bridge (the default setting is to be EP mode).
|
||||
|
@ -899,7 +914,6 @@ static void __brcm_pcie_remove(struct brcm_pcie *pcie)
|
|||
brcm_msi_remove(pcie);
|
||||
brcm_pcie_turn_off(pcie);
|
||||
clk_disable_unprepare(pcie->clk);
|
||||
clk_put(pcie->clk);
|
||||
}
|
||||
|
||||
static int brcm_pcie_remove(struct platform_device *pdev)
|
||||
|
@ -917,11 +931,26 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device_node *np = pdev->dev.of_node, *msi_np;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct device_node *fw_np;
|
||||
struct brcm_pcie *pcie;
|
||||
struct pci_bus *child;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We have to wait for Raspberry Pi's firmware interface to be up as a
|
||||
* PCI fixup, rpi_firmware_init_vl805(), depends on it. This driver's
|
||||
* probe can race with the firmware interface's (see
|
||||
* drivers/firmware/raspberrypi.c) and potentially break the PCI fixup.
|
||||
*/
|
||||
fw_np = of_find_compatible_node(NULL, NULL,
|
||||
"raspberrypi,bcm2835-firmware");
|
||||
if (fw_np && !rpi_firmware_get(fw_np)) {
|
||||
of_node_put(fw_np);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
of_node_put(fw_np);
|
||||
|
||||
bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
#include <linux/export.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
|
||||
#include "pci-quirks.h"
|
||||
#include "xhci-ext-caps.h"
|
||||
|
||||
|
@ -1243,11 +1246,24 @@ iounmap:
|
|||
|
||||
static void quirk_usb_early_handoff(struct pci_dev *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Skip Netlogic mips SoC's internal PCI USB controller.
|
||||
* This device does not need/support EHCI/OHCI handoff
|
||||
*/
|
||||
if (pdev->vendor == 0x184e) /* vendor Netlogic */
|
||||
return;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) {
|
||||
ret = rpi_firmware_init_vl805(pdev);
|
||||
if (ret) {
|
||||
/* Firmware might be outdated, or something failed */
|
||||
dev_warn(&pdev->dev,
|
||||
"Failed to load VL805's firmware: %d. Will continue to attempt to work, but bad things might happen. You should fix this...\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
if (pdev->class != PCI_CLASS_SERIAL_USB_UHCI &&
|
||||
pdev->class != PCI_CLASS_SERIAL_USB_OHCI &&
|
||||
pdev->class != PCI_CLASS_SERIAL_USB_EHCI &&
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/of_device.h>
|
||||
|
||||
struct rpi_firmware;
|
||||
struct pci_dev;
|
||||
|
||||
enum rpi_firmware_property_status {
|
||||
RPI_FIRMWARE_STATUS_REQUEST = 0,
|
||||
|
@ -90,7 +91,7 @@ enum rpi_firmware_property_tag {
|
|||
RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
|
||||
RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049,
|
||||
RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050,
|
||||
|
||||
RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058,
|
||||
|
||||
/* Dispmanx TAGS */
|
||||
RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
|
||||
|
@ -141,6 +142,7 @@ int rpi_firmware_property(struct rpi_firmware *fw,
|
|||
int rpi_firmware_property_list(struct rpi_firmware *fw,
|
||||
void *data, size_t tag_size);
|
||||
struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node);
|
||||
int rpi_firmware_init_vl805(struct pci_dev *pdev);
|
||||
#else
|
||||
static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag,
|
||||
void *data, size_t len)
|
||||
|
@ -158,6 +160,11 @@ static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int rpi_firmware_init_vl805(struct pci_dev *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SOC_RASPBERRY_FIRMWARE_H__ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче