2 * This file is part of the coreboot project.
4 * Copyright 2015 Google, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <arch/acpi.h>
18 #include <commonlib/endian.h>
19 #include <console/console.h>
26 #define WAVEFORMAT_TAG 0xfffe
27 #define DEFAULT_VIRTUAL_BUS_ID 0
29 static const struct sub_format pcm_subformat
= {
33 .data4
= { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 },
36 struct nhlt
*nhlt_init(void)
40 nhlt
= malloc(sizeof(*nhlt
));
45 memset(nhlt
, 0, sizeof(*nhlt
));
50 struct nhlt_endpoint
*nhlt_add_endpoint(struct nhlt
*nhlt
, int link_type
,
51 int device_type
, int dir
,
52 uint16_t vid
, uint16_t did
)
54 struct nhlt_endpoint
*endp
;
56 if (link_type
< NHLT_LINK_HDA
|| link_type
>= NHLT_MAX_LINK_TYPES
)
59 if (nhlt
->num_endpoints
>= MAX_ENDPOINTS
)
62 endp
= &nhlt
->endpoints
[nhlt
->num_endpoints
];
64 endp
->link_type
= link_type
;
65 endp
->instance_id
= nhlt
->current_instance_id
[link_type
];
66 endp
->vendor_id
= vid
;
67 endp
->device_id
= did
;
68 endp
->revision_id
= NHLT_RID
;
69 endp
->subsystem_id
= NHLT_SSID
;
70 endp
->device_type
= device_type
;
71 endp
->direction
= dir
;
72 endp
->virtual_bus_id
= DEFAULT_VIRTUAL_BUS_ID
;
74 nhlt
->num_endpoints
++;
79 static int append_specific_config(struct nhlt_specific_config
*spec_cfg
,
80 const void *config
, size_t config_sz
)
85 if (config
== NULL
|| config_sz
== 0)
88 new_sz
= spec_cfg
->size
+ config_sz
;
90 new_cfg
= malloc(new_sz
);
95 /* Append new config. */
96 memcpy(new_cfg
, spec_cfg
->capabilities
, spec_cfg
->size
);
97 memcpy(new_cfg
+ spec_cfg
->size
, config
, config_sz
);
99 free(spec_cfg
->capabilities
);
101 /* Update with new config data. */
102 spec_cfg
->size
= new_sz
;
103 spec_cfg
->capabilities
= new_cfg
;
108 int nhlt_endpoint_append_config(struct nhlt_endpoint
*endp
, const void *config
,
111 return append_specific_config(&endp
->config
, config
, config_sz
);
114 struct nhlt_format
*nhlt_add_format(struct nhlt_endpoint
*endp
,
117 int container_bits_per_sample
,
118 int valid_bits_per_sample
,
119 uint32_t speaker_mask
)
121 struct nhlt_format
*fmt
;
122 struct nhlt_waveform
*wave
;
124 if (endp
->num_formats
>= MAX_FORMATS
)
127 fmt
= &endp
->formats
[endp
->num_formats
];
128 wave
= &fmt
->waveform
;
130 wave
->tag
= WAVEFORMAT_TAG
;
131 wave
->num_channels
= num_channels
;
132 wave
->samples_per_second
= sample_freq_khz
* KHz
;
133 wave
->bits_per_sample
= container_bits_per_sample
;
134 wave
->extra_size
= sizeof(wave
->valid_bits_per_sample
);
135 wave
->extra_size
+= sizeof(wave
->channel_mask
);
136 wave
->extra_size
+= sizeof(wave
->sub_format
);
137 wave
->valid_bits_per_sample
= valid_bits_per_sample
;
138 wave
->channel_mask
= speaker_mask
;
139 memcpy(&wave
->sub_format
, &pcm_subformat
, sizeof(wave
->sub_format
));
141 /* Calculate the dervied fields. */
142 wave
->block_align
= wave
->num_channels
* wave
->bits_per_sample
/ 8;
143 wave
->bytes_per_second
= wave
->block_align
* wave
->samples_per_second
;
150 int nhlt_format_append_config(struct nhlt_format
*fmt
, const void *config
,
153 return append_specific_config(&fmt
->config
, config
, config_sz
);
156 int nhlt_endpoint_add_formats(struct nhlt_endpoint
*endp
,
157 const struct nhlt_format_config
*formats
,
162 for (i
= 0; i
< num_formats
; i
++) {
163 struct nhlt_format
*fmt
;
165 struct region_device settings
;
167 const struct nhlt_format_config
*cfg
= &formats
[i
];
169 fmt
= nhlt_add_format(endp
, cfg
->num_channels
,
170 cfg
->sample_freq_khz
,
171 cfg
->container_bits_per_sample
,
172 cfg
->valid_bits_per_sample
,
178 if (cfg
->settings_file
== NULL
)
181 /* Find the settings file in CBFS and place it in format. */
182 if (cbfs_boot_locate(&file
, cfg
->settings_file
, NULL
))
185 cbfs_file_data(&settings
, &file
);
187 settings_data
= rdev_mmap_full(&settings
);
189 if (settings_data
== NULL
)
192 if (nhlt_format_append_config(fmt
, settings_data
,
193 region_device_sz(&settings
))) {
194 rdev_munmap(&settings
, settings_data
);
198 rdev_munmap(&settings
, settings_data
);
204 void nhlt_next_instance(struct nhlt
*nhlt
, int link_type
)
206 if (link_type
< NHLT_LINK_HDA
|| link_type
>= NHLT_MAX_LINK_TYPES
)
209 nhlt
->current_instance_id
[link_type
]++;
212 static size_t calc_specific_config_size(struct nhlt_specific_config
*cfg
)
214 return sizeof(cfg
->size
) + cfg
->size
;
217 static size_t calc_format_size(struct nhlt_format
*fmt
)
221 /* Wave format first. */
222 sz
+= sizeof(fmt
->waveform
.tag
);
223 sz
+= sizeof(fmt
->waveform
.num_channels
);
224 sz
+= sizeof(fmt
->waveform
.samples_per_second
);
225 sz
+= sizeof(fmt
->waveform
.bytes_per_second
);
226 sz
+= sizeof(fmt
->waveform
.block_align
);
227 sz
+= sizeof(fmt
->waveform
.bits_per_sample
);
228 sz
+= sizeof(fmt
->waveform
.extra_size
);
229 sz
+= sizeof(fmt
->waveform
.valid_bits_per_sample
);
230 sz
+= sizeof(fmt
->waveform
.channel_mask
);
231 sz
+= sizeof(fmt
->waveform
.sub_format
);
233 sz
+= calc_specific_config_size(&fmt
->config
);
238 static size_t calc_endpoint_size(struct nhlt_endpoint
*endp
)
243 sz
+= sizeof(endp
->length
) + sizeof(endp
->link_type
);
244 sz
+= sizeof(endp
->instance_id
) + sizeof(endp
->vendor_id
);
245 sz
+= sizeof(endp
->device_id
) + sizeof(endp
->revision_id
);
246 sz
+= sizeof(endp
->subsystem_id
) + sizeof(endp
->device_type
);
247 sz
+= sizeof(endp
->direction
) + sizeof(endp
->virtual_bus_id
);
248 sz
+= calc_specific_config_size(&endp
->config
);
249 sz
+= sizeof(endp
->num_formats
);
251 for (i
= 0; i
< endp
->num_formats
; i
++)
252 sz
+= calc_format_size(&endp
->formats
[i
]);
254 /* Adjust endpoint length to reflect current configuration. */
260 static size_t calc_endpoints_size(struct nhlt
*nhlt
)
265 for (i
= 0; i
< nhlt
->num_endpoints
; i
++)
266 sz
+= calc_endpoint_size(&nhlt
->endpoints
[i
]);
271 static size_t calc_size(struct nhlt
*nhlt
)
273 return sizeof(nhlt
->num_endpoints
) + calc_endpoints_size(nhlt
);
276 size_t nhlt_current_size(struct nhlt
*nhlt
)
278 return calc_size(nhlt
) + sizeof(acpi_header_t
);
281 static void nhlt_free_resources(struct nhlt
*nhlt
)
286 /* Free all specific configs. */
287 for (i
= 0; i
< nhlt
->num_endpoints
; i
++) {
288 struct nhlt_endpoint
*endp
= &nhlt
->endpoints
[i
];
290 free(endp
->config
.capabilities
);
291 for (j
= 0; j
< endp
->num_formats
; j
++) {
292 struct nhlt_format
*fmt
= &endp
->formats
[j
];
294 free(fmt
->config
.capabilities
);
298 /* Free nhlt object proper. */
306 static void ser8(struct cursor
*cur
, uint8_t val
)
308 write_le8(cur
->buf
, val
);
309 cur
->buf
+= sizeof(val
);
312 static void ser16(struct cursor
*cur
, uint16_t val
)
314 write_le16(cur
->buf
, val
);
315 cur
->buf
+= sizeof(val
);
318 static void ser32(struct cursor
*cur
, uint32_t val
)
320 write_le32(cur
->buf
, val
);
321 cur
->buf
+= sizeof(val
);
324 static void serblob(struct cursor
*cur
, void *from
, size_t sz
)
326 memcpy(cur
->buf
, from
, sz
);
330 static void serialize_specific_config(struct nhlt_specific_config
*cfg
,
333 ser32(cur
, cfg
->size
);
334 serblob(cur
, cfg
->capabilities
, cfg
->size
);
337 static void serialize_waveform(struct nhlt_waveform
*wave
, struct cursor
*cur
)
339 ser16(cur
, wave
->tag
);
340 ser16(cur
, wave
->num_channels
);
341 ser32(cur
, wave
->samples_per_second
);
342 ser32(cur
, wave
->bytes_per_second
);
343 ser16(cur
, wave
->block_align
);
344 ser16(cur
, wave
->bits_per_sample
);
345 ser16(cur
, wave
->extra_size
);
346 ser16(cur
, wave
->valid_bits_per_sample
);
347 ser32(cur
, wave
->channel_mask
);
348 ser32(cur
, wave
->sub_format
.data1
);
349 ser16(cur
, wave
->sub_format
.data2
);
350 ser16(cur
, wave
->sub_format
.data3
);
351 serblob(cur
, wave
->sub_format
.data4
, sizeof(wave
->sub_format
.data4
));
354 static void serialize_format(struct nhlt_format
*fmt
, struct cursor
*cur
)
356 serialize_waveform(&fmt
->waveform
, cur
);
357 serialize_specific_config(&fmt
->config
, cur
);
360 static void serialize_endpoint(struct nhlt_endpoint
*endp
, struct cursor
*cur
)
364 ser32(cur
, endp
->length
);
365 ser8(cur
, endp
->link_type
);
366 ser8(cur
, endp
->instance_id
);
367 ser16(cur
, endp
->vendor_id
);
368 ser16(cur
, endp
->device_id
);
369 ser16(cur
, endp
->revision_id
);
370 ser32(cur
, endp
->subsystem_id
);
371 ser8(cur
, endp
->device_type
);
372 ser8(cur
, endp
->direction
);
373 ser8(cur
, endp
->virtual_bus_id
);
374 serialize_specific_config(&endp
->config
, cur
);
375 ser8(cur
, endp
->num_formats
);
377 for (i
= 0; i
< endp
->num_formats
; i
++)
378 serialize_format(&endp
->formats
[i
], cur
);
381 static void nhlt_serialize_endpoints(struct nhlt
*nhlt
, struct cursor
*cur
)
385 ser8(cur
, nhlt
->num_endpoints
);
387 for (i
= 0; i
< nhlt
->num_endpoints
; i
++)
388 serialize_endpoint(&nhlt
->endpoints
[i
], cur
);
391 uintptr_t nhlt_serialize(struct nhlt
*nhlt
, uintptr_t acpi_addr
)
393 return nhlt_serialize_oem_overrides(nhlt
, acpi_addr
, NULL
, NULL
);
396 uintptr_t nhlt_serialize_oem_overrides(struct nhlt
*nhlt
,
397 uintptr_t acpi_addr
, const char *oem_id
, const char *oem_table_id
)
400 acpi_header_t
*header
;
403 size_t oem_table_id_len
;
405 printk(BIOS_DEBUG
, "ACPI: * NHLT\n");
407 sz
= nhlt_current_size(nhlt
);
410 header
= (void *)acpi_addr
;
411 memset(header
, 0, sizeof(acpi_header_t
));
412 memcpy(header
->signature
, "NHLT", 4);
413 write_le32(&header
->length
, sz
);
414 write_le8(&header
->revision
, 5);
419 if (oem_table_id
== NULL
)
420 oem_table_id
= ACPI_TABLE_CREATOR
;
422 oem_id_len
= MIN(strlen(oem_id
), 6);
423 oem_table_id_len
= MIN(strlen(oem_table_id
), 8);
425 memcpy(header
->oem_id
, oem_id
, oem_id_len
);
426 memcpy(header
->oem_table_id
, oem_table_id
, oem_table_id_len
);
427 memcpy(header
->asl_compiler_id
, ASLC
, 4);
429 cur
.buf
= (void *)(acpi_addr
+ sizeof(acpi_header_t
));
430 nhlt_serialize_endpoints(nhlt
, &cur
);
432 write_le8(&header
->checksum
, acpi_checksum((void *)header
, sz
));
434 nhlt_free_resources(nhlt
);
437 acpi_addr
= ALIGN_UP(acpi_addr
, 16);
442 static int _nhlt_add_single_endpoint(struct nhlt
*nhlt
, int virtual_bus_id
,
443 const struct nhlt_endp_descriptor
*epd
)
445 struct nhlt_endpoint
*endp
;
447 endp
= nhlt_add_endpoint(nhlt
, epd
->link
, epd
->device
, epd
->direction
,
453 endp
->virtual_bus_id
= virtual_bus_id
;
455 if (nhlt_endpoint_append_config(endp
, epd
->cfg
, epd
->cfg_size
))
458 if (nhlt_endpoint_add_formats(endp
, epd
->formats
, epd
->num_formats
))
464 static int _nhlt_add_endpoints(struct nhlt
*nhlt
, int virtual_bus_id
,
465 const struct nhlt_endp_descriptor
*epds
,
470 for (i
= 0; i
< num_epds
; i
++)
471 if (_nhlt_add_single_endpoint(nhlt
, virtual_bus_id
, &epds
[i
]))
477 int nhlt_add_endpoints(struct nhlt
*nhlt
,
478 const struct nhlt_endp_descriptor
*epds
,
482 ret
= _nhlt_add_endpoints(nhlt
, DEFAULT_VIRTUAL_BUS_ID
, epds
, num_epds
);
486 int nhlt_add_ssp_endpoints(struct nhlt
*nhlt
, int virtual_bus_id
,
487 const struct nhlt_endp_descriptor
*epds
, size_t num_epds
)
491 ret
= _nhlt_add_endpoints(nhlt
, virtual_bus_id
, epds
, num_epds
);
494 nhlt_next_instance(nhlt
, NHLT_LINK_SSP
);