Aplications/Eeprom: Add 'eeprom' command to shell

'eeprom' command brings MvEeprom driver capabilities to UEFI shell.
It allows reading & writing from/to onboard EEPROM device.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Bartosz Szczepanek <bsz@semihalf.com>
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
diff --git a/Applications/EepromCmd/EepromCmd.c b/Applications/EepromCmd/EepromCmd.c
new file mode 100644
index 0000000..f43e411
--- /dev/null
+++ b/Applications/EepromCmd/EepromCmd.c
@@ -0,0 +1,397 @@
+/********************************************************************************

+Copyright (C) 2016 Marvell International Ltd.

+

+Marvell BSD License Option

+

+If you received this File from Marvell, you may opt to use, redistribute and/or

+modify this File under the following licensing terms.

+Redistribution and use in source and binary forms, with or without modification,

+are permitted provided that the following conditions are met:

+

+* Redistributions of source code must retain the above copyright notice,

+  this list of conditions and the following disclaimer.

+

+* Redistributions in binary form must reproduce the above copyright

+  notice, this list of conditions and the following disclaimer in the

+  documentation and/or other materials provided with the distribution.

+

+* Neither the name of Marvell nor the names of its contributors may be

+  used to endorse or promote products derived from this software without

+  specific prior written permission.

+

+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND

+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR

+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON

+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+

+*******************************************************************************/

+

+#include <Uefi.h>

+

+#include <ShellBase.h>

+#include <Library/BaseLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/ShellCommandLib.h>

+#include <Library/ShellLib.h>

+#include <Library/UefiLib.h>

+#include <Library/UefiRuntimeServicesTableLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/PrintLib.h>

+#include <Library/HiiLib.h>

+

+#include <Library/UefiLib.h>

+#include <Library/ShellCEntryLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+

+#include <Protocol/Eeprom.h>

+

+#define I2C_DEVICE_INDEX(bus, address) (((address) & 0xffff) | (bus) << 16)

+#define I2C_DEVICE_ADDRESS(index) ((index) & 0xffff)

+#define I2C_DEVICE_BUS(index) ((index) >> 16)

+

+CONST CHAR16 ShellEepromFileName[] = L"ShellCommand";

+EFI_HANDLE ShellEepromHiiHandle = NULL;

+

+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {

+  {L"-d", TypeValue},

+  {L"-m", TypeValue},

+  {L"read", TypeFlag},

+  {L"write", TypeFlag},

+  {L"list", TypeFlag},

+  {L"help", TypeFlag},

+  {NULL , TypeMax}

+  };

+

+/**

+  Return the file name of the help text file if not using HII.

+

+  @return The string pointer to the file name.

+**/

+STATIC

+CONST CHAR16*

+EFIAPI

+ShellCommandGetManFileNameEeprom (

+  VOID

+  )

+{

+  return ShellEepromFileName;

+}

+

+STATIC

+VOID

+Usage (

+  VOID

+  )

+{

+  Print (L"Basic EEPROM commands:\n"

+         "eeprom [read] [write] [list] [<Chip>] [<Bus>][<Address>] [<Length>] [-d <Data>] [-m <Source>]\n"

+         "All modes except 'list' require Address, Length and Chip set.\n\n"

+         "read    - read from EEPROM\n"

+         "write   - write Data to EEPROM, requires -d\n"

+         "list    - list available EEPROM devices\n\n"

+         "-m      - transfer from/to RAM memory\n\n"

+         "Chip    - EEPROM bus address\n"

+         "Bus     - I2C bus address\n"

+         "Address - address in EEPROM to read/write\n"

+         "Data    - data byte to be written\n"

+         "Length  - length of data to read/write/copy\n"

+         "Source  - address of data in RAM to be copied\n"

+         "Examples:\n"

+         "List devices:\n"

+         " eeprom list\n"

+         "Read 16 bytes from address 0x0 in chip 0x57:\n"

+         " eeprom read 0x57 0x0 0x0 0x10\n"

+         "Fill 16 bytes with 0xab at address 0x0 in chip 0x57:\n"

+         " eeprom write 0x57 0x0 0x0 0x10 -d 0xab\n"

+         "Copy 32 bytes from 0x2000000 in RAM to EEPROM:\n"

+         " eeprom write 0x57 0x0 0x0 0x20 -m 0x2000000\n"

+         "Copy 32 bytes from EEPROM to RAM:\n"

+         " eeprom read 0x57 0x0 0x0 0x20 -m 0x2000000\n"

+  );

+}

+

+STATIC

+EFI_STATUS

+EepromList (

+    )

+{

+  EFI_HANDLE *HandleBuffer;

+  EFI_STATUS Status;

+  UINTN ProtocolCount;

+  MARVELL_EEPROM_PROTOCOL *EepromProtocol;

+  UINTN i;

+  Status = gBS->LocateHandleBuffer ( ByProtocol,

+                                     &gMarvellEepromProtocolGuid,

+                                     NULL,

+                                     &ProtocolCount,

+                                     &HandleBuffer

+                                   );

+  if (ProtocolCount == 0) {

+    Print (L"0 devices found.\n");

+  } else {

+    Print (L"%u devices found: ", ProtocolCount);

+  }

+

+  for (i = 0; i < ProtocolCount; i++) {

+    Status = gBS->OpenProtocol (

+                    HandleBuffer[i],

+                    &gMarvellEepromProtocolGuid,

+                    (VOID **) &EepromProtocol,

+                    gImageHandle,

+                    NULL,

+                    EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );

+    Print (L"0x%x at bus %d\n", I2C_DEVICE_ADDRESS(EepromProtocol->Identifier),

+        I2C_DEVICE_BUS(EepromProtocol->Identifier));

+    Status = gBS->CloseProtocol ( HandleBuffer[i],

+                                  &gMarvellEepromProtocolGuid,

+                                  gImageHandle,

+                                  NULL );

+  }

+  Print (L"\n");

+  return Status;

+}

+

+STATIC

+EFI_STATUS

+EepromLocateProtocol (

+ IN  UINT32 Identifier,

+ OUT EFI_HANDLE *FoundHandle,

+ OUT MARVELL_EEPROM_PROTOCOL **FoundEepromProtocol

+ )

+{

+  EFI_HANDLE *HandleBuffer;

+  EFI_STATUS Status;

+  UINTN ProtocolCount;

+  MARVELL_EEPROM_PROTOCOL *EepromProtocol;

+  UINTN i;

+  Status = gBS->LocateHandleBuffer ( ByProtocol,

+                                     &gMarvellEepromProtocolGuid,

+                                     NULL,

+                                     &ProtocolCount,

+                                     &HandleBuffer

+                                   );

+  if (EFI_ERROR(Status))

+    return Status;

+

+  for (i = 0; i < ProtocolCount; i++) {

+    Status = gBS->OpenProtocol (

+                    HandleBuffer[i],

+                    &gMarvellEepromProtocolGuid,

+                    (VOID **) &EepromProtocol,

+                    gImageHandle,

+                    NULL,

+                    EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );

+    if (EepromProtocol->Identifier == Identifier) {

+      *FoundEepromProtocol = EepromProtocol;

+      *FoundHandle = HandleBuffer[i];

+      return EFI_SUCCESS;

+    }

+    Status = gBS->CloseProtocol ( HandleBuffer[i],

+                                  &gMarvellEepromProtocolGuid,

+                                  gImageHandle,

+                                  NULL );

+  }

+  *FoundEepromProtocol = NULL;

+  return EFI_UNSUPPORTED;

+}

+

+SHELL_STATUS

+EFIAPI

+ShellCommandRunEeprom (

+  IN EFI_HANDLE        ImageHandle,

+  IN EFI_SYSTEM_TABLE  *SystemTable

+  )

+{

+  EFI_STATUS              Status;

+  LIST_ENTRY              *CheckPackage;

+  CHAR16                  *ProblemParam;

+  CONST CHAR16            *ValueStr;

+  UINTN                   Address, Length, Chip, Source, Bus;

+  UINT8                   Data;

+  UINT8                   *Buffer;

+  BOOLEAN                 ReadMode, MemMode;

+  EFI_HANDLE              Handle, ProtHandle;

+  MARVELL_EEPROM_PROTOCOL *EepromProtocol = NULL;

+  UINTN                   Count, HandleSize;

+

+  Handle = NULL;

+  Source = 0;

+  HandleSize = 2 * sizeof (EFI_HANDLE);

+

+  Status = gBS->LocateHandle (ByProtocol, &gMarvellEepromProtocolGuid, NULL,

+    &HandleSize, &ProtHandle);

+  if (EFI_ERROR(Status)) {

+    DEBUG((DEBUG_INFO, "No Eeprom protocol, connect I2C stack\n"));

+    Status = gBS->LocateHandle (ByProtocol, &gEfiI2cMasterProtocolGuid, NULL,

+      &HandleSize, &ProtHandle);

+    if (EFI_ERROR(Status)) {

+      Print (L"Failed to locate I2cMaster protocol, abort!\n");

+      return SHELL_ABORTED;

+    }

+    Status = gBS->ConnectController (ProtHandle, NULL, NULL, TRUE);

+    if (EFI_ERROR(Status)) {

+      Print (L"Cannot connect I2C stack, abort!\n");

+      return SHELL_ABORTED;

+    }

+  }

+

+  Status = ShellInitialize ();

+  if (EFI_ERROR (Status)) {

+    Print (L"Error - failed to initialize shell\n");

+    return SHELL_ABORTED;

+  }

+

+  Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE);

+  if (EFI_ERROR (Status)) {

+    Print (L"Error - failed to parse command line\n");

+    return SHELL_ABORTED;

+  }

+

+  if (ShellCommandLineGetFlag (CheckPackage, L"list")) {

+    EepromList();

+    return SHELL_SUCCESS;

+  }

+

+  if (ShellCommandLineGetFlag (CheckPackage, L"help")) {

+    Usage();

+    return SHELL_SUCCESS;

+  }

+

+  if (ShellCommandLineGetCount(CheckPackage) < 4) {

+    Print (L"Not enough arguments given.\n");

+    Usage();

+  }

+

+  ReadMode = ShellCommandLineGetFlag (CheckPackage, L"read");

+  if (ReadMode == ShellCommandLineGetFlag (CheckPackage, L"write")) {

+    Print (L"Error - type read, write, list or help.\n");

+    return SHELL_INVALID_PARAMETER;

+  }

+

+  MemMode = ShellCommandLineGetFlag (CheckPackage, L"-m");

+  Data = 0;

+  if (!ReadMode && !MemMode) {

+    ValueStr = ShellCommandLineGetValue (CheckPackage, L"-d");

+    if (ValueStr == NULL) {

+      Print (L"Error - no data to write.\n");

+      return SHELL_INVALID_PARAMETER;

+    }

+    Data = ShellHexStrToUintn (ValueStr);

+  }

+

+  ValueStr = ShellCommandLineGetRawValue(CheckPackage, 1);

+  Chip = ShellHexStrToUintn (ValueStr);

+

+  ValueStr = ShellCommandLineGetRawValue(CheckPackage, 2);

+  Bus = ShellHexStrToUintn (ValueStr);

+

+  ValueStr = ShellCommandLineGetRawValue(CheckPackage, 3);

+  Address = ShellHexStrToUintn (ValueStr);

+

+  ValueStr = ShellCommandLineGetRawValue(CheckPackage, 4);

+  Length = ShellHexStrToUintn (ValueStr);

+

+  if (MemMode) {

+    ValueStr = ShellCommandLineGetValue (CheckPackage, L"-m");

+    if (ValueStr == NULL) {

+      Print (L"Error - no memory address given.\n");

+      return SHELL_INVALID_PARAMETER;

+    }

+    Source = ShellHexStrToUintn (ValueStr);

+  }

+

+  EepromLocateProtocol (I2C_DEVICE_INDEX(Bus, Chip), &Handle, &EepromProtocol);

+  if (EepromProtocol == NULL) {

+    Print (L"Failed to locate EEPROM protocol.\n");

+    return SHELL_INVALID_PARAMETER;

+  }

+

+  if (MemMode) {

+    Buffer = (VOID *) Source;

+  } else {

+    Buffer = AllocateZeroPool (Length);

+    if (Buffer == NULL) {

+      Status = SHELL_OUT_OF_RESOURCES;

+      Print (L"Error - out of resources.\n");

+      goto out_close;

+    }

+    if (!ReadMode) {

+      for (Count = 0; Count < Length; Count++)

+        Buffer[Count] = Data;

+    }

+  }

+  EepromProtocol->Transfer(EepromProtocol, Address, Length, Buffer,

+      ReadMode ? EEPROM_READ : EEPROM_WRITE);

+

+  if (MemMode) {

+  Print (L"Transfered succesfully.\n");

+  } else {

+    Print (L"Transfered:\n");

+    for (Count = 0; Count < Length; Count++) {

+      Print(L"0x%x ", Buffer[Count]);

+      if (Count % 8 == 7)

+        Print(L"\n");

+    }

+    Print (L"\n");

+  }

+

+  Status = SHELL_SUCCESS;

+

+  if (!MemMode)

+    FreePool(Buffer);

+out_close:

+  gBS->CloseProtocol ( Handle,

+                       &gMarvellEepromProtocolGuid,

+                       gImageHandle,

+                       NULL );

+

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+ShellEepromCmdLibConstructor (

+  IN EFI_HANDLE        ImageHandle,

+  IN EFI_SYSTEM_TABLE  *SystemTable

+  )

+{

+

+  ShellEepromHiiHandle = NULL;

+

+  ShellEepromHiiHandle = HiiAddPackages (

+                          &gShellEepromHiiGuid, gImageHandle,

+                          UefiShellEepromLibStrings, NULL

+                          );

+  if (ShellEepromHiiHandle == NULL) {

+    Print (L"Filed to add Hii package\n");

+    return EFI_DEVICE_ERROR;

+  }

+  ShellCommandRegisterCommandName (

+     L"eeprom", ShellCommandRunEeprom, ShellCommandGetManFileNameEeprom, 0,

+     L"eeprom", TRUE , ShellEepromHiiHandle, STRING_TOKEN (STR_GET_HELP_EEPROM)

+     );

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+ShellEepromCmdLibDestructor (

+  IN EFI_HANDLE        ImageHandle,

+  IN EFI_SYSTEM_TABLE  *SystemTable

+  )

+{

+

+  if (ShellEepromHiiHandle != NULL) {

+    HiiRemovePackages (ShellEepromHiiHandle);

+  }

+  return EFI_SUCCESS;

+}

diff --git a/Applications/EepromCmd/EepromCmd.inf b/Applications/EepromCmd/EepromCmd.inf
new file mode 100644
index 0000000..1171fc1
--- /dev/null
+++ b/Applications/EepromCmd/EepromCmd.inf
@@ -0,0 +1,71 @@
+#

+# Marvell BSD License Option

+#

+# If you received this File from Marvell, you may opt to use, redistribute

+# and/or modify this File under the following licensing terms.

+# Redistribution and use in source and binary forms, with or without

+# modification, are permitted provided that the following conditions are met:

+#

+# * Redistributions of source code must retain the above copyright notice,

+# this list of conditions and the following disclaimer.

+#

+# * Redistributions in binary form must reproduce the above copyright

+# notice, this list of conditions and the following disclaimer in the

+# documentation and/or other materials provided with the distribution.

+#

+# * Neither the name of Marvell nor the names of its contributors may be

+# used to endorse or promote products derived from this software without

+# specific prior written permission.

+#

+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE

+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL

+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,

+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+#

+

+[Defines]

+  INF_VERSION = 0x00010006

+  BASE_NAME = UefiShellEepromLib

+  FILE_GUID = adf4b61c-2ca3-4e1a-9597-99282f5a4aa2

+  MODULE_TYPE = UEFI_APPLICATION

+  VERSION_STRING = 0.1

+  LIBRARY_CLASS  = NULL|UEFI_APPLICATION UEFI_DRIVER

+  CONSTRUCTOR = ShellEepromCmdLibConstructor

+  DESTRUCTOR  = ShellEepromCmdLibDestructor

+

+[Sources]

+  EepromCmd.c

+  EepromCmd.uni

+

+[Packages]

+  MdePkg/MdePkg.dec

+  ShellPkg/ShellPkg.dec

+  StdLib/StdLib.dec

+  MdeModulePkg/MdeModulePkg.dec

+  OpenPlatformPkg/Platforms/Marvell/Marvell.dec

+

+[LibraryClasses]

+  UefiLib

+  UefiBootServicesTableLib

+  MemoryAllocationLib

+  BaseLib

+  BaseMemoryLib

+  DebugLib

+  ShellCommandLib

+  ShellLib

+  UefiLib

+  UefiRuntimeServicesTableLib

+  PcdLib

+

+[Protocols]

+ gMarvellEepromProtocolGuid

+ gEfiI2cMasterProtocolGuid

+

+[Guids]

+  gShellEepromHiiGuid

diff --git a/Applications/EepromCmd/EepromCmd.uni b/Applications/EepromCmd/EepromCmd.uni
new file mode 100644
index 0000000..e41c6d8
--- /dev/null
+++ b/Applications/EepromCmd/EepromCmd.uni
Binary files differ
diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec
index bc4ac7a..a9c5a12 100644
--- a/Platforms/Marvell/Marvell.dec
+++ b/Platforms/Marvell/Marvell.dec
@@ -52,6 +52,8 @@
 [Guids.common]

   gMarvellTokenSpaceGuid = { 0xf995c6c8, 0xbc9b, 0x4e93, { 0xbd, 0xcf, 0x49, 0x90, 0xc6, 0xe7, 0x8c, 0x7f } }

 

+  gShellEepromHiiGuid = { 0xb2f4c714, 0x147f, 0x4ff7, { 0x82, 0x1b, 0xce, 0x7b, 0x91, 0x7f, 0x5f, 0x2f } }

+

 [PcdsFixedAtBuild.common]

 #MPP

   gMarvellTokenSpaceGuid.PcdMppChipCount|0|UINT32|0x30000001