/** @file

  Copyright (c) 2020, Hisilicon Limited. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <Uefi.h>
#include <PiDxe.h>
#include <Library/BaseLib.h>
#include <Library/CpldD06.h>
#include <Library/CpldIoLib.h>
#include <Library/DebugLib.h>
#include <Library/RtcHelperLib.h>
#include <Library/TimeBaseLib.h>
#include <Library/TimerLib.h>
#include <Library/UefiRuntimeLib.h>

EFI_STATUS
SwitchRtcI2cChannelAndLock (
  VOID
  )
{
  UINT8   Temp;
  UINT8   Count;

  for (Count = 0; Count < 100; Count++) {
    // To get the other side's state is idle first
    Temp = ReadCpldReg (CPLD_I2C_SWITCH_FLAG);
    if ((Temp & BIT3) != 0) {
      (VOID) MicroSecondDelay (RTC_DELAY_30_MS);
      // Try 100 times, if BMC has not released the bus, return preemption failed
      if (Count == 99) {
        if (!EfiAtRuntime ()) {
          DEBUG ((DEBUG_ERROR, "[%a]:[%dL] Clear cpu_i2c_rtc_state 100 times fail!\n",
            __FUNCTION__, __LINE__));
        }
        return EFI_DEVICE_ERROR;
      }
      continue;
    }

    // if BMC free the bus, can be set 1 preemption
    Temp = ReadCpldReg (CPLD_I2C_SWITCH_FLAG);
    Temp = Temp | CPU_GET_I2C_CONTROL;
    // CPU occupied RTC I2C State
    WriteCpldReg (CPLD_I2C_SWITCH_FLAG, Temp);
    (VOID)MicroSecondDelay (RTC_DELAY_2_MICROSECOND);
    Temp = ReadCpldReg (CPLD_I2C_SWITCH_FLAG);
    // Is preempt success
    if (CPU_GET_I2C_CONTROL == (Temp & CPU_GET_I2C_CONTROL)) {
      break;
    }
    if (Count == 99) {
      if (!EfiAtRuntime ()) {
        DEBUG ((DEBUG_ERROR, "[%a]:[%dL]  Clear cpu_i2c_rtc_state fail !!! \n",
          __FUNCTION__, __LINE__));
      }
      return EFI_DEVICE_ERROR;
    }
    (VOID)MicroSecondDelay (RTC_DELAY_30_MS);
  }

  //Polling BMC RTC I2C status
  for (Count = 0; Count < 100; Count++) {
    Temp = ReadCpldReg (CPLD_I2C_SWITCH_FLAG);
    if ((Temp & BIT3) == 0) {
      return EFI_SUCCESS;
    }
    (VOID)MicroSecondDelay (RTC_DELAY_30_MS);
  }

  //If the BMC occupies the RTC I2C Channel, write back the CPU side is idle
  // or the subsequent BMC will not preempt
  Temp = ReadCpldReg (CPLD_I2C_SWITCH_FLAG);
  Temp = Temp & (~CPU_GET_I2C_CONTROL);
  WriteCpldReg (CPLD_I2C_SWITCH_FLAG, Temp);

  return EFI_NOT_READY;
}

VOID
ReleaseOwnershipOfRtc (
  VOID
  )
{
  UINT8   Temp;

  Temp = ReadCpldReg (CPLD_I2C_SWITCH_FLAG);
  Temp = Temp & ~CPU_GET_I2C_CONTROL;
  WriteCpldReg (CPLD_I2C_SWITCH_FLAG, Temp);
  return ;
}
