blob: a1ea3386ba736830238c478fe1477dc0b2ffc876 [file] [log] [blame]
/* 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)
}
}