diff mbox series

[edk2,edk2-platforms,v2,1/7] Silicon/Atmel: add support for AtSha204a RNG

Message ID 20180220174944.525-2-ard.biesheuvel@linaro.org
State New
Headers show
Series Add Secure96 mezzanine support | expand

Commit Message

Ard Biesheuvel Feb. 20, 2018, 5:49 p.m. UTC
This adds support for using the random number generator in the Atmel
AtSha204a over I2C. Other functionality of the chip is currently
unsupported.

Note that the the I2C support in this device essentially violates the
protocol layering, by requiring that the device is woken up by driving
SDA low for a certain amount of time, which is something that cannot be
expressed in terms of an I2C packet sent to the device's slave address.
Instead, the slave address 0x0 is added to the device's address array,
and the wake is sent by sending a dummy write to address 0x0, and
ignoring the subsequent error. This requires the I2C bus to be clocked
at 100 kHz.

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

---
 Silicon/Atmel/AtSha204a/AtSha204a.dec     |  22 ++
 Silicon/Atmel/AtSha204a/AtSha204aDriver.c | 309 ++++++++++++++++++++
 Silicon/Atmel/AtSha204a/AtSha204aDriver.h |  81 +++++
 Silicon/Atmel/AtSha204a/AtSha204aDxe.inf  |  52 ++++
 Silicon/Atmel/AtSha204a/ComponentName.c   | 186 ++++++++++++
 Silicon/Atmel/AtSha204a/DriverBinding.c   | 242 +++++++++++++++
 6 files changed, 892 insertions(+)

-- 
2.11.0

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

Comments

Leif Lindholm Feb. 22, 2018, 1:08 p.m. UTC | #1
On Tue, Feb 20, 2018 at 05:49:38PM +0000, Ard Biesheuvel wrote:
> This adds support for using the random number generator in the Atmel

> AtSha204a over I2C. Other functionality of the chip is currently

> unsupported.

> 

> Note that the the I2C support in this device essentially violates the

> protocol layering, by requiring that the device is woken up by driving

> SDA low for a certain amount of time, which is something that cannot be

> expressed in terms of an I2C packet sent to the device's slave address.

> Instead, the slave address 0x0 is added to the device's address array,

> and the wake is sent by sending a dummy write to address 0x0, and

> ignoring the subsequent error. This requires the I2C bus to be clocked

> at 100 kHz.

> 

> Contributed-under: TianoCore Contribution Agreement 1.1

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


All of my feedback from v1 has been addressed, so:
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Ard Biesheuvel Feb. 23, 2018, 3:33 p.m. UTC | #2
On 22 February 2018 at 13:08, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Tue, Feb 20, 2018 at 05:49:38PM +0000, Ard Biesheuvel wrote:

>> This adds support for using the random number generator in the Atmel

>> AtSha204a over I2C. Other functionality of the chip is currently

>> unsupported.

>>

>> Note that the the I2C support in this device essentially violates the

>> protocol layering, by requiring that the device is woken up by driving

>> SDA low for a certain amount of time, which is something that cannot be

>> expressed in terms of an I2C packet sent to the device's slave address.

>> Instead, the slave address 0x0 is added to the device's address array,

>> and the wake is sent by sending a dummy write to address 0x0, and

>> ignoring the subsequent error. This requires the I2C bus to be clocked

>> at 100 kHz.

>>

>> Contributed-under: TianoCore Contribution Agreement 1.1

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

>

> All of my feedback from v1 has been addressed, so:

> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>


Thanks.

Pushed as 487015fb23c1a40f0d05240cadde4faf979483ee
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
diff mbox series

Patch

diff --git a/Silicon/Atmel/AtSha204a/AtSha204a.dec b/Silicon/Atmel/AtSha204a/AtSha204a.dec
new file mode 100644
index 000000000000..f1fdea59843d
--- /dev/null
+++ b/Silicon/Atmel/AtSha204a/AtSha204a.dec
@@ -0,0 +1,22 @@ 
+## @file
+#
+#  Copyright (c) 2018, Linaro Ltd. 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.
+#
+##
+
+[Defines]
+  DEC_SPECIFICATION              = 0x0001001A
+  PACKAGE_NAME                   = AtSha204a
+  PACKAGE_GUID                   = 86085a5b-355b-4e72-92ab-fc3e1d71c9ad
+  PACKAGE_VERSION                = 0.1
+
+[Guids]
+  gAtSha204aI2cDeviceGuid = { 0x52e9b64b, 0x4ec1, 0x4bd6, { 0x9e, 0x1c, 0x6d, 0xac, 0xef, 0x35, 0x18, 0x21 } }
diff --git a/Silicon/Atmel/AtSha204a/AtSha204aDriver.c b/Silicon/Atmel/AtSha204a/AtSha204aDriver.c
new file mode 100644
index 000000000000..5db2de21a731
--- /dev/null
+++ b/Silicon/Atmel/AtSha204a/AtSha204aDriver.c
@@ -0,0 +1,309 @@ 
+/** @file
+  Device driver for the Atmel ATSHA204A random number generator.
+
+  Copyright (c) 2018, 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.
+
+**/
+
+#include "AtSha204aDriver.h"
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#define MAX_RETRIES                 5
+
+// Don't bother calculating the CRC for the immutable RANDOM opcode packet
+#define OPCODE_COMMAND_PACKET_CRC   0xcd24
+
+/**
+  Returns information about the random number generation implementation.
+
+  @param[in]     This               A pointer to the EFI_RNG_PROTOCOL instance.
+  @param[in,out] AlgorithmListSize  On input, the size in bytes of AlgorithmList
+                                    On output with a return code of EFI_SUCCESS,
+                                    the size in bytes of the data returned in
+                                    AlgorithmList. On output with a return
+                                    code of EFI_BUFFER_TOO_SMALL, the size of
+                                    AlgorithmList required to obtain the list.
+  @param[out] AlgorithmList         A caller-allocated memory buffer filled by
+                                    the driver with one EFI_RNG_ALGORITHM
+                                    element for each supported RNG algorithm.
+                                    The list must not change across multiple
+                                    calls to the same driver. The first
+                                    algorithm in the list is the default
+                                    algorithm for the driver.
+
+  @retval EFI_SUCCESS               The RNG algorithm list was returned
+                                    successfully.
+  @retval EFI_UNSUPPORTED           The services is not supported by this driver
+  @retval EFI_DEVICE_ERROR          The list of algorithms could not be
+                                    retrieved due to a hardware or firmware
+                                    error.
+  @retval EFI_INVALID_PARAMETER     One or more of the parameters are incorrect.
+  @retval EFI_BUFFER_TOO_SMALL      The buffer RNGAlgorithmList is too small to
+                                    hold the result.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AtSha240aGetInfo (
+  IN      EFI_RNG_PROTOCOL    *This,
+  IN  OUT UINTN               *AlgorithmListSize,
+  OUT     EFI_RNG_ALGORITHM   *AlgorithmList
+)
+{
+  UINTN Size;
+
+  //
+  // We only implement the raw algorithm
+  //
+  Size = sizeof (EFI_GUID);
+
+  if (*AlgorithmListSize < Size) {
+    *AlgorithmListSize = Size;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  CopyGuid (AlgorithmList, &gEfiRngAlgorithmRaw);
+  *AlgorithmListSize = Size;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Produces and returns an RNG value using either the default or specified RNG
+  algorithm.
+
+  @param[in]  This                A pointer to the EFI_RNG_PROTOCOL instance.
+  @param[in]  Algorithm           A pointer to the EFI_RNG_ALGORITHM that
+                                  identifies the RNG algorithm to use. May be
+                                  NULL in which case the function will use its
+                                  default RNG algorithm.
+  @param[in]  ValueLength         The length in bytes of the memory buffer
+                                  pointed to by RNGValue. The driver shall
+                                  return exactly this numbers of bytes.
+  @param[out] Value               A caller-allocated memory buffer filled by the
+                                  driver with the resulting RNG value.
+
+  @retval EFI_SUCCESS             The RNG value was returned successfully.
+  @retval EFI_UNSUPPORTED         The algorithm specified by RNGAlgorithm is not
+                                  supported by this driver.
+  @retval EFI_DEVICE_ERROR        An RNG value could not be retrieved due to a
+                                  hardware or firmware error.
+  @retval EFI_NOT_READY           There is not enough random data available to
+                                  satisfy the length requested by
+                                  RNGValueLength.
+  @retval EFI_INVALID_PARAMETER   RNGValue is NULL or RNGValueLength is zero.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AtSha240aGetRNG (
+  IN EFI_RNG_PROTOCOL   *This,
+  IN EFI_RNG_ALGORITHM  *Algorithm OPTIONAL,
+  IN UINTN              ValueLength,
+  OUT UINT8             *Value
+)
+{
+  EFI_STATUS                  Status;
+  ATSHA204A_DEV               *AtSha204a;
+  ATSHA204A_I2C_RNG_COMMAND   Command;
+  ATSHA204A_I2C_RNG_RESULT    Result;
+  I2C_RNG_REQUEST             Request;
+  I2C_RNG_REQUEST             Response;
+  UINTN                       Retries;
+
+  if (Algorithm != NULL && !CompareGuid (Algorithm, &gEfiRngAlgorithmRaw)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  AtSha204a = ATSHA204A_DEV_FROM_THIS (This);
+
+  Request.OperationCount  = 1;
+  Request.Operation.Flags = 0;
+
+  Command.Command   = ATSHA204A_COMMAND;
+  Command.Count     = sizeof (Command) - 1;
+  Command.Opcode    = ATSHA204A_OPCODE_RANDOM;
+  Command.Param1    = 0;
+  Command.Param2    = 0;
+  Command.Crc       = OPCODE_COMMAND_PACKET_CRC;
+
+  Response.OperationCount           = 1;
+  Response.Operation.Flags          = I2C_FLAG_READ;
+  Response.Operation.LengthInBytes  = sizeof (Result);
+  Response.Operation.Buffer         = (VOID *)&Result;
+
+  Retries = 0;
+  while (ValueLength > 0) {
+    //
+    // The AtSha204a will go back to sleep right in the middle of a transaction
+    // if it does not complete in ~1.3 seconds. So send the wake sequence for
+    // each iteration, which consists of a dummy write to slave address 0x0.
+    //
+    Request.Operation.LengthInBytes = 0;
+    Status = AtSha204a->I2cIo->QueueRequest (AtSha204a->I2cIo, 1, NULL,
+                                 (VOID *)&Request, NULL);
+    DEBUG ((DEBUG_INFO, "%a: wake AtSha204a: I2cIo->QueueRequest() - %r\n",
+      __FUNCTION__, Status));
+
+    gBS->Stall (2500); // wait 2.5 ms for wake to complete
+
+    Request.Operation.LengthInBytes = sizeof (Command);
+    Request.Operation.Buffer = (VOID *)&Command;
+    Status = AtSha204a->I2cIo->QueueRequest (AtSha204a->I2cIo, 0, NULL,
+                                 (VOID *)&Request, NULL);
+    if (EFI_ERROR (Status)) {
+      if (++Retries <= MAX_RETRIES) {
+        continue;
+      }
+      DEBUG ((DEBUG_ERROR, "%a: I2C request transfer failed, Status == %r\n",
+        __FUNCTION__, Status));
+      return EFI_DEVICE_ERROR;
+    }
+
+    gBS->Stall (50 * 1000); // 50 ms max execution time for RANDOM opcode
+
+    Status = AtSha204a->I2cIo->QueueRequest (AtSha204a->I2cIo, 0, NULL,
+                                 (VOID *)&Response, NULL);
+    if (EFI_ERROR (Status)) {
+      if (++Retries <= MAX_RETRIES) {
+        continue;
+      }
+      DEBUG ((DEBUG_ERROR, "%a: I2C response transfer failed, Status == %r\n",
+        __FUNCTION__, Status));
+      return EFI_DEVICE_ERROR;
+    }
+
+    if (Result.Count < sizeof (Result)) {
+      //
+      // Incomplete packet received, most likely due to an error. Retry.
+      //
+      if (++Retries <= MAX_RETRIES) {
+        continue;
+      }
+      DEBUG ((DEBUG_WARN, "%a: incomplete packet received\n", __FUNCTION__));
+      return EFI_DEVICE_ERROR;
+    }
+
+    gBS->CopyMem (Value, Result.Result, MIN (ValueLength,
+                                             ATSHA204A_OUTPUT_SIZE));
+    if (ValueLength < ATSHA204A_OUTPUT_SIZE) {
+      break;
+    }
+
+    Value += ATSHA204A_OUTPUT_SIZE;
+    ValueLength -= ATSHA204A_OUTPUT_SIZE;
+    Retries = 0;
+  }
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtSha204aInit (
+  IN      EFI_HANDLE        DriverBindingHandle,
+  IN      EFI_HANDLE        ControllerHandle
+  )
+{
+  EFI_STATUS                Status;
+  ATSHA204A_DEV             *AtSha204a;
+
+  Status = gBS->AllocatePool (EfiBootServicesData, sizeof (ATSHA204A_DEV),
+                  (VOID **) &AtSha204a);
+  if (EFI_ERROR (Status)) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  AtSha204a->Signature    = ATSHA204A_DEV_SIGNATURE;
+  AtSha204a->Rng.GetInfo  = AtSha240aGetInfo;
+  AtSha204a->Rng.GetRNG   = AtSha240aGetRNG;
+
+  //
+  // Open I2C I/O Protocol
+  //
+  Status = gBS->OpenProtocol (ControllerHandle,
+                              &gEfiI2cIoProtocolGuid,
+                              (VOID **)&AtSha204a->I2cIo,
+                              DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_BY_DRIVER);
+  if (EFI_ERROR (Status)) {
+    goto ErrorFreeDev;
+  }
+
+  Status = gBS->InstallProtocolInterface (&ControllerHandle,
+                                          &gEfiRngProtocolGuid,
+                                          EFI_NATIVE_INTERFACE,
+                                          &AtSha204a->Rng);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "Failed to install RNG protocol interface (Status == %r)\n",
+    Status));
+    goto ErrorCloseProtocol;
+  }
+
+  return EFI_SUCCESS;
+
+ErrorCloseProtocol:
+  gBS->CloseProtocol (ControllerHandle, &gEfiI2cIoProtocolGuid,
+         DriverBindingHandle, ControllerHandle);
+
+ErrorFreeDev:
+  gBS->FreePool (AtSha204a);
+
+  return Status;
+}
+
+EFI_STATUS
+AtSha204aRelease (
+  IN  EFI_HANDLE        DriverBindingHandle,
+  IN  EFI_HANDLE        ControllerHandle
+  )
+{
+  EFI_RNG_PROTOCOL    *Rng;
+  ATSHA204A_DEV       *AtSha204a;
+  EFI_STATUS          Status;
+
+  Status = gBS->HandleProtocol (ControllerHandle,
+                                &gEfiRngProtocolGuid,
+                                (VOID **)&Rng);
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  AtSha204a = ATSHA204A_DEV_FROM_THIS (Rng);
+
+  Status = gBS->UninstallProtocolInterface (ControllerHandle,
+                                            &gEfiRngProtocolGuid,
+                                            Rng);
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->CloseProtocol (ControllerHandle,
+                               &gEfiI2cIoProtocolGuid,
+                               DriverBindingHandle,
+                               ControllerHandle);
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  gBS->FreePool (AtSha204a);
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Atmel/AtSha204a/AtSha204aDriver.h b/Silicon/Atmel/AtSha204a/AtSha204aDriver.h
new file mode 100644
index 000000000000..315a450d34f2
--- /dev/null
+++ b/Silicon/Atmel/AtSha204a/AtSha204aDriver.h
@@ -0,0 +1,81 @@ 
+/** @file
+  Device driver for the Atmel ATSHA204A random number generator.
+
+  Copyright (c) 2018, 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.
+
+**/
+
+#ifndef _ATSHA204A_I2C_HWRNG_DRIVER_H_
+#define _ATSHA204A_I2C_HWRNG_DRIVER_H_
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/Rng.h>
+#include <Protocol/I2cIo.h>
+
+#define ATSHA204A_OUTPUT_SIZE     32
+
+#define ATSHA204A_DEV_SIGNATURE   SIGNATURE_32('a','t','s','h')
+
+typedef struct {
+  UINT32                        Signature;
+  EFI_I2C_IO_PROTOCOL           *I2cIo;
+  EFI_RNG_PROTOCOL              Rng;
+} ATSHA204A_DEV;
+
+#define ATSHA204A_DEV_FROM_THIS(a) \
+  CR(a, ATSHA204A_DEV, Rng, ATSHA204A_DEV_SIGNATURE)
+
+#pragma pack(1)
+typedef struct {
+  UINT8                           Command;
+  UINT8                           Count;
+  UINT8                           Opcode;
+  UINT8                           Param1;
+  UINT16                          Param2;
+  UINT16                          Crc;
+} ATSHA204A_I2C_RNG_COMMAND;
+
+typedef struct {
+  UINT8                           Count;
+  UINT8                           Result[ATSHA204A_OUTPUT_SIZE];
+  UINT16                          Crc;
+} ATSHA204A_I2C_RNG_RESULT;
+#pragma pack()
+
+typedef struct {
+  UINTN                           OperationCount;
+  EFI_I2C_OPERATION               Operation;
+} I2C_RNG_REQUEST;
+
+#define ATSHA204A_COMMAND         0x3
+
+#define ATSHA204A_OPCODE_RANDOM   0x1b
+
+extern EFI_COMPONENT_NAME2_PROTOCOL gAtSha204aDriverComponentName2;
+
+EFI_STATUS
+AtSha204aInit (
+  IN  EFI_HANDLE        DriverBindingHandle,
+  IN  EFI_HANDLE        ControllerHandle
+  );
+
+EFI_STATUS
+AtSha204aRelease (
+  IN  EFI_HANDLE        DriverBindingHandle,
+  IN  EFI_HANDLE        ControllerHandle
+  );
+
+#endif // _ATSHA204A_I2C_HWRNG_DRIVER_H_
diff --git a/Silicon/Atmel/AtSha204a/AtSha204aDxe.inf b/Silicon/Atmel/AtSha204a/AtSha204aDxe.inf
new file mode 100644
index 000000000000..fe90cc538114
--- /dev/null
+++ b/Silicon/Atmel/AtSha204a/AtSha204aDxe.inf
@@ -0,0 +1,52 @@ 
+## @file
+#  Device driver for the Atmel ATSHA204A random number generator.
+#
+#  Copyright (c) 2018, 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                    = 0x0001001A
+  BASE_NAME                      = AtSha204aDxe
+  FILE_GUID                      = 8b8f683b-f376-4ba0-b8d7-b4bbd30319cc
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = EntryPoint
+  UNLOAD_IMAGE                   = UnloadImage
+
+#
+#  VALID_ARCHITECTURES           = AARCH64 ARM EBC IA32 IPF X64
+#
+
+[Sources]
+  AtSha204aDriver.c
+  AtSha204aDriver.h
+  ComponentName.c
+  DriverBinding.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  Silicon/Atmel/AtSha204a/AtSha204a.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+
+[Protocols]
+  gEfiRngProtocolGuid                 # PROTOCOL BY_START
+  gEfiI2cIoProtocolGuid               # PROTOCOL TO_START
+
+[Guids]
+  gAtSha204aI2cDeviceGuid
+  gEfiRngAlgorithmRaw
diff --git a/Silicon/Atmel/AtSha204a/ComponentName.c b/Silicon/Atmel/AtSha204a/ComponentName.c
new file mode 100644
index 000000000000..9893e7c4c2bf
--- /dev/null
+++ b/Silicon/Atmel/AtSha204a/ComponentName.c
@@ -0,0 +1,186 @@ 
+/** @file
+  UEFI Component Name(2) protocol implementation for AtSha204a driver.
+
+  Copyright (c) 2018, Linaro Ltd. 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 "AtSha204aDriver.h"
+
+STATIC EFI_UNICODE_STRING_TABLE mAtSha204aDriverNameTable[] = {
+  {
+    "en",
+    (CHAR16 *)L"AtSha204a RNG I2C driver"
+  },
+  { }
+};
+
+STATIC EFI_UNICODE_STRING_TABLE mAtSha204aControllerNameTable[] = {
+  {
+    "en",
+    (CHAR16 *)L"AtSha204a Random Number Generator (I2C)"
+  },
+  { }
+};
+
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 4646 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AtSha204aGetDriverName (
+  IN  EFI_COMPONENT_NAME2_PROTOCOL  *This,
+  IN  CHAR8                         *Language,
+  OUT CHAR16                        **DriverName
+  )
+{
+  return LookupUnicodeString2 (Language,
+                               This->SupportedLanguages,
+                               mAtSha204aDriverNameTable,
+                               DriverName,
+                               FALSE);
+}
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 4646 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AtSha204aGetControllerName (
+  IN  EFI_COMPONENT_NAME2_PROTOCOL                    *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  return LookupUnicodeString2 (Language,
+                               This->SupportedLanguages,
+                               mAtSha204aControllerNameTable,
+                               ControllerName,
+                               FALSE);
+}
+
+//
+// EFI Component Name 2 Protocol
+//
+EFI_COMPONENT_NAME2_PROTOCOL gAtSha204aDriverComponentName2 = {
+  AtSha204aGetDriverName,
+  AtSha204aGetControllerName,
+  "en"
+};
diff --git a/Silicon/Atmel/AtSha204a/DriverBinding.c b/Silicon/Atmel/AtSha204a/DriverBinding.c
new file mode 100644
index 000000000000..17e61f96e8c5
--- /dev/null
+++ b/Silicon/Atmel/AtSha204a/DriverBinding.c
@@ -0,0 +1,242 @@ 
+/** @file
+  Device driver for the Atmel ATSHA204A random number generator.
+
+  Copyright (c) 2018, 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.
+
+**/
+
+#include <Library/UefiDriverEntryPoint.h>
+
+#include "AtSha204aDriver.h"
+
+/**
+  Tests to see if this driver supports a given controller.
+
+  @param  This[in]                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+                                   instance.
+  @param  ControllerHandle[in]     The handle of the controller to test.
+  @param  RemainingDevicePath[in]  The remaining device path.
+                                   (Ignored - this is not a bus driver.)
+
+  @retval EFI_SUCCESS              The driver supports this controller.
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle is
+                                   already being managed by the driver specified
+                                   by This.
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle is
+                                   not supported by the driver specified by This.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cHwrngDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_I2C_IO_PROTOCOL        *I2cIo;
+  EFI_STATUS                 Status;
+
+  //
+  //  Connect to the I2C stack
+  //
+  Status = gBS->OpenProtocol (ControllerHandle,
+                              &gEfiI2cIoProtocolGuid,
+                              (VOID **) &I2cIo,
+                              This->DriverBindingHandle,
+                              ControllerHandle,
+                              EFI_OPEN_PROTOCOL_BY_DRIVER);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (CompareGuid (I2cIo->DeviceGuid, &gAtSha204aI2cDeviceGuid)) {
+    DEBUG ((DEBUG_INIT | DEBUG_INFO, "Detected AtSha204a RNG device\n"));
+    Status = EFI_SUCCESS;
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+
+  //
+  // Clean up.
+  //
+  gBS->CloseProtocol (ControllerHandle,
+                      &gEfiI2cIoProtocolGuid,
+                      This->DriverBindingHandle,
+                      ControllerHandle);
+
+  return Status;
+}
+
+
+/**
+  Starts a device controller or a bus controller.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+                                   instance.
+  @param[in]  ControllerHandle     The handle of the device to start. This
+                                   handle must support a protocol interface that
+                                   supplies an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  The remaining portion of the device path.
+                                   (Ignored - this is not a bus driver.)
+
+  @retval EFI_SUCCESS              The device was started.
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a
+                                   device error.
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a
+                                   lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cHwrngDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
+  )
+{
+  return AtSha204aInit (This->DriverBindingHandle, ControllerHandle);
+}
+
+
+/**
+  Stops a device controller or a bus controller.
+
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+                                instance.
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle
+                                must support a bus specific I/O protocol for the
+                                driver to use to stop the device.
+  @param[in]  NumberOfChildren  The number of child device handles in
+                                ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be
+                                NULL if NumberOfChildren is 0.
+
+  @retval EFI_SUCCESS           The device was stopped.
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device
+                                error.
+
+**/
+EFI_STATUS
+EFIAPI
+I2cHwrngDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                  ControllerHandle,
+  IN  UINTN                       NumberOfChildren,
+  IN  EFI_HANDLE                  *ChildHandleBuffer OPTIONAL
+  )
+{
+  return AtSha204aRelease (This->DriverBindingHandle, ControllerHandle);
+}
+
+
+STATIC
+EFI_DRIVER_BINDING_PROTOCOL  gI2cHwrngDriverBinding = {
+  I2cHwrngDriverBindingSupported,
+  I2cHwrngDriverBindingStart,
+  I2cHwrngDriverBindingStop,
+  0xa,
+  NULL,
+  NULL
+};
+
+
+/**
+  The entry point of AtSha204a UEFI Driver.
+
+  @param  ImageHandle                The image handle of the UEFI Driver.
+  @param  SystemTable                A pointer to the EFI System Table.
+
+  @retval  EFI_SUCCESS               The Driver or UEFI Driver exited normally.
+  @retval  EFI_INCOMPATIBLE_VERSION  _gUefiDriverRevision is greater than
+                                     SystemTable->Hdr.Revision.
+
+**/
+EFI_STATUS
+EFIAPI
+EntryPoint (
+  IN  EFI_HANDLE          ImageHandle,
+  IN  EFI_SYSTEM_TABLE    *SystemTable
+  )
+{
+  EFI_STATUS    Status;
+
+  //
+  //  Add the driver to the list of drivers
+  //
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle, SystemTable, &gI2cHwrngDriverBinding, ImageHandle,
+             NULL, &gAtSha204aDriverComponentName2);
+  ASSERT_EFI_ERROR (Status);
+
+  DEBUG ((DEBUG_INIT | DEBUG_INFO, "*** Installed AtSha204a driver! ***\n"));
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Unload function for the AtSha204a Driver.
+
+  @param  ImageHandle[in]        The allocated handle for the EFI image
+
+  @retval EFI_SUCCESS            The driver was unloaded successfully
+  @retval EFI_INVALID_PARAMETER  ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+UnloadImage (
+  IN EFI_HANDLE  ImageHandle
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  *HandleBuffer;
+  UINTN       HandleCount;
+  UINTN       Index;
+
+  //
+  // Retrieve all I2C I/O handles in the handle database
+  //
+  Status = gBS->LocateHandleBuffer (ByProtocol,
+                                    &gEfiI2cIoProtocolGuid,
+                                    NULL,
+                                    &HandleCount,
+                                    &HandleBuffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Disconnect the driver from the handles in the handle database
+  //
+  for (Index = 0; Index < HandleCount; Index++) {
+    Status = gBS->DisconnectController (HandleBuffer[Index],
+                                        gImageHandle,
+                                        NULL);
+  }
+
+  //
+  // Free the handle array
+  //
+  gBS->FreePool (HandleBuffer);
+
+  //
+  // Uninstall protocols installed by the driver in its entrypoint
+  //
+  Status = gBS->UninstallMultipleProtocolInterfaces (ImageHandle,
+                  &gEfiDriverBindingProtocolGuid,
+                  &gI2cHwrngDriverBinding,
+                  NULL
+                  );
+
+  return EFI_SUCCESS;
+}