18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ACPI device specific properties support. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014, Intel Corporation 68c2ecf20Sopenharmony_ci * All rights reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> 98c2ecf20Sopenharmony_ci * Darren Hart <dvhart@linux.intel.com> 108c2ecf20Sopenharmony_ci * Rafael J. Wysocki <rafael.j.wysocki@intel.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/acpi.h> 148c2ecf20Sopenharmony_ci#include <linux/device.h> 158c2ecf20Sopenharmony_ci#include <linux/export.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "internal.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int acpi_data_get_property_array(const struct acpi_device_data *data, 208c2ecf20Sopenharmony_ci const char *name, 218c2ecf20Sopenharmony_ci acpi_object_type type, 228c2ecf20Sopenharmony_ci const union acpi_object **obj); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * The GUIDs here are made equivalent to each other in order to avoid extra 268c2ecf20Sopenharmony_ci * complexity in the properties handling code, with the caveat that the 278c2ecf20Sopenharmony_ci * kernel will accept certain combinations of GUID and properties that are 288c2ecf20Sopenharmony_ci * not defined without a warning. For instance if any of the properties 298c2ecf20Sopenharmony_ci * from different GUID appear in a property list of another, it will be 308c2ecf20Sopenharmony_ci * accepted by the kernel. Firmware validation tools should catch these. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_cistatic const guid_t prp_guids[] = { 338c2ecf20Sopenharmony_ci /* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */ 348c2ecf20Sopenharmony_ci GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c, 358c2ecf20Sopenharmony_ci 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01), 368c2ecf20Sopenharmony_ci /* Hotplug in D3 GUID: 6211e2c0-58a3-4af3-90e1-927a4e0c55a4 */ 378c2ecf20Sopenharmony_ci GUID_INIT(0x6211e2c0, 0x58a3, 0x4af3, 388c2ecf20Sopenharmony_ci 0x90, 0xe1, 0x92, 0x7a, 0x4e, 0x0c, 0x55, 0xa4), 398c2ecf20Sopenharmony_ci /* External facing port GUID: efcc06cc-73ac-4bc3-bff0-76143807c389 */ 408c2ecf20Sopenharmony_ci GUID_INIT(0xefcc06cc, 0x73ac, 0x4bc3, 418c2ecf20Sopenharmony_ci 0xbf, 0xf0, 0x76, 0x14, 0x38, 0x07, 0xc3, 0x89), 428c2ecf20Sopenharmony_ci /* Thunderbolt GUID for IMR_VALID: c44d002f-69f9-4e7d-a904-a7baabdf43f7 */ 438c2ecf20Sopenharmony_ci GUID_INIT(0xc44d002f, 0x69f9, 0x4e7d, 448c2ecf20Sopenharmony_ci 0xa9, 0x04, 0xa7, 0xba, 0xab, 0xdf, 0x43, 0xf7), 458c2ecf20Sopenharmony_ci /* Thunderbolt GUID for WAKE_SUPPORTED: 6c501103-c189-4296-ba72-9bf5a26ebe5d */ 468c2ecf20Sopenharmony_ci GUID_INIT(0x6c501103, 0xc189, 0x4296, 478c2ecf20Sopenharmony_ci 0xba, 0x72, 0x9b, 0xf5, 0xa2, 0x6e, 0xbe, 0x5d), 488c2ecf20Sopenharmony_ci /* Storage device needs D3 GUID: 5025030f-842f-4ab4-a561-99a5189762d0 */ 498c2ecf20Sopenharmony_ci GUID_INIT(0x5025030f, 0x842f, 0x4ab4, 508c2ecf20Sopenharmony_ci 0xa5, 0x61, 0x99, 0xa5, 0x18, 0x97, 0x62, 0xd0), 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */ 548c2ecf20Sopenharmony_cistatic const guid_t ads_guid = 558c2ecf20Sopenharmony_ci GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6, 568c2ecf20Sopenharmony_ci 0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic bool acpi_enumerate_nondev_subnodes(acpi_handle scope, 598c2ecf20Sopenharmony_ci const union acpi_object *desc, 608c2ecf20Sopenharmony_ci struct acpi_device_data *data, 618c2ecf20Sopenharmony_ci struct fwnode_handle *parent); 628c2ecf20Sopenharmony_cistatic bool acpi_extract_properties(const union acpi_object *desc, 638c2ecf20Sopenharmony_ci struct acpi_device_data *data); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic bool acpi_nondev_subnode_extract(const union acpi_object *desc, 668c2ecf20Sopenharmony_ci acpi_handle handle, 678c2ecf20Sopenharmony_ci const union acpi_object *link, 688c2ecf20Sopenharmony_ci struct list_head *list, 698c2ecf20Sopenharmony_ci struct fwnode_handle *parent) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct acpi_data_node *dn; 728c2ecf20Sopenharmony_ci bool result; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci dn = kzalloc(sizeof(*dn), GFP_KERNEL); 758c2ecf20Sopenharmony_ci if (!dn) 768c2ecf20Sopenharmony_ci return false; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci dn->name = link->package.elements[0].string.pointer; 798c2ecf20Sopenharmony_ci dn->fwnode.ops = &acpi_data_fwnode_ops; 808c2ecf20Sopenharmony_ci dn->parent = parent; 818c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dn->data.properties); 828c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dn->data.subnodes); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci result = acpi_extract_properties(desc, &dn->data); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (handle) { 878c2ecf20Sopenharmony_ci acpi_handle scope; 888c2ecf20Sopenharmony_ci acpi_status status; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* 918c2ecf20Sopenharmony_ci * The scope for the subnode object lookup is the one of the 928c2ecf20Sopenharmony_ci * namespace node (device) containing the object that has 938c2ecf20Sopenharmony_ci * returned the package. That is, it's the scope of that 948c2ecf20Sopenharmony_ci * object's parent. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci status = acpi_get_parent(handle, &scope); 978c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status) 988c2ecf20Sopenharmony_ci && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data, 998c2ecf20Sopenharmony_ci &dn->fwnode)) 1008c2ecf20Sopenharmony_ci result = true; 1018c2ecf20Sopenharmony_ci } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data, 1028c2ecf20Sopenharmony_ci &dn->fwnode)) { 1038c2ecf20Sopenharmony_ci result = true; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (result) { 1078c2ecf20Sopenharmony_ci dn->handle = handle; 1088c2ecf20Sopenharmony_ci dn->data.pointer = desc; 1098c2ecf20Sopenharmony_ci list_add_tail(&dn->sibling, list); 1108c2ecf20Sopenharmony_ci return true; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci kfree(dn); 1148c2ecf20Sopenharmony_ci acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n"); 1158c2ecf20Sopenharmony_ci return false; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic bool acpi_nondev_subnode_data_ok(acpi_handle handle, 1198c2ecf20Sopenharmony_ci const union acpi_object *link, 1208c2ecf20Sopenharmony_ci struct list_head *list, 1218c2ecf20Sopenharmony_ci struct fwnode_handle *parent) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; 1248c2ecf20Sopenharmony_ci acpi_status status; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf, 1278c2ecf20Sopenharmony_ci ACPI_TYPE_PACKAGE); 1288c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 1298c2ecf20Sopenharmony_ci return false; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list, 1328c2ecf20Sopenharmony_ci parent)) 1338c2ecf20Sopenharmony_ci return true; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci ACPI_FREE(buf.pointer); 1368c2ecf20Sopenharmony_ci return false; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic bool acpi_nondev_subnode_ok(acpi_handle scope, 1408c2ecf20Sopenharmony_ci const union acpi_object *link, 1418c2ecf20Sopenharmony_ci struct list_head *list, 1428c2ecf20Sopenharmony_ci struct fwnode_handle *parent) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci acpi_handle handle; 1458c2ecf20Sopenharmony_ci acpi_status status; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (!scope) 1488c2ecf20Sopenharmony_ci return false; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci status = acpi_get_handle(scope, link->package.elements[1].string.pointer, 1518c2ecf20Sopenharmony_ci &handle); 1528c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 1538c2ecf20Sopenharmony_ci return false; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return acpi_nondev_subnode_data_ok(handle, link, list, parent); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic bool acpi_add_nondev_subnodes(acpi_handle scope, 1598c2ecf20Sopenharmony_ci const union acpi_object *links, 1608c2ecf20Sopenharmony_ci struct list_head *list, 1618c2ecf20Sopenharmony_ci struct fwnode_handle *parent) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci bool ret = false; 1648c2ecf20Sopenharmony_ci int i; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci for (i = 0; i < links->package.count; i++) { 1678c2ecf20Sopenharmony_ci const union acpi_object *link, *desc; 1688c2ecf20Sopenharmony_ci acpi_handle handle; 1698c2ecf20Sopenharmony_ci bool result; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci link = &links->package.elements[i]; 1728c2ecf20Sopenharmony_ci /* Only two elements allowed. */ 1738c2ecf20Sopenharmony_ci if (link->package.count != 2) 1748c2ecf20Sopenharmony_ci continue; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* The first one must be a string. */ 1778c2ecf20Sopenharmony_ci if (link->package.elements[0].type != ACPI_TYPE_STRING) 1788c2ecf20Sopenharmony_ci continue; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* The second one may be a string, a reference or a package. */ 1818c2ecf20Sopenharmony_ci switch (link->package.elements[1].type) { 1828c2ecf20Sopenharmony_ci case ACPI_TYPE_STRING: 1838c2ecf20Sopenharmony_ci result = acpi_nondev_subnode_ok(scope, link, list, 1848c2ecf20Sopenharmony_ci parent); 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci case ACPI_TYPE_LOCAL_REFERENCE: 1878c2ecf20Sopenharmony_ci handle = link->package.elements[1].reference.handle; 1888c2ecf20Sopenharmony_ci result = acpi_nondev_subnode_data_ok(handle, link, list, 1898c2ecf20Sopenharmony_ci parent); 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci case ACPI_TYPE_PACKAGE: 1928c2ecf20Sopenharmony_ci desc = &link->package.elements[1]; 1938c2ecf20Sopenharmony_ci result = acpi_nondev_subnode_extract(desc, NULL, link, 1948c2ecf20Sopenharmony_ci list, parent); 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci default: 1978c2ecf20Sopenharmony_ci result = false; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci ret = ret || result; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return ret; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic bool acpi_enumerate_nondev_subnodes(acpi_handle scope, 2078c2ecf20Sopenharmony_ci const union acpi_object *desc, 2088c2ecf20Sopenharmony_ci struct acpi_device_data *data, 2098c2ecf20Sopenharmony_ci struct fwnode_handle *parent) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci int i; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* Look for the ACPI data subnodes GUID. */ 2148c2ecf20Sopenharmony_ci for (i = 0; i < desc->package.count; i += 2) { 2158c2ecf20Sopenharmony_ci const union acpi_object *guid, *links; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci guid = &desc->package.elements[i]; 2188c2ecf20Sopenharmony_ci links = &desc->package.elements[i + 1]; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* 2218c2ecf20Sopenharmony_ci * The first element must be a GUID and the second one must be 2228c2ecf20Sopenharmony_ci * a package. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci if (guid->type != ACPI_TYPE_BUFFER || 2258c2ecf20Sopenharmony_ci guid->buffer.length != 16 || 2268c2ecf20Sopenharmony_ci links->type != ACPI_TYPE_PACKAGE) 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (!guid_equal((guid_t *)guid->buffer.pointer, &ads_guid)) 2308c2ecf20Sopenharmony_ci continue; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return acpi_add_nondev_subnodes(scope, links, &data->subnodes, 2338c2ecf20Sopenharmony_ci parent); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci return false; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic bool acpi_property_value_ok(const union acpi_object *value) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci int j; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* 2448c2ecf20Sopenharmony_ci * The value must be an integer, a string, a reference, or a package 2458c2ecf20Sopenharmony_ci * whose every element must be an integer, a string, or a reference. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci switch (value->type) { 2488c2ecf20Sopenharmony_ci case ACPI_TYPE_INTEGER: 2498c2ecf20Sopenharmony_ci case ACPI_TYPE_STRING: 2508c2ecf20Sopenharmony_ci case ACPI_TYPE_LOCAL_REFERENCE: 2518c2ecf20Sopenharmony_ci return true; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci case ACPI_TYPE_PACKAGE: 2548c2ecf20Sopenharmony_ci for (j = 0; j < value->package.count; j++) 2558c2ecf20Sopenharmony_ci switch (value->package.elements[j].type) { 2568c2ecf20Sopenharmony_ci case ACPI_TYPE_INTEGER: 2578c2ecf20Sopenharmony_ci case ACPI_TYPE_STRING: 2588c2ecf20Sopenharmony_ci case ACPI_TYPE_LOCAL_REFERENCE: 2598c2ecf20Sopenharmony_ci continue; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci default: 2628c2ecf20Sopenharmony_ci return false; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return true; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci return false; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic bool acpi_properties_format_valid(const union acpi_object *properties) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci int i; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci for (i = 0; i < properties->package.count; i++) { 2758c2ecf20Sopenharmony_ci const union acpi_object *property; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci property = &properties->package.elements[i]; 2788c2ecf20Sopenharmony_ci /* 2798c2ecf20Sopenharmony_ci * Only two elements allowed, the first one must be a string and 2808c2ecf20Sopenharmony_ci * the second one has to satisfy certain conditions. 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_ci if (property->package.count != 2 2838c2ecf20Sopenharmony_ci || property->package.elements[0].type != ACPI_TYPE_STRING 2848c2ecf20Sopenharmony_ci || !acpi_property_value_ok(&property->package.elements[1])) 2858c2ecf20Sopenharmony_ci return false; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci return true; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void acpi_init_of_compatible(struct acpi_device *adev) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci const union acpi_object *of_compatible; 2938c2ecf20Sopenharmony_ci int ret; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci ret = acpi_data_get_property_array(&adev->data, "compatible", 2968c2ecf20Sopenharmony_ci ACPI_TYPE_STRING, &of_compatible); 2978c2ecf20Sopenharmony_ci if (ret) { 2988c2ecf20Sopenharmony_ci ret = acpi_dev_get_property(adev, "compatible", 2998c2ecf20Sopenharmony_ci ACPI_TYPE_STRING, &of_compatible); 3008c2ecf20Sopenharmony_ci if (ret) { 3018c2ecf20Sopenharmony_ci if (adev->parent 3028c2ecf20Sopenharmony_ci && adev->parent->flags.of_compatible_ok) 3038c2ecf20Sopenharmony_ci goto out; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci adev->data.of_compatible = of_compatible; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci out: 3118c2ecf20Sopenharmony_ci adev->flags.of_compatible_ok = 1; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic bool acpi_is_property_guid(const guid_t *guid) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci int i; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(prp_guids); i++) { 3198c2ecf20Sopenharmony_ci if (guid_equal(guid, &prp_guids[i])) 3208c2ecf20Sopenharmony_ci return true; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return false; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistruct acpi_device_properties * 3278c2ecf20Sopenharmony_ciacpi_data_add_props(struct acpi_device_data *data, const guid_t *guid, 3288c2ecf20Sopenharmony_ci const union acpi_object *properties) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct acpi_device_properties *props; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci props = kzalloc(sizeof(*props), GFP_KERNEL); 3338c2ecf20Sopenharmony_ci if (props) { 3348c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&props->list); 3358c2ecf20Sopenharmony_ci props->guid = guid; 3368c2ecf20Sopenharmony_ci props->properties = properties; 3378c2ecf20Sopenharmony_ci list_add_tail(&props->list, &data->properties); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return props; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic bool acpi_extract_properties(const union acpi_object *desc, 3448c2ecf20Sopenharmony_ci struct acpi_device_data *data) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci int i; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (desc->package.count % 2) 3498c2ecf20Sopenharmony_ci return false; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* Look for the device properties GUID. */ 3528c2ecf20Sopenharmony_ci for (i = 0; i < desc->package.count; i += 2) { 3538c2ecf20Sopenharmony_ci const union acpi_object *guid, *properties; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci guid = &desc->package.elements[i]; 3568c2ecf20Sopenharmony_ci properties = &desc->package.elements[i + 1]; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* 3598c2ecf20Sopenharmony_ci * The first element must be a GUID and the second one must be 3608c2ecf20Sopenharmony_ci * a package. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci if (guid->type != ACPI_TYPE_BUFFER || 3638c2ecf20Sopenharmony_ci guid->buffer.length != 16 || 3648c2ecf20Sopenharmony_ci properties->type != ACPI_TYPE_PACKAGE) 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (!acpi_is_property_guid((guid_t *)guid->buffer.pointer)) 3688c2ecf20Sopenharmony_ci continue; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* 3718c2ecf20Sopenharmony_ci * We found the matching GUID. Now validate the format of the 3728c2ecf20Sopenharmony_ci * package immediately following it. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci if (!acpi_properties_format_valid(properties)) 3758c2ecf20Sopenharmony_ci continue; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci acpi_data_add_props(data, (const guid_t *)guid->buffer.pointer, 3788c2ecf20Sopenharmony_ci properties); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return !list_empty(&data->properties); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_civoid acpi_init_properties(struct acpi_device *adev) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; 3878c2ecf20Sopenharmony_ci struct acpi_hardware_id *hwid; 3888c2ecf20Sopenharmony_ci acpi_status status; 3898c2ecf20Sopenharmony_ci bool acpi_of = false; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adev->data.properties); 3928c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adev->data.subnodes); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (!adev->handle) 3958c2ecf20Sopenharmony_ci return; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* 3988c2ecf20Sopenharmony_ci * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in 3998c2ecf20Sopenharmony_ci * Device Tree compatible properties for this device. 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_ci list_for_each_entry(hwid, &adev->pnp.ids, list) { 4028c2ecf20Sopenharmony_ci if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) { 4038c2ecf20Sopenharmony_ci acpi_of = true; 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf, 4098c2ecf20Sopenharmony_ci ACPI_TYPE_PACKAGE); 4108c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 4118c2ecf20Sopenharmony_ci goto out; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (acpi_extract_properties(buf.pointer, &adev->data)) { 4148c2ecf20Sopenharmony_ci adev->data.pointer = buf.pointer; 4158c2ecf20Sopenharmony_ci if (acpi_of) 4168c2ecf20Sopenharmony_ci acpi_init_of_compatible(adev); 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer, 4198c2ecf20Sopenharmony_ci &adev->data, acpi_fwnode_handle(adev))) 4208c2ecf20Sopenharmony_ci adev->data.pointer = buf.pointer; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (!adev->data.pointer) { 4238c2ecf20Sopenharmony_ci acpi_handle_debug(adev->handle, "Invalid _DSD data, skipping\n"); 4248c2ecf20Sopenharmony_ci ACPI_FREE(buf.pointer); 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci out: 4288c2ecf20Sopenharmony_ci if (acpi_of && !adev->flags.of_compatible_ok) 4298c2ecf20Sopenharmony_ci acpi_handle_info(adev->handle, 4308c2ecf20Sopenharmony_ci ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n"); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (!adev->data.pointer) 4338c2ecf20Sopenharmony_ci acpi_extract_apple_properties(adev); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic void acpi_free_device_properties(struct list_head *list) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct acpi_device_properties *props, *tmp; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci list_for_each_entry_safe(props, tmp, list, list) { 4418c2ecf20Sopenharmony_ci list_del(&props->list); 4428c2ecf20Sopenharmony_ci kfree(props); 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic void acpi_destroy_nondev_subnodes(struct list_head *list) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct acpi_data_node *dn, *next; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (list_empty(list)) 4518c2ecf20Sopenharmony_ci return; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci list_for_each_entry_safe_reverse(dn, next, list, sibling) { 4548c2ecf20Sopenharmony_ci acpi_destroy_nondev_subnodes(&dn->data.subnodes); 4558c2ecf20Sopenharmony_ci wait_for_completion(&dn->kobj_done); 4568c2ecf20Sopenharmony_ci list_del(&dn->sibling); 4578c2ecf20Sopenharmony_ci ACPI_FREE((void *)dn->data.pointer); 4588c2ecf20Sopenharmony_ci acpi_free_device_properties(&dn->data.properties); 4598c2ecf20Sopenharmony_ci kfree(dn); 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_civoid acpi_free_properties(struct acpi_device *adev) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci acpi_destroy_nondev_subnodes(&adev->data.subnodes); 4668c2ecf20Sopenharmony_ci ACPI_FREE((void *)adev->data.pointer); 4678c2ecf20Sopenharmony_ci adev->data.of_compatible = NULL; 4688c2ecf20Sopenharmony_ci adev->data.pointer = NULL; 4698c2ecf20Sopenharmony_ci acpi_free_device_properties(&adev->data.properties); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/** 4738c2ecf20Sopenharmony_ci * acpi_data_get_property - return an ACPI property with given name 4748c2ecf20Sopenharmony_ci * @data: ACPI device deta object to get the property from 4758c2ecf20Sopenharmony_ci * @name: Name of the property 4768c2ecf20Sopenharmony_ci * @type: Expected property type 4778c2ecf20Sopenharmony_ci * @obj: Location to store the property value (if not %NULL) 4788c2ecf20Sopenharmony_ci * 4798c2ecf20Sopenharmony_ci * Look up a property with @name and store a pointer to the resulting ACPI 4808c2ecf20Sopenharmony_ci * object at the location pointed to by @obj if found. 4818c2ecf20Sopenharmony_ci * 4828c2ecf20Sopenharmony_ci * Callers must not attempt to free the returned objects. These objects will be 4838c2ecf20Sopenharmony_ci * freed by the ACPI core automatically during the removal of @data. 4848c2ecf20Sopenharmony_ci * 4858c2ecf20Sopenharmony_ci * Return: %0 if property with @name has been found (success), 4868c2ecf20Sopenharmony_ci * %-EINVAL if the arguments are invalid, 4878c2ecf20Sopenharmony_ci * %-EINVAL if the property doesn't exist, 4888c2ecf20Sopenharmony_ci * %-EPROTO if the property value type doesn't match @type. 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_cistatic int acpi_data_get_property(const struct acpi_device_data *data, 4918c2ecf20Sopenharmony_ci const char *name, acpi_object_type type, 4928c2ecf20Sopenharmony_ci const union acpi_object **obj) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci const struct acpi_device_properties *props; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (!data || !name) 4978c2ecf20Sopenharmony_ci return -EINVAL; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (!data->pointer || list_empty(&data->properties)) 5008c2ecf20Sopenharmony_ci return -EINVAL; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci list_for_each_entry(props, &data->properties, list) { 5038c2ecf20Sopenharmony_ci const union acpi_object *properties; 5048c2ecf20Sopenharmony_ci unsigned int i; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci properties = props->properties; 5078c2ecf20Sopenharmony_ci for (i = 0; i < properties->package.count; i++) { 5088c2ecf20Sopenharmony_ci const union acpi_object *propname, *propvalue; 5098c2ecf20Sopenharmony_ci const union acpi_object *property; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci property = &properties->package.elements[i]; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci propname = &property->package.elements[0]; 5148c2ecf20Sopenharmony_ci propvalue = &property->package.elements[1]; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (!strcmp(name, propname->string.pointer)) { 5178c2ecf20Sopenharmony_ci if (type != ACPI_TYPE_ANY && 5188c2ecf20Sopenharmony_ci propvalue->type != type) 5198c2ecf20Sopenharmony_ci return -EPROTO; 5208c2ecf20Sopenharmony_ci if (obj) 5218c2ecf20Sopenharmony_ci *obj = propvalue; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return 0; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci return -EINVAL; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci/** 5318c2ecf20Sopenharmony_ci * acpi_dev_get_property - return an ACPI property with given name. 5328c2ecf20Sopenharmony_ci * @adev: ACPI device to get the property from. 5338c2ecf20Sopenharmony_ci * @name: Name of the property. 5348c2ecf20Sopenharmony_ci * @type: Expected property type. 5358c2ecf20Sopenharmony_ci * @obj: Location to store the property value (if not %NULL). 5368c2ecf20Sopenharmony_ci */ 5378c2ecf20Sopenharmony_ciint acpi_dev_get_property(const struct acpi_device *adev, const char *name, 5388c2ecf20Sopenharmony_ci acpi_object_type type, const union acpi_object **obj) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci return adev ? acpi_data_get_property(&adev->data, name, type, obj) : -EINVAL; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_dev_get_property); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic const struct acpi_device_data * 5458c2ecf20Sopenharmony_ciacpi_device_data_of_node(const struct fwnode_handle *fwnode) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci if (is_acpi_device_node(fwnode)) { 5488c2ecf20Sopenharmony_ci const struct acpi_device *adev = to_acpi_device_node(fwnode); 5498c2ecf20Sopenharmony_ci return &adev->data; 5508c2ecf20Sopenharmony_ci } else if (is_acpi_data_node(fwnode)) { 5518c2ecf20Sopenharmony_ci const struct acpi_data_node *dn = to_acpi_data_node(fwnode); 5528c2ecf20Sopenharmony_ci return &dn->data; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci return NULL; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci/** 5588c2ecf20Sopenharmony_ci * acpi_node_prop_get - return an ACPI property with given name. 5598c2ecf20Sopenharmony_ci * @fwnode: Firmware node to get the property from. 5608c2ecf20Sopenharmony_ci * @propname: Name of the property. 5618c2ecf20Sopenharmony_ci * @valptr: Location to store a pointer to the property value (if not %NULL). 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_ciint acpi_node_prop_get(const struct fwnode_handle *fwnode, 5648c2ecf20Sopenharmony_ci const char *propname, void **valptr) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci return acpi_data_get_property(acpi_device_data_of_node(fwnode), 5678c2ecf20Sopenharmony_ci propname, ACPI_TYPE_ANY, 5688c2ecf20Sopenharmony_ci (const union acpi_object **)valptr); 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci/** 5728c2ecf20Sopenharmony_ci * acpi_data_get_property_array - return an ACPI array property with given name 5738c2ecf20Sopenharmony_ci * @adev: ACPI data object to get the property from 5748c2ecf20Sopenharmony_ci * @name: Name of the property 5758c2ecf20Sopenharmony_ci * @type: Expected type of array elements 5768c2ecf20Sopenharmony_ci * @obj: Location to store a pointer to the property value (if not NULL) 5778c2ecf20Sopenharmony_ci * 5788c2ecf20Sopenharmony_ci * Look up an array property with @name and store a pointer to the resulting 5798c2ecf20Sopenharmony_ci * ACPI object at the location pointed to by @obj if found. 5808c2ecf20Sopenharmony_ci * 5818c2ecf20Sopenharmony_ci * Callers must not attempt to free the returned objects. Those objects will be 5828c2ecf20Sopenharmony_ci * freed by the ACPI core automatically during the removal of @data. 5838c2ecf20Sopenharmony_ci * 5848c2ecf20Sopenharmony_ci * Return: %0 if array property (package) with @name has been found (success), 5858c2ecf20Sopenharmony_ci * %-EINVAL if the arguments are invalid, 5868c2ecf20Sopenharmony_ci * %-EINVAL if the property doesn't exist, 5878c2ecf20Sopenharmony_ci * %-EPROTO if the property is not a package or the type of its elements 5888c2ecf20Sopenharmony_ci * doesn't match @type. 5898c2ecf20Sopenharmony_ci */ 5908c2ecf20Sopenharmony_cistatic int acpi_data_get_property_array(const struct acpi_device_data *data, 5918c2ecf20Sopenharmony_ci const char *name, 5928c2ecf20Sopenharmony_ci acpi_object_type type, 5938c2ecf20Sopenharmony_ci const union acpi_object **obj) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci const union acpi_object *prop; 5968c2ecf20Sopenharmony_ci int ret, i; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci ret = acpi_data_get_property(data, name, ACPI_TYPE_PACKAGE, &prop); 5998c2ecf20Sopenharmony_ci if (ret) 6008c2ecf20Sopenharmony_ci return ret; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (type != ACPI_TYPE_ANY) { 6038c2ecf20Sopenharmony_ci /* Check that all elements are of correct type. */ 6048c2ecf20Sopenharmony_ci for (i = 0; i < prop->package.count; i++) 6058c2ecf20Sopenharmony_ci if (prop->package.elements[i].type != type) 6068c2ecf20Sopenharmony_ci return -EPROTO; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci if (obj) 6098c2ecf20Sopenharmony_ci *obj = prop; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return 0; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic struct fwnode_handle * 6158c2ecf20Sopenharmony_ciacpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode, 6168c2ecf20Sopenharmony_ci const char *childname) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct fwnode_handle *child; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci fwnode_for_each_child_node(fwnode, child) { 6218c2ecf20Sopenharmony_ci if (is_acpi_data_node(child)) { 6228c2ecf20Sopenharmony_ci if (acpi_data_node_match(child, childname)) 6238c2ecf20Sopenharmony_ci return child; 6248c2ecf20Sopenharmony_ci continue; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (!strncmp(acpi_device_bid(to_acpi_device_node(child)), 6288c2ecf20Sopenharmony_ci childname, ACPI_NAMESEG_SIZE)) 6298c2ecf20Sopenharmony_ci return child; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return NULL; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci/** 6368c2ecf20Sopenharmony_ci * __acpi_node_get_property_reference - returns handle to the referenced object 6378c2ecf20Sopenharmony_ci * @fwnode: Firmware node to get the property from 6388c2ecf20Sopenharmony_ci * @propname: Name of the property 6398c2ecf20Sopenharmony_ci * @index: Index of the reference to return 6408c2ecf20Sopenharmony_ci * @num_args: Maximum number of arguments after each reference 6418c2ecf20Sopenharmony_ci * @args: Location to store the returned reference with optional arguments 6428c2ecf20Sopenharmony_ci * (may be NULL) 6438c2ecf20Sopenharmony_ci * 6448c2ecf20Sopenharmony_ci * Find property with @name, verifify that it is a package containing at least 6458c2ecf20Sopenharmony_ci * one object reference and if so, store the ACPI device object pointer to the 6468c2ecf20Sopenharmony_ci * target object in @args->adev. If the reference includes arguments, store 6478c2ecf20Sopenharmony_ci * them in the @args->args[] array. 6488c2ecf20Sopenharmony_ci * 6498c2ecf20Sopenharmony_ci * If there's more than one reference in the property value package, @index is 6508c2ecf20Sopenharmony_ci * used to select the one to return. 6518c2ecf20Sopenharmony_ci * 6528c2ecf20Sopenharmony_ci * It is possible to leave holes in the property value set like in the 6538c2ecf20Sopenharmony_ci * example below: 6548c2ecf20Sopenharmony_ci * 6558c2ecf20Sopenharmony_ci * Package () { 6568c2ecf20Sopenharmony_ci * "cs-gpios", 6578c2ecf20Sopenharmony_ci * Package () { 6588c2ecf20Sopenharmony_ci * ^GPIO, 19, 0, 0, 6598c2ecf20Sopenharmony_ci * ^GPIO, 20, 0, 0, 6608c2ecf20Sopenharmony_ci * 0, 6618c2ecf20Sopenharmony_ci * ^GPIO, 21, 0, 0, 6628c2ecf20Sopenharmony_ci * } 6638c2ecf20Sopenharmony_ci * } 6648c2ecf20Sopenharmony_ci * 6658c2ecf20Sopenharmony_ci * Calling this function with index %2 or index %3 return %-ENOENT. If the 6668c2ecf20Sopenharmony_ci * property does not contain any more values %-ENOENT is returned. The NULL 6678c2ecf20Sopenharmony_ci * entry must be single integer and preferably contain value %0. 6688c2ecf20Sopenharmony_ci * 6698c2ecf20Sopenharmony_ci * Return: %0 on success, negative error code on failure. 6708c2ecf20Sopenharmony_ci */ 6718c2ecf20Sopenharmony_ciint __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, 6728c2ecf20Sopenharmony_ci const char *propname, size_t index, size_t num_args, 6738c2ecf20Sopenharmony_ci struct fwnode_reference_args *args) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci const union acpi_object *element, *end; 6768c2ecf20Sopenharmony_ci const union acpi_object *obj; 6778c2ecf20Sopenharmony_ci const struct acpi_device_data *data; 6788c2ecf20Sopenharmony_ci struct acpi_device *device; 6798c2ecf20Sopenharmony_ci int ret, idx = 0; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci data = acpi_device_data_of_node(fwnode); 6828c2ecf20Sopenharmony_ci if (!data) 6838c2ecf20Sopenharmony_ci return -ENOENT; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj); 6868c2ecf20Sopenharmony_ci if (ret) 6878c2ecf20Sopenharmony_ci return ret == -EINVAL ? -ENOENT : -EINVAL; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* 6908c2ecf20Sopenharmony_ci * The simplest case is when the value is a single reference. Just 6918c2ecf20Sopenharmony_ci * return that reference then. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) { 6948c2ecf20Sopenharmony_ci if (index) 6958c2ecf20Sopenharmony_ci return -ENOENT; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci ret = acpi_bus_get_device(obj->reference.handle, &device); 6988c2ecf20Sopenharmony_ci if (ret) 6998c2ecf20Sopenharmony_ci return ret == -ENODEV ? -EINVAL : ret; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (!args) 7028c2ecf20Sopenharmony_ci return 0; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci args->fwnode = acpi_fwnode_handle(device); 7058c2ecf20Sopenharmony_ci args->nargs = 0; 7068c2ecf20Sopenharmony_ci return 0; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* 7108c2ecf20Sopenharmony_ci * If it is not a single reference, then it is a package of 7118c2ecf20Sopenharmony_ci * references followed by number of ints as follows: 7128c2ecf20Sopenharmony_ci * 7138c2ecf20Sopenharmony_ci * Package () { REF, INT, REF, INT, INT } 7148c2ecf20Sopenharmony_ci * 7158c2ecf20Sopenharmony_ci * The index argument is then used to determine which reference 7168c2ecf20Sopenharmony_ci * the caller wants (along with the arguments). 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_ci if (obj->type != ACPI_TYPE_PACKAGE) 7198c2ecf20Sopenharmony_ci return -EINVAL; 7208c2ecf20Sopenharmony_ci if (index >= obj->package.count) 7218c2ecf20Sopenharmony_ci return -ENOENT; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci element = obj->package.elements; 7248c2ecf20Sopenharmony_ci end = element + obj->package.count; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci while (element < end) { 7278c2ecf20Sopenharmony_ci u32 nargs, i; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci if (element->type == ACPI_TYPE_LOCAL_REFERENCE) { 7308c2ecf20Sopenharmony_ci struct fwnode_handle *ref_fwnode; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci ret = acpi_bus_get_device(element->reference.handle, 7338c2ecf20Sopenharmony_ci &device); 7348c2ecf20Sopenharmony_ci if (ret) 7358c2ecf20Sopenharmony_ci return -EINVAL; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci nargs = 0; 7388c2ecf20Sopenharmony_ci element++; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* 7418c2ecf20Sopenharmony_ci * Find the referred data extension node under the 7428c2ecf20Sopenharmony_ci * referred device node. 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci for (ref_fwnode = acpi_fwnode_handle(device); 7458c2ecf20Sopenharmony_ci element < end && element->type == ACPI_TYPE_STRING; 7468c2ecf20Sopenharmony_ci element++) { 7478c2ecf20Sopenharmony_ci ref_fwnode = acpi_fwnode_get_named_child_node( 7488c2ecf20Sopenharmony_ci ref_fwnode, element->string.pointer); 7498c2ecf20Sopenharmony_ci if (!ref_fwnode) 7508c2ecf20Sopenharmony_ci return -EINVAL; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* assume following integer elements are all args */ 7548c2ecf20Sopenharmony_ci for (i = 0; element + i < end && i < num_args; i++) { 7558c2ecf20Sopenharmony_ci int type = element[i].type; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (type == ACPI_TYPE_INTEGER) 7588c2ecf20Sopenharmony_ci nargs++; 7598c2ecf20Sopenharmony_ci else if (type == ACPI_TYPE_LOCAL_REFERENCE) 7608c2ecf20Sopenharmony_ci break; 7618c2ecf20Sopenharmony_ci else 7628c2ecf20Sopenharmony_ci return -EINVAL; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (nargs > NR_FWNODE_REFERENCE_ARGS) 7668c2ecf20Sopenharmony_ci return -EINVAL; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (idx == index) { 7698c2ecf20Sopenharmony_ci args->fwnode = ref_fwnode; 7708c2ecf20Sopenharmony_ci args->nargs = nargs; 7718c2ecf20Sopenharmony_ci for (i = 0; i < nargs; i++) 7728c2ecf20Sopenharmony_ci args->args[i] = element[i].integer.value; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci return 0; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci element += nargs; 7788c2ecf20Sopenharmony_ci } else if (element->type == ACPI_TYPE_INTEGER) { 7798c2ecf20Sopenharmony_ci if (idx == index) 7808c2ecf20Sopenharmony_ci return -ENOENT; 7818c2ecf20Sopenharmony_ci element++; 7828c2ecf20Sopenharmony_ci } else { 7838c2ecf20Sopenharmony_ci return -EINVAL; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci idx++; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return -ENOENT; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__acpi_node_get_property_reference); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic int acpi_data_prop_read_single(const struct acpi_device_data *data, 7948c2ecf20Sopenharmony_ci const char *propname, 7958c2ecf20Sopenharmony_ci enum dev_prop_type proptype, void *val) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci const union acpi_object *obj; 7988c2ecf20Sopenharmony_ci int ret; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) { 8018c2ecf20Sopenharmony_ci ret = acpi_data_get_property(data, propname, ACPI_TYPE_INTEGER, &obj); 8028c2ecf20Sopenharmony_ci if (ret) 8038c2ecf20Sopenharmony_ci return ret; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci switch (proptype) { 8068c2ecf20Sopenharmony_ci case DEV_PROP_U8: 8078c2ecf20Sopenharmony_ci if (obj->integer.value > U8_MAX) 8088c2ecf20Sopenharmony_ci return -EOVERFLOW; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (val) 8118c2ecf20Sopenharmony_ci *(u8 *)val = obj->integer.value; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci break; 8148c2ecf20Sopenharmony_ci case DEV_PROP_U16: 8158c2ecf20Sopenharmony_ci if (obj->integer.value > U16_MAX) 8168c2ecf20Sopenharmony_ci return -EOVERFLOW; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci if (val) 8198c2ecf20Sopenharmony_ci *(u16 *)val = obj->integer.value; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci case DEV_PROP_U32: 8238c2ecf20Sopenharmony_ci if (obj->integer.value > U32_MAX) 8248c2ecf20Sopenharmony_ci return -EOVERFLOW; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (val) 8278c2ecf20Sopenharmony_ci *(u32 *)val = obj->integer.value; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci break; 8308c2ecf20Sopenharmony_ci default: 8318c2ecf20Sopenharmony_ci if (val) 8328c2ecf20Sopenharmony_ci *(u64 *)val = obj->integer.value; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci break; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (!val) 8388c2ecf20Sopenharmony_ci return 1; 8398c2ecf20Sopenharmony_ci } else if (proptype == DEV_PROP_STRING) { 8408c2ecf20Sopenharmony_ci ret = acpi_data_get_property(data, propname, ACPI_TYPE_STRING, &obj); 8418c2ecf20Sopenharmony_ci if (ret) 8428c2ecf20Sopenharmony_ci return ret; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (val) 8458c2ecf20Sopenharmony_ci *(char **)val = obj->string.pointer; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci return 1; 8488c2ecf20Sopenharmony_ci } else { 8498c2ecf20Sopenharmony_ci ret = -EINVAL; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci return ret; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ciint acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname, 8558c2ecf20Sopenharmony_ci enum dev_prop_type proptype, void *val) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci int ret; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (!adev || !val) 8608c2ecf20Sopenharmony_ci return -EINVAL; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci ret = acpi_data_prop_read_single(&adev->data, propname, proptype, val); 8638c2ecf20Sopenharmony_ci if (ret < 0 || proptype != ACPI_TYPE_STRING) 8648c2ecf20Sopenharmony_ci return ret; 8658c2ecf20Sopenharmony_ci return 0; 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val, 8698c2ecf20Sopenharmony_ci size_t nval) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci int i; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci for (i = 0; i < nval; i++) { 8748c2ecf20Sopenharmony_ci if (items[i].type != ACPI_TYPE_INTEGER) 8758c2ecf20Sopenharmony_ci return -EPROTO; 8768c2ecf20Sopenharmony_ci if (items[i].integer.value > U8_MAX) 8778c2ecf20Sopenharmony_ci return -EOVERFLOW; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci val[i] = items[i].integer.value; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci return 0; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic int acpi_copy_property_array_u16(const union acpi_object *items, 8858c2ecf20Sopenharmony_ci u16 *val, size_t nval) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci int i; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci for (i = 0; i < nval; i++) { 8908c2ecf20Sopenharmony_ci if (items[i].type != ACPI_TYPE_INTEGER) 8918c2ecf20Sopenharmony_ci return -EPROTO; 8928c2ecf20Sopenharmony_ci if (items[i].integer.value > U16_MAX) 8938c2ecf20Sopenharmony_ci return -EOVERFLOW; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci val[i] = items[i].integer.value; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci return 0; 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cistatic int acpi_copy_property_array_u32(const union acpi_object *items, 9018c2ecf20Sopenharmony_ci u32 *val, size_t nval) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci int i; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci for (i = 0; i < nval; i++) { 9068c2ecf20Sopenharmony_ci if (items[i].type != ACPI_TYPE_INTEGER) 9078c2ecf20Sopenharmony_ci return -EPROTO; 9088c2ecf20Sopenharmony_ci if (items[i].integer.value > U32_MAX) 9098c2ecf20Sopenharmony_ci return -EOVERFLOW; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci val[i] = items[i].integer.value; 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci return 0; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic int acpi_copy_property_array_u64(const union acpi_object *items, 9178c2ecf20Sopenharmony_ci u64 *val, size_t nval) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci int i; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci for (i = 0; i < nval; i++) { 9228c2ecf20Sopenharmony_ci if (items[i].type != ACPI_TYPE_INTEGER) 9238c2ecf20Sopenharmony_ci return -EPROTO; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci val[i] = items[i].integer.value; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci return 0; 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic int acpi_copy_property_array_string(const union acpi_object *items, 9318c2ecf20Sopenharmony_ci char **val, size_t nval) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci int i; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci for (i = 0; i < nval; i++) { 9368c2ecf20Sopenharmony_ci if (items[i].type != ACPI_TYPE_STRING) 9378c2ecf20Sopenharmony_ci return -EPROTO; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci val[i] = items[i].string.pointer; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci return nval; 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_cistatic int acpi_data_prop_read(const struct acpi_device_data *data, 9458c2ecf20Sopenharmony_ci const char *propname, 9468c2ecf20Sopenharmony_ci enum dev_prop_type proptype, 9478c2ecf20Sopenharmony_ci void *val, size_t nval) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci const union acpi_object *obj; 9508c2ecf20Sopenharmony_ci const union acpi_object *items; 9518c2ecf20Sopenharmony_ci int ret; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (nval == 1 || !val) { 9548c2ecf20Sopenharmony_ci ret = acpi_data_prop_read_single(data, propname, proptype, val); 9558c2ecf20Sopenharmony_ci /* 9568c2ecf20Sopenharmony_ci * The overflow error means that the property is there and it is 9578c2ecf20Sopenharmony_ci * single-value, but its type does not match, so return. 9588c2ecf20Sopenharmony_ci */ 9598c2ecf20Sopenharmony_ci if (ret >= 0 || ret == -EOVERFLOW) 9608c2ecf20Sopenharmony_ci return ret; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci /* 9638c2ecf20Sopenharmony_ci * Reading this property as a single-value one failed, but its 9648c2ecf20Sopenharmony_ci * value may still be represented as one-element array, so 9658c2ecf20Sopenharmony_ci * continue. 9668c2ecf20Sopenharmony_ci */ 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci ret = acpi_data_get_property_array(data, propname, ACPI_TYPE_ANY, &obj); 9708c2ecf20Sopenharmony_ci if (ret) 9718c2ecf20Sopenharmony_ci return ret; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (!val) 9748c2ecf20Sopenharmony_ci return obj->package.count; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (proptype != DEV_PROP_STRING && nval > obj->package.count) 9778c2ecf20Sopenharmony_ci return -EOVERFLOW; 9788c2ecf20Sopenharmony_ci else if (nval <= 0) 9798c2ecf20Sopenharmony_ci return -EINVAL; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci items = obj->package.elements; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci switch (proptype) { 9848c2ecf20Sopenharmony_ci case DEV_PROP_U8: 9858c2ecf20Sopenharmony_ci ret = acpi_copy_property_array_u8(items, (u8 *)val, nval); 9868c2ecf20Sopenharmony_ci break; 9878c2ecf20Sopenharmony_ci case DEV_PROP_U16: 9888c2ecf20Sopenharmony_ci ret = acpi_copy_property_array_u16(items, (u16 *)val, nval); 9898c2ecf20Sopenharmony_ci break; 9908c2ecf20Sopenharmony_ci case DEV_PROP_U32: 9918c2ecf20Sopenharmony_ci ret = acpi_copy_property_array_u32(items, (u32 *)val, nval); 9928c2ecf20Sopenharmony_ci break; 9938c2ecf20Sopenharmony_ci case DEV_PROP_U64: 9948c2ecf20Sopenharmony_ci ret = acpi_copy_property_array_u64(items, (u64 *)val, nval); 9958c2ecf20Sopenharmony_ci break; 9968c2ecf20Sopenharmony_ci case DEV_PROP_STRING: 9978c2ecf20Sopenharmony_ci ret = acpi_copy_property_array_string( 9988c2ecf20Sopenharmony_ci items, (char **)val, 9998c2ecf20Sopenharmony_ci min_t(u32, nval, obj->package.count)); 10008c2ecf20Sopenharmony_ci break; 10018c2ecf20Sopenharmony_ci default: 10028c2ecf20Sopenharmony_ci ret = -EINVAL; 10038c2ecf20Sopenharmony_ci break; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci return ret; 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ciint acpi_dev_prop_read(const struct acpi_device *adev, const char *propname, 10098c2ecf20Sopenharmony_ci enum dev_prop_type proptype, void *val, size_t nval) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci return adev ? acpi_data_prop_read(&adev->data, propname, proptype, val, nval) : -EINVAL; 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci/** 10158c2ecf20Sopenharmony_ci * acpi_node_prop_read - retrieve the value of an ACPI property with given name. 10168c2ecf20Sopenharmony_ci * @fwnode: Firmware node to get the property from. 10178c2ecf20Sopenharmony_ci * @propname: Name of the property. 10188c2ecf20Sopenharmony_ci * @proptype: Expected property type. 10198c2ecf20Sopenharmony_ci * @val: Location to store the property value (if not %NULL). 10208c2ecf20Sopenharmony_ci * @nval: Size of the array pointed to by @val. 10218c2ecf20Sopenharmony_ci * 10228c2ecf20Sopenharmony_ci * If @val is %NULL, return the number of array elements comprising the value 10238c2ecf20Sopenharmony_ci * of the property. Otherwise, read at most @nval values to the array at the 10248c2ecf20Sopenharmony_ci * location pointed to by @val. 10258c2ecf20Sopenharmony_ci */ 10268c2ecf20Sopenharmony_ciint acpi_node_prop_read(const struct fwnode_handle *fwnode, 10278c2ecf20Sopenharmony_ci const char *propname, enum dev_prop_type proptype, 10288c2ecf20Sopenharmony_ci void *val, size_t nval) 10298c2ecf20Sopenharmony_ci{ 10308c2ecf20Sopenharmony_ci return acpi_data_prop_read(acpi_device_data_of_node(fwnode), 10318c2ecf20Sopenharmony_ci propname, proptype, val, nval); 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci/** 10358c2ecf20Sopenharmony_ci * acpi_get_next_subnode - Return the next child node handle for a fwnode 10368c2ecf20Sopenharmony_ci * @fwnode: Firmware node to find the next child node for. 10378c2ecf20Sopenharmony_ci * @child: Handle to one of the device's child nodes or a null handle. 10388c2ecf20Sopenharmony_ci */ 10398c2ecf20Sopenharmony_cistruct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode, 10408c2ecf20Sopenharmony_ci struct fwnode_handle *child) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci const struct acpi_device *adev = to_acpi_device_node(fwnode); 10438c2ecf20Sopenharmony_ci const struct list_head *head; 10448c2ecf20Sopenharmony_ci struct list_head *next; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if (!child || is_acpi_device_node(child)) { 10478c2ecf20Sopenharmony_ci struct acpi_device *child_adev; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (adev) 10508c2ecf20Sopenharmony_ci head = &adev->children; 10518c2ecf20Sopenharmony_ci else 10528c2ecf20Sopenharmony_ci goto nondev; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci if (list_empty(head)) 10558c2ecf20Sopenharmony_ci goto nondev; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (child) { 10588c2ecf20Sopenharmony_ci adev = to_acpi_device_node(child); 10598c2ecf20Sopenharmony_ci next = adev->node.next; 10608c2ecf20Sopenharmony_ci if (next == head) { 10618c2ecf20Sopenharmony_ci child = NULL; 10628c2ecf20Sopenharmony_ci goto nondev; 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci child_adev = list_entry(next, struct acpi_device, node); 10658c2ecf20Sopenharmony_ci } else { 10668c2ecf20Sopenharmony_ci child_adev = list_first_entry(head, struct acpi_device, 10678c2ecf20Sopenharmony_ci node); 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci return acpi_fwnode_handle(child_adev); 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci nondev: 10738c2ecf20Sopenharmony_ci if (!child || is_acpi_data_node(child)) { 10748c2ecf20Sopenharmony_ci const struct acpi_data_node *data = to_acpi_data_node(fwnode); 10758c2ecf20Sopenharmony_ci struct acpi_data_node *dn; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* 10788c2ecf20Sopenharmony_ci * We can have a combination of device and data nodes, e.g. with 10798c2ecf20Sopenharmony_ci * hierarchical _DSD properties. Make sure the adev pointer is 10808c2ecf20Sopenharmony_ci * restored before going through data nodes, otherwise we will 10818c2ecf20Sopenharmony_ci * be looking for data_nodes below the last device found instead 10828c2ecf20Sopenharmony_ci * of the common fwnode shared by device_nodes and data_nodes. 10838c2ecf20Sopenharmony_ci */ 10848c2ecf20Sopenharmony_ci adev = to_acpi_device_node(fwnode); 10858c2ecf20Sopenharmony_ci if (adev) 10868c2ecf20Sopenharmony_ci head = &adev->data.subnodes; 10878c2ecf20Sopenharmony_ci else if (data) 10888c2ecf20Sopenharmony_ci head = &data->data.subnodes; 10898c2ecf20Sopenharmony_ci else 10908c2ecf20Sopenharmony_ci return NULL; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (list_empty(head)) 10938c2ecf20Sopenharmony_ci return NULL; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (child) { 10968c2ecf20Sopenharmony_ci dn = to_acpi_data_node(child); 10978c2ecf20Sopenharmony_ci next = dn->sibling.next; 10988c2ecf20Sopenharmony_ci if (next == head) 10998c2ecf20Sopenharmony_ci return NULL; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci dn = list_entry(next, struct acpi_data_node, sibling); 11028c2ecf20Sopenharmony_ci } else { 11038c2ecf20Sopenharmony_ci dn = list_first_entry(head, struct acpi_data_node, sibling); 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci return &dn->fwnode; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci return NULL; 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci/** 11118c2ecf20Sopenharmony_ci * acpi_node_get_parent - Return parent fwnode of this fwnode 11128c2ecf20Sopenharmony_ci * @fwnode: Firmware node whose parent to get 11138c2ecf20Sopenharmony_ci * 11148c2ecf20Sopenharmony_ci * Returns parent node of an ACPI device or data firmware node or %NULL if 11158c2ecf20Sopenharmony_ci * not available. 11168c2ecf20Sopenharmony_ci */ 11178c2ecf20Sopenharmony_cistruct fwnode_handle *acpi_node_get_parent(const struct fwnode_handle *fwnode) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci if (is_acpi_data_node(fwnode)) { 11208c2ecf20Sopenharmony_ci /* All data nodes have parent pointer so just return that */ 11218c2ecf20Sopenharmony_ci return to_acpi_data_node(fwnode)->parent; 11228c2ecf20Sopenharmony_ci } else if (is_acpi_device_node(fwnode)) { 11238c2ecf20Sopenharmony_ci struct device *dev = to_acpi_device_node(fwnode)->dev.parent; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (dev) 11268c2ecf20Sopenharmony_ci return acpi_fwnode_handle(to_acpi_device(dev)); 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci return NULL; 11308c2ecf20Sopenharmony_ci} 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci/* 11338c2ecf20Sopenharmony_ci * Return true if the node is an ACPI graph node. Called on either ports 11348c2ecf20Sopenharmony_ci * or endpoints. 11358c2ecf20Sopenharmony_ci */ 11368c2ecf20Sopenharmony_cistatic bool is_acpi_graph_node(struct fwnode_handle *fwnode, 11378c2ecf20Sopenharmony_ci const char *str) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci unsigned int len = strlen(str); 11408c2ecf20Sopenharmony_ci const char *name; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (!len || !is_acpi_data_node(fwnode)) 11438c2ecf20Sopenharmony_ci return false; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci name = to_acpi_data_node(fwnode)->name; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci return (fwnode_property_present(fwnode, "reg") && 11488c2ecf20Sopenharmony_ci !strncmp(name, str, len) && name[len] == '@') || 11498c2ecf20Sopenharmony_ci fwnode_property_present(fwnode, str); 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci/** 11538c2ecf20Sopenharmony_ci * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node 11548c2ecf20Sopenharmony_ci * @fwnode: Pointer to the parent firmware node 11558c2ecf20Sopenharmony_ci * @prev: Previous endpoint node or %NULL to get the first 11568c2ecf20Sopenharmony_ci * 11578c2ecf20Sopenharmony_ci * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns 11588c2ecf20Sopenharmony_ci * %NULL if there is no next endpoint or in case of error. In case of success 11598c2ecf20Sopenharmony_ci * the next endpoint is returned. 11608c2ecf20Sopenharmony_ci */ 11618c2ecf20Sopenharmony_cistatic struct fwnode_handle *acpi_graph_get_next_endpoint( 11628c2ecf20Sopenharmony_ci const struct fwnode_handle *fwnode, struct fwnode_handle *prev) 11638c2ecf20Sopenharmony_ci{ 11648c2ecf20Sopenharmony_ci struct fwnode_handle *port = NULL; 11658c2ecf20Sopenharmony_ci struct fwnode_handle *endpoint; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (!prev) { 11688c2ecf20Sopenharmony_ci do { 11698c2ecf20Sopenharmony_ci port = fwnode_get_next_child_node(fwnode, port); 11708c2ecf20Sopenharmony_ci /* 11718c2ecf20Sopenharmony_ci * The names of the port nodes begin with "port@" 11728c2ecf20Sopenharmony_ci * followed by the number of the port node and they also 11738c2ecf20Sopenharmony_ci * have a "reg" property that also has the number of the 11748c2ecf20Sopenharmony_ci * port node. For compatibility reasons a node is also 11758c2ecf20Sopenharmony_ci * recognised as a port node from the "port" property. 11768c2ecf20Sopenharmony_ci */ 11778c2ecf20Sopenharmony_ci if (is_acpi_graph_node(port, "port")) 11788c2ecf20Sopenharmony_ci break; 11798c2ecf20Sopenharmony_ci } while (port); 11808c2ecf20Sopenharmony_ci } else { 11818c2ecf20Sopenharmony_ci port = fwnode_get_parent(prev); 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci if (!port) 11858c2ecf20Sopenharmony_ci return NULL; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci endpoint = fwnode_get_next_child_node(port, prev); 11888c2ecf20Sopenharmony_ci while (!endpoint) { 11898c2ecf20Sopenharmony_ci port = fwnode_get_next_child_node(fwnode, port); 11908c2ecf20Sopenharmony_ci if (!port) 11918c2ecf20Sopenharmony_ci break; 11928c2ecf20Sopenharmony_ci if (is_acpi_graph_node(port, "port")) 11938c2ecf20Sopenharmony_ci endpoint = fwnode_get_next_child_node(port, NULL); 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* 11978c2ecf20Sopenharmony_ci * The names of the endpoint nodes begin with "endpoint@" followed by 11988c2ecf20Sopenharmony_ci * the number of the endpoint node and they also have a "reg" property 11998c2ecf20Sopenharmony_ci * that also has the number of the endpoint node. For compatibility 12008c2ecf20Sopenharmony_ci * reasons a node is also recognised as an endpoint node from the 12018c2ecf20Sopenharmony_ci * "endpoint" property. 12028c2ecf20Sopenharmony_ci */ 12038c2ecf20Sopenharmony_ci if (!is_acpi_graph_node(endpoint, "endpoint")) 12048c2ecf20Sopenharmony_ci return NULL; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci return endpoint; 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci/** 12108c2ecf20Sopenharmony_ci * acpi_graph_get_child_prop_value - Return a child with a given property value 12118c2ecf20Sopenharmony_ci * @fwnode: device fwnode 12128c2ecf20Sopenharmony_ci * @prop_name: The name of the property to look for 12138c2ecf20Sopenharmony_ci * @val: the desired property value 12148c2ecf20Sopenharmony_ci * 12158c2ecf20Sopenharmony_ci * Return the port node corresponding to a given port number. Returns 12168c2ecf20Sopenharmony_ci * the child node on success, NULL otherwise. 12178c2ecf20Sopenharmony_ci */ 12188c2ecf20Sopenharmony_cistatic struct fwnode_handle *acpi_graph_get_child_prop_value( 12198c2ecf20Sopenharmony_ci const struct fwnode_handle *fwnode, const char *prop_name, 12208c2ecf20Sopenharmony_ci unsigned int val) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci struct fwnode_handle *child; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci fwnode_for_each_child_node(fwnode, child) { 12258c2ecf20Sopenharmony_ci u32 nr; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(child, prop_name, &nr)) 12288c2ecf20Sopenharmony_ci continue; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (val == nr) 12318c2ecf20Sopenharmony_ci return child; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci return NULL; 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci/** 12398c2ecf20Sopenharmony_ci * acpi_graph_get_remote_endpoint - Parses and returns remote end of an endpoint 12408c2ecf20Sopenharmony_ci * @fwnode: Endpoint firmware node pointing to a remote device 12418c2ecf20Sopenharmony_ci * @endpoint: Firmware node of remote endpoint is filled here if not %NULL 12428c2ecf20Sopenharmony_ci * 12438c2ecf20Sopenharmony_ci * Returns the remote endpoint corresponding to @__fwnode. NULL on error. 12448c2ecf20Sopenharmony_ci */ 12458c2ecf20Sopenharmony_cistatic struct fwnode_handle * 12468c2ecf20Sopenharmony_ciacpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode) 12478c2ecf20Sopenharmony_ci{ 12488c2ecf20Sopenharmony_ci struct fwnode_handle *fwnode; 12498c2ecf20Sopenharmony_ci unsigned int port_nr, endpoint_nr; 12508c2ecf20Sopenharmony_ci struct fwnode_reference_args args; 12518c2ecf20Sopenharmony_ci int ret; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 12548c2ecf20Sopenharmony_ci ret = acpi_node_get_property_reference(__fwnode, "remote-endpoint", 0, 12558c2ecf20Sopenharmony_ci &args); 12568c2ecf20Sopenharmony_ci if (ret) 12578c2ecf20Sopenharmony_ci return NULL; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci /* Direct endpoint reference? */ 12608c2ecf20Sopenharmony_ci if (!is_acpi_device_node(args.fwnode)) 12618c2ecf20Sopenharmony_ci return args.nargs ? NULL : args.fwnode; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci /* 12648c2ecf20Sopenharmony_ci * Always require two arguments with the reference: port and 12658c2ecf20Sopenharmony_ci * endpoint indices. 12668c2ecf20Sopenharmony_ci */ 12678c2ecf20Sopenharmony_ci if (args.nargs != 2) 12688c2ecf20Sopenharmony_ci return NULL; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci fwnode = args.fwnode; 12718c2ecf20Sopenharmony_ci port_nr = args.args[0]; 12728c2ecf20Sopenharmony_ci endpoint_nr = args.args[1]; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci return acpi_graph_get_child_prop_value(fwnode, "endpoint", endpoint_nr); 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci if (!is_acpi_device_node(fwnode)) 12828c2ecf20Sopenharmony_ci return false; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci return acpi_device_is_present(to_acpi_device_node(fwnode)); 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic bool acpi_fwnode_property_present(const struct fwnode_handle *fwnode, 12888c2ecf20Sopenharmony_ci const char *propname) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci return !acpi_node_prop_get(fwnode, propname, NULL); 12918c2ecf20Sopenharmony_ci} 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_cistatic int 12948c2ecf20Sopenharmony_ciacpi_fwnode_property_read_int_array(const struct fwnode_handle *fwnode, 12958c2ecf20Sopenharmony_ci const char *propname, 12968c2ecf20Sopenharmony_ci unsigned int elem_size, void *val, 12978c2ecf20Sopenharmony_ci size_t nval) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci enum dev_prop_type type; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci switch (elem_size) { 13028c2ecf20Sopenharmony_ci case sizeof(u8): 13038c2ecf20Sopenharmony_ci type = DEV_PROP_U8; 13048c2ecf20Sopenharmony_ci break; 13058c2ecf20Sopenharmony_ci case sizeof(u16): 13068c2ecf20Sopenharmony_ci type = DEV_PROP_U16; 13078c2ecf20Sopenharmony_ci break; 13088c2ecf20Sopenharmony_ci case sizeof(u32): 13098c2ecf20Sopenharmony_ci type = DEV_PROP_U32; 13108c2ecf20Sopenharmony_ci break; 13118c2ecf20Sopenharmony_ci case sizeof(u64): 13128c2ecf20Sopenharmony_ci type = DEV_PROP_U64; 13138c2ecf20Sopenharmony_ci break; 13148c2ecf20Sopenharmony_ci default: 13158c2ecf20Sopenharmony_ci return -ENXIO; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci return acpi_node_prop_read(fwnode, propname, type, val, nval); 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cistatic int 13228c2ecf20Sopenharmony_ciacpi_fwnode_property_read_string_array(const struct fwnode_handle *fwnode, 13238c2ecf20Sopenharmony_ci const char *propname, const char **val, 13248c2ecf20Sopenharmony_ci size_t nval) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, 13278c2ecf20Sopenharmony_ci val, nval); 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_cistatic int 13318c2ecf20Sopenharmony_ciacpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode, 13328c2ecf20Sopenharmony_ci const char *prop, const char *nargs_prop, 13338c2ecf20Sopenharmony_ci unsigned int args_count, unsigned int index, 13348c2ecf20Sopenharmony_ci struct fwnode_reference_args *args) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci return __acpi_node_get_property_reference(fwnode, prop, index, 13378c2ecf20Sopenharmony_ci args_count, args); 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic const char *acpi_fwnode_get_name(const struct fwnode_handle *fwnode) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci const struct acpi_device *adev; 13438c2ecf20Sopenharmony_ci struct fwnode_handle *parent; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci /* Is this the root node? */ 13468c2ecf20Sopenharmony_ci parent = fwnode_get_parent(fwnode); 13478c2ecf20Sopenharmony_ci if (!parent) 13488c2ecf20Sopenharmony_ci return "\\"; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci fwnode_handle_put(parent); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (is_acpi_data_node(fwnode)) { 13538c2ecf20Sopenharmony_ci const struct acpi_data_node *dn = to_acpi_data_node(fwnode); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci return dn->name; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci adev = to_acpi_device_node(fwnode); 13598c2ecf20Sopenharmony_ci if (WARN_ON(!adev)) 13608c2ecf20Sopenharmony_ci return NULL; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci return acpi_device_bid(adev); 13638c2ecf20Sopenharmony_ci} 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_cistatic const char * 13668c2ecf20Sopenharmony_ciacpi_fwnode_get_name_prefix(const struct fwnode_handle *fwnode) 13678c2ecf20Sopenharmony_ci{ 13688c2ecf20Sopenharmony_ci struct fwnode_handle *parent; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci /* Is this the root node? */ 13718c2ecf20Sopenharmony_ci parent = fwnode_get_parent(fwnode); 13728c2ecf20Sopenharmony_ci if (!parent) 13738c2ecf20Sopenharmony_ci return ""; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci /* Is this 2nd node from the root? */ 13768c2ecf20Sopenharmony_ci parent = fwnode_get_next_parent(parent); 13778c2ecf20Sopenharmony_ci if (!parent) 13788c2ecf20Sopenharmony_ci return ""; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci fwnode_handle_put(parent); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci /* ACPI device or data node. */ 13838c2ecf20Sopenharmony_ci return "."; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic struct fwnode_handle * 13878c2ecf20Sopenharmony_ciacpi_fwnode_get_parent(struct fwnode_handle *fwnode) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci return acpi_node_get_parent(fwnode); 13908c2ecf20Sopenharmony_ci} 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_cistatic int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, 13938c2ecf20Sopenharmony_ci struct fwnode_endpoint *endpoint) 13948c2ecf20Sopenharmony_ci{ 13958c2ecf20Sopenharmony_ci struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci endpoint->local_fwnode = fwnode; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port)) 14008c2ecf20Sopenharmony_ci fwnode_property_read_u32(port_fwnode, "port", &endpoint->port); 14018c2ecf20Sopenharmony_ci if (fwnode_property_read_u32(fwnode, "reg", &endpoint->id)) 14028c2ecf20Sopenharmony_ci fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci return 0; 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_cistatic const void * 14088c2ecf20Sopenharmony_ciacpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, 14098c2ecf20Sopenharmony_ci const struct device *dev) 14108c2ecf20Sopenharmony_ci{ 14118c2ecf20Sopenharmony_ci return acpi_device_get_match_data(dev); 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci#define DECLARE_ACPI_FWNODE_OPS(ops) \ 14158c2ecf20Sopenharmony_ci const struct fwnode_operations ops = { \ 14168c2ecf20Sopenharmony_ci .device_is_available = acpi_fwnode_device_is_available, \ 14178c2ecf20Sopenharmony_ci .device_get_match_data = acpi_fwnode_device_get_match_data, \ 14188c2ecf20Sopenharmony_ci .property_present = acpi_fwnode_property_present, \ 14198c2ecf20Sopenharmony_ci .property_read_int_array = \ 14208c2ecf20Sopenharmony_ci acpi_fwnode_property_read_int_array, \ 14218c2ecf20Sopenharmony_ci .property_read_string_array = \ 14228c2ecf20Sopenharmony_ci acpi_fwnode_property_read_string_array, \ 14238c2ecf20Sopenharmony_ci .get_parent = acpi_node_get_parent, \ 14248c2ecf20Sopenharmony_ci .get_next_child_node = acpi_get_next_subnode, \ 14258c2ecf20Sopenharmony_ci .get_named_child_node = acpi_fwnode_get_named_child_node, \ 14268c2ecf20Sopenharmony_ci .get_name = acpi_fwnode_get_name, \ 14278c2ecf20Sopenharmony_ci .get_name_prefix = acpi_fwnode_get_name_prefix, \ 14288c2ecf20Sopenharmony_ci .get_reference_args = acpi_fwnode_get_reference_args, \ 14298c2ecf20Sopenharmony_ci .graph_get_next_endpoint = \ 14308c2ecf20Sopenharmony_ci acpi_graph_get_next_endpoint, \ 14318c2ecf20Sopenharmony_ci .graph_get_remote_endpoint = \ 14328c2ecf20Sopenharmony_ci acpi_graph_get_remote_endpoint, \ 14338c2ecf20Sopenharmony_ci .graph_get_port_parent = acpi_fwnode_get_parent, \ 14348c2ecf20Sopenharmony_ci .graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, \ 14358c2ecf20Sopenharmony_ci }; \ 14368c2ecf20Sopenharmony_ci EXPORT_SYMBOL_GPL(ops) 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ciDECLARE_ACPI_FWNODE_OPS(acpi_device_fwnode_ops); 14398c2ecf20Sopenharmony_ciDECLARE_ACPI_FWNODE_OPS(acpi_data_fwnode_ops); 14408c2ecf20Sopenharmony_ciconst struct fwnode_operations acpi_static_fwnode_ops; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_cibool is_acpi_device_node(const struct fwnode_handle *fwnode) 14438c2ecf20Sopenharmony_ci{ 14448c2ecf20Sopenharmony_ci return !IS_ERR_OR_NULL(fwnode) && 14458c2ecf20Sopenharmony_ci fwnode->ops == &acpi_device_fwnode_ops; 14468c2ecf20Sopenharmony_ci} 14478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(is_acpi_device_node); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_cibool is_acpi_data_node(const struct fwnode_handle *fwnode) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &acpi_data_fwnode_ops; 14528c2ecf20Sopenharmony_ci} 14538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(is_acpi_data_node); 1454