Simon Glass | 0e5a0a0 | 2020-07-07 13:11:56 -0600 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | /* |
| 3 | * Device properties, a temporary data structure for adding to ACPI code |
| 4 | * |
| 5 | * Copyright 2019 Google LLC |
| 6 | * Mostly taken from coreboot file acpi_device.h |
| 7 | */ |
| 8 | |
| 9 | #ifndef __ACPI_DP_H |
| 10 | #define __ACPI_DP_H |
| 11 | |
| 12 | struct acpi_ctx; |
| 13 | |
Simon Glass | 2357234 | 2020-07-07 13:11:57 -0600 | [diff] [blame] | 14 | #include <acpi/acpi_device.h> |
| 15 | |
Simon Glass | 0e5a0a0 | 2020-07-07 13:11:56 -0600 | [diff] [blame] | 16 | /* |
| 17 | * Writing Device Properties objects via _DSD |
| 18 | * |
| 19 | * This is described in ACPI 6.3 section 6.2.5 |
| 20 | * |
| 21 | * This provides a structure to handle nested device-specific data which ends |
| 22 | * up in a _DSD table. |
| 23 | * |
| 24 | * https://www.kernel.org/doc/html/latest/firmware-guide/acpi/DSD-properties-rules.html |
| 25 | * https://uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf |
| 26 | * https://uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf |
| 27 | * |
| 28 | * The Device Property Hierarchy can be multiple levels deep with multiple |
| 29 | * children possible in each level. In order to support this flexibility |
| 30 | * the device property hierarchy must be built up before being written out. |
| 31 | * |
| 32 | * For example: |
| 33 | * |
| 34 | * Child table with string and integer: |
| 35 | * struct acpi_dp *child = acpi_dp_new_table("CHLD"); |
| 36 | * acpi_dp_add_string(child, "childstring", "CHILD"); |
| 37 | * acpi_dp_add_integer(child, "childint", 100); |
| 38 | * |
| 39 | * _DSD table with integer and gpio and child pointer: |
| 40 | * struct acpi_dp *dsd = acpi_dp_new_table("_DSD"); |
| 41 | * acpi_dp_add_integer(dsd, "number1", 1); |
| 42 | * acpi_dp_add_gpio(dsd, "gpio", "\_SB.PCI0.GPIO", 0, 0, 1); |
| 43 | * acpi_dp_add_child(dsd, "child", child); |
| 44 | * |
| 45 | * Write entries into SSDT and clean up resources: |
| 46 | * acpi_dp_write(dsd); |
| 47 | * |
| 48 | * Name(_DSD, Package() { |
| 49 | * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301") |
| 50 | * Package() { |
| 51 | * Package() { "gpio", Package() { \_SB.PCI0.GPIO, 0, 0, 0 } } |
| 52 | * Package() { "number1", 1 } |
| 53 | * } |
| 54 | * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b") |
| 55 | * Package() { |
| 56 | * Package() { "child", CHLD } |
| 57 | * } |
| 58 | * } |
| 59 | * Name(CHLD, Package() { |
| 60 | * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301") |
| 61 | * Package() { |
| 62 | * Package() { "childstring", "CHILD" } |
| 63 | * Package() { "childint", 100 } |
| 64 | * } |
| 65 | * } |
| 66 | */ |
| 67 | |
| 68 | #define ACPI_DP_UUID "daffd814-6eba-4d8c-8a91-bc9bbf4aa301" |
| 69 | #define ACPI_DP_CHILD_UUID "dbb8e3e6-5886-4ba6-8795-1319f52a966b" |
| 70 | |
| 71 | /** |
| 72 | * enum acpi_dp_type - types of device property objects |
| 73 | * |
| 74 | * These refer to the types defined by struct acpi_dp below |
| 75 | * |
| 76 | * @ACPI_DP_TYPE_UNKNOWN: Unknown / do not use |
| 77 | * @ACPI_DP_TYPE_INTEGER: Integer value (u64) in @integer |
| 78 | * @ACPI_DP_TYPE_STRING: String value in @string |
| 79 | * @ACPI_DP_TYPE_REFERENCE: Reference to another object, with value in @string |
| 80 | * @ACPI_DP_TYPE_TABLE: Type for a top-level table which may have children |
| 81 | * @ACPI_DP_TYPE_ARRAY: Array of items with first item in @array and following |
| 82 | * items linked from that item's @next |
| 83 | * @ACPI_DP_TYPE_CHILD: Child object, with siblings in that child's @next |
| 84 | */ |
| 85 | enum acpi_dp_type { |
| 86 | ACPI_DP_TYPE_UNKNOWN, |
| 87 | ACPI_DP_TYPE_INTEGER, |
| 88 | ACPI_DP_TYPE_STRING, |
| 89 | ACPI_DP_TYPE_REFERENCE, |
| 90 | ACPI_DP_TYPE_TABLE, |
| 91 | ACPI_DP_TYPE_ARRAY, |
| 92 | ACPI_DP_TYPE_CHILD, |
| 93 | }; |
| 94 | |
| 95 | /** |
| 96 | * struct acpi_dp - ACPI device properties |
| 97 | * |
| 98 | * @type: Table type |
| 99 | * @name: Name of object, typically _DSD but could be CHLD for a child object. |
| 100 | * This can be NULL if there is no name |
| 101 | * @next: Next object in list (next array element or next sibling) |
| 102 | * @child: Pointer to first child, if @type == ACPI_DP_TYPE_CHILD, else NULL |
| 103 | * @array: First array element, if @type == ACPI_DP_TYPE_ARRAY, else NULL |
| 104 | * @integer: Integer value of the property, if @type == ACPI_DP_TYPE_INTEGER |
| 105 | * @string: String value of the property, if @type == ACPI_DP_TYPE_STRING; |
| 106 | * child name if @type == ACPI_DP_TYPE_CHILD; |
| 107 | * reference name if @type == ACPI_DP_TYPE_REFERENCE; |
| 108 | */ |
| 109 | struct acpi_dp { |
| 110 | enum acpi_dp_type type; |
| 111 | const char *name; |
| 112 | struct acpi_dp *next; |
| 113 | union { |
| 114 | struct acpi_dp *child; |
| 115 | struct acpi_dp *array; |
| 116 | }; |
| 117 | union { |
| 118 | u64 integer; |
| 119 | const char *string; |
| 120 | }; |
| 121 | }; |
| 122 | |
| 123 | /** |
| 124 | * acpi_dp_new_table() - Start a new Device Property table |
| 125 | * |
| 126 | * @ref: ACPI reference (e.g. "_DSD") |
| 127 | * @return pointer to table, or NULL if out of memory |
| 128 | */ |
| 129 | struct acpi_dp *acpi_dp_new_table(const char *ref); |
| 130 | |
| 131 | /** |
| 132 | * acpi_dp_add_integer() - Add integer Device Property |
| 133 | * |
| 134 | * A new node is added to the end of the property list of @dp |
| 135 | * |
| 136 | * @dp: Table to add this property to |
| 137 | * @name: Name of property, or NULL for none |
| 138 | * @value: Integer value |
| 139 | * @return pointer to new node, or NULL if out of memory |
| 140 | */ |
| 141 | struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name, |
| 142 | u64 value); |
| 143 | |
| 144 | /** |
| 145 | * acpi_dp_add_string() - Add string Device Property |
| 146 | * |
| 147 | * A new node is added to the end of the property list of @dp |
| 148 | * |
| 149 | * @dp: Table to add this property to |
| 150 | * @name: Name of property, or NULL for none |
| 151 | * @string: String value |
| 152 | * @return pointer to new node, or NULL if out of memory |
| 153 | */ |
| 154 | struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name, |
| 155 | const char *string); |
| 156 | |
| 157 | /** |
| 158 | * acpi_dp_add_reference() - Add reference Device Property |
| 159 | * |
| 160 | * A new node is added to the end of the property list of @dp |
| 161 | * |
| 162 | * @dp: Table to add this property to |
| 163 | * @name: Name of property, or NULL for none |
| 164 | * @reference: Reference value |
| 165 | * @return pointer to new node, or NULL if out of memory |
| 166 | */ |
| 167 | struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name, |
| 168 | const char *reference); |
| 169 | |
| 170 | /** |
| 171 | * acpi_dp_add_array() - Add array Device Property |
| 172 | * |
| 173 | * A new node is added to the end of the property list of @dp, with the array |
| 174 | * attached to that. |
| 175 | * |
| 176 | * @dp: Table to add this property to |
| 177 | * @name: Name of property, or NULL for none |
| 178 | * @return pointer to new node, or NULL if out of memory |
| 179 | */ |
| 180 | struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array); |
| 181 | |
| 182 | /** |
| 183 | * acpi_dp_add_integer_array() - Add an array of integers |
| 184 | * |
| 185 | * A new node is added to the end of the property list of @dp, with the array |
| 186 | * attached to that. Each element of the array becomes a new node. |
| 187 | * |
| 188 | * @dp: Table to add this property to |
| 189 | * @name: Name of property, or NULL for none |
| 190 | * @return pointer to new array node, or NULL if out of memory |
| 191 | */ |
| 192 | struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name, |
| 193 | u64 *array, int len); |
| 194 | |
| 195 | /** |
| 196 | * acpi_dp_add_child() - Add a child table of Device Properties |
| 197 | * |
| 198 | * A new node is added as a child of @dp |
| 199 | * |
| 200 | * @dp: Table to add this child to |
| 201 | * @name: Name of child, or NULL for none |
| 202 | * @child: Child node to add |
| 203 | * @return pointer to new child node, or NULL if out of memory |
| 204 | */ |
| 205 | struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name, |
| 206 | struct acpi_dp *child); |
| 207 | |
| 208 | /** |
Simon Glass | 2357234 | 2020-07-07 13:11:57 -0600 | [diff] [blame] | 209 | * acpi_dp_add_gpio() - Add a GPIO to a list of Device Properties |
| 210 | * |
| 211 | * A new node is added to the end of the property list of @dp, with the |
| 212 | * GPIO properties added to the the new node |
| 213 | * |
| 214 | * @dp: Table to add this property to |
| 215 | * @name: Name of property |
| 216 | * @ref: Reference to device with a _CRS containing GpioIO or GpioInt |
| 217 | * @index: Index of the GPIO resource in _CRS starting from zero |
| 218 | * @pin: Pin in the GPIO resource, typically zero |
| 219 | * @polarity: GPIO polarity. Note that ACPI_IRQ_ACTIVE_BOTH is not supported |
| 220 | * @return pointer to new node, or NULL if out of memory |
| 221 | */ |
| 222 | struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name, |
| 223 | const char *ref, int index, int pin, |
Simon Glass | 23dd0ea | 2020-09-22 12:44:59 -0600 | [diff] [blame] | 224 | enum acpi_gpio_polarity polarity); |
Simon Glass | 2357234 | 2020-07-07 13:11:57 -0600 | [diff] [blame] | 225 | |
| 226 | /** |
Simon Glass | 0e5a0a0 | 2020-07-07 13:11:56 -0600 | [diff] [blame] | 227 | * acpi_dp_write() - Write Device Property hierarchy and clean up resources |
| 228 | * |
| 229 | * This writes the table using acpigen and then frees it |
| 230 | * |
| 231 | * @ctx: ACPI context |
| 232 | * @table: Table to write |
| 233 | * @return 0 if OK, -ve on error |
| 234 | */ |
| 235 | int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table); |
| 236 | |
Simon Glass | 0667900 | 2020-07-07 13:11:58 -0600 | [diff] [blame] | 237 | /** |
| 238 | * acpi_dp_ofnode_copy_int() - Copy a property from device tree to DP |
| 239 | * |
| 240 | * This copies an integer property from the device tree to the ACPI DP table. |
| 241 | * |
| 242 | * @node: Node to copy from |
| 243 | * @dp: DP to copy to |
| 244 | * @prop: Property name to copy |
| 245 | * @return 0 if OK, -ve on error |
| 246 | */ |
| 247 | int acpi_dp_ofnode_copy_int(ofnode node, struct acpi_dp *dp, const char *prop); |
| 248 | |
| 249 | /** |
| 250 | * acpi_dp_ofnode_copy_str() - Copy a property from device tree to DP |
| 251 | * |
| 252 | * This copies a string property from the device tree to the ACPI DP table. |
| 253 | * |
| 254 | * @node: Node to copy from |
| 255 | * @dp: DP to copy to |
| 256 | * @prop: Property name to copy |
| 257 | * @return 0 if OK, -ve on error |
| 258 | */ |
| 259 | int acpi_dp_ofnode_copy_str(ofnode node, struct acpi_dp *dp, const char *prop); |
| 260 | |
| 261 | /** |
| 262 | * acpi_dp_dev_copy_int() - Copy a property from device tree to DP |
| 263 | * |
| 264 | * This copies an integer property from the device tree to the ACPI DP table. |
| 265 | * |
| 266 | * @dev: Device to copy from |
| 267 | * @dp: DP to copy to |
| 268 | * @prop: Property name to copy |
| 269 | * @return 0 if OK, -ve on error |
| 270 | */ |
| 271 | int acpi_dp_dev_copy_int(const struct udevice *dev, struct acpi_dp *dp, |
| 272 | const char *prop); |
| 273 | |
| 274 | /** |
| 275 | * acpi_dp_dev_copy_str() - Copy a property from device tree to DP |
| 276 | * |
| 277 | * This copies a string property from the device tree to the ACPI DP table. |
| 278 | * |
| 279 | * @dev: Device to copy from |
| 280 | * @dp: DP to copy to |
| 281 | * @prop: Property name to copy |
| 282 | * @return 0 if OK, -ve on error |
| 283 | */ |
| 284 | int acpi_dp_dev_copy_str(const struct udevice *dev, struct acpi_dp *dp, |
| 285 | const char *prop); |
| 286 | |
Simon Glass | 0e5a0a0 | 2020-07-07 13:11:56 -0600 | [diff] [blame] | 287 | #endif |