Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ACPI Entries for MPTF

Windows will boot and run without the MPTF driver loading, however it will not provide any inbox default handling of thermal control.

For any MPTF functionality the Core Driver must be loaded with the following ACPI entry

// MPTFCore Driver
Device(MPC0) {
  Name(_HID, "MSFT000D")
  Name (_UID, 1)
}

There is no requirement to define further resources through the core driver those are all controlled by the IO driver entries.

Microsoft Temperature Sensor Driver

This driver is loaded uner MSFT000A entry, it must always define a _TMP method and _DSM with support for function 0 and function1. If just these two functions are supported function 0 will return 0x3

  Method (_TMP) {
    // Check to make sure FFA is available and not unloaded
    If(LEqual(\_SB.FFA0.AVAL,One)) {
      Name(BUFF, Buffer(24){}) // Create buffer for send/recv data
      CreateByteField(BUFF,0,STAT) // Out – Status for req/rsp
      CreateByteField(BUFF,1,LENG) // In/Out – Bytes in req, updates bytes returned
      CreateField(BUFF,16,128,UUID) // UUID of service
      CreateByteField(BUFF,18, CMDD) // In – First byte of command
      CreateByteField(BUFF,19, TMP1) // In – Thermal Zone Identifier
      CreateField(BUFF,144,32,TMPD) // Out – temperature for TZ

      Store(20, LENG)
      Store(0x1, CMDD) // EC_THM_GET_TMP
      Store(1,TMP1)
      Store(ToUUID("31f56da7-593c-4d72-a4b3-8fc7171ac073"), UUID) // Thermal
      Store(Store(BUFF, \_SB_.FFA0.FFAC), BUFF)

      If(LEqual(STAT,0x0) ) // Check FF-A successful?
      {
        Return (TMPD)
      }
    }
    Return(Zero)
  }

  // Update Thresholds
  Method(STMP, 0x2, Serialized) {
    // Check to make sure FFA is available and not unloaded
    If(LEqual(\_SB.FFA0.AVAL,One)) {
      Name(BUFF, Buffer(32){}) // Create buffer for send/recv data
      CreateByteField(BUFF,0,STAT) // Out – Status for req/rsp
      CreateByteField(BUFF,1,LENG) // In/Out – Bytes in req, updates bytes returned
      CreateField(BUFF,16,128,UUID) // UUID of service
      CreateByteField(BUFF,18, CMDD) // In – First byte of command
      CreateByteField(BUFF,19, TID1) // In – Thermal Zone Identifier
      CreateDwordField(BUFF,20,THS1) // In – Timeout in ms
      CreateDwordField(BUFF,24,THS2) // In – Low threshold tenth Kelvin
      CreateDwordField(BUFF,28,THS3) // In – High threshold tenth Kelvin
      CreateField(BUFF,144,32,THSD) // Out – Status from EC

      Store(0x30, LENG)
      Store(0x2, CMDD) // EC_THM_SET_THRS
      Store(1,TID1)
      Store(0,THS1) // Timout in ms 0 ignore
      Store(Arg0,THS2) // Low Threshold
      Store(Arg1,THS3) // High Threshold
      Store(ToUUID("31f56da7-593c-4d72-a4b3-8fc7171ac073"), UUID) // Thermal
      Store(Store(BUFF, \_SB_.FFA0.FFAC), BUFF)

      If(LEqual(STAT,0x0) ) // Check FF-A successful?
      {
        Return (THSD)
      }
    }
    Return(Zero)
  }


  // Arg0 GUID
  //      1f0849fc-a845-4fcf-865c-4101bf8e8d79 - Temperature GUID
  // Arg1 Revision
  // Arg2 Function Index
  // Arg3 Function dependent
  Method(_DSM, 0x4, Serialized) {
    // Input Variable
    If(LEqual(ToUuid("1f0849fc-a845-4fcf-865c-4101bf8e8d79"),Arg0)) {
        Switch(Arg2) {
          Case(0) {
            // We support function 0,1
            Return (Buffer() {0x03, 0x00, 0x00, 0x00})
          }
          // Update Thresholds
          // Arg3 = Package () { LowTemp, HighTemp }
          Case(1) {
            Return(STMP(DeRefOf(Index(Arg3,0)),DeRefOf(Index(Arg3,1)))) // Set Temp low and high threshold
          }
        }
    }

    Return (Ones)
  }

Microsoft Customized IO Signal Driver

This driver is loaded under MSFT0011 entry, and must always define Function 0 for both input and output devices. Function 0 is a bitmask of all the other variables that are supported on this platform. If you support functions 1,2,3 you would return 0b1111 (0xf) to indicate support for function 0-3.

  // Arg0 GUID
  //      07ff6382-e29a-47c9-ac87-e79dad71dd82 - Input
  //      d9b9b7f3-2a3e-4064-8841-cb13d317669e - Output
  // Arg1 Revision
  // Arg2 Function Index
  // Arg3 Function dependent
  Method(_DSM, 0x4, Serialized) {
    // Input Variable
    If(LEqual(ToUuid("07ff6382-e29a-47c9-ac87-e79dad71dd82"),Arg0)) {
        Switch(Arg2) {
          Case(0) {
            // We support function 0-3
            Return (Buffer() {0x0f, 0x00, 0x00, 0x00})
          }
          Case(1) {
            Return(GVAR(1,ToUuid("db261c77-934b-45e2-9742-256c62badb7a"))) // MinRPM
          }
          Case(2) {
            Return(GVAR(1,ToUuid("5cf839df-8be7-42b9-9ac5-3403ca2c8a6a"))) // MaxRPM
          }
          Case(3) {
            Return(GVAR(1,ToUuid("adf95492-0776-4ffc-84f3-b6c8b5269683"))) // CurrentRPM
          }
        }
        Return(Ones)
    }
    // Output Variable
    If(LEqual(ToUuid("d9b9b7f3-2a3e-4064-8841-cb13d317669e"),Arg0)) {
        Switch(Arg2) {
          Case(0) {
            // We support function 0-3
            Return (Buffer() {0x0f, 0x00, 0x00, 0x00})
          }
          Case(1) {
            Return(SVAR(1,ToUuid("db261c77-934b-45e2-9742-256c62badb7a"),Arg3)) // MinRPM
          }
          Case(2) {
            Return(SVAR(1,ToUuid("5cf839df-8be7-42b9-9ac5-3403ca2c8a6a"),Arg3)) // MaxRPM
          }
          Case(3) {
            Return(SVAR(1,ToUuid("adf95492-0776-4ffc-84f3-b6c8b5269683"),Arg3)) // CurrentRPM
          }
        }
        Return(Ones)
    }

    Return (Ones)
  }

In this case we've assigned the following meanings to supported functions

Function 1 --> MinRPM
Function 2 --> MaxRPM
Function 3 --> CurrentRPM

The meaning of what Function 1 does is mapped by the configuration Blob for your device, so Function 1 need not always be MinRPM. For communication with the EC we've assigned UUID's to each variable we support on the EC. This allows us to keep the same UUID for MinRPM on all platform implementations even though it may be a different function.

The following is the list of UUID's and variables we have defined for our reference implementation, but further mappings can be added by OEM's as well.

Variable GUID Description
OnTemp ba17b567-c368-48d5-bc6f-a312a41583c1 Lowest temperature at which the fan is turned on.
RampTemp 3a62688c-d95b-4d2d-bacc-90d7a5816bcd Temperature at which the fan starts ramping from min speed.
MaxTemp dcb758b1-f0fd-4ec7-b2c0-ef1e2a547b76 Temperature at top of fan ramp where fan is at maximum speed.
CrtTemp 218246e7-baf6-45f1-aa13-07e4845256b8 Critical temperature at which we need to shut down the system.
ProcHotTemp 22dc52d2-fd0b-47ab-95b8-26552f9831a5 Temperature at which the EC will assert the PROCHOT notification.
MinRpm db261c77-934b-45e2-9742-256c62badb7a Minimum RPM FAN speed
MinDba (Optional) 0457a722-58f4-41ca-b053-c7088fcfb89d Minimum Dba from FAN

MinSones (Optional)

311668e2-09aa-416e-a7ce-7b978e7f88be Minimum Sones from FAN
MaxRpm 5cf839df-8be7-42b9-9ac5-3403ca2c8a6a Maximum RPM for FAN
MaxDba (Optional) 372ae76b-eb64-466d-ae6b-1228397cf374 Maximum DBA for FAN
MaxSones (Optional) 6deb7eb1-839a-4482-8757-502ac31b20b7 Maximum Sones for FAN
ProfileType 23b4a025-cdfd-4af9-a411-37a24c574615 Set profile for EC, gaming, quiet, lap, etc
CurrentRpm adf95492-0776-4ffc-84f3-b6c8b5269683 The current RPM of FAN
CurrentDba (Optional) 4bb2ccd9-c7d7-4629-9fd6-1bc46300ee77 The current Dba from FAN
CurrentSones (Optional) 7719d686-02af-48a5-8283-20ba6ca2e940 The current Sones from FAN

ACPI communication to EC

MPTF refers to input and output channel values, however these need to be communicated to the EC. Above code refers to GVAR and SVAR to get a variable or set a variable. The following ACPI shows example of how to conver this to an FFA command which is sent to the secure EC service and then communicated to the EC. Further details of how this data is sent to the EC is covered in the EC Service section.

  // Arg0 Instance ID
  // Arg1 UUID of variable
  // Return (Status,Value)
  Method(GVAR,2,Serialized) {
    If(LEqual(\_SB.FFA0.AVAL,One)) {
        Name(BUFF, Buffer(52){})
        CreateField(BUFF, 0, 64, STAT) // Out – Status
        CreateField(BUFF, 64, 64, RCVD) // ReceiverId(only lower 16-bits are used) 
        CreateField(BUFF, 128, 128, UUID) // UUID of service
        CreateField(BUFF, 256, 8, CMDD) // Command register
        CreateField(BUFF, 264, 8, INST) // In – Instance ID
        CreateField(BUFF, 272, 16, VLEN) // In – Variable Length in bytes
        CreateField(BUFF, 288, 128, VUID) // In – Variable UUID
        CreateField(BUFF, 264, 64, RVAL) // Out – Variable value

        Store(ToUUID("31f56da7-593c-4d72-a4b3-8fc7171ac073"), UUID)
        Store(0x5, CMDD) // EC_THM_GET_VAR
        Store(Arg0,INST) // Save instance ID
        Store(4,VLEN) // Variable is always DWORD here
        Store(Arg1, VUID)
        Store(Store(BUFF, \_SB_.FFA0.FFAC), BUFF)
    
        If(LEqual(STAT,0x0) ) // Check FF-A successful?
        {
        Return (RVAL)
        }
      }
      Return (Ones)
    }

  // Arg0 Instance ID
  // Arg1 UUID of variable
  // Return (Status,Value)
  Method(SVAR,3,Serialized) {
    If(LEqual(\_SB_.FFA0.AVAL,One)) {
      Name(BUFF, Buffer(56){})
    
      CreateField(BUFF, 0, 64, STAT) // Out – Status
      CreateField(BUFF, 64, 64, RCVD) // ReceiverId(only lower 16-bits are used) 
      CreateField(BUFF, 128, 128, UUID) // UUID of service
      CreateField(BUFF, 256, 8, CMDD) // Command register
      CreateField(BUFF, 264, 8, INST) // In – Instance ID
      CreateField(BUFF, 272, 16, VLEN) // In – Variable Length in bytes
      CreateField(BUFF, 288, 128, VUID) // In – Variable UUID
      CreateField(BUFF, 416, 32, DVAL) // In – Variable Data
      CreateField(BUFF, 264, 64, RVAL) // Out – Variable value

      Store(ToUUID("31f56da7-593c-4d72-a4b3-8fc7171ac073"), UUID)
      Store(0x6, CMDD) // EC_THM_SET_VAR
      Store(Arg0,INST) // Save instance ID
      Store(4,VLEN) // Variable is always DWORD here
      Store(Arg1, VUID)
      Store(Arg2,DVAL)
      Store(Store(BUFF, \_SB_.FFA0.FFAC), BUFF)
      If(LEqual(STAT,0x0) ) // Check FF-A successful?
      {
        Return (RVAL)
      }
    }
    Return (Ones)
  }