blob: bbe1cfc57ad92c8744c670a294cb828d88d827d8 [file] [log] [blame]
Simon Glass1361a532020-07-07 13:11:39 -06001// 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 of the same name
7 */
8
9#include <common.h>
10#include <dm.h>
Simon Glassff715c62020-07-07 13:11:43 -060011#include <irq.h>
Simon Glass1361a532020-07-07 13:11:39 -060012#include <log.h>
13#include <acpi/acpi_device.h>
Simon Glassff715c62020-07-07 13:11:43 -060014#include <acpi/acpigen.h>
Simon Glassa9e0a072020-07-07 13:11:46 -060015#include <asm-generic/gpio.h>
Simon Glass1361a532020-07-07 13:11:39 -060016#include <dm/acpi.h>
17
18/**
19 * acpi_device_path_fill() - Find the root device and build a path from there
20 *
21 * This recursively reaches back to the root device and progressively adds path
22 * elements until the device is reached.
23 *
24 * @dev: Device to return path of
25 * @buf: Buffer to hold the path
26 * @buf_len: Length of buffer
27 * @cur: Current position in the buffer
28 * @return new position in buffer after adding @dev, or -ve on error
29 */
30static int acpi_device_path_fill(const struct udevice *dev, char *buf,
31 size_t buf_len, int cur)
32{
33 char name[ACPI_NAME_MAX];
34 int next = 0;
35 int ret;
36
37 ret = acpi_get_name(dev, name);
38 if (ret)
39 return ret;
40
41 /*
42 * Make sure this name segment will fit, including the path segment
43 * separator and possible NULL terminator, if this is the last segment.
44 */
45 if (cur + strlen(name) + 2 > buf_len)
46 return -ENOSPC;
47
48 /* Walk up the tree to the root device */
49 if (dev_get_parent(dev)) {
50 next = acpi_device_path_fill(dev_get_parent(dev), buf, buf_len,
51 cur);
52 if (next < 0)
53 return next;
54 }
55
56 /* Fill in the path from the root device */
57 next += snprintf(buf + next, buf_len - next, "%s%s",
58 dev_get_parent(dev) && *name ? "." : "", name);
59
60 return next;
61}
62
63int acpi_device_path(const struct udevice *dev, char *buf, int maxlen)
64{
65 int ret;
66
67 ret = acpi_device_path_fill(dev, buf, maxlen, 0);
68 if (ret < 0)
69 return ret;
70
71 return 0;
72}
73
74int acpi_device_scope(const struct udevice *dev, char *scope, int maxlen)
75{
76 int ret;
77
78 if (!dev_get_parent(dev))
79 return log_msg_ret("noparent", -EINVAL);
80
81 ret = acpi_device_path_fill(dev_get_parent(dev), scope, maxlen, 0);
82 if (ret < 0)
83 return log_msg_ret("fill", ret);
84
85 return 0;
86}
Simon Glass2715b362020-07-07 13:11:40 -060087
88enum acpi_dev_status acpi_device_status(const struct udevice *dev)
89{
90 return ACPI_DSTATUS_ALL_ON;
91}
Simon Glassff715c62020-07-07 13:11:43 -060092
93/**
94 * largeres_write_len_f() - Write a placeholder word value
95 *
96 * Write a forward length for a large resource (2 bytes)
97 *
98 * @return pointer to the zero word (for fixing up later)
99 */
100static void *largeres_write_len_f(struct acpi_ctx *ctx)
101{
102 u8 *p = acpigen_get_current(ctx);
103
104 acpigen_emit_word(ctx, 0);
105
106 return p;
107}
108
109/**
110 * largeres_fill_from_len() - Fill in a length value
111 *
112 * This calculated the number of bytes since the provided @start and writes it
113 * to @ptr, which was previous returned by largeres_write_len_f().
114 *
115 * @ptr: Word to update
116 * @start: Start address to count from to calculated the length
117 */
118static void largeres_fill_from_len(struct acpi_ctx *ctx, char *ptr, u8 *start)
119{
120 u16 len = acpigen_get_current(ctx) - start;
121
122 ptr[0] = len & 0xff;
123 ptr[1] = (len >> 8) & 0xff;
124}
125
126/**
127 * largeres_fill_len() - Fill in a length value, excluding the length itself
128 *
129 * Fill in the length field with the value calculated from after the 16bit
130 * field to acpigen current. This is useful since the length value does not
131 * include the length field itself.
132 *
133 * This calls acpi_device_largeres_fill_len() passing @ptr + 2 as @start
134 *
135 * @ptr: Word to update.
136 */
137static void largeres_fill_len(struct acpi_ctx *ctx, void *ptr)
138{
139 largeres_fill_from_len(ctx, ptr, ptr + sizeof(u16));
140}
141
142/* ACPI 6.3 section 6.4.3.6: Extended Interrupt Descriptor */
143static int acpi_device_write_interrupt(struct acpi_ctx *ctx,
144 const struct acpi_irq *irq)
145{
146 void *desc_length;
147 u8 flags;
148
149 if (!irq->pin)
150 return -ENOENT;
151
152 /* This is supported by GpioInt() but not Interrupt() */
153 if (irq->polarity == ACPI_IRQ_ACTIVE_BOTH)
154 return -EINVAL;
155
156 /* Byte 0: Descriptor Type */
157 acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_INTERRUPT);
158
159 /* Byte 1-2: Length (filled in later) */
160 desc_length = largeres_write_len_f(ctx);
161
162 /*
163 * Byte 3: Flags
164 * [7:5]: Reserved
165 * [4]: Wake (0=NO_WAKE 1=WAKE)
166 * [3]: Sharing (0=EXCLUSIVE 1=SHARED)
167 * [2]: Polarity (0=HIGH 1=LOW)
168 * [1]: Mode (0=LEVEL 1=EDGE)
169 * [0]: Resource (0=PRODUCER 1=CONSUMER)
170 */
171 flags = BIT(0); /* ResourceConsumer */
172 if (irq->mode == ACPI_IRQ_EDGE_TRIGGERED)
173 flags |= BIT(1);
174 if (irq->polarity == ACPI_IRQ_ACTIVE_LOW)
175 flags |= BIT(2);
176 if (irq->shared == ACPI_IRQ_SHARED)
177 flags |= BIT(3);
178 if (irq->wake == ACPI_IRQ_WAKE)
179 flags |= BIT(4);
180 acpigen_emit_byte(ctx, flags);
181
182 /* Byte 4: Interrupt Table Entry Count */
183 acpigen_emit_byte(ctx, 1);
184
185 /* Byte 5-8: Interrupt Number */
186 acpigen_emit_dword(ctx, irq->pin);
187
188 /* Fill in Descriptor Length (account for len word) */
189 largeres_fill_len(ctx, desc_length);
190
191 return 0;
192}
193
194int acpi_device_write_interrupt_irq(struct acpi_ctx *ctx,
195 const struct irq *req_irq)
196{
197 struct acpi_irq irq;
198 int ret;
199
200 ret = irq_get_acpi(req_irq, &irq);
201 if (ret)
202 return log_msg_ret("get", ret);
203 ret = acpi_device_write_interrupt(ctx, &irq);
204 if (ret)
205 return log_msg_ret("write", ret);
206
Simon Glassa9e0a072020-07-07 13:11:46 -0600207 return irq.pin;
208}
209
210/* ACPI 6.3 section 6.4.3.8.1 - GPIO Interrupt or I/O */
211int acpi_device_write_gpio(struct acpi_ctx *ctx, const struct acpi_gpio *gpio)
212{
213 void *start, *desc_length;
214 void *pin_table_offset, *vendor_data_offset, *resource_offset;
215 u16 flags = 0;
216 int pin;
217
218 if (gpio->type > ACPI_GPIO_TYPE_IO)
219 return -EINVAL;
220
221 start = acpigen_get_current(ctx);
222
223 /* Byte 0: Descriptor Type */
224 acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_GPIO);
225
226 /* Byte 1-2: Length (fill in later) */
227 desc_length = largeres_write_len_f(ctx);
228
229 /* Byte 3: Revision ID */
230 acpigen_emit_byte(ctx, ACPI_GPIO_REVISION_ID);
231
232 /* Byte 4: GpioIo or GpioInt */
233 acpigen_emit_byte(ctx, gpio->type);
234
235 /*
236 * Byte 5-6: General Flags
237 * [15:1]: 0 => Reserved
238 * [0]: 1 => ResourceConsumer
239 */
240 acpigen_emit_word(ctx, 1 << 0);
241
242 switch (gpio->type) {
243 case ACPI_GPIO_TYPE_INTERRUPT:
244 /*
245 * Byte 7-8: GPIO Interrupt Flags
246 * [15:5]: 0 => Reserved
247 * [4]: Wake (0=NO_WAKE 1=WAKE)
248 * [3]: Sharing (0=EXCLUSIVE 1=SHARED)
249 * [2:1]: Polarity (0=HIGH 1=LOW 2=BOTH)
250 * [0]: Mode (0=LEVEL 1=EDGE)
251 */
252 if (gpio->irq.mode == ACPI_IRQ_EDGE_TRIGGERED)
253 flags |= 1 << 0;
254 if (gpio->irq.shared == ACPI_IRQ_SHARED)
255 flags |= 1 << 3;
256 if (gpio->irq.wake == ACPI_IRQ_WAKE)
257 flags |= 1 << 4;
258
259 switch (gpio->irq.polarity) {
260 case ACPI_IRQ_ACTIVE_HIGH:
261 flags |= 0 << 1;
262 break;
263 case ACPI_IRQ_ACTIVE_LOW:
264 flags |= 1 << 1;
265 break;
266 case ACPI_IRQ_ACTIVE_BOTH:
267 flags |= 2 << 1;
268 break;
269 }
270 break;
271
272 case ACPI_GPIO_TYPE_IO:
273 /*
274 * Byte 7-8: GPIO IO Flags
275 * [15:4]: 0 => Reserved
276 * [3]: Sharing (0=EXCLUSIVE 1=SHARED)
277 * [2]: 0 => Reserved
278 * [1:0]: IO Restriction
279 * 0 => IoRestrictionNone
280 * 1 => IoRestrictionInputOnly
281 * 2 => IoRestrictionOutputOnly
282 * 3 => IoRestrictionNoneAndPreserve
283 */
284 flags |= gpio->io_restrict & 3;
285 if (gpio->io_shared)
286 flags |= 1 << 3;
287 break;
288 }
289 acpigen_emit_word(ctx, flags);
290
291 /*
292 * Byte 9: Pin Configuration
293 * 0x01 => Default (no configuration applied)
294 * 0x02 => Pull-up
295 * 0x03 => Pull-down
296 * 0x04-0x7F => Reserved
297 * 0x80-0xff => Vendor defined
298 */
299 acpigen_emit_byte(ctx, gpio->pull);
300
301 /* Byte 10-11: Output Drive Strength in 1/100 mA */
302 acpigen_emit_word(ctx, gpio->output_drive_strength);
303
304 /* Byte 12-13: Debounce Timeout in 1/100 ms */
305 acpigen_emit_word(ctx, gpio->interrupt_debounce_timeout);
306
307 /* Byte 14-15: Pin Table Offset, relative to start */
308 pin_table_offset = largeres_write_len_f(ctx);
309
310 /* Byte 16: Reserved */
311 acpigen_emit_byte(ctx, 0);
312
313 /* Byte 17-18: Resource Source Name Offset, relative to start */
314 resource_offset = largeres_write_len_f(ctx);
315
316 /* Byte 19-20: Vendor Data Offset, relative to start */
317 vendor_data_offset = largeres_write_len_f(ctx);
318
319 /* Byte 21-22: Vendor Data Length */
320 acpigen_emit_word(ctx, 0);
321
322 /* Fill in Pin Table Offset */
323 largeres_fill_from_len(ctx, pin_table_offset, start);
324
325 /* Pin Table, one word for each pin */
326 for (pin = 0; pin < gpio->pin_count; pin++)
327 acpigen_emit_word(ctx, gpio->pins[pin]);
328
329 /* Fill in Resource Source Name Offset */
330 largeres_fill_from_len(ctx, resource_offset, start);
331
332 /* Resource Source Name String */
333 acpigen_emit_string(ctx, gpio->resource);
334
335 /* Fill in Vendor Data Offset */
336 largeres_fill_from_len(ctx, vendor_data_offset, start);
337
338 /* Fill in GPIO Descriptor Length (account for len word) */
339 largeres_fill_len(ctx, desc_length);
340
341 return gpio->pins[0];
342}
343
344int acpi_device_write_gpio_desc(struct acpi_ctx *ctx,
345 const struct gpio_desc *desc)
346{
347 struct acpi_gpio gpio;
348 int ret;
349
350 ret = gpio_get_acpi(desc, &gpio);
351 if (ret)
352 return log_msg_ret("desc", ret);
353 ret = acpi_device_write_gpio(ctx, &gpio);
354 if (ret < 0)
355 return log_msg_ret("gpio", ret);
356
Simon Glassff715c62020-07-07 13:11:43 -0600357 return 0;
358}