1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2020 Google LLC
4  *
5  * Modified from coreboot nhlt.c
6  */
7 
8 #define LOG_CATEGORY	LOGC_ACPI
9 
10 #include <common.h>
11 #include <binman.h>
12 #include <dm.h>
13 #include <log.h>
14 #include <malloc.h>
15 #include <tables_csum.h>
16 #include <acpi/acpi_table.h>
17 #include <asm/acpi_nhlt.h>
18 #include <asm/unaligned.h>
19 #include <dm/acpi.h>
20 
21 #define NHLT_RID		1
22 #define NHLT_SSID		1
23 #define WAVEFORMAT_TAG		0xfffe
24 #define DEFAULT_VIRTUAL_BUS_ID	0
25 
26 static const struct sub_format pcm_subformat = {
27 	.data1 = 0x00000001,
28 	.data2 = 0x0000,
29 	.data3 = 0x0010,
30 	.data4 = { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 },
31 };
32 
nhlt_init(void)33 struct nhlt *nhlt_init(void)
34 {
35 	struct nhlt *nhlt;
36 
37 	nhlt = malloc(sizeof(*nhlt));
38 
39 	if (!nhlt)
40 		return NULL;
41 
42 	memset(nhlt, 0, sizeof(*nhlt));
43 	nhlt->subsystem_id = NHLT_SSID;
44 
45 	return nhlt;
46 }
47 
nhlt_add_endpoint(struct nhlt * nhlt,int link_type,int device_type,int dir,u16 vid,u16 did)48 struct nhlt_endpoint *nhlt_add_endpoint(struct nhlt *nhlt, int link_type,
49 					int device_type, int dir,
50 					u16 vid, u16 did)
51 {
52 	struct nhlt_endpoint *endp;
53 
54 	if (link_type < NHLT_LINK_HDA || link_type >= NHLT_MAX_LINK_TYPES)
55 		return NULL;
56 
57 	if (nhlt->num_endpoints >= MAX_ENDPOINTS)
58 		return NULL;
59 
60 	endp = &nhlt->endpoints[nhlt->num_endpoints];
61 
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;
72 
73 	nhlt->num_endpoints++;
74 
75 	return endp;
76 }
77 
append_specific_config(struct nhlt_specific_config * spec_cfg,const void * config,size_t config_sz)78 static int append_specific_config(struct nhlt_specific_config *spec_cfg,
79 				  const void *config, size_t config_sz)
80 {
81 	size_t new_sz;
82 	void *new_cfg;
83 
84 	new_sz = spec_cfg->size + config_sz;
85 	new_cfg = malloc(new_sz);
86 	if (!new_cfg)
87 		return -ENOMEM;
88 
89 	/* Append new config */
90 	memcpy(new_cfg, spec_cfg->capabilities, spec_cfg->size);
91 	memcpy(new_cfg + spec_cfg->size, config, config_sz);
92 
93 	free(spec_cfg->capabilities);
94 
95 	/* Update with new config data */
96 	spec_cfg->size = new_sz;
97 	spec_cfg->capabilities = new_cfg;
98 
99 	return 0;
100 }
101 
nhlt_endpoint_append_config(struct nhlt_endpoint * endp,const void * config,size_t config_sz)102 int nhlt_endpoint_append_config(struct nhlt_endpoint *endp, const void *config,
103 				size_t config_sz)
104 {
105 	return append_specific_config(&endp->config, config, config_sz);
106 }
107 
nhlt_add_format(struct nhlt_endpoint * endp,int num_channels,int sample_freq_khz,int container_bits_per_sample,int valid_bits_per_sample,uint32_t speaker_mask)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)
113 {
114 	struct nhlt_format *fmt;
115 	struct nhlt_waveform *wave;
116 
117 	if (endp->num_formats >= MAX_FORMATS)
118 		return NULL;
119 
120 	fmt = &endp->formats[endp->num_formats];
121 	wave = &fmt->waveform;
122 
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));
133 
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;
137 
138 	endp->num_formats++;
139 
140 	return fmt;
141 }
142 
nhlt_format_append_config(struct nhlt_format * fmt,const void * config,size_t config_sz)143 int nhlt_format_append_config(struct nhlt_format *fmt, const void *config,
144 			      size_t config_sz)
145 {
146 	return append_specific_config(&fmt->config, config, config_sz);
147 }
148 
nhlt_endpoint_add_formats(struct nhlt_endpoint * endp,const struct nhlt_format_config * formats,size_t num_formats)149 int nhlt_endpoint_add_formats(struct nhlt_endpoint *endp,
150 			      const struct nhlt_format_config *formats,
151 			      size_t num_formats)
152 {
153 	ofnode node;
154 	size_t i;
155 
156 	node = binman_section_find_node("private-files");
157 
158 	for (i = 0; i < num_formats; i++) {
159 		const struct nhlt_format_config *cfg = &formats[i];
160 		struct nhlt_format *fmt;
161 		void *data;
162 		int size;
163 		int ret;
164 
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,
169 				      cfg->speaker_mask);
170 		if (!fmt)
171 			return -ENOSPC;
172 
173 		if (!cfg->settings_file)
174 			continue;
175 
176 		ret = binman_entry_map(node, cfg->settings_file, &data, &size);
177 		if (ret) {
178 			log_warning("Failed to find settings file %s\n",
179 				    cfg->settings_file);
180 			return log_msg_ret("settings", ret);
181 		}
182 
183 		ret = nhlt_format_append_config(fmt, data, size);
184 		if (ret)
185 			return log_msg_ret("append", ret);
186 	}
187 
188 	return 0;
189 }
190 
nhlt_next_instance(struct nhlt * nhlt,int link_type)191 void nhlt_next_instance(struct nhlt *nhlt, int link_type)
192 {
193 	if (link_type < NHLT_LINK_HDA || link_type >= NHLT_MAX_LINK_TYPES)
194 		return;
195 
196 	nhlt->current_instance_id[link_type]++;
197 }
198 
calc_specific_config_size(struct nhlt_specific_config * cfg)199 static size_t calc_specific_config_size(struct nhlt_specific_config *cfg)
200 {
201 	return sizeof(cfg->size) + cfg->size;
202 }
203 
calc_format_size(struct nhlt_format * fmt)204 static size_t calc_format_size(struct nhlt_format *fmt)
205 {
206 	size_t sz = 0;
207 
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);
219 
220 	sz += calc_specific_config_size(&fmt->config);
221 
222 	return sz;
223 }
224 
calc_endpoint_size(struct nhlt_endpoint * endp)225 static size_t calc_endpoint_size(struct nhlt_endpoint *endp)
226 {
227 	int i;
228 	size_t sz = 0;
229 
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);
237 
238 	for (i = 0; i < endp->num_formats; i++)
239 		sz += calc_format_size(&endp->formats[i]);
240 
241 	/* Adjust endpoint length to reflect current configuration */
242 	endp->length = sz;
243 
244 	return sz;
245 }
246 
calc_endpoints_size(struct nhlt * nhlt)247 static size_t calc_endpoints_size(struct nhlt *nhlt)
248 {
249 	size_t sz = 0;
250 	int i;
251 
252 	for (i = 0; i < nhlt->num_endpoints; i++)
253 		sz += calc_endpoint_size(&nhlt->endpoints[i]);
254 
255 	return sz;
256 }
257 
calc_size(struct nhlt * nhlt)258 static size_t calc_size(struct nhlt *nhlt)
259 {
260 	return sizeof(nhlt->num_endpoints) + calc_endpoints_size(nhlt);
261 }
262 
nhlt_current_size(struct nhlt * nhlt)263 size_t nhlt_current_size(struct nhlt *nhlt)
264 {
265 	return calc_size(nhlt) + sizeof(struct acpi_table_header);
266 }
267 
nhlt_free_resources(struct nhlt * nhlt)268 static void nhlt_free_resources(struct nhlt *nhlt)
269 {
270 	int i, j;
271 
272 	/* Free all specific configs */
273 	for (i = 0; i < nhlt->num_endpoints; i++) {
274 		struct nhlt_endpoint *endp = &nhlt->endpoints[i];
275 
276 		free(endp->config.capabilities);
277 		for (j = 0; j < endp->num_formats; j++) {
278 			struct nhlt_format *fmt = &endp->formats[j];
279 
280 			free(fmt->config.capabilities);
281 		}
282 	}
283 
284 	/* Free nhlt object proper */
285 	free(nhlt);
286 }
287 
288 struct cursor {
289 	u8 *start;
290 	u8 *buf;
291 };
292 
ser8(struct cursor * cur,uint val)293 static void ser8(struct cursor *cur, uint val)
294 {
295 	*cur->buf = val;
296 	cur->buf += sizeof(u8);
297 }
298 
ser16(struct cursor * cur,uint val)299 static void ser16(struct cursor *cur, uint val)
300 {
301 	put_unaligned_le16(val, cur->buf);
302 	cur->buf += sizeof(u16);
303 }
304 
ser32(struct cursor * cur,uint val)305 static void ser32(struct cursor *cur, uint val)
306 {
307 	put_unaligned_le32(val, cur->buf);
308 	cur->buf += sizeof(u32);
309 }
310 
serblob(struct cursor * cur,void * from,size_t sz)311 static void serblob(struct cursor *cur, void *from, size_t sz)
312 {
313 	memcpy(cur->buf, from, sz);
314 	cur->buf += sz;
315 }
316 
serialise_specific_config(struct nhlt_specific_config * cfg,struct cursor * cur)317 static void serialise_specific_config(struct nhlt_specific_config *cfg,
318 				      struct cursor *cur)
319 {
320 	log_debug("%zx\n", cur->buf - cur->start);
321 	ser32(cur, cfg->size);
322 	serblob(cur, cfg->capabilities, cfg->size);
323 }
324 
serialise_waveform(struct nhlt_waveform * wave,struct cursor * cur)325 static void serialise_waveform(struct nhlt_waveform *wave, struct cursor *cur)
326 {
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));
341 }
342 
serialise_format(struct nhlt_format * fmt,struct cursor * cur)343 static void serialise_format(struct nhlt_format *fmt, struct cursor *cur)
344 {
345 	log_debug("%zx\n", cur->buf - cur->start);
346 	serialise_waveform(&fmt->waveform, cur);
347 	serialise_specific_config(&fmt->config, cur);
348 }
349 
serialise_endpoint(struct nhlt_endpoint * endp,struct cursor * cur)350 static void serialise_endpoint(struct nhlt_endpoint *endp, struct cursor *cur)
351 {
352 	int i;
353 
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);
367 
368 	for (i = 0; i < endp->num_formats; i++)
369 		serialise_format(&endp->formats[i], cur);
370 }
371 
nhlt_serialise_endpoints(struct nhlt * nhlt,struct cursor * cur)372 static void nhlt_serialise_endpoints(struct nhlt *nhlt, struct cursor *cur)
373 {
374 	int i;
375 
376 	ser8(cur, nhlt->num_endpoints);
377 
378 	for (i = 0; i < nhlt->num_endpoints; i++)
379 		serialise_endpoint(&nhlt->endpoints[i], cur);
380 }
381 
nhlt_serialise_oem_overrides(struct acpi_ctx * ctx,struct nhlt * nhlt,const char * oem_id,const char * oem_table_id,uint32_t oem_revision)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)
385 {
386 	struct cursor cur;
387 	struct acpi_table_header *header;
388 	size_t sz;
389 	size_t oem_id_len;
390 	size_t oem_table_id_len;
391 	int ret;
392 
393 	log_debug("ACPI:    * NHLT\n");
394 	sz = nhlt_current_size(nhlt);
395 
396 	/* Create header */
397 	header = (void *)ctx->current;
398 	memset(header, '\0', sizeof(struct acpi_table_header));
399 	memcpy(header->signature, "NHLT", 4);
400 	header->length = sz;
401 	header->revision = acpi_get_table_revision(ACPITAB_NHLT);
402 
403 	if (oem_id) {
404 		oem_id_len = min((int)strlen(oem_id), 6);
405 		memcpy(header->oem_id, oem_id, oem_id_len);
406 	}
407 	if (oem_table_id) {
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);
410 	}
411 	header->oem_revision = oem_revision;
412 	memcpy(header->aslc_id, ASLC_ID, 4);
413 
414 	cur.buf = (void *)(header + 1);
415 	cur.start = (void *)header;
416 	nhlt_serialise_endpoints(nhlt, &cur);
417 
418 	header->checksum = table_compute_checksum(header, sz);
419 	nhlt_free_resources(nhlt);
420 	assert(cur.buf - cur.start == sz);
421 
422 	ret = acpi_add_table(ctx, ctx->current);
423 	if (ret)
424 		return log_msg_ret("add", ret);
425 	acpi_inc_align(ctx, sz);
426 
427 	return 0;
428 }
429 
_nhlt_add_single_endpoint(struct nhlt * nhlt,int virtual_bus_id,const struct nhlt_endp_descriptor * epd)430 static int _nhlt_add_single_endpoint(struct nhlt *nhlt, int virtual_bus_id,
431 				     const struct nhlt_endp_descriptor *epd)
432 {
433 	struct nhlt_endpoint *endp;
434 	int ret;
435 
436 	endp = nhlt_add_endpoint(nhlt, epd->link, epd->device, epd->direction,
437 				 epd->vid, epd->did);
438 	if (!endp)
439 		return -EINVAL;
440 
441 	endp->virtual_bus_id = virtual_bus_id;
442 
443 	ret = nhlt_endpoint_append_config(endp, epd->cfg, epd->cfg_size);
444 	if (ret)
445 		return ret;
446 
447 	ret = nhlt_endpoint_add_formats(endp, epd->formats, epd->num_formats);
448 	if (ret)
449 		return log_msg_ret("formats", ret);
450 
451 	return 0;
452 }
453 
_nhlt_add_endpoints(struct nhlt * nhlt,int virtual_bus_id,const struct nhlt_endp_descriptor * epds,size_t num_epds)454 static int _nhlt_add_endpoints(struct nhlt *nhlt, int virtual_bus_id,
455 			       const struct nhlt_endp_descriptor *epds,
456 			       size_t num_epds)
457 {
458 	size_t i;
459 	int ret;
460 
461 	for (i = 0; i < num_epds; i++) {
462 		ret = _nhlt_add_single_endpoint(nhlt, virtual_bus_id, &epds[i]);
463 		if (ret)
464 			return log_ret(ret);
465 	}
466 
467 	return 0;
468 }
469 
nhlt_add_endpoints(struct nhlt * nhlt,const struct nhlt_endp_descriptor * epds,size_t num_epds)470 int nhlt_add_endpoints(struct nhlt *nhlt,
471 		       const struct nhlt_endp_descriptor *epds, size_t num_epds)
472 {
473 	int ret;
474 
475 	ret = _nhlt_add_endpoints(nhlt, DEFAULT_VIRTUAL_BUS_ID, epds, num_epds);
476 
477 	return ret;
478 }
479 
nhlt_add_ssp_endpoints(struct nhlt * nhlt,int virtual_bus_id,const struct nhlt_endp_descriptor * epds,size_t num_epds)480 int nhlt_add_ssp_endpoints(struct nhlt *nhlt, int virtual_bus_id,
481 			   const struct nhlt_endp_descriptor *epds,
482 			   size_t num_epds)
483 {
484 	int ret;
485 
486 	ret = _nhlt_add_endpoints(nhlt, virtual_bus_id, epds, num_epds);
487 	if (!ret)
488 		nhlt_next_instance(nhlt, NHLT_LINK_SSP);
489 
490 	return ret;
491 }
492