Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Info

This page is a work in progress!

...

Table of Contents
minLevel1
maxLevel7

Introduction

Device drivers (e.g: UART, I2C, Audio, etc.) need to know the input clock rate for the device to configure and function properly. Some device drivers only need to know the configured clock rate, while others (such as audio, display, etc) may need to change the clock rate based on the requirements, such as supporting different sampling rates, resolutions, etc.

Several Arm implementations provide the clock rate to the device drivers using non-standard AML methods, objects, and _DSD properties. The ACPI v6.5 specification. standardized this by introducing the ClockInput resource descriptor.

Code Block
ClockInput (FrequencyNumerator, FrequencyDivisor, Scale, FixedMode, ResourceSource, ˓ResourceSourceIndex)

Examples from ACPI spec.

Case 1: Simple clock input descriptor, with a fixed frequency of 33 1/3 MHz and no Device shown as a clock source.

Code Block
ClockInput (100, 3, MHz, Fixed,,)

Case 2: Clock input descriptor referencing a variable clock input of 19.2 kHz, with a source device and index.

...

This page captures our investigation and suggestions for using the ClockInput resource.

Option 1: ClockInput resources and configurability with _PRS and _SRS

This approach leverages the existing _PRS and _SRS methods to get the possible clock input resources and set one of the resources based on device requirements.

An example AML implementation is given below

Code Block
Device(DEV) {
  ...
  
  // Possible resources for the device
  Name (_PRS, ResourceTemplate ()
  {
          ClockInput(100000, 1, Hz, Variable, “\\_SB.PCI0.CLK4”, 3)

SCMI Clock Driver with ClockInput resources

Code Block
Device (SCMI) {
  Name (_HID, "PNP####")
  ...
}

Device(I2C) {
  ...
  Name(_CLK, 13Fixed,,)  // 100 KHz
          ClockInput(400000, 1, Hz, Fixed,,)  // 400 KHz
          ClockInput(1000000, 1, Hz, Fixed,,) // SCMI1 clockMHz
ID for I2C})
root
clock   Method (_CRS, 00x0, NotSerialized)
  {
    Name ( RBUF, ResourceTemplate () {
      ClockInput(100000, 1, Hz, Fixed,,)
      MEMORY32FIXED(ReadWrite, 0x30A400000x30A20000, 0x14, )
      Interrupt(ResourceConsumer, Level, ActiveHigh, Exclusive) { 67 }
   69 })
    // Update ClockInput with configured frequency
    CreateDWordField (24RBUF, 1, MHz, Variable, “\\_SB.SCMI”, _CLK)
    })0x08, FQN)
    FQN = CLK1.FQN
    CreateWordField (RBUF, 0x06, FQD)
    FQD = CLK1.FQD
    Return(RBUF)
  }

  Method (_SRS, 1, NotSerialized)
  {
      // only ClockInput is configurable, ignore the rest of the resources
      CreateDWordField (Arg0, 0x08, FQN)
      CLK1...
}FQN = FQN
      CreateWordField (Arg0, 0x06, FQD)
      CLK1.FQD = FQD
  }

ACPI ClockInput resources with variable clock rate would require support from the operating system. Clock drivers and clock framework support will be required from OS.

ClockInput resources with _PRS, SRS, and _CRS

Another approach is to support ClockInput resources from AML without requiring operating system infrastructures.

Code Block
CLK:
  Method(GCLK, ...)}

Pros:

  • No extra AML methods are required to configure the clocks.

  • No additional OS infrastructure support is required (except support for ClockInput resources, _PRS, _SRS, etc.)

Cons:

  • _PRS and _SRS are generally used for full resource configuration at device enumeration and dynamic configuring clock input using _SRS might not be aligned with the original design intent.

  • ClockInput resource control with multiple clock inputs is tricky as we don’t have any unique identifier for clocks. (except resource label and index which are optional for Fixed clocks)

There are potentially a few extra changes required at the spec to support this.

  • Add clarification to spec. around the use of _SRS

  • Add identifier to ClockInput resource to support multiple clock inputs

  • Add descriptor name to ClockInput resource to select the resource from the resource buffer.

Linux Kernel Prototype

...

  1. Option 1: Devices directly use the ACPI resources to get and set clock inputs.

  2. Option 2: Add an acpi-clk device to the clock framework that uses the clock resources to get and set rates.

Kernel Changes

Device driver could use the above framework to get and select the clock rate

Code Block
// get the current clock rate from _CRS
acpi_freq = acpi_dev_get_clock_input_rate(ACPI_COMPANION(&pdev->dev), 0);

// request 40KHz clock rate for the device
// acpi clock framework will first look for a matching clock input from _PRS and
// invokes _SRS to configure the clock
ret = acpi_dev_set_clock_input_rate(ACPI_COMPANION(&pdev->dev), 400000, 0);

Option 2: ClockInput resources with a standard clock resource provider

This option uses a standard clock controller known to the kernel.

AML methods for the standard clock provider can be standardized and the kernel can use that to provide the clock bindings required for the devices.

Code Block
Device (CLK) {

  Name (_HID, "PNP####") // Standard clock device with defined AML interfaces
  ...
  
  // Get Clock Rate
  Method(SCLK, _GCR, )
  {
    ...)
  }
  
  // Set Clock Rate
  DEV:

  _PRS:
    ClockInput(FREQ_1, 1, MHz, Variable, CLK,)
    ClockInput(FREQ_2, 1, MHz, Variable, CLK, )Method(_SCR, )
  {
    ...
  }
  
  // Set State (enable/disable etc.)
  Method(_SET, )
  {
    ...
  }
  
}
Device(DEV) {
      ...
      
    Method (_CRS, 0, NotSerialized)
    {
      ...
      ClockInput (FREQ_324, 1, MHz, Variable, CLK“\\_SB.CLK”, 1)
    }
    
    _CRS:
    freq_num, freq_div = CLK.GCLK(...)
    ClockInput(freq_num, freq_div, ... , Variable, "//SB.CLK", )

  _SRS:
    ...
    local0 = decode(Arg0)
    CLK.SCLK(local0)

Challenges

...

ClockInput resource doesn't have resource names so we cannot index them for modification.

...

...
    
}

This option would be able to support multiple clock input resources and allows supporting other clock control methods beyond setting the clock rate.

Kernel only has to provide the AML binding for clock resources and the clock management will be done from AML.

Option 3: ClockInput resources with SCMI clock provider

The above two options used the AML-based approach to configure the clock to avoid adding overhead to the kernel. However, this option requires SCMI driver support at the kernel side and uses that to provide clock control.

Code Block
Device (SCMI) {
  Name (_HID, "PNP####") // SCMI Device ID
  ...
  
  // Objects and Methods to provide SCMI transport channel
  // needs to be defined for the device
  
}

  
Device(DEV) {
    ...
    Method (_CRS, 0, NotSerialized)
    {
      ...
      ClockInput (24, 1, MHz, Variable, “\\_SB.SCMI”, 1)
    }
    ...
}

SCMI supports multiple APIs for clock (e.g: enable/disable clock, get/set rate, get notification for clock change, etc.). See the SCMI specification here https://developer.arm.com/documentation/den0056/e/?lang=en

This approach would avoid having to implement the clock framework in AML and platform vendors can implement the clock control in the firmware that can be driven through the SCMI protocol.

Linux already has support for SCMI driver and adding the binding for ACPI support wouldn’t require significant changes.

Option 4: Clock Framework support at Kernel

This would require the kernel to provide a clock framework and platform vendors to provide clock drivers.

Code Block
Device (GCCP}) {
  Name (_HID, "QCOMXXXX")
  ...
}

Device(DEV) {
    ...
    Method (_CRS, 0, NotSerialized)
    {
      ...
      ClockInput (24, 1, MHz, Variable, “\\_SB.GCCP”, 1)
    }
    ...
}

ACPICA

ClockInput resource is supported by Intel ACPICA.

https://github.com/acpica/acpica/pull/838