blob: 27d4eab7a60783d6b75d31ef42063ba085d6ecdc [file] [log] [blame]
Simon Glass61cc9332020-07-07 13:11:42 -06001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Generation of ACPI (Advanced Configuration and Power Interface) tables
4 *
5 * Copyright 2019 Google LLC
6 * Mostly taken from coreboot
7 */
8
9#define LOG_CATEGORY LOGC_ACPI
10
11#include <common.h>
12#include <dm.h>
Simon Glass7e148f22020-07-07 13:11:50 -060013#include <log.h>
Simon Glass61cc9332020-07-07 13:11:42 -060014#include <acpi/acpigen.h>
15#include <dm/acpi.h>
16
17u8 *acpigen_get_current(struct acpi_ctx *ctx)
18{
19 return ctx->current;
20}
21
22void acpigen_emit_byte(struct acpi_ctx *ctx, uint data)
23{
24 *(u8 *)ctx->current++ = data;
25}
26
27void acpigen_emit_word(struct acpi_ctx *ctx, uint data)
28{
29 acpigen_emit_byte(ctx, data & 0xff);
30 acpigen_emit_byte(ctx, (data >> 8) & 0xff);
31}
32
33void acpigen_emit_dword(struct acpi_ctx *ctx, uint data)
34{
35 /* Output the value in little-endian format */
36 acpigen_emit_byte(ctx, data & 0xff);
37 acpigen_emit_byte(ctx, (data >> 8) & 0xff);
38 acpigen_emit_byte(ctx, (data >> 16) & 0xff);
39 acpigen_emit_byte(ctx, (data >> 24) & 0xff);
40}
Simon Glass7fb8da42020-07-07 13:11:45 -060041
Simon Glass7e148f22020-07-07 13:11:50 -060042/*
43 * Maximum length for an ACPI object generated by this code,
44 *
45 * If you need to change this, change acpigen_write_len_f(ctx) and
46 * acpigen_pop_len(ctx)
47 */
48#define ACPIGEN_MAXLEN 0xfffff
49
50void acpigen_write_len_f(struct acpi_ctx *ctx)
51{
52 assert(ctx->ltop < (ACPIGEN_LENSTACK_SIZE - 1));
53 ctx->len_stack[ctx->ltop++] = ctx->current;
54 acpigen_emit_byte(ctx, 0);
55 acpigen_emit_byte(ctx, 0);
56 acpigen_emit_byte(ctx, 0);
57}
58
59void acpigen_pop_len(struct acpi_ctx *ctx)
60{
61 int len;
62 char *p;
63
64 assert(ctx->ltop > 0);
65 p = ctx->len_stack[--ctx->ltop];
66 len = ctx->current - (void *)p;
67 assert(len <= ACPIGEN_MAXLEN);
68 /* generate store length for 0xfffff max */
69 p[0] = ACPI_PKG_LEN_3_BYTES | (len & 0xf);
70 p[1] = len >> 4 & 0xff;
71 p[2] = len >> 12 & 0xff;
72}
73
Simon Glass03967ce2020-07-07 13:11:51 -060074char *acpigen_write_package(struct acpi_ctx *ctx, int nr_el)
75{
76 char *p;
77
78 acpigen_emit_byte(ctx, PACKAGE_OP);
79 acpigen_write_len_f(ctx);
80 p = ctx->current;
81 acpigen_emit_byte(ctx, nr_el);
82
83 return p;
84}
85
Simon Glass83b2bd52020-07-07 13:11:52 -060086void acpigen_write_byte(struct acpi_ctx *ctx, unsigned int data)
87{
88 acpigen_emit_byte(ctx, BYTE_PREFIX);
89 acpigen_emit_byte(ctx, data & 0xff);
90}
91
92void acpigen_write_word(struct acpi_ctx *ctx, unsigned int data)
93{
94 acpigen_emit_byte(ctx, WORD_PREFIX);
95 acpigen_emit_word(ctx, data);
96}
97
98void acpigen_write_dword(struct acpi_ctx *ctx, unsigned int data)
99{
100 acpigen_emit_byte(ctx, DWORD_PREFIX);
101 acpigen_emit_dword(ctx, data);
102}
103
104void acpigen_write_qword(struct acpi_ctx *ctx, u64 data)
105{
106 acpigen_emit_byte(ctx, QWORD_PREFIX);
107 acpigen_emit_dword(ctx, data & 0xffffffff);
108 acpigen_emit_dword(ctx, (data >> 32) & 0xffffffff);
109}
110
111void acpigen_write_zero(struct acpi_ctx *ctx)
112{
113 acpigen_emit_byte(ctx, ZERO_OP);
114}
115
116void acpigen_write_one(struct acpi_ctx *ctx)
117{
118 acpigen_emit_byte(ctx, ONE_OP);
119}
120
121void acpigen_write_integer(struct acpi_ctx *ctx, u64 data)
122{
123 if (data == 0)
124 acpigen_write_zero(ctx);
125 else if (data == 1)
126 acpigen_write_one(ctx);
127 else if (data <= 0xff)
128 acpigen_write_byte(ctx, (unsigned char)data);
129 else if (data <= 0xffff)
130 acpigen_write_word(ctx, (unsigned int)data);
131 else if (data <= 0xffffffff)
132 acpigen_write_dword(ctx, (unsigned int)data);
133 else
134 acpigen_write_qword(ctx, data);
135}
136
Simon Glass7fb8da42020-07-07 13:11:45 -0600137void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size)
138{
139 int i;
140
141 for (i = 0; i < size; i++)
142 acpigen_emit_byte(ctx, data[i]);
143}
144
145void acpigen_emit_string(struct acpi_ctx *ctx, const char *str)
146{
147 acpigen_emit_stream(ctx, str, str ? strlen(str) : 0);
148 acpigen_emit_byte(ctx, '\0');
149}