162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * apple.c - Apple ACPI quirks 462306a36Sopenharmony_ci * Copyright (C) 2017 Lukas Wunner <lukas@wunner.de> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/acpi.h> 862306a36Sopenharmony_ci#include <linux/bitmap.h> 962306a36Sopenharmony_ci#include <linux/platform_data/x86/apple.h> 1062306a36Sopenharmony_ci#include <linux/uuid.h> 1162306a36Sopenharmony_ci#include "../internal.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* Apple _DSM device properties GUID */ 1462306a36Sopenharmony_cistatic const guid_t apple_prp_guid = 1562306a36Sopenharmony_ci GUID_INIT(0xa0b5b7c6, 0x1318, 0x441c, 1662306a36Sopenharmony_ci 0xb0, 0xc9, 0xfe, 0x69, 0x5e, 0xaf, 0x94, 0x9b); 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/** 1962306a36Sopenharmony_ci * acpi_extract_apple_properties - retrieve and convert Apple _DSM properties 2062306a36Sopenharmony_ci * @adev: ACPI device for which to retrieve the properties 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Invoke Apple's custom _DSM once to check the protocol version and once more 2362306a36Sopenharmony_ci * to retrieve the properties. They are marshalled up in a single package as 2462306a36Sopenharmony_ci * alternating key/value elements, unlike _DSD which stores them as a package 2562306a36Sopenharmony_ci * of 2-element packages. Convert to _DSD format and make them available under 2662306a36Sopenharmony_ci * the primary fwnode. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_civoid acpi_extract_apple_properties(struct acpi_device *adev) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci unsigned int i, j = 0, newsize = 0, numprops, numvalid; 3162306a36Sopenharmony_ci union acpi_object *props, *newprops; 3262306a36Sopenharmony_ci unsigned long *valid = NULL; 3362306a36Sopenharmony_ci void *free_space; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (!x86_apple_machine) 3662306a36Sopenharmony_ci return; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 0, 3962306a36Sopenharmony_ci NULL, ACPI_TYPE_BUFFER); 4062306a36Sopenharmony_ci if (!props) 4162306a36Sopenharmony_ci return; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!props->buffer.length) 4462306a36Sopenharmony_ci goto out_free; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (props->buffer.pointer[0] != 3) { 4762306a36Sopenharmony_ci acpi_handle_info(adev->handle, FW_INFO 4862306a36Sopenharmony_ci "unsupported properties version %*ph\n", 4962306a36Sopenharmony_ci props->buffer.length, props->buffer.pointer); 5062306a36Sopenharmony_ci goto out_free; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci ACPI_FREE(props); 5462306a36Sopenharmony_ci props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 1, 5562306a36Sopenharmony_ci NULL, ACPI_TYPE_PACKAGE); 5662306a36Sopenharmony_ci if (!props) 5762306a36Sopenharmony_ci return; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci numprops = props->package.count / 2; 6062306a36Sopenharmony_ci if (!numprops) 6162306a36Sopenharmony_ci goto out_free; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci valid = bitmap_zalloc(numprops, GFP_KERNEL); 6462306a36Sopenharmony_ci if (!valid) 6562306a36Sopenharmony_ci goto out_free; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* newsize = key length + value length of each tuple */ 6862306a36Sopenharmony_ci for (i = 0; i < numprops; i++) { 6962306a36Sopenharmony_ci union acpi_object *key = &props->package.elements[i * 2]; 7062306a36Sopenharmony_ci union acpi_object *val = &props->package.elements[i * 2 + 1]; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if ( key->type != ACPI_TYPE_STRING || 7362306a36Sopenharmony_ci (val->type != ACPI_TYPE_INTEGER && 7462306a36Sopenharmony_ci val->type != ACPI_TYPE_BUFFER && 7562306a36Sopenharmony_ci val->type != ACPI_TYPE_STRING)) 7662306a36Sopenharmony_ci continue; /* skip invalid properties */ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci __set_bit(i, valid); 7962306a36Sopenharmony_ci newsize += key->string.length + 1; 8062306a36Sopenharmony_ci if ( val->type == ACPI_TYPE_BUFFER) 8162306a36Sopenharmony_ci newsize += val->buffer.length; 8262306a36Sopenharmony_ci else if (val->type == ACPI_TYPE_STRING) 8362306a36Sopenharmony_ci newsize += val->string.length + 1; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci numvalid = bitmap_weight(valid, numprops); 8762306a36Sopenharmony_ci if (numprops > numvalid) 8862306a36Sopenharmony_ci acpi_handle_info(adev->handle, FW_INFO 8962306a36Sopenharmony_ci "skipped %u properties: wrong type\n", 9062306a36Sopenharmony_ci numprops - numvalid); 9162306a36Sopenharmony_ci if (numvalid == 0) 9262306a36Sopenharmony_ci goto out_free; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* newsize += top-level package + 3 objects for each key/value tuple */ 9562306a36Sopenharmony_ci newsize += (1 + 3 * numvalid) * sizeof(union acpi_object); 9662306a36Sopenharmony_ci newprops = ACPI_ALLOCATE_ZEROED(newsize); 9762306a36Sopenharmony_ci if (!newprops) 9862306a36Sopenharmony_ci goto out_free; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* layout: top-level package | packages | key/value tuples | strings */ 10162306a36Sopenharmony_ci newprops->type = ACPI_TYPE_PACKAGE; 10262306a36Sopenharmony_ci newprops->package.count = numvalid; 10362306a36Sopenharmony_ci newprops->package.elements = &newprops[1]; 10462306a36Sopenharmony_ci free_space = &newprops[1 + 3 * numvalid]; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci for_each_set_bit(i, valid, numprops) { 10762306a36Sopenharmony_ci union acpi_object *key = &props->package.elements[i * 2]; 10862306a36Sopenharmony_ci union acpi_object *val = &props->package.elements[i * 2 + 1]; 10962306a36Sopenharmony_ci unsigned int k = 1 + numvalid + j * 2; /* index into newprops */ 11062306a36Sopenharmony_ci unsigned int v = k + 1; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci newprops[1 + j].type = ACPI_TYPE_PACKAGE; 11362306a36Sopenharmony_ci newprops[1 + j].package.count = 2; 11462306a36Sopenharmony_ci newprops[1 + j].package.elements = &newprops[k]; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci newprops[k].type = ACPI_TYPE_STRING; 11762306a36Sopenharmony_ci newprops[k].string.length = key->string.length; 11862306a36Sopenharmony_ci newprops[k].string.pointer = free_space; 11962306a36Sopenharmony_ci memcpy(free_space, key->string.pointer, key->string.length); 12062306a36Sopenharmony_ci free_space += key->string.length + 1; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci newprops[v].type = val->type; 12362306a36Sopenharmony_ci if (val->type == ACPI_TYPE_INTEGER) { 12462306a36Sopenharmony_ci newprops[v].integer.value = val->integer.value; 12562306a36Sopenharmony_ci } else if (val->type == ACPI_TYPE_STRING) { 12662306a36Sopenharmony_ci newprops[v].string.length = val->string.length; 12762306a36Sopenharmony_ci newprops[v].string.pointer = free_space; 12862306a36Sopenharmony_ci memcpy(free_space, val->string.pointer, 12962306a36Sopenharmony_ci val->string.length); 13062306a36Sopenharmony_ci free_space += val->string.length + 1; 13162306a36Sopenharmony_ci } else { 13262306a36Sopenharmony_ci newprops[v].buffer.length = val->buffer.length; 13362306a36Sopenharmony_ci newprops[v].buffer.pointer = free_space; 13462306a36Sopenharmony_ci memcpy(free_space, val->buffer.pointer, 13562306a36Sopenharmony_ci val->buffer.length); 13662306a36Sopenharmony_ci free_space += val->buffer.length; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci j++; /* count valid properties */ 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci WARN_ON(free_space != (void *)newprops + newsize); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci adev->data.pointer = newprops; 14362306a36Sopenharmony_ci acpi_data_add_props(&adev->data, &apple_prp_guid, newprops); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ciout_free: 14662306a36Sopenharmony_ci ACPI_FREE(props); 14762306a36Sopenharmony_ci bitmap_free(valid); 14862306a36Sopenharmony_ci} 149