| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| /* |
| * This device provides an ACPI interface to read VPD keys from either |
| * the RO_VPD or RW_VPD region. For example: |
| * |
| * VPD.VPDF ("RO", "ro_key_name") |
| * VPD.VPDF ("RW", "rw_key_name") |
| */ |
| |
| Device (VPD) |
| { |
| Name (_HID, "GOOG000F") |
| Name (_UID, 1) |
| Name (_STA, 0xf) |
| |
| Name (VOFS, 0x600) /* Start of VPD header in VPD region */ |
| Name (VIHL, 0x10) /* Length of VPD info header */ |
| Name (VPET, 0x00) /* VPD Entry Type: Terminator */ |
| Name (VPES, 0x01) /* VPD Entry Type: String */ |
| Name (VPEI, 0xfe) /* VPD Entry Type: Info (header) */ |
| Name (MORE, 0x80) /* Bit to indicate more length bytes */ |
| |
| Name (VPTR, Zero) /* Pointer to current byte in VPD for parser */ |
| Name (VEND, Zero) /* End of VPD region */ |
| |
| /* |
| * VLOC() - Return location and length of VPD region in memory. |
| * These values must be initialized in GNVS by coreboot. |
| * |
| * Returns: Package indicating start and length of region: |
| * [0] = Address of the start of VPD region. |
| * [1] = Length of the VPD region. |
| */ |
| Method (VLOC, 1, Serialized) |
| { |
| Switch (ToString (Arg0)) |
| { |
| Case ("RO") { |
| Return (Package () { \ROVP, \ROVL }) |
| } |
| Case ("RW") { |
| Return (Package () { \RWVP, \RWVL }) |
| } |
| Default { |
| Return (Package () { Zero, Zero }) |
| } |
| } |
| } |
| |
| /* |
| * VVPD() - Verify VPD info header. |
| * Arg0: VPD partition base address. |
| * Returns: VPD length or Zero if VPD header is not valid. |
| */ |
| Method (VVPD, 1, Serialized) |
| { |
| Local0 = Arg0 + ^VOFS |
| |
| OperationRegion (VPDH, SystemMemory, Local0, ^VIHL) |
| Field (VPDH, DWordAcc, NoLock, Preserve) |
| { |
| TYPE, 8, /* VPD Header Tag (=0xfe) */ |
| KLEN, 8, /* Key length (=9) */ |
| IVER, 8, /* Info version (=1) */ |
| SIGN, 64, /* Signature (="gVpdInfo") */ |
| VLEN, 8, /* Value length (=4) */ |
| SIZE, 32, /* VPD length */ |
| } |
| |
| If (TYPE != ^VPEI) { |
| Return (Zero) |
| } |
| If (KLEN != 9) { |
| Return (Zero) |
| } |
| If (IVER != 1) { |
| Return (Zero) |
| } |
| If (ToString (SIGN) != "gVpdInfo") { |
| Return (Zero) |
| } |
| If (VLEN != 4) { |
| Return (Zero) |
| } |
| |
| Return (SIZE) |
| } |
| |
| /* Return next byte from VPD at pointer VPTR, and increment VPTR. */ |
| Method (VPRB, 0, Serialized) |
| { |
| If (^VPTR > ^VEND) { |
| Printf ("Access beyond end of VPD region") |
| Return (Zero) |
| } |
| |
| Local0 = ^VPTR |
| OperationRegion (VPDR, SystemMemory, Local0, One) |
| Field (VPDR, DWordAcc, NoLock, Preserve) |
| { |
| BYTE, 8, |
| } |
| |
| /* Increment address pointer */ |
| ^VPTR++ |
| Return (BYTE) |
| } |
| |
| /* Extract and return next string from VPD. */ |
| Method (VPDE, 0, Serialized) |
| { |
| Local0 = One /* Indicates if there are more bytes */ |
| Local1 = Zero /* Length */ |
| |
| /* Decode the string length */ |
| While (Local0) { |
| /* Read the next byte at indicated address */ |
| Local2 = ^VPRB () |
| |
| /* Update the more bit from the byte in Local2 */ |
| Local0 = Local2 >> 7 |
| |
| /* Save the length bits from Local2 */ |
| Local1 <<= 7 |
| Local1 |= Local2 & 0x7f |
| } |
| If (Local1 == Zero) { |
| Return (Zero) |
| } |
| |
| /* Extract the string */ |
| Local3 = Zero |
| Local4 = "" |
| While (Local3 < Local1) { |
| Concatenate (Local4, ToString (^VPRB ()), Local4) |
| Local3++ |
| } |
| |
| Return (Local4) |
| } |
| |
| /* |
| * VPDS() - Find next VPD key and value. |
| * Returns: Package containing key and value: |
| * [0] = VPD key string |
| * [1] = VPD value string |
| */ |
| Method (VPDS, 0, Serialized) |
| { |
| Name (VPKV, Package () { "", "" }) |
| |
| /* Read the VPD type and ensure it is a string */ |
| If (^VPRB () != ^VPES) { |
| Printf ("VPDS: Type is not a string") |
| Return (VPKV) |
| } |
| |
| /* Extract the key string and value */ |
| VPKV[0] = VPDE () |
| VPKV[1] = VPDE () |
| |
| Return (VPKV) |
| } |
| |
| /* |
| * VPDF() - Find VPD key with matching name. |
| * Arg0: VPD Partition, either "RO" or "RW". |
| * Arg1: VPD key name to search for. |
| * Returns: VPD string corresponding to VPD key, or Zero if not found. |
| */ |
| Method (VPDF, 2, Serialized) |
| { |
| Local0 = VLOC (Arg0) |
| |
| /* Start of VPD region */ |
| ^VPTR = DerefOf (Local0[0]) |
| |
| /* End address of VPD region */ |
| ^VEND = ^VPTR + DerefOf (Local0[1]) |
| |
| If (^VPTR == Zero || ^VEND == Zero) { |
| Printf ("Unable to find VPD region") |
| Return (Zero) |
| } |
| |
| /* Verify VPD info header and save size */ |
| Local0 = VVPD (^VPTR) |
| If (Local0 == Zero) { |
| Printf ("VPD region %o did not verify", Arg0) |
| Return (Zero) |
| } |
| |
| /* Set VPD pointer to start of VPD entries */ |
| ^VPTR += ^VOFS + ^VIHL |
| |
| /* Search through VPD entries until key is found */ |
| Local1 = "" |
| While (Local1 != ToString (Arg1)) { |
| Local2 = VPDS () |
| Local1 = DerefOf (Local2[0]) |
| If (Local1 == "") { |
| Printf ("VPD KEY %o not found", Arg1) |
| Return (Zero) |
| } |
| } |
| Local3 = DerefOf (Local2[1]) |
| |
| Printf ("Found VPD KEY %o = %o", Local1, Local3) |
| Return (Local3) |
| } |
| } |