On Fri, Apr 29, 2016 at 07:25:55PM +0200, Marcin Wojtas wrote:
From: Bartosz Szczepanek bsz@semihalf.com
MvI2cDxe driver was adapted to generic UEFI I2C stack. Connection with following interfaces was required:
- EFI_I2C_MASTER_PROTOCOL
 - EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL
 - EFI_I2C_ENUMERATE_PROTOCOL
 Driver exports configuration options via PCDs. Configurable options include:
- PcdI2cSlaveAddresses - should contain a list of valid I2C devices' addresses on bus
 - PcdI2cBaseAddress - physical address of I2C controller registers
 - PcdI2cClockFrequency - I2c clock frequency on platform
 Drivers of devices on I2C bus should never use EFI_I2C_MASTER_PROTOCOL directly. Instead, these ought to utilise EFI_I2C_IO_PROTOCOL produced by generic UEFI stack.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Bartosz Szczepanek bsz@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com
Documentation/Marvell/Drivers/I2cDriver.txt | 64 +++ Documentation/Marvell/PortingGuide/I2c.txt | 16 + Drivers/I2c/MvI2cDxe/MvI2cDxe.c | 683 ++++++++++++++++++++++++++++ Drivers/I2c/MvI2cDxe/MvI2cDxe.h | 258 +++++++++++ Drivers/I2c/MvI2cDxe/MvI2cDxe.inf | 72 +++ Platforms/Marvell/Marvell.dec | 6 + 6 files changed, 1099 insertions(+) create mode 100644 Documentation/Marvell/Drivers/I2cDriver.txt create mode 100644 Documentation/Marvell/PortingGuide/I2c.txt create mode 100644 Drivers/I2c/MvI2cDxe/MvI2cDxe.c create mode 100644 Drivers/I2c/MvI2cDxe/MvI2cDxe.h create mode 100644 Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
diff --git a/Documentation/Marvell/Drivers/I2cDriver.txt b/Documentation/Marvell/Drivers/I2cDriver.txt new file mode 100644 index 0000000..2f890de --- /dev/null +++ b/Documentation/Marvell/Drivers/I2cDriver.txt @@ -0,0 +1,64 @@ +1. Introduction +--------------- +**MvI2cDxe** is a driver supporting I2C controller on Marvell SOCs boards. +It is connected through protocols to generic UEFI I2C stack, which exposes +IO functionality to drivers of specific devices on I2C bus.
+2. MvI2cDxe driver design +-------------------------- +MvI2cDxe produces several protocols from generic I2C stack:
- EFI_I2C_MASTER_PROTOCOL,
 
- EFI_I2C_ENUMERATE_PROTOCOL,
 
- EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL
 
- general-purpose EFI_DRIVER_BINDING_PROTOCOL.
 - 2.1 EFI_I2C_MASTER_PROTOCOL
 
- This is the most important protocol produced by MvI2cDxe. Following functions
 - are implemented:
 ////// Reset the I2C host controller.///EFI_I2C_MASTER_PROTOCOL_RESET Reset;////// Start an I2C transaction in master mode on the host controller.///EFI_I2C_MASTER_PROTOCOL_START_REQUEST StartRequest;- StartRequest and Reset functions are used by I2cHost.
 - These should **not** be used by I2C device drivers - required
 - synchronization is not provided. Instead, members of EFI_I2C_IO_PROTOCOL
 - should be used.
 - 2.2 EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL
 
- The only function exposed via this protocol is MvI2cEnableConf. It is
 - required by I2C stack in order to allow changing I2C bus configuration from
 - device drivers.
 - 2.3 EFI_I2C_ENUMERATE_PROTOCOL
 
- Provides Enumerate function, which is used by I2cBus code as an iterator over
 - devices on I2C bus.
 - typedef
 - EFI_STATUS
 - (EFIAPI *EFI_I2C_ENUMERATE_PROTOCOL_ENUMERATE) (
 IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,IN OUT CONST EFI_I2C_DEVICE **Device- );
 - ///
 - /// Traverse the set of I2C devices on an I2C bus. This routine
 - /// returns the next I2C device on an I2C bus.
 - ///
 - EFI_I2C_ENUMERATE_PROTOCOL_ENUMERATE Enumerate;
 - MvI2cDevice creates EFI_I2C_DEVICE structure for every device on the bus.
 - Due to the fact that hardware-based I2C enumeration isn't safe, information
 - about attached devices should be provided through PCDs. After EFI_I2C_DEVICE
 - structure is created and filled properly, it is returned to I2cBus. It is
 - followed by attachment of I2C device driver.
 diff --git a/Documentation/Marvell/PortingGuide/I2c.txt b/Documentation/Marvell/PortingGuide/I2c.txt new file mode 100644 index 0000000..7b78367 --- /dev/null +++ b/Documentation/Marvell/PortingGuide/I2c.txt @@ -0,0 +1,16 @@ +1. Porting I2C driver to a new SOC +---------------------------------- +In order to enable driver on a new platform, following steps need to be taken:
- add following line to .dsc file:
 - OpenPlatformPkg/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
 
- add following line to .fdf file:
 - INF OpenPlatformPkg/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf
 
- add PCDs with relevant values to .dsc file:
 gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0x50, 0x57 }- (addresses of I2C slave devices on bus)
 gMarvellTokenSpaceGuid.PcdI2cBaseAddress|0xF0511000- (base address of I2C controller)
 gMarvellTokenSpaceGuid.PcdI2cClockFrequency|200000000- (I2C host controller clock frequency)
 gMarvellTokenSpaceGuid.PcdI2cBaudRate|100000- (baud rate used in I2C transmission)
 diff --git a/Drivers/I2c/MvI2cDxe/MvI2cDxe.c b/Drivers/I2c/MvI2cDxe/MvI2cDxe.c new file mode 100644 index 0000000..b91ccfe --- /dev/null +++ b/Drivers/I2c/MvI2cDxe/MvI2cDxe.c @@ -0,0 +1,683 @@ +/******************************************************************************** +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 <Protocol/I2cMaster.h> +#include <Protocol/I2cEnumerate.h> +#include <Protocol/I2cBusConfigurationManagement.h> +#include <Protocol/DevicePath.h>
+#include <Library/BaseLib.h> +#include <Library/IoLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/UefiLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h>
+#include "MvI2cDxe.h"
+STATIC MV_I2C_BAUD_RATE baud_rate;
+MV_I2C_DEVICE_PATH gDevicePathProtocol = {
If this is meant to be a global variable, could it be renamed gMvI2cDevicePathProtocol? If not, keep the name but make it STATIC.
- {
 - {
 HARDWARE_DEVICE_PATH,HW_VENDOR_DP,{- (UINT8) (sizeof(VENDOR_DEVICE_PATH)),
 - (UINT8) (sizeof(VENDOR_DEVICE_PATH) >> 8),
 },- },
 - EFI_CALLER_ID_GUID
 - },
 - {
 - END_DEVICE_PATH_TYPE,
 - END_ENTIRE_DEVICE_PATH_SUBTYPE,
 - {
 sizeof(EFI_DEVICE_PATH_PROTOCOL),0- }
 - }
 +};
+STATIC +UINT32 +I2C_READ(
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINTN off)
 +{
- ASSERT (I2cMasterContext != NULL);
 - return MmioRead32 (I2cMasterContext->BaseAddress + off);
 +}
+STATIC +EFI_STATUS +I2C_WRITE (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINTN off,
 - IN UINT32 Value)
 +{
- ASSERT (I2cMasterContext != NULL);
 - return MmioWrite32 (I2cMasterContext->BaseAddress + off, Value);
 +}
+EFI_STATUS +EFIAPI +MvI2cInitialise (
- IN EFI_HANDLE ImageHandle,
 - IN EFI_SYSTEM_TABLE *SystemTable
 - )
 +{
- EFI_STATUS Status;
 - I2C_MASTER_CONTEXT *I2cMasterContext;
 - /* if attachment succeeds, this gets freed at ExitBootServices */
 - I2cMasterContext = AllocateZeroPool (sizeof (I2C_MASTER_CONTEXT));
 - if (I2cMasterContext == NULL) {
 - DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C master context allocation failed\n"));
 - return EFI_OUT_OF_RESOURCES;
 - }
 - I2cMasterContext->Signature = I2C_MASTER_SIGNATURE;
 - I2cMasterContext->I2cMaster.Reset = MvI2cReset;
 - I2cMasterContext->I2cMaster.StartRequest = MvI2cStartRequest;
 - I2cMasterContext->I2cEnumerate.Enumerate = MvI2cEnumerate;
 - I2cMasterContext->I2cBusConf.EnableI2cBusConfiguration = MvI2cEnableConf;
 - I2cMasterContext->TclkFrequency = PcdGet32 (PcdI2cClockFrequency);
 - I2cMasterContext->BaseAddress = PcdGet64 (PcdI2cBaseAddress);
 - /* I2cMasterContext->Lock is responsible for serializing I2C operations */
 - EfiInitializeLock(&I2cMasterContext->Lock, TPL_NOTIFY);
 - /* Checks if protocol is *not yet* installed */
 - ASSERT_PROTOCOL_ALREADY_INSTALLED(NULL, &gEfiI2cMasterProtocolGuid);
 - ASSERT_PROTOCOL_ALREADY_INSTALLED(NULL, &gEfiI2cEnumerateProtocolGuid);
 - ASSERT_PROTOCOL_ALREADY_INSTALLED(NULL, &gEfiI2cBusConfigurationManagementProtocolGuid);
 - MvI2cCalBaudRate( I2cMasterContext,
 PcdGet32 (PcdI2cBaudRate),&baud_rate,I2cMasterContext->TclkFrequency);- Status = gBS->InstallMultipleProtocolInterfaces(
 &I2cMasterContext->Controller,&gEfiI2cMasterProtocolGuid,&I2cMasterContext->I2cMaster,&gEfiI2cEnumerateProtocolGuid,&I2cMasterContext->I2cEnumerate,&gEfiI2cBusConfigurationManagementProtocolGuid,&I2cMasterContext->I2cBusConf,&gEfiDevicePathProtocolGuid,(EFI_DEVICE_PATH_PROTOCOL *) &gDevicePathProtocol,NULL);- if (EFI_ERROR(Status)) {
 - DEBUG((DEBUG_ERROR, "MvI2cDxe: Installing protocol interfaces failed!\n"));
 - goto fail;
 - }
 - return EFI_SUCCESS;
 +fail:
- FreePool(I2cMasterContext);
 - return Status;
 +}
+STATIC +VOID +MvI2cControlClear (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINT32 Mask)
 +{
- UINT32 Value;
 - /* clears given bits in I2C_CONTROL register */
 - Value = I2C_READ(I2cMasterContext, I2C_CONTROL);
 - Value &= ~Mask;
 - I2C_WRITE(I2cMasterContext, I2C_CONTROL, Value);
 +}
+STATIC +VOID +MvI2cControlSet (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINT32 Mask)
 +{
- UINT32 Value;
 - /* sets given bits in I2C_CONTROL register */
 - Value = I2C_READ(I2cMasterContext, I2C_CONTROL);
 - Value |= Mask;
 - I2C_WRITE(I2cMasterContext, I2C_CONTROL, Value);
 +}
+STATIC +VOID +MvI2cClearIflg (
- IN I2C_MASTER_CONTEXT *I2cMasterContext
 - )
 +{
- gBS->Stall(I2C_OPERATION_TIMEOUT);
 - MvI2cControlClear(I2cMasterContext, I2C_CONTROL_IFLG);
 - gBS->Stall(I2C_OPERATION_TIMEOUT);
 +}
+/* Timeout is given in us */ +STATIC +UINTN +MvI2cPollCtrl (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINTN Timeout,
 - IN UINT32 Mask)
 +{
- Timeout /= 10;
 - while (!(I2C_READ(I2cMasterContext, I2C_CONTROL) & Mask)) {
 - gBS->Stall(10);
 - if (--Timeout == 0)
 return (Timeout);- }
 - return (0);
 +}
+/*
- 'Timeout' is given in us. Note also that Timeout handling is not exact --
 
- MvI2cLockedStart() total wait can be more than 2 x Timeout
 
- (MvI2cPollCtrl() is called twice). 'Mask' can be either I2C_STATUS_START
 
- or I2C_STATUS_RPTD_START
 - */
 +STATIC +EFI_STATUS +MvI2cLockedStart (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN INT32 Mask,
 - IN UINT8 Slave,
 - IN UINTN Timeout
 - )
 +{
- UINTN ReadAccess, IflgSet = 0;
 - UINT32 I2cStatus;
 - if (Mask == I2C_STATUS_RPTD_START) {
 - /* read IFLG to know if it should be cleared later */
 - IflgSet = I2C_READ(I2cMasterContext, I2C_CONTROL) & I2C_CONTROL_IFLG;
 - }
 - MvI2cControlSet(I2cMasterContext, I2C_CONTROL_START);
 - if (Mask == I2C_STATUS_RPTD_START && IflgSet) {
 - DEBUG((DEBUG_INFO, "MvI2cDxe: IFLG set, clearing\n"));
 - MvI2cClearIflg(I2cMasterContext);
 - }
 - /* Without this delay we Timeout checking IFLG if the Timeout is 0 */
 - gBS->Stall(I2C_OPERATION_TIMEOUT);
 - if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
 - DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout sending %sSTART condition\n",
 Mask == I2C_STATUS_START ? "" : "repeated "));- return EFI_NO_RESPONSE;
 - }
 - I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
 - if (I2cStatus != Mask) {
 - DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong I2cStatus (%02x) after sending %sSTART condition\n",
 I2cStatus, Mask == I2C_STATUS_START ? "" : "repeated "));- return EFI_DEVICE_ERROR;
 - }
 - I2C_WRITE(I2cMasterContext, I2C_DATA, Slave);
 - gBS->Stall(I2C_OPERATION_TIMEOUT);
 - MvI2cClearIflg(I2cMasterContext);
 - if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
 - DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout sending Slave address\n"));
 - return EFI_NO_RESPONSE;
 - }
 - ReadAccess = (Slave & 0x1) ? 1 : 0;
 - I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
 - if (I2cStatus != (ReadAccess ?
 I2C_STATUS_ADDR_R_ACK : I2C_STATUS_ADDR_W_ACK)) {- DEBUG((DEBUG_ERROR, "MvI2cDxe: no ACK (I2cStatus: %02x) after sending Slave address\n",
 I2cStatus));- return EFI_NO_RESPONSE;
 - }
 - return EFI_SUCCESS;
 +}
+#define ABSSUB(a,b) (((a) > (b)) ? (a) - (b) : (b) - (a)) +STATIC +VOID +MvI2cCalBaudRate (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN CONST UINT32 target,
 - IN OUT MV_I2C_BAUD_RATE *rate,
 - UINT32 clk
 - )
 +{
- UINT32 cur, diff, diff0, baud;
 - UINTN m, n, m0, n0;
 - /* Read initial m0, n0 values from register */
 - baud = I2C_READ(I2cMasterContext, I2C_BAUD_RATE);
 - m0 = I2C_M_FROM_BAUD(baud);
 - n0 = I2C_N_FROM_BAUD(baud);
 - /* Calculate baud rate. */
 - diff0 = 0xffffffff;
 - for (n = 0; n < 8; n++) {
 - for (m = 0; m < 16; m++) {
 cur = I2C_BAUD_RATE_RAW(clk,m,n);diff = ABSSUB(target, cur);if (diff < diff0) {m0 = m;n0 = n;diff0 = diff;}- }
 - }
 - rate->raw = I2C_BAUD_RATE_RAW(clk, m0, n0);
 - rate->param = I2C_BAUD_RATE_PARAM(m0, n0);
 - rate->m = m0;
 - rate->n = n0;
 +}
+EFI_STATUS +EFIAPI +MvI2cReset (
- IN CONST EFI_I2C_MASTER_PROTOCOL *This
 - )
 +{
- UINT32 param;
 - I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_MASTER(This);
 - param = baud_rate.param;
 - EfiAcquireLock (&I2cMasterContext->Lock);
 - I2C_WRITE(I2cMasterContext, I2C_SOFT_RESET, 0x0);
 - gBS->Stall(2 * I2C_OPERATION_TIMEOUT);
 - I2C_WRITE(I2cMasterContext, I2C_BAUD_RATE, param);
 - I2C_WRITE(I2cMasterContext, I2C_CONTROL, I2C_CONTROL_I2CEN | I2C_CONTROL_ACK);
 - gBS->Stall(I2C_OPERATION_TIMEOUT);
 - EfiReleaseLock (&I2cMasterContext->Lock);
 - return EFI_SUCCESS;
 +}
+/*
- Timeout is given in us
 - */
 +STATIC +EFI_STATUS +MvI2cRepeatedStart (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINT8 Slave,
 - IN UINTN Timeout
 - )
 +{
- EFI_STATUS Status;
 - EfiAcquireLock (&I2cMasterContext->Lock);
 - Status = MvI2cLockedStart(I2cMasterContext, I2C_STATUS_RPTD_START, Slave,
 Timeout);- EfiReleaseLock (&I2cMasterContext->Lock);
 - if (EFI_ERROR(Status)) {
 - MvI2cStop(I2cMasterContext);
 - }
 - return Status;
 +}
+/*
- Timeout is given in us
 - */
 +STATIC +EFI_STATUS +MvI2cStart (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINT8 Slave,
 - IN UINTN Timeout
 - )
 +{
- EFI_STATUS Status;
 - EfiAcquireLock (&I2cMasterContext->Lock);
 - Status = MvI2cLockedStart(I2cMasterContext, I2C_STATUS_START, Slave, Timeout);
 - EfiReleaseLock (&I2cMasterContext->Lock);
 - if (EFI_ERROR(Status)) {
 - MvI2cStop(I2cMasterContext);
 - }
 - return Status;
 +}
+STATIC +EFI_STATUS +MvI2cStop (
- IN I2C_MASTER_CONTEXT *I2cMasterContext
 - )
 +{
- EfiAcquireLock (&I2cMasterContext->Lock);
 - MvI2cControlSet(I2cMasterContext, I2C_CONTROL_STOP);
 - gBS->Stall(I2C_OPERATION_TIMEOUT);
 - MvI2cClearIflg(I2cMasterContext);
 - EfiReleaseLock (&I2cMasterContext->Lock);
 - return EFI_SUCCESS;
 +}
+STATIC +EFI_STATUS +MvI2cRead (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN OUT UINT8 *Buf,
 - IN UINTN Length,
 - IN OUT UINTN *read,
 - IN UINTN last,
 - IN UINTN delay
 - )
 +{
- UINT32 I2cStatus;
 - UINTN LastByte;
 - EFI_STATUS Status;
 - EfiAcquireLock (&I2cMasterContext->Lock);
 - *read = 0;
 - while (*read < Length) {
 - /*
 * Check if we are reading last byte of the last Buffer,* do not send ACK then, per I2C specs*/- LastByte = ((*read == Length - 1) && last) ? 1 : 0;
 - if (LastByte)
 MvI2cControlClear(I2cMasterContext, I2C_CONTROL_ACK);- else
 MvI2cControlSet(I2cMasterContext, I2C_CONTROL_ACK);- gBS->Stall (I2C_OPERATION_TIMEOUT);
 - MvI2cClearIflg(I2cMasterContext);
 - if (MvI2cPollCtrl(I2cMasterContext, delay, I2C_CONTROL_IFLG)) {
 DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout reading data\n"));Status = EFI_NO_RESPONSE;goto out;- }
 - I2cStatus = I2C_READ(I2cMasterContext, I2C_STATUS);
 - if (I2cStatus != (LastByte ?
 I2C_STATUS_DATA_RD_NOACK : I2C_STATUS_DATA_RD_ACK)) {DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong I2cStatus (%02x) while reading\n", I2cStatus));Status = EFI_DEVICE_ERROR;goto out;- }
 - *Buf++ = I2C_READ(I2cMasterContext, I2C_DATA);
 - (*read)++;
 - }
 - Status = EFI_SUCCESS;
 +out:
- EfiReleaseLock (&I2cMasterContext->Lock);
 - return (Status);
 +}
+STATIC +EFI_STATUS +MvI2cWrite (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN OUT CONST UINT8 *Buf,
 - IN UINTN Length,
 - IN OUT UINTN *Sent,
 - IN UINTN Timeout
 - )
 +{
- UINT32 status;
 - EFI_STATUS Status;
 - EfiAcquireLock (&I2cMasterContext->Lock);
 - *Sent = 0;
 - while (*Sent < Length) {
 - I2C_WRITE(I2cMasterContext, I2C_DATA, *Buf++);
 - MvI2cClearIflg(I2cMasterContext);
 - if (MvI2cPollCtrl(I2cMasterContext, Timeout, I2C_CONTROL_IFLG)) {
 DEBUG((DEBUG_ERROR, "MvI2cDxe: Timeout writing data\n"));Status = EFI_NO_RESPONSE;goto out;- }
 - status = I2C_READ(I2cMasterContext, I2C_STATUS);
 - if (status != I2C_STATUS_DATA_WR_ACK) {
 DEBUG((DEBUG_ERROR, "MvI2cDxe: wrong status (%02x) while writing\n", status));Status = EFI_DEVICE_ERROR;goto out;- }
 - (*Sent)++;
 - }
 - Status = EFI_SUCCESS;
 +out:
- EfiReleaseLock (&I2cMasterContext->Lock);
 - return (Status);
 +}
+/*
- MvI2cStartRequest should be called only by I2cHost.
 
- I2C device drivers ought to use EFI_I2C_IO_PROTOCOL instead.
 - */
 +STATIC +EFI_STATUS +MvI2cStartRequest (
- IN CONST EFI_I2C_MASTER_PROTOCOL *This,
 - IN UINTN SlaveAddress,
 - IN EFI_I2C_REQUEST_PACKET *RequestPacket,
 - IN EFI_EVENT Event OPTIONAL,
 - OUT EFI_STATUS *I2cStatus OPTIONAL
 - )
 +{
- UINTN Count;
 - UINTN ReadMode;
 - UINTN Transmitted;
 - I2C_MASTER_CONTEXT *I2cMasterContext = I2C_SC_FROM_MASTER(This);
 - EFI_I2C_OPERATION *Operation;
 - ASSERT (RequestPacket != NULL);
 - ASSERT (I2cMasterContext != NULL);
 - for (Count = 0; Count < RequestPacket->OperationCount; Count++) {
 - Operation = &RequestPacket->Operation[Count];
 - ReadMode = Operation->Flags & I2C_FLAG_READ;
 - if (Count == 0) {
 MvI2cStart ( I2cMasterContext,(SlaveAddress << 1) | ReadMode,I2C_TRANSFER_TIMEOUT);- } else if (!(Operation->Flags & I2C_FLAG_NORESTART)) {
 MvI2cRepeatedStart ( I2cMasterContext,(SlaveAddress << 1) | ReadMode,I2C_TRANSFER_TIMEOUT);- }
 - if (ReadMode) {
 MvI2cRead ( I2cMasterContext,Operation->Buffer,Operation->LengthInBytes,&Transmitted,Count == 1,I2C_TRANSFER_TIMEOUT);- } else {
 MvI2cWrite ( I2cMasterContext,Operation->Buffer,Operation->LengthInBytes,&Transmitted,I2C_TRANSFER_TIMEOUT);- }
 - if (Count == RequestPacket->OperationCount - 1) {
 MvI2cStop ( I2cMasterContext );- }
 - }
 - if (I2cStatus != NULL)
 - I2cStatus = EFI_SUCCESS;
 - if (Event != NULL)
 - gBS->SignalEvent(Event);
 - return EFI_SUCCESS;
 +}
+/*
- I2C_GUID is embedded in EFI_I2C_DEVICE structure, with last byte set to
 
- address of device on I2C bus. Device driver should compare its GUID with
 
- offered one in Supported() function.
 
So, I think I commented on this in the last round: I don't think this use of the device address for the last byte is compliant with rfc4122. If you disagree, could you let me know your reasoning?
Regards,
Leif
- */
 +#define I2C_GUID \
- { \
 - 0x391fc679, 0x6cb0, 0x4f01, { 0x9a, 0xc7, 0x8e, 0x1b, 0x78, 0x6b, 0x7a, 0x00 } \
 - }
 +STATIC CONST EFI_GUID DevGuid = I2C_GUID;
+STATIC +EFI_STATUS +MvI2cAllocDevice (
- IN UINT8 SlaveAddress,
 - IN OUT CONST EFI_I2C_DEVICE **Device
 - )
 +{
- EFI_STATUS Status;
 - EFI_I2C_DEVICE *Dev;
 - UINT32 *TmpSlaveArray;
 - EFI_GUID *TmpGuidP;
 - Status = gBS->AllocatePool ( EfiBootServicesData,
 sizeof(EFI_I2C_DEVICE),(VOID **) &Dev );- if (EFI_ERROR(Status)) {
 - DEBUG((DEBUG_ERROR, "MvI2cDxe: I2C device memory allocation failed\n"));
 - return Status;
 - }
 - *Device = Dev;
 - Dev->DeviceIndex = SlaveAddress;
 - Dev->SlaveAddressCount = 1;
 - Dev->I2cBusConfiguration = 0;
 - Status = gBS->AllocatePool ( EfiBootServicesData,
 sizeof(UINT32),(VOID **) &TmpSlaveArray);- if (EFI_ERROR(Status)) {
 - goto fail1;
 - }
 - TmpSlaveArray[0] = SlaveAddress;
 - Dev->SlaveAddressArray = TmpSlaveArray;
 - Status = gBS->AllocatePool ( EfiBootServicesData,
 sizeof(EFI_GUID),(VOID **) &TmpGuidP);- if (EFI_ERROR(Status)) {
 - goto fail2;
 - }
 - *TmpGuidP = DevGuid;
 - Dev->DeviceGuid = TmpGuidP;
 - DEBUG((DEBUG_INFO, "MvI2c: allocated device with address %x\n", (UINTN)SlaveAddress));
 - return EFI_SUCCESS;
 +fail2:
- FreePool(TmpSlaveArray);
 +fail1:
- FreePool(Dev);
 - return Status;
 +}
+/*
- It is called by I2cBus to enumerate devices on I2C bus. In this case,
 
- enumeration is based on PCD configuration - all Slave addresses specified
 
- in PCD get their corresponding EFI_I2C_DEVICE structures here.
 
- After enumeration succeeds, Supported() function of drivers that installed
 
- DriverBinding protocol is called.
 - */
 +STATIC +EFI_STATUS +EFIAPI +MvI2cEnumerate (
- IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,
 - IN OUT CONST EFI_I2C_DEVICE **Device
 - )
 +{
- UINT8 *DevicesPcd;
 - UINTN Index;
 - UINT8 NextDeviceAddress;
 - DevicesPcd = PcdGetPtr (PcdI2cSlaveAddresses);
 - if (*Device == NULL) {
 - if (DevicesPcd[0] != '\0')
 MvI2cAllocDevice (DevicesPcd[0], Device);- return EFI_SUCCESS;
 - } else {
 - /* Device is not NULL, so something was already allocated */
 - for (Index = 0; DevicesPcd[Index] != '\0'; Index++) {
 if (DevicesPcd[Index] == (*Device)->DeviceIndex) {NextDeviceAddress = DevicesPcd[Index + 1];if (NextDeviceAddress != '\0') {MvI2cAllocDevice(NextDeviceAddress, Device);return EFI_SUCCESS;}break;}- }
 - *Device = NULL;
 - return EFI_SUCCESS;
 - }
 +}
+STATIC +EFI_STATUS +EFIAPI +MvI2cEnableConf (
- IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This,
 - IN UINTN I2cBusConfiguration,
 - IN EFI_EVENT Event OPTIONAL,
 - IN EFI_STATUS *I2cStatus OPTIONAL
 - )
 +{
- /* do nothing */
 - if (I2cStatus != NULL)
 - I2cStatus = EFI_SUCCESS;
 - if (Event != NULL)
 - gBS->SignalEvent(Event);
 - return EFI_SUCCESS;
 +} diff --git a/Drivers/I2c/MvI2cDxe/MvI2cDxe.h b/Drivers/I2c/MvI2cDxe/MvI2cDxe.h new file mode 100644 index 0000000..7bdff8f --- /dev/null +++ b/Drivers/I2c/MvI2cDxe/MvI2cDxe.h @@ -0,0 +1,258 @@ +/******************************************************************************** +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.
+*******************************************************************************/
+#ifndef __MV_I2C_H__ +#define __MV_I2C_H__
+#include <Uefi.h>
+#define I2C_BASE_ADDRESS 0xf0511000
+#define I2C_SLAVE_ADDR 0x00 +#define I2C_EXT_SLAVE_ADDR 0x10 +#define I2C_DATA 0x04
+#define I2C_CONTROL 0x08 +#define I2C_CONTROL_ACK (1 << 2) +#define I2C_CONTROL_IFLG (1 << 3) +#define I2C_CONTROL_STOP (1 << 4) +#define I2C_CONTROL_START (1 << 5) +#define I2C_CONTROL_I2CEN (1 << 6) +#define I2C_CONTROL_INTEN (1 << 7)
+#define I2C_STATUS 0x0c +#define I2C_STATUS_START 0x08 +#define I2C_STATUS_RPTD_START 0x10 +#define I2C_STATUS_ADDR_W_ACK 0x18 +#define I2C_STATUS_DATA_WR_ACK 0x28 +#define I2C_STATUS_ADDR_R_ACK 0x40 +#define I2C_STATUS_DATA_RD_ACK 0x50 +#define I2C_STATUS_DATA_RD_NOACK 0x58
+#define I2C_BAUD_RATE 0x0c +#define I2C_BAUD_RATE_PARAM(M,N) ((((M) << 3) | ((N) & 0x7)) & 0x7f) +#define I2C_BAUD_RATE_RAW(C,M,N) ((C)/((10*(M+1))<<(N+1))) +#define I2C_M_FROM_BAUD(baud) (((baud) >> 3) & 0xf) +#define I2C_N_FROM_BAUD(baud) ((baud) & 0x7)
+#define I2C_SOFT_RESET 0x1c +#define I2C_TRANSFER_TIMEOUT 10000 +#define I2C_OPERATION_TIMEOUT 1000
+#define I2C_UNKNOWN 0x0 +#define I2C_SLOW 0x1 +#define I2C_FAST 0x2 +#define I2C_FASTEST 0x3
+/*
- I2C_FLAG_NORESTART is not part of PI spec, it allows to continue
 
- transmission without repeated start operation.
 - */
 +#define I2C_FLAG_NORESTART 0x00000002
+#define I2C_MASTER_SIGNATURE SIGNATURE_32 ('I', '2', 'C', 'M')
+typedef struct {
- UINT32 Signature;
 - EFI_HANDLE Controller;
 - EFI_LOCK Lock;
 - UINTN TclkFrequency;
 - UINTN BaseAddress;
 - EFI_I2C_MASTER_PROTOCOL I2cMaster;
 - EFI_I2C_ENUMERATE_PROTOCOL I2cEnumerate;
 - EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL I2cBusConf;
 +} I2C_MASTER_CONTEXT;
+#define I2C_SC_FROM_MASTER(a) CR (a, I2C_MASTER_CONTEXT, I2cMaster, I2C_MASTER_SIGNATURE) +#define I2C_SC_FROM_ENUMERATE(a) CR (a, I2C_MASTER_CONTEXT, I2cEnumerate, I2C_MASTER_SIGNATURE) +#define I2C_SC_FROM_BUSCONF(a) CR (a, I2C_MASTER_CONTEXT, I2cBusConf, I2C_MASTER_SIGNATURE)
+typedef struct {
- UINT32 raw;
 - UINTN param;
 - UINTN m;
 - UINTN n;
 +} MV_I2C_BAUD_RATE;
+typedef struct {
- VENDOR_DEVICE_PATH Guid;
 - EFI_DEVICE_PATH_PROTOCOL End;
 +} MV_I2C_DEVICE_PATH;
+STATIC +UINT32 +I2C_READ(
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINTN off
 - );
 +STATIC +EFI_STATUS +I2C_WRITE (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINTN off,
 - IN UINT32 val
 - );
 +EFI_STATUS +EFIAPI +MvI2cInitialise (
- IN EFI_HANDLE ImageHandle,
 - IN EFI_SYSTEM_TABLE *SystemTable
 - );
 +STATIC +VOID +MvI2cControlClear (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINT32 mask
 - );
 +STATIC +VOID +MvI2cControlSet (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINT32 mask
 - );
 +STATIC +VOID +MvI2cClearIflg (
- IN I2C_MASTER_CONTEXT *I2cMasterContext
 - );
 +STATIC +UINTN +MvI2cPollCtrl (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINTN timeout,
 - IN UINT32 mask
 - );
 +STATIC +EFI_STATUS +MvI2cLockedStart (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN INT32 mask,
 - IN UINT8 slave,
 - IN UINTN timeout
 - );
 +STATIC +VOID +MvI2cCalBaudRate (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN CONST UINT32 target,
 - IN OUT MV_I2C_BAUD_RATE *rate,
 - UINT32 clk
 - );
 +EFI_STATUS +EFIAPI +MvI2cReset (
- IN CONST EFI_I2C_MASTER_PROTOCOL *This
 - );
 +STATIC +EFI_STATUS +MvI2cRepeatedStart (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINT8 slave,
 - IN UINTN timeout
 - );
 +STATIC +EFI_STATUS +MvI2cStart (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN UINT8 slave,
 - IN UINTN timeout
 - );
 +STATIC +EFI_STATUS +MvI2cStop (
- IN I2C_MASTER_CONTEXT *I2cMasterContext
 - );
 +STATIC +EFI_STATUS +MvI2cRead (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN OUT UINT8 *buf,
 - IN UINTN len,
 - IN OUT UINTN *read,
 - IN UINTN last,
 - IN UINTN delay
 - );
 +STATIC +EFI_STATUS +MvI2cWrite (
- IN I2C_MASTER_CONTEXT *I2cMasterContext,
 - IN OUT CONST UINT8 *buf,
 - IN UINTN len,
 - IN OUT UINTN *sent,
 - IN UINTN timeout
 - );
 +STATIC +EFI_STATUS +EFIAPI +MvI2cStartRequest (
- IN CONST EFI_I2C_MASTER_PROTOCOL *This,
 - IN UINTN SlaveAddress,
 - IN EFI_I2C_REQUEST_PACKET *RequestPacket,
 - IN EFI_EVENT Event OPTIONAL,
 - OUT EFI_STATUS *I2cStatus OPTIONAL
 - );
 +STATIC +EFI_STATUS +EFIAPI +MvI2cEnumerate (
- IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,
 - IN OUT CONST EFI_I2C_DEVICE **Device
 - );
 +STATIC +EFI_STATUS +EFIAPI +MvI2cEnableConf (
- IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This,
 - IN UINTN I2cBusConfiguration,
 - IN EFI_EVENT Event OPTIONAL,
 - IN EFI_STATUS *I2cStatus OPTIONAL
 - );
 +#endif // __MV_I2C_H__ diff --git a/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf b/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf new file mode 100644 index 0000000..328e29d --- /dev/null +++ b/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf @@ -0,0 +1,72 @@ +# +# 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 = 0x00010005
 - BASE_NAME = MvI2cDxe
 - FILE_GUID = 59fc3843-d8d4-40aa-ae07-38967138509b
 - MODULE_TYPE = DXE_DRIVER
 - VERSION_STRING = 1.0
 - ENTRY_POINT = MvI2cInitialise
 +[Sources.common]
- MvI2cDxe.c
 +[Packages]
- MdePkg/MdePkg.dec
 - MdeModulePkg/MdeModulePkg.dec
 - ArmPlatformPkg/ArmPlatformPkg.dec
 - ArmPkg/ArmPkg.dec
 - OpenPlatformPkg/Platforms/Marvell/Marvell.dec
 +[LibraryClasses]
- IoLib
 - PcdLib
 - BaseLib
 - DebugLib
 - UefiLib
 - UefiDriverEntryPoint
 - UefiBootServicesTableLib
 +[Protocols]
- gEfiI2cMasterProtocolGuid
 - gEfiDevicePathProtocolGuid
 - gEfiI2cEnumerateProtocolGuid
 - gEfiI2cBusConfigurationManagementProtocolGuid
 +[Pcd]
- gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses
 - gMarvellTokenSpaceGuid.PcdI2cBaseAddress
 - gMarvellTokenSpaceGuid.PcdI2cClockFrequency
 - gMarvellTokenSpaceGuid.PcdI2cBaudRate
 +[Depex]
- TRUE
 diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index fee8025..9e65986 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -104,3 +104,9 @@ gMarvellTokenSpaceGuid.PcdChip3MppSel6|{ 0 }|VOID*|0x30000044 gMarvellTokenSpaceGuid.PcdChip3MppSel7|{ 0 }|VOID*|0x30000045 +#I2C
- gMarvellTokenSpaceGuid.PcdI2cSlaveAddresses|{ 0 }|VOID*|0x3000046
 - gMarvellTokenSpaceGuid.PcdI2cBaseAddress|0|UINT64|0x3000047
 - gMarvellTokenSpaceGuid.PcdI2cClockFrequency|0|UINT32|0x3000048
 - gMarvellTokenSpaceGuid.PcdI2cBaudRate|0|UINT32|0x3000049
 -- 1.8.3.1