blob: df3d7ba417dd6550a588356b68cbd08821c69ada [file] [log] [blame]
Simon Glass9fb9e9b2020-04-09 10:27:38 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Core driver model support for ACPI table generation
4 *
5 * Copyright 2019 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
9#define LOG_CATEOGRY LOGC_ACPI
10
11#include <common.h>
Simon Glassee61e602020-07-07 13:12:05 -060012#include <malloc.h>
Simon Glass9fb9e9b2020-04-09 10:27:38 -060013#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Simon Glass9fb9e9b2020-04-09 10:27:38 -060015#include <dm/acpi.h>
Simon Glass17968c32020-04-26 09:19:46 -060016#include <dm/device-internal.h>
Simon Glass9fb9e9b2020-04-09 10:27:38 -060017#include <dm/root.h>
18
Simon Glassee61e602020-07-07 13:12:05 -060019#define MAX_ACPI_ITEMS 100
20
21/* Type of table that we collected */
22enum gen_type_t {
23 TYPE_NONE,
24 TYPE_SSDT,
25};
26
Simon Glass17968c32020-04-26 09:19:46 -060027/* Type of method to call */
28enum method_t {
29 METHOD_WRITE_TABLES,
Simon Glassd43e0ba2020-07-07 13:12:03 -060030 METHOD_FILL_SSDT,
Simon Glass17968c32020-04-26 09:19:46 -060031};
32
33/* Prototype for all methods */
34typedef int (*acpi_method)(const struct udevice *dev, struct acpi_ctx *ctx);
35
Simon Glassee61e602020-07-07 13:12:05 -060036/**
37 * struct acpi_item - Holds info about ACPI data generated by a driver method
38 *
39 * @dev: Device that generated this data
40 * @type: Table type it refers to
41 * @buf: Buffer containing the data
42 * @size: Size of the data in bytes
43 */
44struct acpi_item {
45 struct udevice *dev;
46 enum gen_type_t type;
47 char *buf;
48 int size;
49};
50
51/* List of ACPI items collected */
52static struct acpi_item acpi_item[MAX_ACPI_ITEMS];
53static int item_count;
54
Simon Glass9fb9e9b2020-04-09 10:27:38 -060055int acpi_copy_name(char *out_name, const char *name)
56{
57 strncpy(out_name, name, ACPI_NAME_LEN);
58 out_name[ACPI_NAME_LEN] = '\0';
59
60 return 0;
61}
62
63int acpi_get_name(const struct udevice *dev, char *out_name)
64{
65 struct acpi_ops *aops;
66
67 aops = device_get_acpi_ops(dev);
68 if (aops && aops->get_name)
69 return aops->get_name(dev, out_name);
70
71 return -ENOSYS;
72}
Simon Glass17968c32020-04-26 09:19:46 -060073
Simon Glassee61e602020-07-07 13:12:05 -060074/**
75 * acpi_add_item() - Add a new item to the list of data collected
76 *
77 * @ctx: ACPI context
78 * @dev: Device that generated the data
79 * @type: Table type it refers to
80 * @start: The start of the data (the end is obtained from ctx->current)
81 * @return 0 if OK, -ENOSPC if too many items, -ENOMEM if out of memory
82 */
83static int acpi_add_item(struct acpi_ctx *ctx, struct udevice *dev,
84 enum gen_type_t type, void *start)
85{
86 struct acpi_item *item;
87 void *end = ctx->current;
88
89 if (item_count == MAX_ACPI_ITEMS) {
90 log_err("Too many items\n");
91 return log_msg_ret("mem", -ENOSPC);
92 }
93
94 item = &acpi_item[item_count];
95 item->dev = dev;
96 item->type = type;
97 item->size = end - start;
98 if (!item->size)
99 return 0;
100 item->buf = malloc(item->size);
101 if (!item->buf)
102 return log_msg_ret("mem", -ENOMEM);
103 memcpy(item->buf, start, item->size);
104 item_count++;
105 log_debug("* %s: Added type %d, %p, size %x\n", dev->name, type, start,
106 item->size);
107
108 return 0;
109}
110
Simon Glass17968c32020-04-26 09:19:46 -0600111acpi_method acpi_get_method(struct udevice *dev, enum method_t method)
112{
113 struct acpi_ops *aops;
114
115 aops = device_get_acpi_ops(dev);
116 if (aops) {
117 switch (method) {
118 case METHOD_WRITE_TABLES:
119 return aops->write_tables;
Simon Glassd43e0ba2020-07-07 13:12:03 -0600120 case METHOD_FILL_SSDT:
121 return aops->fill_ssdt;
Simon Glass17968c32020-04-26 09:19:46 -0600122 }
123 }
124
125 return NULL;
126}
127
128int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent,
Simon Glassee61e602020-07-07 13:12:05 -0600129 enum method_t method, enum gen_type_t type)
Simon Glass17968c32020-04-26 09:19:46 -0600130{
131 struct udevice *dev;
132 acpi_method func;
133 int ret;
134
135 func = acpi_get_method(parent, method);
136 if (func) {
Simon Glassee61e602020-07-07 13:12:05 -0600137 void *start = ctx->current;
138
Simon Glass17968c32020-04-26 09:19:46 -0600139 log_debug("\n");
140 log_debug("- %s %p\n", parent->name, func);
141 ret = device_ofdata_to_platdata(parent);
142 if (ret)
143 return log_msg_ret("ofdata", ret);
144 ret = func(parent, ctx);
145 if (ret)
146 return log_msg_ret("func", ret);
Simon Glassee61e602020-07-07 13:12:05 -0600147
148 /* Add the item to the internal list */
149 if (type != TYPE_NONE) {
150 ret = acpi_add_item(ctx, parent, type, start);
151 if (ret)
152 return log_msg_ret("add", ret);
153 }
Simon Glass17968c32020-04-26 09:19:46 -0600154 }
155 device_foreach_child(dev, parent) {
Simon Glassee61e602020-07-07 13:12:05 -0600156 ret = acpi_recurse_method(ctx, dev, method, type);
Simon Glass17968c32020-04-26 09:19:46 -0600157 if (ret)
158 return log_msg_ret("recurse", ret);
159 }
160
161 return 0;
162}
163
Simon Glassd43e0ba2020-07-07 13:12:03 -0600164int acpi_fill_ssdt(struct acpi_ctx *ctx)
165{
166 int ret;
167
168 log_debug("Writing SSDT tables\n");
Simon Glassee61e602020-07-07 13:12:05 -0600169 ret = acpi_recurse_method(ctx, dm_root(), METHOD_FILL_SSDT, TYPE_SSDT);
Simon Glassd43e0ba2020-07-07 13:12:03 -0600170 log_debug("Writing SSDT finished, err=%d\n", ret);
171
172 return ret;
173}
174
Simon Glass17968c32020-04-26 09:19:46 -0600175int acpi_write_dev_tables(struct acpi_ctx *ctx)
176{
177 int ret;
178
179 log_debug("Writing device tables\n");
Simon Glassee61e602020-07-07 13:12:05 -0600180 ret = acpi_recurse_method(ctx, dm_root(), METHOD_WRITE_TABLES,
181 TYPE_NONE);
Simon Glass17968c32020-04-26 09:19:46 -0600182 log_debug("Writing finished, err=%d\n", ret);
183
184 return ret;
185}