uboot/lib/acpi/acpi_dp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Generation of tables for particular device types
   4 *
   5 * Copyright 2019 Google LLC
   6 * Mostly taken from coreboot file acpi_device.c
   7 */
   8
   9#include <common.h>
  10#include <dm.h>
  11#include <log.h>
  12#include <malloc.h>
  13#include <uuid.h>
  14#include <acpi/acpigen.h>
  15#include <acpi/acpi_dp.h>
  16#include <dm/acpi.h>
  17
  18static void acpi_dp_write_array(struct acpi_ctx *ctx,
  19                                const struct acpi_dp *array);
  20
  21static void acpi_dp_write_value(struct acpi_ctx *ctx,
  22                                const struct acpi_dp *prop)
  23{
  24        switch (prop->type) {
  25        case ACPI_DP_TYPE_INTEGER:
  26                acpigen_write_integer(ctx, prop->integer);
  27                break;
  28        case ACPI_DP_TYPE_STRING:
  29        case ACPI_DP_TYPE_CHILD:
  30                acpigen_write_string(ctx, prop->string);
  31                break;
  32        case ACPI_DP_TYPE_REFERENCE:
  33                acpigen_emit_namestring(ctx, prop->string);
  34                break;
  35        case ACPI_DP_TYPE_ARRAY:
  36                acpi_dp_write_array(ctx, prop->array);
  37                break;
  38        default:
  39                break;
  40        }
  41}
  42
  43/* Package (2) { "prop->name", VALUE } */
  44static void acpi_dp_write_property(struct acpi_ctx *ctx,
  45                                   const struct acpi_dp *prop)
  46{
  47        acpigen_write_package(ctx, 2);
  48        acpigen_write_string(ctx, prop->name);
  49        acpi_dp_write_value(ctx, prop);
  50        acpigen_pop_len(ctx);
  51}
  52
  53/* Write array of Device Properties */
  54static void acpi_dp_write_array(struct acpi_ctx *ctx,
  55                                const struct acpi_dp *array)
  56{
  57        const struct acpi_dp *dp;
  58        char *pkg_count;
  59
  60        /* Package element count determined as it is populated */
  61        pkg_count = acpigen_write_package(ctx, 0);
  62
  63        /*
  64         * Only acpi_dp of type DP_TYPE_TABLE is allowed to be an array.
  65         * DP_TYPE_TABLE does not have a value to be written. Thus, start
  66         * the loop from next type in the array.
  67         */
  68        for (dp = array->next; dp; dp = dp->next) {
  69                acpi_dp_write_value(ctx, dp);
  70                (*pkg_count)++;
  71        }
  72
  73        acpigen_pop_len(ctx);
  74}
  75
  76static void acpi_dp_free(struct acpi_dp *dp)
  77{
  78        assert(dp);
  79        while (dp) {
  80                struct acpi_dp *p = dp->next;
  81
  82                switch (dp->type) {
  83                case ACPI_DP_TYPE_CHILD:
  84                        acpi_dp_free(dp->child);
  85                        break;
  86                case ACPI_DP_TYPE_ARRAY:
  87                        acpi_dp_free(dp->array);
  88                        break;
  89                default:
  90                        break;
  91                }
  92
  93                free(dp);
  94                dp = p;
  95        }
  96}
  97
  98static int acpi_dp_write_internal(struct acpi_ctx *ctx, struct acpi_dp *table)
  99{
 100        struct acpi_dp *dp, *prop;
 101        char *dp_count, *prop_count = NULL;
 102        int child_count = 0;
 103        int ret;
 104
 105        assert(table);
 106        if (table->type != ACPI_DP_TYPE_TABLE)
 107                return 0;
 108
 109        /* Name (name) */
 110        acpigen_write_name(ctx, table->name);
 111
 112        /* Device Property list starts with the next entry */
 113        prop = table->next;
 114
 115        /* Package (DP), default to assuming no properties or children */
 116        dp_count = acpigen_write_package(ctx, 0);
 117
 118        /* Print base properties */
 119        for (dp = prop; dp; dp = dp->next) {
 120                if (dp->type == ACPI_DP_TYPE_CHILD) {
 121                        child_count++;
 122                } else {
 123                        /*
 124                         * The UUID and package is only added when
 125                         * we come across the first property.  This
 126                         * is to avoid creating a zero-length package
 127                         * in situations where there are only children.
 128                         */
 129                        if (!prop_count) {
 130                                *dp_count += 2;
 131                                /* ToUUID (ACPI_DP_UUID) */
 132                                ret = acpigen_write_uuid(ctx, ACPI_DP_UUID);
 133                                if (ret)
 134                                        return log_msg_ret("touuid", ret);
 135                                /*
 136                                 * Package (PROP), element count determined as
 137                                 * it is populated
 138                                 */
 139                                prop_count = acpigen_write_package(ctx, 0);
 140                        }
 141                        (*prop_count)++;
 142                        acpi_dp_write_property(ctx, dp);
 143                }
 144        }
 145
 146        if (prop_count) {
 147                /* Package (PROP) length, if a package was written */
 148                acpigen_pop_len(ctx);
 149        }
 150
 151        if (child_count) {
 152                /* Update DP package count to 2 or 4 */
 153                *dp_count += 2;
 154                /* ToUUID (ACPI_DP_CHILD_UUID) */
 155                ret = acpigen_write_uuid(ctx, ACPI_DP_CHILD_UUID);
 156                if (ret)
 157                        return log_msg_ret("child uuid", ret);
 158
 159                /* Print child pointer properties */
 160                acpigen_write_package(ctx, child_count);
 161
 162                for (dp = prop; dp; dp = dp->next)
 163                        if (dp->type == ACPI_DP_TYPE_CHILD)
 164                                acpi_dp_write_property(ctx, dp);
 165                /* Package (CHILD) length */
 166                acpigen_pop_len(ctx);
 167        }
 168
 169        /* Package (DP) length */
 170        acpigen_pop_len(ctx);
 171
 172        /* Recursively parse children into separate tables */
 173        for (dp = prop; dp; dp = dp->next) {
 174                if (dp->type == ACPI_DP_TYPE_CHILD) {
 175                        ret = acpi_dp_write_internal(ctx, dp->child);
 176                        if (ret)
 177                                return log_msg_ret("dp child", ret);
 178                }
 179        }
 180
 181        return 0;
 182}
 183
 184int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table)
 185{
 186        int ret;
 187
 188        ret = acpi_dp_write_internal(ctx, table);
 189
 190        /* Clean up */
 191        acpi_dp_free(table);
 192
 193        if (ret)
 194                return log_msg_ret("write", ret);
 195
 196        return 0;
 197}
 198
 199static struct acpi_dp *acpi_dp_new(struct acpi_dp *dp, enum acpi_dp_type type,
 200                                   const char *name)
 201{
 202        struct acpi_dp *new;
 203
 204        new = malloc(sizeof(struct acpi_dp));
 205        if (!new)
 206                return NULL;
 207
 208        memset(new, '\0', sizeof(*new));
 209        new->type = type;
 210        new->name = name;
 211
 212        if (dp) {
 213                /* Add to end of property list */
 214                while (dp->next)
 215                        dp = dp->next;
 216                dp->next = new;
 217        }
 218
 219        return new;
 220}
 221
 222struct acpi_dp *acpi_dp_new_table(const char *name)
 223{
 224        return acpi_dp_new(NULL, ACPI_DP_TYPE_TABLE, name);
 225}
 226
 227struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
 228                                    u64 value)
 229{
 230        struct acpi_dp *new;
 231
 232        assert(dp);
 233        new = acpi_dp_new(dp, ACPI_DP_TYPE_INTEGER, name);
 234
 235        if (new)
 236                new->integer = value;
 237
 238        return new;
 239}
 240
 241struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
 242                                   const char *string)
 243{
 244        struct acpi_dp *new;
 245
 246        assert(dp);
 247        new = acpi_dp_new(dp, ACPI_DP_TYPE_STRING, name);
 248        if (new)
 249                new->string = string;
 250
 251        return new;
 252}
 253
 254struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
 255                                      const char *reference)
 256{
 257        struct acpi_dp *new;
 258
 259        assert(dp);
 260        new = acpi_dp_new(dp, ACPI_DP_TYPE_REFERENCE, name);
 261        if (new)
 262                new->string = reference;
 263
 264        return new;
 265}
 266
 267struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
 268                                  struct acpi_dp *child)
 269{
 270        struct acpi_dp *new;
 271
 272        assert(dp);
 273        if (child->type != ACPI_DP_TYPE_TABLE)
 274                return NULL;
 275
 276        new = acpi_dp_new(dp, ACPI_DP_TYPE_CHILD, name);
 277        if (new) {
 278                new->child = child;
 279                new->string = child->name;
 280        }
 281
 282        return new;
 283}
 284
 285struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array)
 286{
 287        struct acpi_dp *new;
 288
 289        assert(dp);
 290        assert(array);
 291        if (array->type != ACPI_DP_TYPE_TABLE)
 292                return NULL;
 293
 294        new = acpi_dp_new(dp, ACPI_DP_TYPE_ARRAY, array->name);
 295        if (new)
 296                new->array = array;
 297
 298        return new;
 299}
 300
 301struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
 302                                          u64 *array, int len)
 303{
 304        struct acpi_dp *dp_array;
 305        int i;
 306
 307        assert(dp);
 308        if (len <= 0)
 309                return NULL;
 310
 311        dp_array = acpi_dp_new_table(name);
 312        if (!dp_array)
 313                return NULL;
 314
 315        for (i = 0; i < len; i++)
 316                if (!acpi_dp_add_integer(dp_array, NULL, array[i]))
 317                        break;
 318
 319        if (!acpi_dp_add_array(dp, dp_array))
 320                return NULL;
 321
 322        return dp_array;
 323}
 324
 325struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
 326                                 const char *ref, int index, int pin,
 327                                 enum acpi_gpio_polarity polarity)
 328{
 329        struct acpi_dp *gpio;
 330
 331        assert(dp);
 332        gpio = acpi_dp_new_table(name);
 333        if (!gpio)
 334                return NULL;
 335
 336        if (!acpi_dp_add_reference(gpio, NULL, ref) ||
 337            !acpi_dp_add_integer(gpio, NULL, index) ||
 338            !acpi_dp_add_integer(gpio, NULL, pin) ||
 339            !acpi_dp_add_integer(gpio, NULL, polarity == ACPI_GPIO_ACTIVE_LOW))
 340                return NULL;
 341
 342        if (!acpi_dp_add_array(dp, gpio))
 343                return NULL;
 344
 345        return gpio;
 346}
 347
 348int acpi_dp_ofnode_copy_int(ofnode node, struct acpi_dp *dp, const char *prop)
 349{
 350        int ret;
 351        u32 val = 0;
 352
 353        ret = ofnode_read_u32(node, prop, &val);
 354        if (ret)
 355                return ret;
 356        if (!acpi_dp_add_integer(dp, prop, val))
 357                return log_ret(-ENOMEM);
 358
 359        return 0;
 360}
 361
 362int acpi_dp_ofnode_copy_str(ofnode node, struct acpi_dp *dp, const char *prop)
 363{
 364        const char *val;
 365
 366        val = ofnode_read_string(node, prop);
 367        if (!val)
 368                return -EINVAL;
 369        if (!acpi_dp_add_string(dp, prop, val))
 370                return log_ret(-ENOMEM);
 371
 372        return 0;
 373}
 374
 375int acpi_dp_dev_copy_int(const struct udevice *dev, struct acpi_dp *dp,
 376                         const char *prop)
 377{
 378        int ret;
 379        u32 val = 0;
 380
 381        ret = dev_read_u32(dev, prop, &val);
 382        if (ret)
 383                return ret;
 384        if (!acpi_dp_add_integer(dp, prop, val))
 385                return log_ret(-ENOMEM);
 386
 387        return ret;
 388}
 389
 390int acpi_dp_dev_copy_str(const struct udevice *dev, struct acpi_dp *dp,
 391                         const char *prop)
 392{
 393        const char *val;
 394
 395        val = dev_read_string(dev, prop);
 396        if (!val)
 397                return -EINVAL;
 398        if (!acpi_dp_add_string(dp, prop, val))
 399                return log_ret(-ENOMEM);
 400
 401        return 0;
 402}
 403