On Mon, Apr 18, 2016 at 01:34:50AM +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 | 686 ++++++++++++++++++++++++++++ Drivers/I2c/MvI2cDxe/MvI2cDxe.h | 254 ++++++++++ Drivers/I2c/MvI2cDxe/MvI2cDxe.inf | 73 +++ 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..d1d5293 --- /dev/null +++ b/Drivers/I2c/MvI2cDxe/MvI2cDxe.c @@ -0,0 +1,686 @@ +/******************************************************************************** +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 = {
- {
- {
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)
+{
Spurious blank line?
- 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;
Could {} be added on the above please?
- 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 */
Spurious space?
- 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
- )
+{
Spurious blank line?
- 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.
- */
+#define I2C_GUID \
- { \
- 0x391fc679, 0x6cb0, 0x4f01, { 0x9a, 0xc7, 0x8e, 0x1b, 0x78, 0x6b, 0x7a, 0x00 } \
- }
+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 DevGuid = I2C_GUID;
- EFI_GUID *TmpGuidP;
- DevGuid.Data4[7] = SlaveAddress;
- 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..8322eac --- /dev/null +++ b/Drivers/I2c/MvI2cDxe/MvI2cDxe.h @@ -0,0 +1,254 @@ +/******************************************************************************** +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
+#define I2C_FLAG_NORESTART 0x00000002
It would be worth having a comment on the above not being part of the PI spec and carrying special meaning here.
+#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..28b0199 --- /dev/null +++ b/Drivers/I2c/MvI2cDxe/MvI2cDxe.inf @@ -0,0 +1,73 @@ +# 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. +#
+[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 ae923a9..2a7a7e2 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