13cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei/*++
23cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
33cbfba02fef9dae07a041fdbf2e89611d72d6f90David WeiCopyright (c)  1999  - 2014, Intel Corporation. All rights reserved
43cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
53cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
63cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  This program and the accompanying materials are licensed and made available under
73cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
83cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  the terms and conditions of the BSD License that accompanies this distribution.
93cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
103cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  The full text of the license may be found at
113cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
123cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  http://opensource.org/licenses/bsd-license.php.
133cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
143cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
153cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
163cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
173cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
183cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
193cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
203cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
213cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
223cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
233cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
243cbfba02fef9dae07a041fdbf2e89611d72d6f90David WeiModule Name:
253cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
263cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  SmmIo.c
273cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
283cbfba02fef9dae07a041fdbf2e89611d72d6f90David WeiAbstract:
293cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
303cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  SMM I/O access utility implementation file, for Ia32
313cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
323cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei--*/
333cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
343cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei//
353cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei// Include files
363cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei//
373cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei#include "Library/StallSmmLib.h"
383cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei#include "Pi/PiSmmCis.h"
393cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei#include "PiDxe.h"
403cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei#include <Library/IoLib.h>
413cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei#include <Library/PcdLib.h>
423cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei#include "PchAccess.h"
433cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
443cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei/**
453cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  Delay for at least the request number of microseconds.
463cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  Timer used is ACPI time counter, which has 1us granularity.
473cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
483cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  @param Microseconds  Number of microseconds to delay.
493cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
503cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  @retval None
513cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
523cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei**/
533cbfba02fef9dae07a041fdbf2e89611d72d6f90David WeiVOID
543cbfba02fef9dae07a041fdbf2e89611d72d6f90David WeiSmmStall (
553cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  IN  UINTN   Microseconds
563cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  )
573cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei{
583cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  UINTN   Ticks;
593cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  UINTN   Counts;
603cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  UINTN   CurrentTick;
613cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  UINTN   OriginalTick;
623cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  UINTN   RemainingTick;
633cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  UINT16  AcpiBaseAddr;
643cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
653cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  if (Microseconds == 0) {
663cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei    return;
673cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  }
683cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
693cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  AcpiBaseAddr = PchLpcPciCfg16 (R_PCH_LPC_ACPI_BASE) & B_PCH_LPC_ACPI_BASE_BAR;
703cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
713cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  OriginalTick = IoRead32 (AcpiBaseAddr + R_PCH_ACPI_PM1_TMR);
723cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  CurrentTick = OriginalTick;
733cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
743cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  //
753cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  // The timer frequency is 3.579545 MHz, so 1 ms corresponds 3.58 clocks
763cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  //
773cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  Ticks = Microseconds * 358 / 100 + OriginalTick + 1;
783cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
793cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  //
803cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  // The loops needed by timer overflow
813cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  //
823cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  Counts = Ticks / V_PCH_ACPI_PM1_TMR_MAX_VAL;
833cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
843cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  //
853cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  // Remaining clocks within one loop
863cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  //
873cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  RemainingTick = Ticks % V_PCH_ACPI_PM1_TMR_MAX_VAL;
883cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei
893cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  //
903cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  // not intend to use TMROF_STS bit of register PM1_STS, because this adds extra
913cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  // one I/O operation, and maybe generate SMI
923cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  //
933cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei  while ((Counts != 0) || (RemainingTick > CurrentTick)) {
943cbfba02fef9dae07a041fdbf2e89611d72d6f90David Wei    CurrentTick = IoRead32 (AcpiBaseAddr + R_PCH_ACPI_PM1_TMR);
95    //
96    // Check if timer overflow
97    //
98    if (CurrentTick < OriginalTick) {
99      Counts--;
100    }
101    OriginalTick = CurrentTick;
102  }
103}
104