mirror of https://github.com/acidanthera/audk.git
326 lines
6.3 KiB
C
326 lines
6.3 KiB
C
/** @file
|
|
|
|
Copyright (c) 2008 - 2009, Apple Inc. 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 <Uefi.h>
|
|
#include <Omap3530/Omap3530.h>
|
|
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/IoLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
|
|
#include <Protocol/SmbusHc.h>
|
|
|
|
#define MAX_RETRY 1000
|
|
|
|
//
|
|
// Internal Functions
|
|
//
|
|
STATIC
|
|
EFI_STATUS
|
|
WaitForBusBusy (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Retry = 0;
|
|
|
|
while (++Retry < MAX_RETRY && (MmioRead16(I2C_STAT) & BB) == 0x1);
|
|
|
|
if (Retry == MAX_RETRY) {
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
PollForStatus(
|
|
UINT16 StatusBit
|
|
)
|
|
{
|
|
UINTN Retry = 0;
|
|
|
|
while(Retry < MAX_RETRY) {
|
|
if (MmioRead16(I2C_STAT) & StatusBit) {
|
|
//Clear particular status bit from Status register.
|
|
MmioOr16(I2C_STAT, StatusBit);
|
|
break;
|
|
}
|
|
Retry++;
|
|
}
|
|
|
|
if (Retry == MAX_RETRY) {
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
ConfigureI2c (
|
|
VOID
|
|
)
|
|
{
|
|
//Program prescaler to obtain 12-MHz clock
|
|
MmioWrite16(I2C_PSC, 0x0000);
|
|
|
|
//Program SCLL and SCLH
|
|
//NOTE: Following values are the register dump after U-Boot code executed.
|
|
//We need to figure out how its calculated based on the I2C functional clock and I2C_PSC.
|
|
MmioWrite16(I2C_SCLL, 0x0035);
|
|
MmioWrite16(I2C_SCLH, 0x0035);
|
|
|
|
//Take the I2C controller out of reset.
|
|
MmioOr16(I2C_CON, I2C_EN);
|
|
|
|
//Initialize the I2C controller.
|
|
|
|
//Set I2C controller in Master mode.
|
|
MmioOr16(I2C_CON, MST);
|
|
|
|
//Enable interrupts for receive/transmit mode.
|
|
MmioOr16(I2C_IE, (XRDY_IE | RRDY_IE | ARDY_IE | NACK_IE));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
I2CReadOneByte (
|
|
UINT8 *Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//I2C bus status checking
|
|
Status = WaitForBusBusy();
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//Poll till Receive ready bit is set.
|
|
Status = PollForStatus(RRDY);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
*Data = MmioRead8(I2C_DATA);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
I2CWriteOneByte (
|
|
UINT8 Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//I2C bus status checking
|
|
Status = WaitForBusBusy();
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//Data transfer
|
|
//Poll till Transmit ready bit is set
|
|
Status = PollForStatus(XRDY);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
MmioWrite8(I2C_DATA, Data);
|
|
|
|
//Wait and check if the NACK is not set.
|
|
gBS->Stall(1000);
|
|
if (MmioRead16(I2C_STAT) & NACK) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
SmbusBlockRead (
|
|
OUT UINT8 *Buffer,
|
|
IN UINTN Length
|
|
)
|
|
{
|
|
UINTN Index = 0;
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
|
|
//Transfer configuration for receiving data.
|
|
MmioWrite16(I2C_CNT, Length);
|
|
//Need stop bit before sending data.
|
|
MmioWrite16(I2C_CON, (I2C_EN | MST | STP | STT));
|
|
|
|
while (Index < Length) {
|
|
//Read a byte
|
|
Status = I2CReadOneByte(&Buffer[Index++]);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
//Transfer completion
|
|
Status = PollForStatus(ARDY);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
SmbusBlockWrite (
|
|
IN UINT8 *Buffer,
|
|
IN UINTN Length
|
|
)
|
|
{
|
|
UINTN Index = 0;
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
|
|
//Transfer configuration for transmitting data
|
|
MmioWrite16(I2C_CNT, Length);
|
|
MmioWrite16(I2C_CON, (I2C_EN | TRX | MST | STT | STP));
|
|
|
|
while (Index < Length) {
|
|
//Send a byte
|
|
Status = I2CWriteOneByte(Buffer[Index++]);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
//Transfer completion
|
|
Status = PollForStatus(ARDY);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Public Functions.
|
|
//
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SmbusExecute (
|
|
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
|
|
IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
|
|
IN CONST EFI_SMBUS_DEVICE_COMMAND Command,
|
|
IN CONST EFI_SMBUS_OPERATION Operation,
|
|
IN CONST BOOLEAN PecCheck,
|
|
IN OUT UINTN *Length,
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
UINT8 *ByteBuffer = Buffer;
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
UINT8 SlaveAddr = (UINT8)(SlaveAddress.SmbusDeviceAddress);
|
|
|
|
if (PecCheck) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if ((Operation != EfiSmbusWriteBlock) && (Operation != EfiSmbusReadBlock)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//Set the Slave address.
|
|
MmioWrite16(I2C_SA, SlaveAddr);
|
|
|
|
if (Operation == EfiSmbusReadBlock) {
|
|
Status = SmbusBlockRead(ByteBuffer, *Length);
|
|
} else if (Operation == EfiSmbusWriteBlock) {
|
|
Status = SmbusBlockWrite(ByteBuffer, *Length);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SmbusArpDevice (
|
|
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
|
|
IN CONST BOOLEAN ArpAll,
|
|
IN CONST EFI_SMBUS_UDID *SmbusUdid OPTIONAL,
|
|
IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress OPTIONAL
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SmbusGetArpMap (
|
|
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
|
|
IN OUT UINTN *Length,
|
|
IN OUT EFI_SMBUS_DEVICE_MAP **SmbusDeviceMap
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SmbusNotify (
|
|
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
|
|
IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
|
|
IN CONST UINTN Data,
|
|
IN CONST EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFI_SMBUS_HC_PROTOCOL SmbusProtocol =
|
|
{
|
|
SmbusExecute,
|
|
SmbusArpDevice,
|
|
SmbusGetArpMap,
|
|
SmbusNotify
|
|
};
|
|
|
|
EFI_STATUS
|
|
InitializeSmbus (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_HANDLE Handle = NULL;
|
|
EFI_STATUS Status;
|
|
|
|
//Configure I2C controller.
|
|
Status = ConfigureI2c();
|
|
if (EFI_ERROR(Status)) {
|
|
DEBUG ((EFI_D_ERROR, "InitializeI2c fails.\n"));
|
|
return Status;
|
|
}
|
|
|
|
// Install the SMBUS interface
|
|
Status = gBS->InstallMultipleProtocolInterfaces(&Handle, &gEfiSmbusHcProtocolGuid, &SmbusProtocol, NULL);
|
|
ASSERT_EFI_ERROR(Status);
|
|
|
|
return Status;
|
|
}
|
|
|