Skip to end of banner
Go to start of banner

Timer enablement with ACPI

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Next »

Many functions in Linux kernel need time management, such as periodic scheduler, delay program and timer. The hardware timer provides the clock source. The frequency of the clock source can be set. After setting, the timing interrupt will be generated periodically. The system uses the timing interrupt to time. The frequency generated periodically by interrupts is the system frequency, also known as the tick rate.

HW requirement

For a Arm Linux system, it require HW support generic timer for system scheduler, and external timer for CPU idle requirement.

System counter generate event (Arm system ready recommend it to 1GHz) to CPU private timer (called as local timer), or to external timer (can be acted as global timer)

CPU private time MAY be stop when CPU enter idle state, at this time system should switch to broadcast time like global timer in below picture.

For NXP i.MX8MP platform, it integrates 6 GPT external timers, which can be registered as system global timer. And, the system counter in i.MX8MP also support compare function that means it can be registered as one clock event. Since system counter is in always-on domain, so the clock event can be used as system global timer. Once cpu enter idle, system can switch cpu private timer to the system counter.

ACPI requirement

For ACPI on arm64, tables also fall into the following categories:

  • Required: DSDT, FADT, GTDT, MADT, MCFG, RSDP, SPCR, XSDT

Generic Timer Description Table (GTDT) provides OSPM with information about a system’s Generic Timers configuration. The Generic Timer (GT) is a standard timer interface implemented on ARM processor-based systems. The GT hardware specification can be found at Links to ACPI-Related Documents (http://uefi.org/acpi ) under the heading ARM Architecture.
The GTDT provides OSPM with information about a system's GT interrupt configurations, for both perprocessor timers, and platform (memory-mapped) timers.


The GT specification defines the following per-processor timers:

  • Secure EL1 timer,

  • Non-Secure EL1 timer,

  • EL2 timer,

  • Virtual EL1 timer,

  • Virtual EL2 timer,

and defines the following memory-mapped Platform timers:

  • GT Block,

  • Server Base System Architecture (SBSA) Generic Watchdog.

GTDT table structure

ACPI table defined in UEFI:

typedef struct {
UINT32 Signature;
UINT32 Length;
UINT8 Revision;
UINT8 Checksum;
UINT8 OemId[6];
UINT64 OemTableId;
UINT32 OemRevision;
UINT32 CreatorId;
UINT32 CreatorRevision;
} EFI_ACPI_DESCRIPTION_HEADER;

///
/// Generic Timer Description Table definition.
///
typedef struct {
EFI_ACPI_DESCRIPTION_HEADER Header;
UINT64 PhysicalAddress;
UINT32 GlobalFlags;
UINT32 SecurePL1TimerGSIV;
UINT32 SecurePL1TimerFlags;
UINT32 NonSecurePL1TimerGSIV;
UINT32 NonSecurePL1TimerFlags;
UINT32 VirtualTimerGSIV;
UINT32 VirtualTimerFlags;
UINT32 NonSecurePL2TimerGSIV;
UINT32 NonSecurePL2TimerFlags;
} EFI_ACPI_5_0_GENERIC_TIMER_DESCRIPTION_TABLE;

SW Status

Generic timer work well on i.MX8MP.

Code for ACPI

GTDT table for i.MX8MP:

# ARM Architectural Timer Interrupt(GIC PPI) numbers
  gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum|29|UINT32|0x00000035
  gArmTokenSpaceGuid.PcdArmArchTimerIntrNum|30|UINT32|0x00000036
  gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|26|UINT32|0x00000040
  gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|27|UINT32|0x00000041
  

#define GTDT_GLOBAL_FLAGS_MAPPED      EFI_ACPI_5_0_GTDT_GLOBAL_FLAG_MEMORY_MAPPED_BLOCK_PRESENT
#define GTDT_GLOBAL_FLAGS_NOT_MAPPED  0
#define GTDT_GLOBAL_FLAGS_EDGE        EFI_ACPI_5_0_GTDT_GLOBAL_FLAG_INTERRUPT_MODE
#define GTDT_GLOBAL_FLAGS_LEVEL       0

// Note: We could have a build flag that switches between memory mapped/non-memory mapped timer
#ifdef SYSTEM_TIMER_BASE_ADDRESS
  #define GTDT_GLOBAL_FLAGS             (GTDT_GLOBAL_FLAGS_MAPPED | GTDT_GLOBAL_FLAGS_LEVEL)
#else
  #define GTDT_GLOBAL_FLAGS             (GTDT_GLOBAL_FLAGS_NOT_MAPPED | GTDT_GLOBAL_FLAGS_LEVEL)
  #define SYSTEM_TIMER_BASE_ADDRESS     0xFFFFFFFFFFFFFFFF
#endif

#define GTDT_TIMER_EDGE_TRIGGERED   EFI_ACPI_5_0_GTDT_TIMER_FLAG_TIMER_INTERRUPT_MODE
#define GTDT_TIMER_LEVEL_TRIGGERED  0
#define GTDT_TIMER_ACTIVE_LOW       EFI_ACPI_5_0_GTDT_TIMER_FLAG_TIMER_INTERRUPT_POLARITY
#define GTDT_TIMER_ACTIVE_HIGH      0

#define GTDT_GTIMER_FLAGS           (GTDT_TIMER_ACTIVE_LOW | GTDT_TIMER_LEVEL_TRIGGERED)

  EFI_ACPI_5_0_GENERIC_TIMER_DESCRIPTION_TABLE Gtdt = {
    ARM_ACPI_HEADER(
      EFI_ACPI_5_0_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE,
      EFI_ACPI_5_0_GENERIC_TIMER_DESCRIPTION_TABLE,
      EFI_ACPI_5_0_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION
    ),
    SYSTEM_TIMER_BASE_ADDRESS,                            // UINT64  PhysicalAddress
    GTDT_GLOBAL_FLAGS,                                            // UINT32  GlobalFlags
    FixedPcdGet32 (PcdArmArchTimerSecIntrNum),    // UINT32  SecurePL1TimerGSIV
    GTDT_GTIMER_FLAGS,                                             // UINT32  SecurePL1TimerFlags
    FixedPcdGet32 (PcdArmArchTimerIntrNum),          // UINT32  NonSecurePL1TimerGSIV
    GTDT_GTIMER_FLAGS,                                             // UINT32  NonSecurePL1TimerFlags
    FixedPcdGet32 (PcdArmArchTimerVirtIntrNum),    // UINT32  VirtualTimerGSIV
    GTDT_GTIMER_FLAGS,                                             // UINT32  VirtualTimerFlags
    FixedPcdGet32 (PcdArmArchTimerHypIntrNum),   // UINT32  NonSecurePL2TimerGSIV
    GTDT_GTIMER_FLAGS                                              // UINT32  NonSecurePL2TimerFlags
  };

  • No labels