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