Skip to content
Permalink
Browse files
Platform/RaspberryPi4: notify VPU to load xHCI firmware before XhciDx…
…e binds

Newer Pi 4 boards (such as 8GiB variant) no longer carry a SPI
EEPROM with the VLI805 (USB) controller firmware. So, ask the
VPU firmare to load the image it has into the controller
specified by BDF.

This is benign on non-8GiB boards (reloading that firmware if
VPU fw is new enough or doing nothing on old VPU firmware).

Tested on 4GB. Also have a positive test report for an 8GB board
from a forum member.

Signed-off-by: Andrei Warkentin <andrey.warkentin@gmail.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
  • Loading branch information
andreiw authored and Ard Biesheuvel committed Jun 1, 2020
1 parent 01005f9 commit dae68d51c5df1a6f9dee1fb45a8189fca5af69f1
Showing 7 changed files with 200 additions and 3 deletions.
@@ -1,7 +1,7 @@
/** @file
*
* Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.
* Copyright (c) 2018 - 2019, Andrei Warkentin <andrey.warkentin@gmail.com>
* Copyright (c) 2018 - 2020, Andrei Warkentin <andrey.warkentin@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
@@ -26,6 +26,7 @@
#include <Protocol/RpiFirmware.h>
#include <ConfigVars.h>
#include "ConfigDxeFormSetGuid.h"
#include "ConfigDxe.h"

#define FREQ_1_MHZ 1000000

@@ -584,5 +585,10 @@ ConfigInitialize (
NULL, &gEfiEndOfDxeEventGroupGuid, &EndOfDxeEvent);
ASSERT_EFI_ERROR (Status);


if (mModelFamily == 4) {
RegisterXhciQuirkHandler (mFwProtocol);
}

return EFI_SUCCESS;
}
@@ -0,0 +1,19 @@
/** @file
*
* Copyright (c) 2020, Andrei Warkentin <andrey.warkentin@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/

#ifndef _CONFIG_DXE_H_
#define _CONFIG_DXE_H_

#include <Uefi.h>
#include <Protocol/RpiFirmware.h>

VOID RegisterXhciQuirkHandler (
IN RASPBERRY_PI_FIRMWARE_PROTOCOL *FwProtocol
);

#endif /* _CONFIG_DXE_H_ */
@@ -3,7 +3,7 @@
# Component description file for the RasbperryPi DXE platform config driver.
#
# Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.
# Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com>
# Copyright (c) 2018 - 2020, Andrei Warkentin <andrey.warkentin@gmail.com>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -28,6 +28,7 @@
ConfigDxeFormSetGuid.h
ConfigDxeHii.vfr
ConfigDxeHii.uni
XhciQuirk.c

[Packages]
ArmPkg/ArmPkg.dec
@@ -52,6 +53,7 @@
PcdLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiLib
UefiRuntimeServicesTableLib

[Guids]
@@ -60,6 +62,7 @@

[Protocols]
gBcmGenetPlatformDeviceProtocolGuid ## PRODUCES
gEfiPciIoProtocolGuid ## CONSUMES
gRaspberryPiFirmwareProtocolGuid ## CONSUMES
gRaspberryPiConfigAppliedProtocolGuid ## PRODUCES

@@ -0,0 +1,99 @@
/** @file
*
* Copyright (c) 2020, Andrei Warkentin <andrey.warkentin@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/

#include "ConfigDxe.h"
#include <IndustryStandard/Pci.h>
#include <Protocol/PciIo.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>

#pragma pack(1)
typedef struct {
UINT8 ProgInterface;
UINT8 SubClassCode;
UINT8 BaseCode;
} USB_CLASSC;
#pragma pack()

STATIC VOID *mPciIoNotificationRegistration = NULL;

STATIC
VOID
EFIAPI
PciIoNotificationEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
USB_CLASSC UsbClassCReg;
UINTN SegmentNumber;
UINTN BusNumber;
UINTN DeviceNumber;
UINTN FunctionNumber;
RASPBERRY_PI_FIRMWARE_PROTOCOL *FwProtocol = Context;

Status = gBS->LocateProtocol (&gEfiPciIoProtocolGuid,
mPciIoNotificationRegistration, (VOID **)&PciIo);
if (EFI_ERROR (Status)) {
return;
}

Status = PciIo->Pci.Read (PciIo,
EfiPciIoWidthUint8,
PCI_CLASSCODE_OFFSET,
sizeof (USB_CLASSC) / sizeof (UINT8),
&UsbClassCReg
);

if (EFI_ERROR (Status)) {
return;
}

//
// Test whether the controller belongs to Xhci type
//
if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
(UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
(UsbClassCReg.ProgInterface != PCI_IF_XHCI)) {
return;
}

Status = PciIo->GetLocation (PciIo, &SegmentNumber, &BusNumber,
&DeviceNumber, &FunctionNumber);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "%a: failed to get SBDF for xHCI controller: %r\n",
__FUNCTION__, Status));
return;
}

DEBUG ((DEBUG_INFO, "xHCI found at %u:%u:%u:%u\n",
SegmentNumber, BusNumber, DeviceNumber, FunctionNumber));

ASSERT (SegmentNumber == 0);
Status = FwProtocol->NotifyXhciReset(BusNumber, DeviceNumber, FunctionNumber);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "%a: couldn't signal xHCI firmware load: %r\n",
__FUNCTION__, Status));
}
}

VOID
RegisterXhciQuirkHandler (
IN RASPBERRY_PI_FIRMWARE_PROTOCOL *FwProtocol
)
{
EfiCreateProtocolNotifyEvent (&gEfiPciIoProtocolGuid,
TPL_NOTIFY,
PciIoNotificationEvent,
FwProtocol,
&mPciIoNotificationRegistration
);
}
@@ -2,7 +2,7 @@
*
* Copyright (c) 2020, Pete Batard <pete@akeo.ie>
* Copyright (c) 2019, ARM Limited. All rights reserved.
* Copyright (c) 2017-2018, Andrei Warkentin <andrey.warkentin@gmail.com>
* Copyright (c) 2017-2020, Andrei Warkentin <andrey.warkentin@gmail.com>
* Copyright (c) 2016, Linaro, Ltd. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -1237,6 +1237,62 @@ RpiFirmwareSetLed (
}
}

#pragma pack()
typedef struct {
UINT32 DeviceAddress;
} RPI_FW_NOTIFY_XHCI_RESET_TAG;

typedef struct {
RPI_FW_BUFFER_HEAD BufferHead;
RPI_FW_TAG_HEAD TagHead;
RPI_FW_NOTIFY_XHCI_RESET_TAG TagBody;
UINT32 EndTag;
} RPI_FW_NOTIFY_XHCI_RESET_CMD;
#pragma pack()

STATIC
EFI_STATUS
EFIAPI
RpiFirmwareNotifyXhciReset (
IN UINTN BusNumber,
IN UINTN DeviceNumber,
IN UINTN FunctionNumber
)
{
RPI_FW_NOTIFY_XHCI_RESET_CMD *Cmd;
EFI_STATUS Status;
UINT32 Result;

if (!AcquireSpinLockOrFail (&mMailboxLock)) {
DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
return EFI_DEVICE_ERROR;
}

Cmd = mDmaBuffer;
ZeroMem (Cmd, sizeof (*Cmd));

Cmd->BufferHead.BufferSize = sizeof (*Cmd);
Cmd->BufferHead.Response = 0;
Cmd->TagHead.TagId = RPI_MBOX_NOTIFY_XHCI_RESET;
Cmd->TagHead.TagSize = sizeof (Cmd->TagBody);
Cmd->TagHead.TagValueSize = 0;
Cmd->TagBody.DeviceAddress = BusNumber << 20 | DeviceNumber << 15 | FunctionNumber << 12;
Cmd->EndTag = 0;

Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);

ReleaseSpinLock (&mMailboxLock);

if (EFI_ERROR (Status) ||
Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
DEBUG ((DEBUG_ERROR,
"%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
__FUNCTION__, Status, Cmd->BufferHead.Response));
}

return Status;
}

STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL mRpiFirmwareProtocol = {
RpiFirmwareSetPowerState,
RpiFirmwareGetMacAddress,
@@ -1259,6 +1315,7 @@ STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL mRpiFirmwareProtocol = {
RpiFirmwareGetCpuName,
RpiFirmwareGetArmMemory,
RPiFirmwareGetModelInstalledMB,
RpiFirmwareNotifyXhciReset
};

/**
@@ -1,6 +1,7 @@
/** @file
*
* Copyright (c) 2019-2020, Pete Batard <pete@akeo.ie>
* Copyright (c) 2017-2020, Andrei Warkentin <andrey.warkentin@gmail.com>
* Copyright (c) 2016, Linaro Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -61,6 +62,8 @@
#define RPI_MBOX_GET_MAX_CLOCK_RATE 0x00030004
#define RPI_MBOX_GET_MIN_CLOCK_RATE 0x00030007

#define RPI_MBOX_NOTIFY_XHCI_RESET 0x00030058

#define RPI_MBOX_SET_CLOCK_RATE 0x00038002
#define RPI_MBOX_SET_GPIO 0x00038041

@@ -1,6 +1,7 @@
/** @file
*
* Copyright (c) 2019, ARM Limited. All rights reserved.
* Copyright (c) 2017 - 2020, Andrei Warkentin <andrey.warkentin@gmail.com>
* Copyright (c) 2016, Linaro Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -140,6 +141,14 @@ EFI_STATUS
UINT32 *Size
);

typedef
EFI_STATUS
(EFIAPI *NOTIFY_XHCI_RESET) (
UINTN BusNumber,
UINTN DeviceNumber,
UINTN FunctionNumber
);

typedef struct {
SET_POWER_STATE SetPowerState;
GET_MAC_ADDRESS GetMacAddress;
@@ -162,6 +171,7 @@ typedef struct {
GET_CPU_NAME GetCpuName;
GET_ARM_MEM GetArmMem;
GET_MODEL_INSTALLED_MB GetModelInstalledMB;
NOTIFY_XHCI_RESET NotifyXhciReset;
} RASPBERRY_PI_FIRMWARE_PROTOCOL;

extern EFI_GUID gRaspberryPiFirmwareProtocolGuid;

0 comments on commit dae68d5

Please sign in to comment.