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