1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2020 Google LLC
5 * Modified from coreboot nhlt.c
8 #define LOG_CATEGORY LOGC_ACPI
15 #include <tables_csum.h>
16 #include <acpi/acpi_table.h>
17 #include <asm/acpi_nhlt.h>
18 #include <asm/unaligned.h>
23 #define WAVEFORMAT_TAG 0xfffe
24 #define DEFAULT_VIRTUAL_BUS_ID 0
26 static const struct sub_format pcm_subformat
= {
30 .data4
= { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 },
33 struct nhlt
*nhlt_init(void)
37 nhlt
= malloc(sizeof(*nhlt
));
42 memset(nhlt
, 0, sizeof(*nhlt
));
43 nhlt
->subsystem_id
= NHLT_SSID
;
48 struct nhlt_endpoint
*nhlt_add_endpoint(struct nhlt
*nhlt
, int link_type
,
49 int device_type
, int dir
,
52 struct nhlt_endpoint
*endp
;
54 if (link_type
< NHLT_LINK_HDA
|| link_type
>= NHLT_MAX_LINK_TYPES
)
57 if (nhlt
->num_endpoints
>= MAX_ENDPOINTS
)
60 endp
= &nhlt
->endpoints
[nhlt
->num_endpoints
];
62 endp
->link_type
= link_type
;
63 endp
->instance_id
= nhlt
->current_instance_id
[link_type
];
64 endp
->vendor_id
= vid
;
65 endp
->device_id
= did
;
66 endp
->revision_id
= NHLT_RID
;
67 endp
->subsystem_id
= nhlt
->subsystem_id
;
68 endp
->device_type
= device_type
;
69 endp
->direction
= dir
;
70 endp
->virtual_bus_id
= DEFAULT_VIRTUAL_BUS_ID
;
71 endp
->num_formats
= 0;
73 nhlt
->num_endpoints
++;
78 static int append_specific_config(struct nhlt_specific_config
*spec_cfg
,
79 const void *config
, size_t config_sz
)
84 new_sz
= spec_cfg
->size
+ config_sz
;
85 new_cfg
= malloc(new_sz
);
89 /* Append new config */
90 memcpy(new_cfg
, spec_cfg
->capabilities
, spec_cfg
->size
);
91 memcpy(new_cfg
+ spec_cfg
->size
, config
, config_sz
);
93 free(spec_cfg
->capabilities
);
95 /* Update with new config data */
96 spec_cfg
->size
= new_sz
;
97 spec_cfg
->capabilities
= new_cfg
;
102 int nhlt_endpoint_append_config(struct nhlt_endpoint
*endp
, const void *config
,
105 return append_specific_config(&endp
->config
, config
, config_sz
);
108 struct nhlt_format
*nhlt_add_format(struct nhlt_endpoint
*endp
,
109 int num_channels
, int sample_freq_khz
,
110 int container_bits_per_sample
,
111 int valid_bits_per_sample
,
112 uint32_t speaker_mask
)
114 struct nhlt_format
*fmt
;
115 struct nhlt_waveform
*wave
;
117 if (endp
->num_formats
>= MAX_FORMATS
)
120 fmt
= &endp
->formats
[endp
->num_formats
];
121 wave
= &fmt
->waveform
;
123 wave
->tag
= WAVEFORMAT_TAG
;
124 wave
->num_channels
= num_channels
;
125 wave
->samples_per_second
= sample_freq_khz
* 1000;
126 wave
->bits_per_sample
= container_bits_per_sample
;
127 wave
->extra_size
= sizeof(wave
->valid_bits_per_sample
);
128 wave
->extra_size
+= sizeof(wave
->channel_mask
);
129 wave
->extra_size
+= sizeof(wave
->sub_format
);
130 wave
->valid_bits_per_sample
= valid_bits_per_sample
;
131 wave
->channel_mask
= speaker_mask
;
132 memcpy(&wave
->sub_format
, &pcm_subformat
, sizeof(wave
->sub_format
));
134 /* Calculate the dervied fields */
135 wave
->block_align
= wave
->num_channels
* wave
->bits_per_sample
/ 8;
136 wave
->bytes_per_second
= wave
->block_align
* wave
->samples_per_second
;
143 int nhlt_format_append_config(struct nhlt_format
*fmt
, const void *config
,
146 return append_specific_config(&fmt
->config
, config
, config_sz
);
149 int nhlt_endpoint_add_formats(struct nhlt_endpoint
*endp
,
150 const struct nhlt_format_config
*formats
,
156 node
= binman_section_find_node("private-files");
158 for (i
= 0; i
< num_formats
; i
++) {
159 const struct nhlt_format_config
*cfg
= &formats
[i
];
160 struct nhlt_format
*fmt
;
165 fmt
= nhlt_add_format(endp
, cfg
->num_channels
,
166 cfg
->sample_freq_khz
,
167 cfg
->container_bits_per_sample
,
168 cfg
->valid_bits_per_sample
,
173 if (!cfg
->settings_file
)
176 ret
= binman_entry_map(node
, cfg
->settings_file
, &data
, &size
);
178 log_warning("Failed to find settings file %s\n",
180 return log_msg_ret("settings", ret
);
183 ret
= nhlt_format_append_config(fmt
, data
, size
);
185 return log_msg_ret("append", ret
);
191 void nhlt_next_instance(struct nhlt
*nhlt
, int link_type
)
193 if (link_type
< NHLT_LINK_HDA
|| link_type
>= NHLT_MAX_LINK_TYPES
)
196 nhlt
->current_instance_id
[link_type
]++;
199 static size_t calc_specific_config_size(struct nhlt_specific_config
*cfg
)
201 return sizeof(cfg
->size
) + cfg
->size
;
204 static size_t calc_format_size(struct nhlt_format
*fmt
)
208 /* Wave format first */
209 sz
+= sizeof(fmt
->waveform
.tag
);
210 sz
+= sizeof(fmt
->waveform
.num_channels
);
211 sz
+= sizeof(fmt
->waveform
.samples_per_second
);
212 sz
+= sizeof(fmt
->waveform
.bytes_per_second
);
213 sz
+= sizeof(fmt
->waveform
.block_align
);
214 sz
+= sizeof(fmt
->waveform
.bits_per_sample
);
215 sz
+= sizeof(fmt
->waveform
.extra_size
);
216 sz
+= sizeof(fmt
->waveform
.valid_bits_per_sample
);
217 sz
+= sizeof(fmt
->waveform
.channel_mask
);
218 sz
+= sizeof(fmt
->waveform
.sub_format
);
220 sz
+= calc_specific_config_size(&fmt
->config
);
225 static size_t calc_endpoint_size(struct nhlt_endpoint
*endp
)
230 sz
+= sizeof(endp
->length
) + sizeof(endp
->link_type
);
231 sz
+= sizeof(endp
->instance_id
) + sizeof(endp
->vendor_id
);
232 sz
+= sizeof(endp
->device_id
) + sizeof(endp
->revision_id
);
233 sz
+= sizeof(endp
->subsystem_id
) + sizeof(endp
->device_type
);
234 sz
+= sizeof(endp
->direction
) + sizeof(endp
->virtual_bus_id
);
235 sz
+= calc_specific_config_size(&endp
->config
);
236 sz
+= sizeof(endp
->num_formats
);
238 for (i
= 0; i
< endp
->num_formats
; i
++)
239 sz
+= calc_format_size(&endp
->formats
[i
]);
241 /* Adjust endpoint length to reflect current configuration */
247 static size_t calc_endpoints_size(struct nhlt
*nhlt
)
252 for (i
= 0; i
< nhlt
->num_endpoints
; i
++)
253 sz
+= calc_endpoint_size(&nhlt
->endpoints
[i
]);
258 static size_t calc_size(struct nhlt
*nhlt
)
260 return sizeof(nhlt
->num_endpoints
) + calc_endpoints_size(nhlt
);
263 size_t nhlt_current_size(struct nhlt
*nhlt
)
265 return calc_size(nhlt
) + sizeof(struct acpi_table_header
);
268 static void nhlt_free_resources(struct nhlt
*nhlt
)
272 /* Free all specific configs */
273 for (i
= 0; i
< nhlt
->num_endpoints
; i
++) {
274 struct nhlt_endpoint
*endp
= &nhlt
->endpoints
[i
];
276 free(endp
->config
.capabilities
);
277 for (j
= 0; j
< endp
->num_formats
; j
++) {
278 struct nhlt_format
*fmt
= &endp
->formats
[j
];
280 free(fmt
->config
.capabilities
);
284 /* Free nhlt object proper */
293 static void ser8(struct cursor
*cur
, uint val
)
296 cur
->buf
+= sizeof(u8
);
299 static void ser16(struct cursor
*cur
, uint val
)
301 put_unaligned_le16(val
, cur
->buf
);
302 cur
->buf
+= sizeof(u16
);
305 static void ser32(struct cursor
*cur
, uint val
)
307 put_unaligned_le32(val
, cur
->buf
);
308 cur
->buf
+= sizeof(u32
);
311 static void serblob(struct cursor
*cur
, void *from
, size_t sz
)
313 memcpy(cur
->buf
, from
, sz
);
317 static void serialise_specific_config(struct nhlt_specific_config
*cfg
,
320 log_debug("%zx\n", cur
->buf
- cur
->start
);
321 ser32(cur
, cfg
->size
);
322 serblob(cur
, cfg
->capabilities
, cfg
->size
);
325 static void serialise_waveform(struct nhlt_waveform
*wave
, struct cursor
*cur
)
327 log_debug("%zx\n", cur
->buf
- cur
->start
);
328 ser16(cur
, wave
->tag
);
329 ser16(cur
, wave
->num_channels
);
330 ser32(cur
, wave
->samples_per_second
);
331 ser32(cur
, wave
->bytes_per_second
);
332 ser16(cur
, wave
->block_align
);
333 ser16(cur
, wave
->bits_per_sample
);
334 ser16(cur
, wave
->extra_size
);
335 ser16(cur
, wave
->valid_bits_per_sample
);
336 ser32(cur
, wave
->channel_mask
);
337 ser32(cur
, wave
->sub_format
.data1
);
338 ser16(cur
, wave
->sub_format
.data2
);
339 ser16(cur
, wave
->sub_format
.data3
);
340 serblob(cur
, wave
->sub_format
.data4
, sizeof(wave
->sub_format
.data4
));
343 static void serialise_format(struct nhlt_format
*fmt
, struct cursor
*cur
)
345 log_debug("%zx\n", cur
->buf
- cur
->start
);
346 serialise_waveform(&fmt
->waveform
, cur
);
347 serialise_specific_config(&fmt
->config
, cur
);
350 static void serialise_endpoint(struct nhlt_endpoint
*endp
, struct cursor
*cur
)
354 log_debug("%zx\n", cur
->buf
- cur
->start
);
355 ser32(cur
, endp
->length
);
356 ser8(cur
, endp
->link_type
);
357 ser8(cur
, endp
->instance_id
);
358 ser16(cur
, endp
->vendor_id
);
359 ser16(cur
, endp
->device_id
);
360 ser16(cur
, endp
->revision_id
);
361 ser32(cur
, endp
->subsystem_id
);
362 ser8(cur
, endp
->device_type
);
363 ser8(cur
, endp
->direction
);
364 ser8(cur
, endp
->virtual_bus_id
);
365 serialise_specific_config(&endp
->config
, cur
);
366 ser8(cur
, endp
->num_formats
);
368 for (i
= 0; i
< endp
->num_formats
; i
++)
369 serialise_format(&endp
->formats
[i
], cur
);
372 static void nhlt_serialise_endpoints(struct nhlt
*nhlt
, struct cursor
*cur
)
376 ser8(cur
, nhlt
->num_endpoints
);
378 for (i
= 0; i
< nhlt
->num_endpoints
; i
++)
379 serialise_endpoint(&nhlt
->endpoints
[i
], cur
);
382 int nhlt_serialise_oem_overrides(struct acpi_ctx
*ctx
, struct nhlt
*nhlt
,
383 const char *oem_id
, const char *oem_table_id
,
384 uint32_t oem_revision
)
387 struct acpi_table_header
*header
;
390 size_t oem_table_id_len
;
393 log_debug("ACPI: * NHLT\n");
394 sz
= nhlt_current_size(nhlt
);
397 header
= (void *)ctx
->current
;
398 memset(header
, '\0', sizeof(struct acpi_table_header
));
399 memcpy(header
->signature
, "NHLT", 4);
401 header
->revision
= acpi_get_table_revision(ACPITAB_NHLT
);
404 oem_id_len
= min((int)strlen(oem_id
), 6);
405 memcpy(header
->oem_id
, oem_id
, oem_id_len
);
408 oem_table_id_len
= min((int)strlen(oem_table_id
), 8);
409 memcpy(header
->oem_table_id
, oem_table_id
, oem_table_id_len
);
411 header
->oem_revision
= oem_revision
;
412 memcpy(header
->creator_id
, ASLC_ID
, 4);
414 cur
.buf
= (void *)(header
+ 1);
415 cur
.start
= (void *)header
;
416 nhlt_serialise_endpoints(nhlt
, &cur
);
418 header
->checksum
= table_compute_checksum(header
, sz
);
419 nhlt_free_resources(nhlt
);
420 assert(cur
.buf
- cur
.start
== sz
);
422 ret
= acpi_add_table(ctx
, ctx
->current
);
424 return log_msg_ret("add", ret
);
425 acpi_inc_align(ctx
, sz
);
430 static int _nhlt_add_single_endpoint(struct nhlt
*nhlt
, int virtual_bus_id
,
431 const struct nhlt_endp_descriptor
*epd
)
433 struct nhlt_endpoint
*endp
;
436 endp
= nhlt_add_endpoint(nhlt
, epd
->link
, epd
->device
, epd
->direction
,
441 endp
->virtual_bus_id
= virtual_bus_id
;
443 ret
= nhlt_endpoint_append_config(endp
, epd
->cfg
, epd
->cfg_size
);
447 ret
= nhlt_endpoint_add_formats(endp
, epd
->formats
, epd
->num_formats
);
449 return log_msg_ret("formats", ret
);
454 static int _nhlt_add_endpoints(struct nhlt
*nhlt
, int virtual_bus_id
,
455 const struct nhlt_endp_descriptor
*epds
,
461 for (i
= 0; i
< num_epds
; i
++) {
462 ret
= _nhlt_add_single_endpoint(nhlt
, virtual_bus_id
, &epds
[i
]);
470 int nhlt_add_endpoints(struct nhlt
*nhlt
,
471 const struct nhlt_endp_descriptor
*epds
, size_t num_epds
)
475 ret
= _nhlt_add_endpoints(nhlt
, DEFAULT_VIRTUAL_BUS_ID
, epds
, num_epds
);
480 int nhlt_add_ssp_endpoints(struct nhlt
*nhlt
, int virtual_bus_id
,
481 const struct nhlt_endp_descriptor
*epds
,
486 ret
= _nhlt_add_endpoints(nhlt
, virtual_bus_id
, epds
, num_epds
);
488 nhlt_next_instance(nhlt
, NHLT_LINK_SSP
);