Home | History | Annotate | Download | only in RenesasFirmwarePD720202
      1 /**  @file
      2   Implementation of driver entry point and driver binding protocol.
      3 
      4 Copyright (c) 2016, Linaro Limited. All rights reserved.
      5 
      6 This program and the accompanying materials are licensed
      7 and made available under the terms and conditions of the BSD License which
      8 accompanies this distribution. The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include <PiDxe.h>
     17 
     18 #include <Library/DebugLib.h>
     19 #include <Library/DxeServicesLib.h>
     20 #include <Library/UefiBootServicesTableLib.h>
     21 #include <Library/UefiLib.h>
     22 
     23 #include <IndustryStandard/Pci22.h>
     24 
     25 #include <Protocol/PciIo.h>
     26 
     27 #define PCI_VENDOR_ID_RENESAS               0x1912
     28 #define PCI_DEVICE_ID_PD720201              0x14
     29 #define PCI_DEVICE_ID_PD720202              0x15
     30 
     31 #define PCI_FW_CTL_STAT_REG                 0xF4
     32 #define PCI_FW_CTL_DATA_REG                 0xF5
     33 #define PCI_EXT_ROM_CTL_REG                 0xF6
     34 #define PCI_FW_DATA0                        0xF8
     35 #define PCI_FW_DATA1                        0xFC
     36 
     37 #define PCI_FW_CTL_STAT_REG_FW_DL_ENABLE    (1U << 0)
     38 #define PCI_FW_CTL_STAT_REG_RESULT_CODE     (7U << 4)
     39 #define PCI_FW_CTL_STAT_REG_RESULT_INVALID  (0)
     40 #define PCI_FW_CTL_STAT_REG_RESULT_OK       (1U << 4)
     41 #define PCI_FW_CTL_STAT_REG_SET_DATA0       (1U << 0)
     42 #define PCI_FW_CTL_STAT_REG_SET_DATA1       (1U << 1)
     43 
     44 #define PCI_EXT_ROM_CTL_REG_ROM_EXISTS      (1U << 15)
     45 
     46 STATIC CONST UINT32   *mFirmwareImage;
     47 STATIC UINTN          mFirmwareImageSize;
     48 
     49 STATIC
     50 UINT8
     51 ReadCtlStatVal (
     52   IN EFI_PCI_IO_PROTOCOL     *PciIo,
     53   IN UINTN                   Offset
     54   )
     55 {
     56   UINT8       CtlStatVal;
     57   EFI_STATUS  Status;
     58 
     59   Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, Offset, 1, &CtlStatVal);
     60   ASSERT_EFI_ERROR (Status);
     61 
     62   return CtlStatVal;
     63 }
     64 
     65 STATIC
     66 VOID
     67 WriteCtlStatVal (
     68   IN EFI_PCI_IO_PROTOCOL     *PciIo,
     69   IN UINTN                   Offset,
     70   IN UINT8                   CtlStatVal
     71   )
     72 {
     73   EFI_STATUS  Status;
     74 
     75   Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, Offset, 1, &CtlStatVal);
     76   ASSERT_EFI_ERROR (Status);
     77 }
     78 
     79 STATIC
     80 VOID
     81 WriteDataVal (
     82   IN EFI_PCI_IO_PROTOCOL     *PciIo,
     83   IN UINTN                   Offset,
     84   IN UINT32                  DataVal
     85   )
     86 {
     87   EFI_STATUS  Status;
     88 
     89   Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &DataVal);
     90   ASSERT_EFI_ERROR (Status);
     91 }
     92 
     93 STATIC
     94 BOOLEAN
     95 WaitReadCtlStatVal (
     96   IN EFI_PCI_IO_PROTOCOL     *PciIo,
     97   IN UINTN                   Offset,
     98   IN UINT8                   Mask,
     99   IN UINT8                   Val
    100   )
    101 {
    102   UINTN Timeout;
    103 
    104   for (Timeout = 0; (ReadCtlStatVal (PciIo, Offset) & Mask) != Val; Timeout++) {
    105     if (Timeout > 1000) {
    106       DEBUG ((EFI_D_ERROR,
    107         "%a: Timeout waiting for reg [+0x%x] & 0x%x to become 0x%x\n",
    108         __FUNCTION__, Offset, Mask, Val));
    109       return FALSE;
    110     }
    111     gBS->Stall (10);
    112   }
    113   return TRUE;
    114 }
    115 
    116 STATIC
    117 VOID
    118 DownloadPD720202Firmware (
    119   IN EFI_PCI_IO_PROTOCOL     *PciIo
    120   )
    121 {
    122   UINTN   Idx;
    123 
    124   Idx = 0;
    125 
    126   // 1. Set "FW Download Enable" to '1b'.
    127   WriteCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG,
    128     PCI_FW_CTL_STAT_REG_FW_DL_ENABLE);
    129 
    130   // 2. Read "Set DATA0" and confirm it is '0b'.
    131   if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,
    132          PCI_FW_CTL_STAT_REG_SET_DATA0, 0)) {
    133     return;
    134   }
    135 
    136   // 3. Write FW data to "DATA0".
    137   WriteDataVal (PciIo, PCI_FW_DATA0, mFirmwareImage[Idx++]);
    138 
    139   // 4. Read "Set DATA1" and confirm it is '0b'.
    140   if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,
    141          PCI_FW_CTL_STAT_REG_SET_DATA1, 0)) {
    142     return;
    143   }
    144 
    145   // 5. Write FW data to "DATA1".
    146   WriteDataVal (PciIo, PCI_FW_DATA1, mFirmwareImage[Idx++]);
    147 
    148   // 6. Set "Set DATA0" & "Set DATA1" to '1b'.
    149   WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,
    150     PCI_FW_CTL_STAT_REG_SET_DATA0 | PCI_FW_CTL_STAT_REG_SET_DATA1);
    151 
    152   while (Idx < mFirmwareImageSize / sizeof(UINT32)) {
    153 
    154     // 7. Read "Set DATA0" and confirm it is '0b'.
    155     if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,
    156            PCI_FW_CTL_STAT_REG_SET_DATA0, 0)) {
    157       return;
    158     }
    159 
    160     // 8. Write FW data to"DATA0". Set "Set DATA0" to '1b'.
    161     WriteDataVal (PciIo, PCI_FW_DATA0, mFirmwareImage[Idx++]);
    162     WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG, PCI_FW_CTL_STAT_REG_SET_DATA0);
    163 
    164     // 9. Read "Set DATA1" and confirm it is '0b'.
    165     if (!WaitReadCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG,
    166            PCI_FW_CTL_STAT_REG_SET_DATA1, 0)) {
    167       return;
    168     }
    169 
    170     // 10. Write FW data to"DATA1". Set "Set DATA1" to '1b'.
    171     WriteDataVal (PciIo, PCI_FW_DATA1, mFirmwareImage[Idx++]);
    172     WriteCtlStatVal (PciIo, PCI_FW_CTL_DATA_REG, PCI_FW_CTL_STAT_REG_SET_DATA1);
    173 
    174     // 11. Return to step 7 and repeat the sequence from step 7 to step 10.
    175   }
    176 
    177   // 12. After writing the last data of FW, the System Software must set "FW Download Enable" to '0b'.
    178   WriteCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG, 0);
    179 
    180   // 13. Read "Result Code" and confirm it is '001b'.
    181   if (WaitReadCtlStatVal (PciIo, PCI_FW_CTL_STAT_REG,
    182         PCI_FW_CTL_STAT_REG_RESULT_CODE, PCI_FW_CTL_STAT_REG_RESULT_OK)) {
    183     DEBUG ((EFI_D_INFO, "%a: Renesas PD720202 firmware download successful\n",
    184       __FUNCTION__));
    185   } else {
    186     DEBUG ((EFI_D_ERROR, "%a: Renesas PD720202 firmware download FAILED\n",
    187       __FUNCTION__));
    188   }
    189 }
    190 
    191 /**
    192   Test to see if this driver supports ControllerHandle. This service
    193   is called by the EFI boot service ConnectController(). In
    194   order to make drivers as small as possible, there are a few calling
    195   restrictions for this service. ConnectController() must
    196   follow these calling restrictions. If any other agent wishes to call
    197   Supported() it must also follow these calling restrictions.
    198 
    199    @param  This                   Protocol instance pointer.
    200    @param  ControllerHandle       Handle of device to test.
    201    @param  RemainingDevicePath    Optional parameter use to pick a specific child
    202                                                          device to start.
    203 
    204    @retval EFI_SUCCESS            This driver supports this device.
    205    @retval EFI_ALREADY_STARTED    This driver is already running on this device.
    206    @retval other                  This driver does not support this device.
    207 
    208 **/
    209 STATIC
    210 EFI_STATUS
    211 EFIAPI
    212 RenesasPD720202DriverSupported (
    213     IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    214     IN EFI_HANDLE                     Controller,
    215     IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    216     )
    217 {
    218   EFI_STATUS              Status;
    219   EFI_PCI_IO_PROTOCOL     *PciIo;
    220   UINT32                  PciID;
    221   UINT8                   CtlStatVal;
    222 
    223   //
    224   // Check for the PCI IO Protocol
    225   //
    226   Status = gBS->OpenProtocol (Controller, &gEfiPciIoProtocolGuid,
    227                   (VOID **)&PciIo, This->DriverBindingHandle, Controller,
    228                   EFI_OPEN_PROTOCOL_BY_DRIVER);
    229 
    230   if (EFI_ERROR (Status)) {
    231     return Status;
    232   }
    233 
    234   Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, PCI_VENDOR_ID_OFFSET,
    235                         1, &PciID);
    236   if (EFI_ERROR (Status)) {
    237     DEBUG ((EFI_D_ERROR,
    238       "%a: Pci->Pci.Read() of vendor/device id failed (Status == %r)\n",
    239       __FUNCTION__, Status));
    240     goto CloseProtocol;
    241   }
    242 
    243   if ((PciID & 0xffff) != PCI_VENDOR_ID_RENESAS ||
    244       ((PciID >> 16) != PCI_DEVICE_ID_PD720201 &&
    245        (PciID >> 16) != PCI_DEVICE_ID_PD720202)) {
    246     DEBUG ((EFI_D_INFO, "%a: ignoring unsupported PCI device 0x%04x:0x%04x\n",
    247       __FUNCTION__, PciID & 0xffff, PciID >> 16));
    248     goto CloseProtocol;
    249   }
    250 
    251   Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_FW_CTL_STAT_REG,
    252                         1, &CtlStatVal);
    253   if (!EFI_ERROR (Status) &&
    254       (CtlStatVal & PCI_FW_CTL_STAT_REG_RESULT_CODE) == PCI_FW_CTL_STAT_REG_RESULT_INVALID) {
    255     //
    256     // Firmware download required
    257     //
    258     DEBUG ((EFI_D_INFO, "%a: downloading firmware\n", __FUNCTION__));
    259     DownloadPD720202Firmware (PciIo);
    260   }
    261 
    262 CloseProtocol:
    263   gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid,
    264          This->DriverBindingHandle, Controller);
    265 
    266   //
    267   // Always return unsupported: we are not interested in driving the device,
    268   // only in having the opportunity to install the firmware before the real
    269   // driver attaches to it.
    270   //
    271   return EFI_UNSUPPORTED;
    272 }
    273 
    274 /**
    275   Start this driver on Controller. Not used.
    276 
    277   @param [in] This                    Protocol instance pointer.
    278   @param [in] Controller              Handle of device to work with.
    279   @param [in] RemainingDevicePath     Not used, always produce all possible children.
    280 
    281   @retval EFI_SUCCESS                 This driver is added to Controller.
    282   @retval other                       This driver does not support this device.
    283 
    284 **/
    285 STATIC
    286 EFI_STATUS
    287 EFIAPI
    288 RenesasPD720202DriverStart (
    289     IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    290     IN EFI_HANDLE                   Controller,
    291     IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    292     )
    293 {
    294   //
    295   // We are not interested in driving the device, we only poke the firmware
    296   // in the .Supported() callback.
    297   //
    298   ASSERT (FALSE);
    299   return EFI_INVALID_PARAMETER;
    300 }
    301 
    302 /**
    303   Stop this driver on Controller. Not used.
    304 
    305   @param [in] This                    Protocol instance pointer.
    306   @param [in] Controller              Handle of device to stop driver on.
    307   @param [in] NumberOfChildren        How many children need to be stopped.
    308   @param [in] ChildHandleBuffer       Not used.
    309 
    310   @retval EFI_SUCCESS                 This driver is removed Controller.
    311   @retval EFI_DEVICE_ERROR            The device could not be stopped due to a device error.
    312   @retval other                       This driver was not removed from this device.
    313 
    314 **/
    315 STATIC
    316 EFI_STATUS
    317 EFIAPI
    318 RenesasPD720202DriverStop (
    319     IN  EFI_DRIVER_BINDING_PROTOCOL *This,
    320     IN  EFI_HANDLE                  Controller,
    321     IN  UINTN                       NumberOfChildren,
    322     IN  EFI_HANDLE                  *ChildHandleBuffer
    323     )
    324 {
    325   ASSERT (FALSE);
    326   return EFI_SUCCESS;
    327 }
    328 
    329 //
    330 // UEFI Driver Model entry point
    331 //
    332 STATIC EFI_DRIVER_BINDING_PROTOCOL RenesasPD720202DriverBinding = {
    333   RenesasPD720202DriverSupported,
    334   RenesasPD720202DriverStart,
    335   RenesasPD720202DriverStop,
    336 
    337   // Version values of 0xfffffff0-0xffffffff are reserved for platform/OEM
    338   // specific drivers. Protocol instances with higher 'Version' properties
    339   // will be used before lower 'Version' ones. XhciDxe uses version 0x30,
    340   // so this driver will be called in preference, and XhciDxe will be invoked
    341   // after RenesasPD720202DriverSupported returns EFI_UNSUPPORTED.
    342   0xfffffff0,
    343   NULL,
    344   NULL
    345 };
    346 
    347 EFI_STATUS
    348 EFIAPI
    349 InitializeRenesasPD720202Driver (
    350     IN EFI_HANDLE       ImageHandle,
    351     IN EFI_SYSTEM_TABLE *SystemTable
    352     )
    353 {
    354   EFI_STATUS    Status;
    355 
    356   //
    357   // First, try to locate the firmware image. If it is missing, there is no
    358   // point in proceeding.
    359   //
    360   Status = GetSectionFromAnyFv (&gRenesasFirmwarePD720202ImageId,
    361     EFI_SECTION_RAW, 0, (VOID **) (VOID **)&mFirmwareImage,
    362     &mFirmwareImageSize);
    363   if (EFI_ERROR (Status)) {
    364     DEBUG ((EFI_D_ERROR, "%a: could not locate PD720202 firmware image\n",
    365       __FUNCTION__));
    366     ASSERT_EFI_ERROR (Status);
    367     return Status;
    368   }
    369 
    370   return EfiLibInstallDriverBinding (ImageHandle, SystemTable,
    371         &RenesasPD720202DriverBinding, NULL);
    372 }
    373