ACPI: video: Add force_native quirk for Sony Vaio VPCY11S1E
[platform/kernel/linux-starfive.git] / drivers / acpi / x86 / apple.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * apple.c - Apple ACPI quirks
4  * Copyright (C) 2017 Lukas Wunner <lukas@wunner.de>
5  */
6
7 #include <linux/acpi.h>
8 #include <linux/bitmap.h>
9 #include <linux/platform_data/x86/apple.h>
10 #include <linux/uuid.h>
11 #include "../internal.h"
12
13 /* Apple _DSM device properties GUID */
14 static const guid_t apple_prp_guid =
15         GUID_INIT(0xa0b5b7c6, 0x1318, 0x441c,
16                   0xb0, 0xc9, 0xfe, 0x69, 0x5e, 0xaf, 0x94, 0x9b);
17
18 /**
19  * acpi_extract_apple_properties - retrieve and convert Apple _DSM properties
20  * @adev: ACPI device for which to retrieve the properties
21  *
22  * Invoke Apple's custom _DSM once to check the protocol version and once more
23  * to retrieve the properties.  They are marshalled up in a single package as
24  * alternating key/value elements, unlike _DSD which stores them as a package
25  * of 2-element packages.  Convert to _DSD format and make them available under
26  * the primary fwnode.
27  */
28 void acpi_extract_apple_properties(struct acpi_device *adev)
29 {
30         unsigned int i, j = 0, newsize = 0, numprops, numvalid;
31         union acpi_object *props, *newprops;
32         unsigned long *valid = NULL;
33         void *free_space;
34
35         if (!x86_apple_machine)
36                 return;
37
38         props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 0,
39                                         NULL, ACPI_TYPE_BUFFER);
40         if (!props)
41                 return;
42
43         if (!props->buffer.length)
44                 goto out_free;
45
46         if (props->buffer.pointer[0] != 3) {
47                 acpi_handle_info(adev->handle, FW_INFO
48                                  "unsupported properties version %*ph\n",
49                                  props->buffer.length, props->buffer.pointer);
50                 goto out_free;
51         }
52
53         ACPI_FREE(props);
54         props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 1,
55                                         NULL, ACPI_TYPE_PACKAGE);
56         if (!props)
57                 return;
58
59         numprops = props->package.count / 2;
60         if (!numprops)
61                 goto out_free;
62
63         valid = bitmap_zalloc(numprops, GFP_KERNEL);
64         if (!valid)
65                 goto out_free;
66
67         /* newsize = key length + value length of each tuple */
68         for (i = 0; i < numprops; i++) {
69                 union acpi_object *key = &props->package.elements[i * 2];
70                 union acpi_object *val = &props->package.elements[i * 2 + 1];
71
72                 if ( key->type != ACPI_TYPE_STRING ||
73                     (val->type != ACPI_TYPE_INTEGER &&
74                      val->type != ACPI_TYPE_BUFFER))
75                         continue; /* skip invalid properties */
76
77                 __set_bit(i, valid);
78                 newsize += key->string.length + 1;
79                 if ( val->type == ACPI_TYPE_BUFFER)
80                         newsize += val->buffer.length;
81         }
82
83         numvalid = bitmap_weight(valid, numprops);
84         if (numprops > numvalid)
85                 acpi_handle_info(adev->handle, FW_INFO
86                                  "skipped %u properties: wrong type\n",
87                                  numprops - numvalid);
88         if (numvalid == 0)
89                 goto out_free;
90
91         /* newsize += top-level package + 3 objects for each key/value tuple */
92         newsize += (1 + 3 * numvalid) * sizeof(union acpi_object);
93         newprops = ACPI_ALLOCATE_ZEROED(newsize);
94         if (!newprops)
95                 goto out_free;
96
97         /* layout: top-level package | packages | key/value tuples | strings */
98         newprops->type = ACPI_TYPE_PACKAGE;
99         newprops->package.count = numvalid;
100         newprops->package.elements = &newprops[1];
101         free_space = &newprops[1 + 3 * numvalid];
102
103         for_each_set_bit(i, valid, numprops) {
104                 union acpi_object *key = &props->package.elements[i * 2];
105                 union acpi_object *val = &props->package.elements[i * 2 + 1];
106                 unsigned int k = 1 + numvalid + j * 2; /* index into newprops */
107                 unsigned int v = k + 1;
108
109                 newprops[1 + j].type = ACPI_TYPE_PACKAGE;
110                 newprops[1 + j].package.count = 2;
111                 newprops[1 + j].package.elements = &newprops[k];
112
113                 newprops[k].type = ACPI_TYPE_STRING;
114                 newprops[k].string.length = key->string.length;
115                 newprops[k].string.pointer = free_space;
116                 memcpy(free_space, key->string.pointer, key->string.length);
117                 free_space += key->string.length + 1;
118
119                 newprops[v].type = val->type;
120                 if (val->type == ACPI_TYPE_INTEGER) {
121                         newprops[v].integer.value = val->integer.value;
122                 } else {
123                         newprops[v].buffer.length = val->buffer.length;
124                         newprops[v].buffer.pointer = free_space;
125                         memcpy(free_space, val->buffer.pointer,
126                                val->buffer.length);
127                         free_space += val->buffer.length;
128                 }
129                 j++; /* count valid properties */
130         }
131         WARN_ON(free_space != (void *)newprops + newsize);
132
133         adev->data.pointer = newprops;
134         acpi_data_add_props(&adev->data, &apple_prp_guid, newprops);
135
136 out_free:
137         ACPI_FREE(props);
138         bitmap_free(valid);
139 }