diff mbox

[edk2] OptionRomPkg: add firmware loader driver for Renesas PD72020x

Message ID 20170418175334.17765-1-ard.biesheuvel@linaro.org
State New
Headers show

Commit Message

Ard Biesheuvel April 18, 2017, 5:53 p.m. UTC
Some versions of the Renesas PD72020x XHCI controller can be integrated
into platforms without any non-volatile storage for the controller's
firmware, in which case it is the job of the system firmware to upload
a firmware image before attempting to attach the generic XHCI driver to
it.

So implement a driver that does just this: it will upload the bundled
firmware image (accessible via its FFS GUID) in the Supported() method
of the driver binding protocol, and subsequently decline to bind to the
device, which allows the real XHCI driver to attach to it instead.

The firmware itself is not part of this patch: it is up to the integrator
to incorporate it into a firmware volume under the associated GUID
(gRenesasFirmwarePD720202ImageId)

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

---
 OptionRomPkg/OptionRomPkg.dec                                    |   3 +
 OptionRomPkg/OptionRomPkg.dsc                                    |   5 +
 OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c   | 372 ++++++++++++++++++++
 OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.inf |  43 +++
 4 files changed, 423 insertions(+)

-- 
2.9.3

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Comments

Ni, Ruiyu April 19, 2017, 2:51 a.m. UTC | #1
Ard,
My understanding is the new driver downloads firmware into the XHCI controller in Supported().
The generic XHCI driver can be started successfully only after the firmware is downloaded.

But what if the XHCI driver Supported()/Start() is called before your new driver's Supported()?
I see a dependency but your code doesn't guarantee the dependency.

Thanks/Ray

> -----Original Message-----

> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of

> Ard Biesheuvel

> Sent: Wednesday, April 19, 2017 1:54 AM

> To: edk2-devel@lists.01.org; leif.lindholm@linaro.org; Ni, Ruiyu

> <ruiyu.ni@intel.com>

> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> Subject: [edk2] [PATCH] OptionRomPkg: add firmware loader driver for

> Renesas PD72020x

> 

> Some versions of the Renesas PD72020x XHCI controller can be integrated

> into platforms without any non-volatile storage for the controller's firmware,

> in which case it is the job of the system firmware to upload a firmware image

> before attempting to attach the generic XHCI driver to it.

> 

> So implement a driver that does just this: it will upload the bundled firmware

> image (accessible via its FFS GUID) in the Supported() method of the driver

> binding protocol, and subsequently decline to bind to the device, which

> allows the real XHCI driver to attach to it instead.

> 

> The firmware itself is not part of this patch: it is up to the integrator to

> incorporate it into a firmware volume under the associated GUID

> (gRenesasFirmwarePD720202ImageId)

> 

> Contributed-under: TianoCore Contribution Agreement 1.0

> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---

>  OptionRomPkg/OptionRomPkg.dec                                    |   3 +

>  OptionRomPkg/OptionRomPkg.dsc                                    |   5 +

>  OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c   |

> 372 ++++++++++++++++++++

>  OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.inf

> |  43 +++

>  4 files changed, 423 insertions(+)

> 

> diff --git a/OptionRomPkg/OptionRomPkg.dec

> b/OptionRomPkg/OptionRomPkg.dec index ea4d57b996ae..dc98ff58e374

> 100644

> --- a/OptionRomPkg/OptionRomPkg.dec

> +++ b/OptionRomPkg/OptionRomPkg.dec

> @@ -36,6 +36,9 @@ [LibraryClasses]

>  [Guids]

>    gOptionRomPkgTokenSpaceGuid = { 0x1e43298f, 0x3478, 0x41a7, { 0xb5,

> 0x77, 0x86, 0x6, 0x46, 0x35, 0xc7, 0x28 } }

> 

> +  ## GUID for RenesasFirmwarePD720202 firmware image

> + gRenesasFirmwarePD720202ImageId = {0xA059EBC4, 0xD73D, 0x4279,

> + {0x81,0xBF,0xE4,0xA8,0x93,0x08,0xB9,0x23}}

> +

>  [PcdsFeatureFlag]

> 

> gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru|TRUE|BOOLEAN|

> 0x00010001

> 

> gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru|TRUE|BOOLEA

> N|0x00010002

> diff --git a/OptionRomPkg/OptionRomPkg.dsc

> b/OptionRomPkg/OptionRomPkg.dsc index 33655567109b..07c26117251d

> 100644

> --- a/OptionRomPkg/OptionRomPkg.dsc

> +++ b/OptionRomPkg/OptionRomPkg.dsc

> @@ -115,5 +115,10 @@ [Components]

>    OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf

>    OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf

> 

> +

> OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.inf {

> +    <LibraryClasses>

> +      DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf

> +  }

> +

>  [Components.IA32, Components.X64, Components.IPF]

>    OptionRomPkg/Application/BltLibSample/BltLibSample.inf

> diff --git

> a/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c

> b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c

> new file mode 100644

> index 000000000000..c7d3f1820840

> --- /dev/null

> +++

> b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c

> @@ -0,0 +1,372 @@

> +/**  @file

> +  Implementation of driver entry point and driver binding protocol.

> +

> +Copyright (c) 2016 - 2017, Linaro Limited. All rights reserved.

> +

> +This program and the accompanying materials are licensed and made

> +available under the terms and conditions of the BSD License which

> +accompanies this distribution. The full text of the license may be

> +found at http://opensource.org/licenses/bsd-license.php

> +

> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"

> BASIS,

> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER

> EXPRESS OR IMPLIED.

> +

> +**/

> +

> +#include <PiDxe.h>

> +

> +#include <Library/DebugLib.h>

> +#include <Library/DxeServicesLib.h>

> +#include <Library/UefiBootServicesTableLib.h>

> +#include <Library/UefiLib.h>

> +

> +#include <IndustryStandard/Pci22.h>

> +

> +#include <Protocol/PciIo.h>

> +

> +#define PCI_VENDOR_ID_RENESAS               0x1912

> +#define PCI_DEVICE_ID_PD720201              0x14

> +#define PCI_DEVICE_ID_PD720202              0x15

> +

> +#define PCI_FW_CTL_STAT_REG                 0xF4

> +#define PCI_FW_CTL_DATA_REG                 0xF5

> +#define PCI_EXT_ROM_CTL_REG                 0xF6

> +#define PCI_FW_DATA0                        0xF8

> +#define PCI_FW_DATA1                        0xFC

> +

> +#define PCI_FW_CTL_STAT_REG_FW_DL_ENABLE    (1U << 0)

> +#define PCI_FW_CTL_STAT_REG_RESULT_CODE     (7U << 4)

> +#define PCI_FW_CTL_STAT_REG_RESULT_INVALID  (0)

> +#define PCI_FW_CTL_STAT_REG_RESULT_OK       (1U << 4)

> +#define PCI_FW_CTL_STAT_REG_SET_DATA0       (1U << 0)

> +#define PCI_FW_CTL_STAT_REG_SET_DATA1       (1U << 1)

> +

> +#define PCI_EXT_ROM_CTL_REG_ROM_EXISTS      (1U << 15)

> +

> +STATIC CONST UINT32   *mFirmwareImage;

> +STATIC UINTN          mFirmwareImageSize;

> +

> +STATIC

> +UINT8

> +ReadCtlStatVal (

> +  IN EFI_PCI_IO_PROTOCOL     *PciIo,

> +  IN UINTN                   Offset

> +  )

> +{

> +  UINT8       CtlStatVal;

> +  EFI_STATUS  Status;

> +

> +  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, Offset, 1,

> + &CtlStatVal);  ASSERT_EFI_ERROR (Status);

> +

> +  return CtlStatVal;

> +}

> +

> +STATIC

> +VOID

> +WriteCtlStatVal (

> +  IN EFI_PCI_IO_PROTOCOL     *PciIo,

> +  IN UINTN                   Offset,

> +  IN UINT8                   CtlStatVal

> +  )

> +{

> +  EFI_STATUS  Status;

> +

> +  Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, Offset, 1,

> +&CtlStatVal);

> +  ASSERT_EFI_ERROR (Status);

> +}

> +

> +STATIC

> +VOID

> +WriteDataVal (

> +  IN EFI_PCI_IO_PROTOCOL     *PciIo,

> +  IN UINTN                   Offset,

> +  IN UINT32                  DataVal

> +  )

> +{

> +  EFI_STATUS  Status;

> +

> +  Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1,

> +&DataVal);

> +  ASSERT_EFI_ERROR (Status);

> +}

> +

> +STATIC

> +BOOLEAN

> +WaitReadCtlStatVal (

> +  IN EFI_PCI_IO_PROTOCOL     *PciIo,

> +  IN UINTN                   Offset,

> +  IN UINT8                   Mask,

> +  IN UINT8                   Val

> +  )

> +{

> +  UINTN Timeout;

> +

> +  for (Timeout = 0; (ReadCtlStatVal (PciIo, Offset) & Mask) != Val; Timeout++)

> {

> +    if (Timeout > 1000) {

> +      DEBUG ((EFI_D_ERROR,

> +        "%a: Timeout waiting for reg [+0x%x] & 0x%x to become 0x%x\n",

> +        __FUNCTION__, Offset, Mask, Val));

> +      return FALSE;

> +    }

> +    gBS->Stall (10);

> +  }

> +  return TRUE;

> +}

> +

> +STATIC

> +VOID

> +DownloadPD720202Firmware (

> +  IN EFI_PCI_IO_PROTOCOL     *PciIo

> +  )

> +{

> +  UINTN   Idx;

> +

> +  Idx = 0;

> +

> +  // 1. Set "FW Download Enable" to '1b'.

> +  WriteCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG,

> +    PCI_FW_CTL_STAT_REG_FW_DL_ENABLE);

> +

> +  // 2. Read "Set DATA0" and confirm it is '0b'.

> +  if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

> +         PCI_FW_CTL_STAT_REG_SET_DATA0, 0)) {

> +    return;

> +  }

> +

> +  // 3. Write FW data to "DATA0".

> +  WriteDataVal (PciIo, PCI_FW_DATA0, mFirmwareImage[Idx++]);

> +

> +  // 4. Read "Set DATA1" and confirm it is '0b'.

> +  if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

> +         PCI_FW_CTL_STAT_REG_SET_DATA1, 0)) {

> +    return;

> +  }

> +

> +  // 5. Write FW data to "DATA1".

> +  WriteDataVal (PciIo, PCI_FW_DATA1, mFirmwareImage[Idx++]);

> +

> +  // 6. Set "Set DATA0" & "Set DATA1" to '1b'.

> +  WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

> +    PCI_FW_CTL_STAT_REG_SET_DATA0 |

> PCI_FW_CTL_STAT_REG_SET_DATA1);

> +

> +  while (Idx < mFirmwareImageSize / sizeof(UINT32)) {

> +

> +    // 7. Read "Set DATA0" and confirm it is '0b'.

> +    if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

> +           PCI_FW_CTL_STAT_REG_SET_DATA0, 0)) {

> +      return;

> +    }

> +

> +    // 8. Write FW data to"DATA0". Set "Set DATA0" to '1b'.

> +    WriteDataVal (PciIo, PCI_FW_DATA0, mFirmwareImage[Idx++]);

> +    WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

> + PCI_FW_CTL_STAT_REG_SET_DATA0);

> +

> +    // 9. Read "Set DATA1" and confirm it is '0b'.

> +    if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

> +           PCI_FW_CTL_STAT_REG_SET_DATA1, 0)) {

> +      return;

> +    }

> +

> +    // 10. Write FW data to"DATA1". Set "Set DATA1" to '1b'.

> +    WriteDataVal (PciIo, PCI_FW_DATA1, mFirmwareImage[Idx++]);

> +    WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

> + PCI_FW_CTL_STAT_REG_SET_DATA1);

> +

> +    // 11. Return to step 7 and repeat the sequence from step 7 to step 10.

> +  }

> +

> +  // 12. After writing the last data of FW, the System Software must set "FW

> Download Enable" to '0b'.

> +  WriteCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG, 0);

> +

> +  // 13. Read "Result Code" and confirm it is '001b'.

> +  if (WaitReadCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG,

> +        PCI_FW_CTL_STAT_REG_RESULT_CODE,

> PCI_FW_CTL_STAT_REG_RESULT_OK)) {

> +    DEBUG ((EFI_D_INFO, "%a: Renesas PD720202 firmware download

> successful\n",

> +      __FUNCTION__));

> +  } else {

> +    DEBUG ((EFI_D_ERROR, "%a: Renesas PD720202 firmware download

> FAILED\n",

> +      __FUNCTION__));

> +  }

> +}

> +

> +/**

> +  Test to see if this driver supports ControllerHandle. This service

> +  is called by the EFI boot service ConnectController(). In

> +  order to make drivers as small as possible, there are a few calling

> +  restrictions for this service. ConnectController() must

> +  follow these calling restrictions. If any other agent wishes to call

> +  Supported() it must also follow these calling restrictions.

> +

> +   @param  This                   Protocol instance pointer.

> +   @param  ControllerHandle       Handle of device to test.

> +   @param  RemainingDevicePath    Optional parameter use to pick a specific

> child

> +                                                         device to start.

> +

> +   @retval EFI_SUCCESS            This driver supports this device.

> +   @retval EFI_ALREADY_STARTED    This driver is already running on this

> device.

> +   @retval other                  This driver does not support this device.

> +

> +**/

> +STATIC

> +EFI_STATUS

> +EFIAPI

> +RenesasPD720202DriverSupported (

> +    IN EFI_DRIVER_BINDING_PROTOCOL    *This,

> +    IN EFI_HANDLE                     Controller,

> +    IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath

> +    )

> +{

> +  EFI_STATUS              Status;

> +  EFI_PCI_IO_PROTOCOL     *PciIo;

> +  UINT32                  PciID;

> +  UINT8                   CtlStatVal;

> +

> +  //

> +  // Check for the PCI IO Protocol

> +  //

> +  Status = gBS->OpenProtocol (Controller, &gEfiPciIoProtocolGuid,

> +                  (VOID **)&PciIo, This->DriverBindingHandle, Controller,

> +                  EFI_OPEN_PROTOCOL_BY_DRIVER);

> +

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32,

> PCI_VENDOR_ID_OFFSET,

> +                        1, &PciID);

> +  if (EFI_ERROR (Status)) {

> +    DEBUG ((EFI_D_ERROR,

> +      "%a: Pci->Pci.Read() of vendor/device id failed (Status == %r)\n",

> +      __FUNCTION__, Status));

> +    goto CloseProtocol;

> +  }

> +

> +  if ((PciID & 0xffff) != PCI_VENDOR_ID_RENESAS ||

> +      ((PciID >> 16) != PCI_DEVICE_ID_PD720201 &&

> +       (PciID >> 16) != PCI_DEVICE_ID_PD720202)) {

> +    DEBUG ((EFI_D_INFO, "%a: ignoring unsupported PCI device

> 0x%04x:0x%04x\n",

> +      __FUNCTION__, PciID & 0xffff, PciID >> 16));

> +    goto CloseProtocol;

> +  }

> +

> +  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8,

> PCI_FW_CTL_STAT_REG,

> +                        1, &CtlStatVal);  if (!EFI_ERROR (Status) &&

> +      (CtlStatVal & PCI_FW_CTL_STAT_REG_RESULT_CODE) ==

> PCI_FW_CTL_STAT_REG_RESULT_INVALID) {

> +    //

> +    // Firmware download required

> +    //

> +    DEBUG ((EFI_D_INFO, "%a: downloading firmware\n", __FUNCTION__));

> +    DownloadPD720202Firmware (PciIo);

> +  }

> +

> +CloseProtocol:

> +  gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid,

> +         This->DriverBindingHandle, Controller);

> +

> +  //

> +  // Always return unsupported: we are not interested in driving the

> +device,

> +  // only in having the opportunity to install the firmware before the

> +real

> +  // driver attaches to it.

> +  //

> +  return EFI_UNSUPPORTED;

> +}

> +

> +/**

> +  Start this driver on Controller. Not used.

> +

> +  @param [in] This                    Protocol instance pointer.

> +  @param [in] Controller              Handle of device to work with.

> +  @param [in] RemainingDevicePath     Not used, always produce all possible

> children.

> +

> +  @retval EFI_SUCCESS                 This driver is added to Controller.

> +  @retval other                       This driver does not support this device.

> +

> +**/

> +STATIC

> +EFI_STATUS

> +EFIAPI

> +RenesasPD720202DriverStart (

> +    IN EFI_DRIVER_BINDING_PROTOCOL  *This,

> +    IN EFI_HANDLE                   Controller,

> +    IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

> +    )

> +{

> +  //

> +  // We are not interested in driving the device, we only poke the

> +firmware

> +  // in the .Supported() callback.

> +  //

> +  ASSERT (FALSE);

> +  return EFI_INVALID_PARAMETER;

> +}

> +

> +/**

> +  Stop this driver on Controller. Not used.

> +

> +  @param [in] This                    Protocol instance pointer.

> +  @param [in] Controller              Handle of device to stop driver on.

> +  @param [in] NumberOfChildren        How many children need to be

> stopped.

> +  @param [in] ChildHandleBuffer       Not used.

> +

> +  @retval EFI_SUCCESS                 This driver is removed Controller.

> +  @retval EFI_DEVICE_ERROR            The device could not be stopped due to

> a device error.

> +  @retval other                       This driver was not removed from this device.

> +

> +**/

> +STATIC

> +EFI_STATUS

> +EFIAPI

> +RenesasPD720202DriverStop (

> +    IN  EFI_DRIVER_BINDING_PROTOCOL *This,

> +    IN  EFI_HANDLE                  Controller,

> +    IN  UINTN                       NumberOfChildren,

> +    IN  EFI_HANDLE                  *ChildHandleBuffer

> +    )

> +{

> +  ASSERT (FALSE);

> +  return EFI_SUCCESS;

> +}

> +

> +//

> +// UEFI Driver Model entry point

> +//

> +STATIC EFI_DRIVER_BINDING_PROTOCOL RenesasPD720202DriverBinding =

> {

> +  RenesasPD720202DriverSupported,

> +  RenesasPD720202DriverStart,

> +  RenesasPD720202DriverStop,

> +

> +  // Version values of 0xfffffff0-0xffffffff are reserved for

> +platform/OEM

> +  // specific drivers. Protocol instances with higher 'Version'

> +properties

> +  // will be used before lower 'Version' ones. XhciDxe uses version

> +0x30,

> +  // so this driver will be called in preference, and XhciDxe will be

> +invoked

> +  // after RenesasPD720202DriverSupported returns EFI_UNSUPPORTED.

> +  0xfffffff0,

> +  NULL,

> +  NULL

> +};

> +

> +EFI_STATUS

> +EFIAPI

> +InitializeRenesasPD720202Driver (

> +    IN EFI_HANDLE       ImageHandle,

> +    IN EFI_SYSTEM_TABLE *SystemTable

> +    )

> +{

> +  EFI_STATUS    Status;

> +

> +  //

> +  // First, try to locate the firmware image. If it is missing, there

> + is no  // point in proceeding.

> +  //

> +  Status = GetSectionFromAnyFv (&gRenesasFirmwarePD720202ImageId,

> +    EFI_SECTION_RAW, 0, (VOID **) (VOID **)&mFirmwareImage,

> +    &mFirmwareImageSize);

> +  if (EFI_ERROR (Status)) {

> +    DEBUG ((EFI_D_ERROR, "%a: could not locate PD720202 firmware

> image\n",

> +      __FUNCTION__));

> +    ASSERT_EFI_ERROR (Status);

> +    return Status;

> +  }

> +

> +  return EfiLibInstallDriverBinding (ImageHandle, SystemTable,

> +        &RenesasPD720202DriverBinding, NULL); }

> diff --git

> a/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.in

> f

> b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.in

> f

> new file mode 100644

> index 000000000000..7115ec1ba7e8

> --- /dev/null

> +++

> b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.in

> f

> @@ -0,0 +1,43 @@

> +##  @file

> +# Component description file for Reneses PD720202 firmware download

> +driver # # Copyright (c) 2016 - 2017, Linaro Ltd. All rights

> +reserved.<BR> # # This program and the accompanying materials are

> +licensed # and made available under the terms and conditions of the BSD

> +License which # accompanies this distribution. The full text of the

> +license may be found at #

> +http://opensource.org/licenses/bsd-license.php

> +#

> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"

> BASIS,

> +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER

> EXPRESS OR IMPLIED.

> +#

> +##

> +

> +[Defines]

> +  INF_VERSION                    = 0x00010005

> +  BASE_NAME                      = RenesasFirmwarePD720202

> +  FILE_GUID                      = 5979ebfe-d53c-4150-a972-568231583969

> +  MODULE_TYPE                    = UEFI_DRIVER

> +  VERSION_STRING                 = 1.0

> +  ENTRY_POINT                    = InitializeRenesasPD720202Driver

> +

> +[Sources]

> +  RenesasFirmwarePD720202.c

> +

> +[Packages]

> +  MdeModulePkg/MdeModulePkg.dec

> +  MdePkg/MdePkg.dec

> +  OptionRomPkg/OptionRomPkg.dec

> +

> +[LibraryClasses]

> +  DebugLib

> +  DxeServicesLib

> +  UefiBootServicesTableLib

> +  UefiLib

> +  UefiDriverEntryPoint

> +

> +[Protocols]

> +  gEfiPciIoProtocolGuid

> +

> +[Guids]

> +  gRenesasFirmwarePD720202ImageId

> --

> 2.9.3

> 

> _______________________________________________

> edk2-devel mailing list

> edk2-devel@lists.01.org

> https://lists.01.org/mailman/listinfo/edk2-devel

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Ard Biesheuvel April 19, 2017, 7:17 a.m. UTC | #2
On 19 April 2017 at 03:51, Ni, Ruiyu <ruiyu.ni@intel.com> wrote:
> Ard,

> My understanding is the new driver downloads firmware into the XHCI controller in Supported().

> The generic XHCI driver can be started successfully only after the firmware is downloaded.

>

> But what if the XHCI driver Supported()/Start() is called before your new driver's Supported()?

> I see a dependency but your code doesn't guarantee the dependency.

>


We are using the 'Version' field in the DriverBinding protocol to
ensure this. From the spec:

"""
The version number of the UEFI driver that produced the
EFI_DRIVER_BINDING_PROTOCOL. This field is used by
the EFI boot service ConnectController() to determine
the order that driver's Supported() service will be used when
a controller needs to be started. EFI Driver Binding Protocol
instances with higher Version values will be used before ones
with lower Version values. The Version values of 0x0-
0x0f and 0xfffffff0-0xffffffff are reserved for
platform/OEM specific drivers. The Version values of 0x10-
0xffffffef are reserved for IHV-developed drivers
"""

Since the lack of incorporated firmware for an onboard Renesas
PD72020x is arguably a platform issue, this driver uses a 'Version'
value in the platform range to ensure that it gets dispatched before
the generic XHCI driver.



>> -----Original Message-----

>> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of

>> Ard Biesheuvel

>> Sent: Wednesday, April 19, 2017 1:54 AM

>> To: edk2-devel@lists.01.org; leif.lindholm@linaro.org; Ni, Ruiyu

>> <ruiyu.ni@intel.com>

>> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>

>> Subject: [edk2] [PATCH] OptionRomPkg: add firmware loader driver for

>> Renesas PD72020x

>>

>> Some versions of the Renesas PD72020x XHCI controller can be integrated

>> into platforms without any non-volatile storage for the controller's firmware,

>> in which case it is the job of the system firmware to upload a firmware image

>> before attempting to attach the generic XHCI driver to it.

>>

>> So implement a driver that does just this: it will upload the bundled firmware

>> image (accessible via its FFS GUID) in the Supported() method of the driver

>> binding protocol, and subsequently decline to bind to the device, which

>> allows the real XHCI driver to attach to it instead.

>>

>> The firmware itself is not part of this patch: it is up to the integrator to

>> incorporate it into a firmware volume under the associated GUID

>> (gRenesasFirmwarePD720202ImageId)

>>

>> Contributed-under: TianoCore Contribution Agreement 1.0

>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

>> ---

>>  OptionRomPkg/OptionRomPkg.dec                                    |   3 +

>>  OptionRomPkg/OptionRomPkg.dsc                                    |   5 +

>>  OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c   |

>> 372 ++++++++++++++++++++

>>  OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.inf

>> |  43 +++

>>  4 files changed, 423 insertions(+)

>>

>> diff --git a/OptionRomPkg/OptionRomPkg.dec

>> b/OptionRomPkg/OptionRomPkg.dec index ea4d57b996ae..dc98ff58e374

>> 100644

>> --- a/OptionRomPkg/OptionRomPkg.dec

>> +++ b/OptionRomPkg/OptionRomPkg.dec

>> @@ -36,6 +36,9 @@ [LibraryClasses]

>>  [Guids]

>>    gOptionRomPkgTokenSpaceGuid = { 0x1e43298f, 0x3478, 0x41a7, { 0xb5,

>> 0x77, 0x86, 0x6, 0x46, 0x35, 0xc7, 0x28 } }

>>

>> +  ## GUID for RenesasFirmwarePD720202 firmware image

>> + gRenesasFirmwarePD720202ImageId = {0xA059EBC4, 0xD73D, 0x4279,

>> + {0x81,0xBF,0xE4,0xA8,0x93,0x08,0xB9,0x23}}

>> +

>>  [PcdsFeatureFlag]

>>

>> gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru|TRUE|BOOLEAN|

>> 0x00010001

>>

>> gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru|TRUE|BOOLEA

>> N|0x00010002

>> diff --git a/OptionRomPkg/OptionRomPkg.dsc

>> b/OptionRomPkg/OptionRomPkg.dsc index 33655567109b..07c26117251d

>> 100644

>> --- a/OptionRomPkg/OptionRomPkg.dsc

>> +++ b/OptionRomPkg/OptionRomPkg.dsc

>> @@ -115,5 +115,10 @@ [Components]

>>    OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf

>>    OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf

>>

>> +

>> OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.inf {

>> +    <LibraryClasses>

>> +      DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf

>> +  }

>> +

>>  [Components.IA32, Components.X64, Components.IPF]

>>    OptionRomPkg/Application/BltLibSample/BltLibSample.inf

>> diff --git

>> a/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c

>> b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c

>> new file mode 100644

>> index 000000000000..c7d3f1820840

>> --- /dev/null

>> +++

>> b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c

>> @@ -0,0 +1,372 @@

>> +/**  @file

>> +  Implementation of driver entry point and driver binding protocol.

>> +

>> +Copyright (c) 2016 - 2017, Linaro Limited. All rights reserved.

>> +

>> +This program and the accompanying materials are licensed and made

>> +available under the terms and conditions of the BSD License which

>> +accompanies this distribution. The full text of the license may be

>> +found at http://opensource.org/licenses/bsd-license.php

>> +

>> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"

>> BASIS,

>> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER

>> EXPRESS OR IMPLIED.

>> +

>> +**/

>> +

>> +#include <PiDxe.h>

>> +

>> +#include <Library/DebugLib.h>

>> +#include <Library/DxeServicesLib.h>

>> +#include <Library/UefiBootServicesTableLib.h>

>> +#include <Library/UefiLib.h>

>> +

>> +#include <IndustryStandard/Pci22.h>

>> +

>> +#include <Protocol/PciIo.h>

>> +

>> +#define PCI_VENDOR_ID_RENESAS               0x1912

>> +#define PCI_DEVICE_ID_PD720201              0x14

>> +#define PCI_DEVICE_ID_PD720202              0x15

>> +

>> +#define PCI_FW_CTL_STAT_REG                 0xF4

>> +#define PCI_FW_CTL_DATA_REG                 0xF5

>> +#define PCI_EXT_ROM_CTL_REG                 0xF6

>> +#define PCI_FW_DATA0                        0xF8

>> +#define PCI_FW_DATA1                        0xFC

>> +

>> +#define PCI_FW_CTL_STAT_REG_FW_DL_ENABLE    (1U << 0)

>> +#define PCI_FW_CTL_STAT_REG_RESULT_CODE     (7U << 4)

>> +#define PCI_FW_CTL_STAT_REG_RESULT_INVALID  (0)

>> +#define PCI_FW_CTL_STAT_REG_RESULT_OK       (1U << 4)

>> +#define PCI_FW_CTL_STAT_REG_SET_DATA0       (1U << 0)

>> +#define PCI_FW_CTL_STAT_REG_SET_DATA1       (1U << 1)

>> +

>> +#define PCI_EXT_ROM_CTL_REG_ROM_EXISTS      (1U << 15)

>> +

>> +STATIC CONST UINT32   *mFirmwareImage;

>> +STATIC UINTN          mFirmwareImageSize;

>> +

>> +STATIC

>> +UINT8

>> +ReadCtlStatVal (

>> +  IN EFI_PCI_IO_PROTOCOL     *PciIo,

>> +  IN UINTN                   Offset

>> +  )

>> +{

>> +  UINT8       CtlStatVal;

>> +  EFI_STATUS  Status;

>> +

>> +  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, Offset, 1,

>> + &CtlStatVal);  ASSERT_EFI_ERROR (Status);

>> +

>> +  return CtlStatVal;

>> +}

>> +

>> +STATIC

>> +VOID

>> +WriteCtlStatVal (

>> +  IN EFI_PCI_IO_PROTOCOL     *PciIo,

>> +  IN UINTN                   Offset,

>> +  IN UINT8                   CtlStatVal

>> +  )

>> +{

>> +  EFI_STATUS  Status;

>> +

>> +  Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, Offset, 1,

>> +&CtlStatVal);

>> +  ASSERT_EFI_ERROR (Status);

>> +}

>> +

>> +STATIC

>> +VOID

>> +WriteDataVal (

>> +  IN EFI_PCI_IO_PROTOCOL     *PciIo,

>> +  IN UINTN                   Offset,

>> +  IN UINT32                  DataVal

>> +  )

>> +{

>> +  EFI_STATUS  Status;

>> +

>> +  Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1,

>> +&DataVal);

>> +  ASSERT_EFI_ERROR (Status);

>> +}

>> +

>> +STATIC

>> +BOOLEAN

>> +WaitReadCtlStatVal (

>> +  IN EFI_PCI_IO_PROTOCOL     *PciIo,

>> +  IN UINTN                   Offset,

>> +  IN UINT8                   Mask,

>> +  IN UINT8                   Val

>> +  )

>> +{

>> +  UINTN Timeout;

>> +

>> +  for (Timeout = 0; (ReadCtlStatVal (PciIo, Offset) & Mask) != Val; Timeout++)

>> {

>> +    if (Timeout > 1000) {

>> +      DEBUG ((EFI_D_ERROR,

>> +        "%a: Timeout waiting for reg [+0x%x] & 0x%x to become 0x%x\n",

>> +        __FUNCTION__, Offset, Mask, Val));

>> +      return FALSE;

>> +    }

>> +    gBS->Stall (10);

>> +  }

>> +  return TRUE;

>> +}

>> +

>> +STATIC

>> +VOID

>> +DownloadPD720202Firmware (

>> +  IN EFI_PCI_IO_PROTOCOL     *PciIo

>> +  )

>> +{

>> +  UINTN   Idx;

>> +

>> +  Idx = 0;

>> +

>> +  // 1. Set "FW Download Enable" to '1b'.

>> +  WriteCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG,

>> +    PCI_FW_CTL_STAT_REG_FW_DL_ENABLE);

>> +

>> +  // 2. Read "Set DATA0" and confirm it is '0b'.

>> +  if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

>> +         PCI_FW_CTL_STAT_REG_SET_DATA0, 0)) {

>> +    return;

>> +  }

>> +

>> +  // 3. Write FW data to "DATA0".

>> +  WriteDataVal (PciIo, PCI_FW_DATA0, mFirmwareImage[Idx++]);

>> +

>> +  // 4. Read "Set DATA1" and confirm it is '0b'.

>> +  if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

>> +         PCI_FW_CTL_STAT_REG_SET_DATA1, 0)) {

>> +    return;

>> +  }

>> +

>> +  // 5. Write FW data to "DATA1".

>> +  WriteDataVal (PciIo, PCI_FW_DATA1, mFirmwareImage[Idx++]);

>> +

>> +  // 6. Set "Set DATA0" & "Set DATA1" to '1b'.

>> +  WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

>> +    PCI_FW_CTL_STAT_REG_SET_DATA0 |

>> PCI_FW_CTL_STAT_REG_SET_DATA1);

>> +

>> +  while (Idx < mFirmwareImageSize / sizeof(UINT32)) {

>> +

>> +    // 7. Read "Set DATA0" and confirm it is '0b'.

>> +    if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

>> +           PCI_FW_CTL_STAT_REG_SET_DATA0, 0)) {

>> +      return;

>> +    }

>> +

>> +    // 8. Write FW data to"DATA0". Set "Set DATA0" to '1b'.

>> +    WriteDataVal (PciIo, PCI_FW_DATA0, mFirmwareImage[Idx++]);

>> +    WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

>> + PCI_FW_CTL_STAT_REG_SET_DATA0);

>> +

>> +    // 9. Read "Set DATA1" and confirm it is '0b'.

>> +    if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

>> +           PCI_FW_CTL_STAT_REG_SET_DATA1, 0)) {

>> +      return;

>> +    }

>> +

>> +    // 10. Write FW data to"DATA1". Set "Set DATA1" to '1b'.

>> +    WriteDataVal (PciIo, PCI_FW_DATA1, mFirmwareImage[Idx++]);

>> +    WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,

>> + PCI_FW_CTL_STAT_REG_SET_DATA1);

>> +

>> +    // 11. Return to step 7 and repeat the sequence from step 7 to step 10.

>> +  }

>> +

>> +  // 12. After writing the last data of FW, the System Software must set "FW

>> Download Enable" to '0b'.

>> +  WriteCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG, 0);

>> +

>> +  // 13. Read "Result Code" and confirm it is '001b'.

>> +  if (WaitReadCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG,

>> +        PCI_FW_CTL_STAT_REG_RESULT_CODE,

>> PCI_FW_CTL_STAT_REG_RESULT_OK)) {

>> +    DEBUG ((EFI_D_INFO, "%a: Renesas PD720202 firmware download

>> successful\n",

>> +      __FUNCTION__));

>> +  } else {

>> +    DEBUG ((EFI_D_ERROR, "%a: Renesas PD720202 firmware download

>> FAILED\n",

>> +      __FUNCTION__));

>> +  }

>> +}

>> +

>> +/**

>> +  Test to see if this driver supports ControllerHandle. This service

>> +  is called by the EFI boot service ConnectController(). In

>> +  order to make drivers as small as possible, there are a few calling

>> +  restrictions for this service. ConnectController() must

>> +  follow these calling restrictions. If any other agent wishes to call

>> +  Supported() it must also follow these calling restrictions.

>> +

>> +   @param  This                   Protocol instance pointer.

>> +   @param  ControllerHandle       Handle of device to test.

>> +   @param  RemainingDevicePath    Optional parameter use to pick a specific

>> child

>> +                                                         device to start.

>> +

>> +   @retval EFI_SUCCESS            This driver supports this device.

>> +   @retval EFI_ALREADY_STARTED    This driver is already running on this

>> device.

>> +   @retval other                  This driver does not support this device.

>> +

>> +**/

>> +STATIC

>> +EFI_STATUS

>> +EFIAPI

>> +RenesasPD720202DriverSupported (

>> +    IN EFI_DRIVER_BINDING_PROTOCOL    *This,

>> +    IN EFI_HANDLE                     Controller,

>> +    IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath

>> +    )

>> +{

>> +  EFI_STATUS              Status;

>> +  EFI_PCI_IO_PROTOCOL     *PciIo;

>> +  UINT32                  PciID;

>> +  UINT8                   CtlStatVal;

>> +

>> +  //

>> +  // Check for the PCI IO Protocol

>> +  //

>> +  Status = gBS->OpenProtocol (Controller, &gEfiPciIoProtocolGuid,

>> +                  (VOID **)&PciIo, This->DriverBindingHandle, Controller,

>> +                  EFI_OPEN_PROTOCOL_BY_DRIVER);

>> +

>> +  if (EFI_ERROR (Status)) {

>> +    return Status;

>> +  }

>> +

>> +  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32,

>> PCI_VENDOR_ID_OFFSET,

>> +                        1, &PciID);

>> +  if (EFI_ERROR (Status)) {

>> +    DEBUG ((EFI_D_ERROR,

>> +      "%a: Pci->Pci.Read() of vendor/device id failed (Status == %r)\n",

>> +      __FUNCTION__, Status));

>> +    goto CloseProtocol;

>> +  }

>> +

>> +  if ((PciID & 0xffff) != PCI_VENDOR_ID_RENESAS ||

>> +      ((PciID >> 16) != PCI_DEVICE_ID_PD720201 &&

>> +       (PciID >> 16) != PCI_DEVICE_ID_PD720202)) {

>> +    DEBUG ((EFI_D_INFO, "%a: ignoring unsupported PCI device

>> 0x%04x:0x%04x\n",

>> +      __FUNCTION__, PciID & 0xffff, PciID >> 16));

>> +    goto CloseProtocol;

>> +  }

>> +

>> +  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8,

>> PCI_FW_CTL_STAT_REG,

>> +                        1, &CtlStatVal);  if (!EFI_ERROR (Status) &&

>> +      (CtlStatVal & PCI_FW_CTL_STAT_REG_RESULT_CODE) ==

>> PCI_FW_CTL_STAT_REG_RESULT_INVALID) {

>> +    //

>> +    // Firmware download required

>> +    //

>> +    DEBUG ((EFI_D_INFO, "%a: downloading firmware\n", __FUNCTION__));

>> +    DownloadPD720202Firmware (PciIo);

>> +  }

>> +

>> +CloseProtocol:

>> +  gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid,

>> +         This->DriverBindingHandle, Controller);

>> +

>> +  //

>> +  // Always return unsupported: we are not interested in driving the

>> +device,

>> +  // only in having the opportunity to install the firmware before the

>> +real

>> +  // driver attaches to it.

>> +  //

>> +  return EFI_UNSUPPORTED;

>> +}

>> +

>> +/**

>> +  Start this driver on Controller. Not used.

>> +

>> +  @param [in] This                    Protocol instance pointer.

>> +  @param [in] Controller              Handle of device to work with.

>> +  @param [in] RemainingDevicePath     Not used, always produce all possible

>> children.

>> +

>> +  @retval EFI_SUCCESS                 This driver is added to Controller.

>> +  @retval other                       This driver does not support this device.

>> +

>> +**/

>> +STATIC

>> +EFI_STATUS

>> +EFIAPI

>> +RenesasPD720202DriverStart (

>> +    IN EFI_DRIVER_BINDING_PROTOCOL  *This,

>> +    IN EFI_HANDLE                   Controller,

>> +    IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

>> +    )

>> +{

>> +  //

>> +  // We are not interested in driving the device, we only poke the

>> +firmware

>> +  // in the .Supported() callback.

>> +  //

>> +  ASSERT (FALSE);

>> +  return EFI_INVALID_PARAMETER;

>> +}

>> +

>> +/**

>> +  Stop this driver on Controller. Not used.

>> +

>> +  @param [in] This                    Protocol instance pointer.

>> +  @param [in] Controller              Handle of device to stop driver on.

>> +  @param [in] NumberOfChildren        How many children need to be

>> stopped.

>> +  @param [in] ChildHandleBuffer       Not used.

>> +

>> +  @retval EFI_SUCCESS                 This driver is removed Controller.

>> +  @retval EFI_DEVICE_ERROR            The device could not be stopped due to

>> a device error.

>> +  @retval other                       This driver was not removed from this device.

>> +

>> +**/

>> +STATIC

>> +EFI_STATUS

>> +EFIAPI

>> +RenesasPD720202DriverStop (

>> +    IN  EFI_DRIVER_BINDING_PROTOCOL *This,

>> +    IN  EFI_HANDLE                  Controller,

>> +    IN  UINTN                       NumberOfChildren,

>> +    IN  EFI_HANDLE                  *ChildHandleBuffer

>> +    )

>> +{

>> +  ASSERT (FALSE);

>> +  return EFI_SUCCESS;

>> +}

>> +

>> +//

>> +// UEFI Driver Model entry point

>> +//

>> +STATIC EFI_DRIVER_BINDING_PROTOCOL RenesasPD720202DriverBinding =

>> {

>> +  RenesasPD720202DriverSupported,

>> +  RenesasPD720202DriverStart,

>> +  RenesasPD720202DriverStop,

>> +

>> +  // Version values of 0xfffffff0-0xffffffff are reserved for

>> +platform/OEM

>> +  // specific drivers. Protocol instances with higher 'Version'

>> +properties

>> +  // will be used before lower 'Version' ones. XhciDxe uses version

>> +0x30,

>> +  // so this driver will be called in preference, and XhciDxe will be

>> +invoked

>> +  // after RenesasPD720202DriverSupported returns EFI_UNSUPPORTED.

>> +  0xfffffff0,

>> +  NULL,

>> +  NULL

>> +};

>> +

>> +EFI_STATUS

>> +EFIAPI

>> +InitializeRenesasPD720202Driver (

>> +    IN EFI_HANDLE       ImageHandle,

>> +    IN EFI_SYSTEM_TABLE *SystemTable

>> +    )

>> +{

>> +  EFI_STATUS    Status;

>> +

>> +  //

>> +  // First, try to locate the firmware image. If it is missing, there

>> + is no  // point in proceeding.

>> +  //

>> +  Status = GetSectionFromAnyFv (&gRenesasFirmwarePD720202ImageId,

>> +    EFI_SECTION_RAW, 0, (VOID **) (VOID **)&mFirmwareImage,

>> +    &mFirmwareImageSize);

>> +  if (EFI_ERROR (Status)) {

>> +    DEBUG ((EFI_D_ERROR, "%a: could not locate PD720202 firmware

>> image\n",

>> +      __FUNCTION__));

>> +    ASSERT_EFI_ERROR (Status);

>> +    return Status;

>> +  }

>> +

>> +  return EfiLibInstallDriverBinding (ImageHandle, SystemTable,

>> +        &RenesasPD720202DriverBinding, NULL); }

>> diff --git

>> a/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.in

>> f

>> b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.in

>> f

>> new file mode 100644

>> index 000000000000..7115ec1ba7e8

>> --- /dev/null

>> +++

>> b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.in

>> f

>> @@ -0,0 +1,43 @@

>> +##  @file

>> +# Component description file for Reneses PD720202 firmware download

>> +driver # # Copyright (c) 2016 - 2017, Linaro Ltd. All rights

>> +reserved.<BR> # # This program and the accompanying materials are

>> +licensed # and made available under the terms and conditions of the BSD

>> +License which # accompanies this distribution. The full text of the

>> +license may be found at #

>> +http://opensource.org/licenses/bsd-license.php

>> +#

>> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"

>> BASIS,

>> +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER

>> EXPRESS OR IMPLIED.

>> +#

>> +##

>> +

>> +[Defines]

>> +  INF_VERSION                    = 0x00010005

>> +  BASE_NAME                      = RenesasFirmwarePD720202

>> +  FILE_GUID                      = 5979ebfe-d53c-4150-a972-568231583969

>> +  MODULE_TYPE                    = UEFI_DRIVER

>> +  VERSION_STRING                 = 1.0

>> +  ENTRY_POINT                    = InitializeRenesasPD720202Driver

>> +

>> +[Sources]

>> +  RenesasFirmwarePD720202.c

>> +

>> +[Packages]

>> +  MdeModulePkg/MdeModulePkg.dec

>> +  MdePkg/MdePkg.dec

>> +  OptionRomPkg/OptionRomPkg.dec

>> +

>> +[LibraryClasses]

>> +  DebugLib

>> +  DxeServicesLib

>> +  UefiBootServicesTableLib

>> +  UefiLib

>> +  UefiDriverEntryPoint

>> +

>> +[Protocols]

>> +  gEfiPciIoProtocolGuid

>> +

>> +[Guids]

>> +  gRenesasFirmwarePD720202ImageId

>> --

>> 2.9.3

>>

>> _______________________________________________

>> edk2-devel mailing list

>> edk2-devel@lists.01.org

>> https://lists.01.org/mailman/listinfo/edk2-devel

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
diff mbox

Patch

diff --git a/OptionRomPkg/OptionRomPkg.dec b/OptionRomPkg/OptionRomPkg.dec
index ea4d57b996ae..dc98ff58e374 100644
--- a/OptionRomPkg/OptionRomPkg.dec
+++ b/OptionRomPkg/OptionRomPkg.dec
@@ -36,6 +36,9 @@  [LibraryClasses]
 [Guids]
   gOptionRomPkgTokenSpaceGuid = { 0x1e43298f, 0x3478, 0x41a7, { 0xb5, 0x77, 0x86, 0x6, 0x46, 0x35, 0xc7, 0x28 } }
 
+  ## GUID for RenesasFirmwarePD720202 firmware image
+  gRenesasFirmwarePD720202ImageId = {0xA059EBC4, 0xD73D, 0x4279, {0x81,0xBF,0xE4,0xA8,0x93,0x08,0xB9,0x23}}
+
 [PcdsFeatureFlag]
   gOptionRomPkgTokenSpaceGuid.PcdSupportScsiPassThru|TRUE|BOOLEAN|0x00010001
   gOptionRomPkgTokenSpaceGuid.PcdSupportExtScsiPassThru|TRUE|BOOLEAN|0x00010002
diff --git a/OptionRomPkg/OptionRomPkg.dsc b/OptionRomPkg/OptionRomPkg.dsc
index 33655567109b..07c26117251d 100644
--- a/OptionRomPkg/OptionRomPkg.dsc
+++ b/OptionRomPkg/OptionRomPkg.dsc
@@ -115,5 +115,10 @@  [Components]
   OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772/Ax88772.inf
   OptionRomPkg/Bus/Usb/UsbNetworking/Ax88772b/Ax88772b.inf
 
+  OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.inf {
+    <LibraryClasses>
+      DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
+  }
+
 [Components.IA32, Components.X64, Components.IPF]
   OptionRomPkg/Application/BltLibSample/BltLibSample.inf
diff --git a/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c
new file mode 100644
index 000000000000..c7d3f1820840
--- /dev/null
+++ b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.c
@@ -0,0 +1,372 @@ 
+/**  @file
+  Implementation of driver entry point and driver binding protocol.
+
+Copyright (c) 2016 - 2017, Linaro Limited. All rights reserved.
+
+This program and the accompanying materials are licensed
+and made available under the terms and conditions of the BSD License which
+accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <IndustryStandard/Pci22.h>
+
+#include <Protocol/PciIo.h>
+
+#define PCI_VENDOR_ID_RENESAS               0x1912
+#define PCI_DEVICE_ID_PD720201              0x14
+#define PCI_DEVICE_ID_PD720202              0x15
+
+#define PCI_FW_CTL_STAT_REG                 0xF4
+#define PCI_FW_CTL_DATA_REG                 0xF5
+#define PCI_EXT_ROM_CTL_REG                 0xF6
+#define PCI_FW_DATA0                        0xF8
+#define PCI_FW_DATA1                        0xFC
+
+#define PCI_FW_CTL_STAT_REG_FW_DL_ENABLE    (1U << 0)
+#define PCI_FW_CTL_STAT_REG_RESULT_CODE     (7U << 4)
+#define PCI_FW_CTL_STAT_REG_RESULT_INVALID  (0)
+#define PCI_FW_CTL_STAT_REG_RESULT_OK       (1U << 4)
+#define PCI_FW_CTL_STAT_REG_SET_DATA0       (1U << 0)
+#define PCI_FW_CTL_STAT_REG_SET_DATA1       (1U << 1)
+
+#define PCI_EXT_ROM_CTL_REG_ROM_EXISTS      (1U << 15)
+
+STATIC CONST UINT32   *mFirmwareImage;
+STATIC UINTN          mFirmwareImageSize;
+
+STATIC
+UINT8
+ReadCtlStatVal (
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,
+  IN UINTN                   Offset
+  )
+{
+  UINT8       CtlStatVal;
+  EFI_STATUS  Status;
+
+  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, Offset, 1, &CtlStatVal);
+  ASSERT_EFI_ERROR (Status);
+
+  return CtlStatVal;
+}
+
+STATIC
+VOID
+WriteCtlStatVal (
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,
+  IN UINTN                   Offset,
+  IN UINT8                   CtlStatVal
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, Offset, 1, &CtlStatVal);
+  ASSERT_EFI_ERROR (Status);
+}
+
+STATIC
+VOID
+WriteDataVal (
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,
+  IN UINTN                   Offset,
+  IN UINT32                  DataVal
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &DataVal);
+  ASSERT_EFI_ERROR (Status);
+}
+
+STATIC
+BOOLEAN
+WaitReadCtlStatVal (
+  IN EFI_PCI_IO_PROTOCOL     *PciIo,
+  IN UINTN                   Offset,
+  IN UINT8                   Mask,
+  IN UINT8                   Val
+  )
+{
+  UINTN Timeout;
+
+  for (Timeout = 0; (ReadCtlStatVal (PciIo, Offset) & Mask) != Val; Timeout++) {
+    if (Timeout > 1000) {
+      DEBUG ((EFI_D_ERROR,
+        "%a: Timeout waiting for reg [+0x%x] & 0x%x to become 0x%x\n",
+        __FUNCTION__, Offset, Mask, Val));
+      return FALSE;
+    }
+    gBS->Stall (10);
+  }
+  return TRUE;
+}
+
+STATIC
+VOID
+DownloadPD720202Firmware (
+  IN EFI_PCI_IO_PROTOCOL     *PciIo
+  )
+{
+  UINTN   Idx;
+
+  Idx = 0;
+
+  // 1. Set "FW Download Enable" to '1b'.
+  WriteCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG,
+    PCI_FW_CTL_STAT_REG_FW_DL_ENABLE);
+
+  // 2. Read "Set DATA0" and confirm it is '0b'.
+  if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,
+         PCI_FW_CTL_STAT_REG_SET_DATA0, 0)) {
+    return;
+  }
+
+  // 3. Write FW data to "DATA0".
+  WriteDataVal (PciIo, PCI_FW_DATA0, mFirmwareImage[Idx++]);
+
+  // 4. Read "Set DATA1" and confirm it is '0b'.
+  if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,
+         PCI_FW_CTL_STAT_REG_SET_DATA1, 0)) {
+    return;
+  }
+
+  // 5. Write FW data to "DATA1".
+  WriteDataVal (PciIo, PCI_FW_DATA1, mFirmwareImage[Idx++]);
+
+  // 6. Set "Set DATA0" & "Set DATA1" to '1b'.
+  WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,
+    PCI_FW_CTL_STAT_REG_SET_DATA0 | PCI_FW_CTL_STAT_REG_SET_DATA1);
+
+  while (Idx < mFirmwareImageSize / sizeof(UINT32)) {
+
+    // 7. Read "Set DATA0" and confirm it is '0b'.
+    if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,
+           PCI_FW_CTL_STAT_REG_SET_DATA0, 0)) {
+      return;
+    }
+
+    // 8. Write FW data to"DATA0". Set "Set DATA0" to '1b'.
+    WriteDataVal (PciIo, PCI_FW_DATA0, mFirmwareImage[Idx++]);
+    WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG, PCI_FW_CTL_STAT_REG_SET_DATA0);
+
+    // 9. Read "Set DATA1" and confirm it is '0b'.
+    if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,
+           PCI_FW_CTL_STAT_REG_SET_DATA1, 0)) {
+      return;
+    }
+
+    // 10. Write FW data to"DATA1". Set "Set DATA1" to '1b'.
+    WriteDataVal (PciIo, PCI_FW_DATA1, mFirmwareImage[Idx++]);
+    WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG, PCI_FW_CTL_STAT_REG_SET_DATA1);
+
+    // 11. Return to step 7 and repeat the sequence from step 7 to step 10.
+  }
+
+  // 12. After writing the last data of FW, the System Software must set "FW Download Enable" to '0b'.
+  WriteCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG, 0);
+
+  // 13. Read "Result Code" and confirm it is '001b'.
+  if (WaitReadCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG,
+        PCI_FW_CTL_STAT_REG_RESULT_CODE, PCI_FW_CTL_STAT_REG_RESULT_OK)) {
+    DEBUG ((EFI_D_INFO, "%a: Renesas PD720202 firmware download successful\n",
+      __FUNCTION__));
+  } else {
+    DEBUG ((EFI_D_ERROR, "%a: Renesas PD720202 firmware download FAILED\n",
+      __FUNCTION__));
+  }
+}
+
+/**
+  Test to see if this driver supports ControllerHandle. This service
+  is called by the EFI boot service ConnectController(). In
+  order to make drivers as small as possible, there are a few calling
+  restrictions for this service. ConnectController() must
+  follow these calling restrictions. If any other agent wishes to call
+  Supported() it must also follow these calling restrictions.
+
+   @param  This                   Protocol instance pointer.
+   @param  ControllerHandle       Handle of device to test.
+   @param  RemainingDevicePath    Optional parameter use to pick a specific child
+                                                         device to start.
+
+   @retval EFI_SUCCESS            This driver supports this device.
+   @retval EFI_ALREADY_STARTED    This driver is already running on this device.
+   @retval other                  This driver does not support this device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+RenesasPD720202DriverSupported (
+    IN EFI_DRIVER_BINDING_PROTOCOL    *This,
+    IN EFI_HANDLE                     Controller,
+    IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
+    )
+{
+  EFI_STATUS              Status;
+  EFI_PCI_IO_PROTOCOL     *PciIo;
+  UINT32                  PciID;
+  UINT8                   CtlStatVal;
+
+  //
+  // Check for the PCI IO Protocol
+  //
+  Status = gBS->OpenProtocol (Controller, &gEfiPciIoProtocolGuid,
+                  (VOID **)&PciIo, This->DriverBindingHandle, Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER);
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, PCI_VENDOR_ID_OFFSET,
+                        1, &PciID);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR,
+      "%a: Pci->Pci.Read() of vendor/device id failed (Status == %r)\n",
+      __FUNCTION__, Status));
+    goto CloseProtocol;
+  }
+
+  if ((PciID & 0xffff) != PCI_VENDOR_ID_RENESAS ||
+      ((PciID >> 16) != PCI_DEVICE_ID_PD720201 &&
+       (PciID >> 16) != PCI_DEVICE_ID_PD720202)) {
+    DEBUG ((EFI_D_INFO, "%a: ignoring unsupported PCI device 0x%04x:0x%04x\n",
+      __FUNCTION__, PciID & 0xffff, PciID >> 16));
+    goto CloseProtocol;
+  }
+
+  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_FW_CTL_STAT_REG,
+                        1, &CtlStatVal);
+  if (!EFI_ERROR (Status) &&
+      (CtlStatVal & PCI_FW_CTL_STAT_REG_RESULT_CODE) == PCI_FW_CTL_STAT_REG_RESULT_INVALID) {
+    //
+    // Firmware download required
+    //
+    DEBUG ((EFI_D_INFO, "%a: downloading firmware\n", __FUNCTION__));
+    DownloadPD720202Firmware (PciIo);
+  }
+
+CloseProtocol:
+  gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle, Controller);
+
+  //
+  // Always return unsupported: we are not interested in driving the device,
+  // only in having the opportunity to install the firmware before the real
+  // driver attaches to it.
+  //
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Start this driver on Controller. Not used.
+
+  @param [in] This                    Protocol instance pointer.
+  @param [in] Controller              Handle of device to work with.
+  @param [in] RemainingDevicePath     Not used, always produce all possible children.
+
+  @retval EFI_SUCCESS                 This driver is added to Controller.
+  @retval other                       This driver does not support this device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+RenesasPD720202DriverStart (
+    IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+    IN EFI_HANDLE                   Controller,
+    IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+    )
+{
+  //
+  // We are not interested in driving the device, we only poke the firmware
+  // in the .Supported() callback.
+  //
+  ASSERT (FALSE);
+  return EFI_INVALID_PARAMETER;
+}
+
+/**
+  Stop this driver on Controller. Not used.
+
+  @param [in] This                    Protocol instance pointer.
+  @param [in] Controller              Handle of device to stop driver on.
+  @param [in] NumberOfChildren        How many children need to be stopped.
+  @param [in] ChildHandleBuffer       Not used.
+
+  @retval EFI_SUCCESS                 This driver is removed Controller.
+  @retval EFI_DEVICE_ERROR            The device could not be stopped due to a device error.
+  @retval other                       This driver was not removed from this device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+RenesasPD720202DriverStop (
+    IN  EFI_DRIVER_BINDING_PROTOCOL *This,
+    IN  EFI_HANDLE                  Controller,
+    IN  UINTN                       NumberOfChildren,
+    IN  EFI_HANDLE                  *ChildHandleBuffer
+    )
+{
+  ASSERT (FALSE);
+  return EFI_SUCCESS;
+}
+
+//
+// UEFI Driver Model entry point
+//
+STATIC EFI_DRIVER_BINDING_PROTOCOL RenesasPD720202DriverBinding = {
+  RenesasPD720202DriverSupported,
+  RenesasPD720202DriverStart,
+  RenesasPD720202DriverStop,
+
+  // Version values of 0xfffffff0-0xffffffff are reserved for platform/OEM
+  // specific drivers. Protocol instances with higher 'Version' properties
+  // will be used before lower 'Version' ones. XhciDxe uses version 0x30,
+  // so this driver will be called in preference, and XhciDxe will be invoked
+  // after RenesasPD720202DriverSupported returns EFI_UNSUPPORTED.
+  0xfffffff0,
+  NULL,
+  NULL
+};
+
+EFI_STATUS
+EFIAPI
+InitializeRenesasPD720202Driver (
+    IN EFI_HANDLE       ImageHandle,
+    IN EFI_SYSTEM_TABLE *SystemTable
+    )
+{
+  EFI_STATUS    Status;
+
+  //
+  // First, try to locate the firmware image. If it is missing, there is no
+  // point in proceeding.
+  //
+  Status = GetSectionFromAnyFv (&gRenesasFirmwarePD720202ImageId,
+    EFI_SECTION_RAW, 0, (VOID **) (VOID **)&mFirmwareImage,
+    &mFirmwareImageSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "%a: could not locate PD720202 firmware image\n",
+      __FUNCTION__));
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  return EfiLibInstallDriverBinding (ImageHandle, SystemTable,
+        &RenesasPD720202DriverBinding, NULL);
+}
diff --git a/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.inf b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.inf
new file mode 100644
index 000000000000..7115ec1ba7e8
--- /dev/null
+++ b/OptionRomPkg/RenesasFirmwarePD720202/RenesasFirmwarePD720202.inf
@@ -0,0 +1,43 @@ 
+##  @file
+# Component description file for Reneses PD720202 firmware download driver
+#
+# Copyright (c) 2016 - 2017, Linaro Ltd. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed
+# and made available under the terms and conditions of the BSD License which
+# accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = RenesasFirmwarePD720202
+  FILE_GUID                      = 5979ebfe-d53c-4150-a972-568231583969
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializeRenesasPD720202Driver
+
+[Sources]
+  RenesasFirmwarePD720202.c
+
+[Packages]
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  OptionRomPkg/OptionRomPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  DxeServicesLib
+  UefiBootServicesTableLib
+  UefiLib
+  UefiDriverEntryPoint
+
+[Protocols]
+  gEfiPciIoProtocolGuid
+
+[Guids]
+  gRenesasFirmwarePD720202ImageId