1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause
2c72fcc34Sopenharmony_ci//
3c72fcc34Sopenharmony_ci// Copyright(c) 2021 Intel Corporation. All rights reserved.
4c72fcc34Sopenharmony_ci//
5c72fcc34Sopenharmony_ci// Author: Jaska Uimonen <jaska.uimonen@linux.intel.com>
6c72fcc34Sopenharmony_ci
7c72fcc34Sopenharmony_ci#include "aconfig.h"
8c72fcc34Sopenharmony_ci#include <errno.h>
9c72fcc34Sopenharmony_ci#include <stdio.h>
10c72fcc34Sopenharmony_ci#include <stdlib.h>
11c72fcc34Sopenharmony_ci#include <string.h>
12c72fcc34Sopenharmony_ci#include <stdbool.h>
13c72fcc34Sopenharmony_ci#include <inttypes.h>
14c72fcc34Sopenharmony_ci#include <alsa/global.h>
15c72fcc34Sopenharmony_ci#include <alsa/input.h>
16c72fcc34Sopenharmony_ci#include <alsa/output.h>
17c72fcc34Sopenharmony_ci#include <alsa/conf.h>
18c72fcc34Sopenharmony_ci#include <alsa/error.h>
19c72fcc34Sopenharmony_ci#include "pre-process-external.h"
20c72fcc34Sopenharmony_ci#include "nhlt.h"
21c72fcc34Sopenharmony_ci#include "intel/intel-nhlt.h"
22c72fcc34Sopenharmony_ci#include "intel/dmic-nhlt.h"
23c72fcc34Sopenharmony_ci#include "intel/ssp-nhlt.h"
24c72fcc34Sopenharmony_ci
25c72fcc34Sopenharmony_ci#define MAX_ENDPOINT_COUNT 20
26c72fcc34Sopenharmony_ci#define ALSA_BYTE_CHARS 5
27c72fcc34Sopenharmony_ci#define SOF_ABI_CHARS 29
28c72fcc34Sopenharmony_ci#define SOF_MANIFEST_DATA_TYPE_NHLT 1
29c72fcc34Sopenharmony_ci
30c72fcc34Sopenharmony_cistruct sof_manifest_tlv {
31c72fcc34Sopenharmony_ci	uint32_t type;
32c72fcc34Sopenharmony_ci	uint32_t size;
33c72fcc34Sopenharmony_ci	uint8_t data[];
34c72fcc34Sopenharmony_ci} __attribute__((packed));
35c72fcc34Sopenharmony_ci
36c72fcc34Sopenharmony_cistruct sof_manifest {
37c72fcc34Sopenharmony_ci	uint16_t abi_major;
38c72fcc34Sopenharmony_ci	uint16_t abi_minor;
39c72fcc34Sopenharmony_ci	uint16_t abi_patch;
40c72fcc34Sopenharmony_ci	uint16_t count;
41c72fcc34Sopenharmony_ci	struct sof_manifest_tlv items[];
42c72fcc34Sopenharmony_ci} __attribute__((packed));
43c72fcc34Sopenharmony_ci
44c72fcc34Sopenharmony_ci#ifdef NHLT_DEBUG
45c72fcc34Sopenharmony_cistatic void debug_print_nhlt(struct nhlt *blob, struct endpoint_descriptor **eps)
46c72fcc34Sopenharmony_ci{
47c72fcc34Sopenharmony_ci	uint8_t *top_p = (uint8_t *)blob;
48c72fcc34Sopenharmony_ci	struct endpoint_descriptor *ep;
49c72fcc34Sopenharmony_ci	uint8_t *ep_p;
50c72fcc34Sopenharmony_ci	int i, j, k, lines, remain;
51c72fcc34Sopenharmony_ci
52c72fcc34Sopenharmony_ci	fprintf(stdout, "printing nhlt as bytes:\n");
53c72fcc34Sopenharmony_ci
54c72fcc34Sopenharmony_ci	lines = sizeof(struct nhlt) / 8;
55c72fcc34Sopenharmony_ci	remain = sizeof(struct nhlt) % 8;
56c72fcc34Sopenharmony_ci	for (i = 0; i < lines; i++) {
57c72fcc34Sopenharmony_ci		for (j = 0; j < 8; j++) {
58c72fcc34Sopenharmony_ci			fprintf(stdout, "0x%02x,", *top_p);
59c72fcc34Sopenharmony_ci			top_p++;
60c72fcc34Sopenharmony_ci		}
61c72fcc34Sopenharmony_ci		fprintf(stdout, "\n");
62c72fcc34Sopenharmony_ci	}
63c72fcc34Sopenharmony_ci	for (i = 0; i < remain; i++) {
64c72fcc34Sopenharmony_ci		fprintf(stdout, "0x%02x,", *top_p);
65c72fcc34Sopenharmony_ci		top_p++;
66c72fcc34Sopenharmony_ci	}
67c72fcc34Sopenharmony_ci	fprintf(stdout, "\n\n");
68c72fcc34Sopenharmony_ci
69c72fcc34Sopenharmony_ci	for (i = 0; i < blob->endpoint_count; i++) {
70c72fcc34Sopenharmony_ci		ep = eps[i];
71c72fcc34Sopenharmony_ci		ep_p = (uint8_t *)ep;
72c72fcc34Sopenharmony_ci		lines = ep->length / 8;
73c72fcc34Sopenharmony_ci		remain = ep->length % 8;
74c72fcc34Sopenharmony_ci		for (j = 0; j < lines; j++) {
75c72fcc34Sopenharmony_ci			for (k = 0; k < 8; k++) {
76c72fcc34Sopenharmony_ci				fprintf(stdout, "0x%02x,", *ep_p);
77c72fcc34Sopenharmony_ci				ep_p++;
78c72fcc34Sopenharmony_ci			}
79c72fcc34Sopenharmony_ci			fprintf(stdout, "\n");
80c72fcc34Sopenharmony_ci		}
81c72fcc34Sopenharmony_ci		for (j = 0; j < remain; j++) {
82c72fcc34Sopenharmony_ci			fprintf(stdout, "0x%02x,", *ep_p);
83c72fcc34Sopenharmony_ci			ep_p++;
84c72fcc34Sopenharmony_ci		}
85c72fcc34Sopenharmony_ci		fprintf(stdout, "\n");
86c72fcc34Sopenharmony_ci	}
87c72fcc34Sopenharmony_ci
88c72fcc34Sopenharmony_ci	fprintf(stdout, "\n");
89c72fcc34Sopenharmony_ci}
90c72fcc34Sopenharmony_ci#else
91c72fcc34Sopenharmony_cistatic void debug_print_nhlt(struct nhlt *blob ATTRIBUTE_UNUSED,
92c72fcc34Sopenharmony_ci			     struct endpoint_descriptor **eps ATTRIBUTE_UNUSED) {}
93c72fcc34Sopenharmony_ci#endif
94c72fcc34Sopenharmony_ci
95c72fcc34Sopenharmony_cistatic int print_as_hex_bytes(uint8_t *manifest_buffer, uint32_t manifest_size,
96c72fcc34Sopenharmony_ci			      uint8_t *nhlt_buffer, uint32_t nhlt_size, char **src)
97c72fcc34Sopenharmony_ci{
98c72fcc34Sopenharmony_ci	char *bytes_string_buffer;
99c72fcc34Sopenharmony_ci	char *dst;
100c72fcc34Sopenharmony_ci	unsigned int i;
101c72fcc34Sopenharmony_ci
102c72fcc34Sopenharmony_ci	bytes_string_buffer = calloc((manifest_size + nhlt_size) * ALSA_BYTE_CHARS + 1,
103c72fcc34Sopenharmony_ci				     sizeof(uint8_t));
104c72fcc34Sopenharmony_ci	if (!bytes_string_buffer)
105c72fcc34Sopenharmony_ci		return -ENOMEM;
106c72fcc34Sopenharmony_ci
107c72fcc34Sopenharmony_ci	dst = bytes_string_buffer;
108c72fcc34Sopenharmony_ci	for (i = 0; i < manifest_size; i++) {
109c72fcc34Sopenharmony_ci		snprintf(dst, ALSA_BYTE_CHARS + 1, "0x%02x,", *manifest_buffer);
110c72fcc34Sopenharmony_ci		dst += ALSA_BYTE_CHARS;
111c72fcc34Sopenharmony_ci		manifest_buffer++;
112c72fcc34Sopenharmony_ci	}
113c72fcc34Sopenharmony_ci
114c72fcc34Sopenharmony_ci	for (i = 0; i < nhlt_size; i++) {
115c72fcc34Sopenharmony_ci		snprintf(dst, ALSA_BYTE_CHARS + 1, "0x%02x,", *nhlt_buffer);
116c72fcc34Sopenharmony_ci		dst += ALSA_BYTE_CHARS;
117c72fcc34Sopenharmony_ci		nhlt_buffer++;
118c72fcc34Sopenharmony_ci	}
119c72fcc34Sopenharmony_ci
120c72fcc34Sopenharmony_ci	/* remove the last comma... */
121c72fcc34Sopenharmony_ci	dst--;
122c72fcc34Sopenharmony_ci	*dst = '\0';
123c72fcc34Sopenharmony_ci
124c72fcc34Sopenharmony_ci	*src = bytes_string_buffer;
125c72fcc34Sopenharmony_ci
126c72fcc34Sopenharmony_ci	return 0;
127c72fcc34Sopenharmony_ci}
128c72fcc34Sopenharmony_ci
129c72fcc34Sopenharmony_cistatic int merge_manifest_data(snd_config_t *cfg, uint8_t *manifest_buffer, uint32_t manifest_size,
130c72fcc34Sopenharmony_ci			       uint8_t *nhlt_buffer, uint32_t nhlt_size)
131c72fcc34Sopenharmony_ci{
132c72fcc34Sopenharmony_ci	const char *data_name = "SOF ABI";
133c72fcc34Sopenharmony_ci	snd_config_t *data_section;
134c72fcc34Sopenharmony_ci	snd_config_t *manifest;
135c72fcc34Sopenharmony_ci	snd_config_t *old_bytes;
136c72fcc34Sopenharmony_ci	snd_config_t *new_bytes;
137c72fcc34Sopenharmony_ci	char *src = NULL;
138c72fcc34Sopenharmony_ci	int ret;
139c72fcc34Sopenharmony_ci
140c72fcc34Sopenharmony_ci	/* merge manifest struct and nhlt bytes as new config into existing SectionData*/
141c72fcc34Sopenharmony_ci	ret = snd_config_search(cfg, "SectionData", &data_section);
142c72fcc34Sopenharmony_ci	if (ret < 0)
143c72fcc34Sopenharmony_ci		return ret;
144c72fcc34Sopenharmony_ci
145c72fcc34Sopenharmony_ci	ret = snd_config_search(data_section, data_name, &manifest);
146c72fcc34Sopenharmony_ci	if (ret < 0)
147c72fcc34Sopenharmony_ci		return ret;
148c72fcc34Sopenharmony_ci
149c72fcc34Sopenharmony_ci	ret = snd_config_search(manifest, "bytes", &old_bytes);
150c72fcc34Sopenharmony_ci	if (ret < 0)
151c72fcc34Sopenharmony_ci		return ret;
152c72fcc34Sopenharmony_ci
153c72fcc34Sopenharmony_ci	ret = snd_config_make(&new_bytes, "bytes", SND_CONFIG_TYPE_STRING);
154c72fcc34Sopenharmony_ci	if (ret < 0)
155c72fcc34Sopenharmony_ci		goto err;
156c72fcc34Sopenharmony_ci
157c72fcc34Sopenharmony_ci	ret = print_as_hex_bytes(manifest_buffer, manifest_size, nhlt_buffer, nhlt_size, &src);
158c72fcc34Sopenharmony_ci	if (ret < 0)
159c72fcc34Sopenharmony_ci		goto err;
160c72fcc34Sopenharmony_ci
161c72fcc34Sopenharmony_ci	ret = snd_config_set_string(new_bytes, src);
162c72fcc34Sopenharmony_ci	if (ret < 0)
163c72fcc34Sopenharmony_ci		goto err;
164c72fcc34Sopenharmony_ci
165c72fcc34Sopenharmony_ci	ret = snd_config_merge(old_bytes, new_bytes, true);
166c72fcc34Sopenharmony_ci	if (ret < 0)
167c72fcc34Sopenharmony_ci		goto err;
168c72fcc34Sopenharmony_ci
169c72fcc34Sopenharmony_ci	free(src);
170c72fcc34Sopenharmony_ci
171c72fcc34Sopenharmony_ci	return 0;
172c72fcc34Sopenharmony_cierr:
173c72fcc34Sopenharmony_ci	if (new_bytes)
174c72fcc34Sopenharmony_ci		snd_config_delete(new_bytes);
175c72fcc34Sopenharmony_ci	if (src)
176c72fcc34Sopenharmony_ci		free(src);
177c72fcc34Sopenharmony_ci
178c72fcc34Sopenharmony_ci	return ret;
179c72fcc34Sopenharmony_ci}
180c72fcc34Sopenharmony_ci
181c72fcc34Sopenharmony_cistatic void save_nhlt_binary(struct nhlt *blob, struct endpoint_descriptor **eps, snd_config_t *cfg)
182c72fcc34Sopenharmony_ci{
183c72fcc34Sopenharmony_ci	const char *bin_file = NULL;
184c72fcc34Sopenharmony_ci	snd_config_t *defines;
185c72fcc34Sopenharmony_ci	FILE *fp;
186c72fcc34Sopenharmony_ci	int ret;
187c72fcc34Sopenharmony_ci	int i;
188c72fcc34Sopenharmony_ci
189c72fcc34Sopenharmony_ci	ret = snd_config_search(cfg, "Define.NHLT_BIN", &defines);
190c72fcc34Sopenharmony_ci	if (ret < 0)
191c72fcc34Sopenharmony_ci		return;
192c72fcc34Sopenharmony_ci
193c72fcc34Sopenharmony_ci	if (snd_config_get_string(defines, &bin_file) < 0)
194c72fcc34Sopenharmony_ci		return;
195c72fcc34Sopenharmony_ci
196c72fcc34Sopenharmony_ci	fp = fopen(bin_file, "wb");
197c72fcc34Sopenharmony_ci	if (fp == NULL) {
198c72fcc34Sopenharmony_ci		fprintf(stderr, "can't open nhlt binary output file %s\n", bin_file);
199c72fcc34Sopenharmony_ci		return;
200c72fcc34Sopenharmony_ci	}
201c72fcc34Sopenharmony_ci
202c72fcc34Sopenharmony_ci	fprintf(stdout, "saving nhlt as binary in %s\n", bin_file);
203c72fcc34Sopenharmony_ci
204c72fcc34Sopenharmony_ci	fwrite(blob, 1, sizeof(struct nhlt), fp);
205c72fcc34Sopenharmony_ci
206c72fcc34Sopenharmony_ci	for (i = 0; i < blob->endpoint_count; i++)
207c72fcc34Sopenharmony_ci		fwrite(eps[i], eps[i]->length, sizeof(uint8_t), fp);
208c72fcc34Sopenharmony_ci
209c72fcc34Sopenharmony_ci	fclose(fp);
210c72fcc34Sopenharmony_ci}
211c72fcc34Sopenharmony_ci
212c72fcc34Sopenharmony_cistatic int manifest_create(snd_config_t *input, uint8_t **manifest_buffer, uint32_t *size, uint32_t nhlt_size)
213c72fcc34Sopenharmony_ci{
214c72fcc34Sopenharmony_ci	struct sof_manifest_tlv manifest_tlv;
215c72fcc34Sopenharmony_ci	struct sof_manifest manifest;
216c72fcc34Sopenharmony_ci	snd_config_t *data_section;
217c72fcc34Sopenharmony_ci	snd_config_t *data;
218c72fcc34Sopenharmony_ci	snd_config_t *old_bytes;
219c72fcc34Sopenharmony_ci	uint32_t manifest_size;
220c72fcc34Sopenharmony_ci	uint8_t *byte_buffer;
221c72fcc34Sopenharmony_ci	const char *abi;
222c72fcc34Sopenharmony_ci	uint8_t *top_p;
223c72fcc34Sopenharmony_ci	uint8_t *dst;
224c72fcc34Sopenharmony_ci	int ret;
225c72fcc34Sopenharmony_ci	unsigned int i;
226c72fcc34Sopenharmony_ci
227c72fcc34Sopenharmony_ci	ret = snd_config_search(input, "SectionData", &data_section);
228c72fcc34Sopenharmony_ci	if (ret < 0)
229c72fcc34Sopenharmony_ci		return ret;
230c72fcc34Sopenharmony_ci
231c72fcc34Sopenharmony_ci	ret = snd_config_search(data_section, "SOF ABI", &data);
232c72fcc34Sopenharmony_ci	if (ret < 0)
233c72fcc34Sopenharmony_ci		return ret;
234c72fcc34Sopenharmony_ci
235c72fcc34Sopenharmony_ci	ret = snd_config_search(data, "bytes", &old_bytes);
236c72fcc34Sopenharmony_ci	if (ret < 0)
237c72fcc34Sopenharmony_ci		return ret;
238c72fcc34Sopenharmony_ci
239c72fcc34Sopenharmony_ci	ret = snd_config_get_string(old_bytes, &abi);
240c72fcc34Sopenharmony_ci	if (ret < 0)
241c72fcc34Sopenharmony_ci		return ret;
242c72fcc34Sopenharmony_ci
243c72fcc34Sopenharmony_ci	/* we have something funny in abi string */
244c72fcc34Sopenharmony_ci	if (strlen(abi) != SOF_ABI_CHARS)
245c72fcc34Sopenharmony_ci		return -EINVAL;
246c72fcc34Sopenharmony_ci
247c72fcc34Sopenharmony_ci	manifest.count = 1;
248c72fcc34Sopenharmony_ci	manifest_tlv.type = SOF_MANIFEST_DATA_TYPE_NHLT;
249c72fcc34Sopenharmony_ci	manifest_tlv.size = nhlt_size;
250c72fcc34Sopenharmony_ci
251c72fcc34Sopenharmony_ci	manifest_size = sizeof(struct sof_manifest) + sizeof(struct sof_manifest_tlv);
252c72fcc34Sopenharmony_ci	byte_buffer = calloc(manifest_size, sizeof(uint8_t));
253c72fcc34Sopenharmony_ci	if (!byte_buffer)
254c72fcc34Sopenharmony_ci		return -ENOMEM;
255c72fcc34Sopenharmony_ci
256c72fcc34Sopenharmony_ci	*size = manifest_size;
257c72fcc34Sopenharmony_ci
258c72fcc34Sopenharmony_ci	dst = byte_buffer;
259c72fcc34Sopenharmony_ci
260c72fcc34Sopenharmony_ci	/* copy the ABI version bytes */
261c72fcc34Sopenharmony_ci	for (i = 0; i < 6; i++)
262c72fcc34Sopenharmony_ci		sscanf(&abi[i * ALSA_BYTE_CHARS], "%" SCNx8, dst++);
263c72fcc34Sopenharmony_ci
264c72fcc34Sopenharmony_ci	/* set the count */
265c72fcc34Sopenharmony_ci	*dst++ = manifest.count;
266c72fcc34Sopenharmony_ci	*dst++ = manifest.count >> 2;
267c72fcc34Sopenharmony_ci
268c72fcc34Sopenharmony_ci	top_p = (uint8_t *)&manifest_tlv;
269c72fcc34Sopenharmony_ci	for (i = 0; i < sizeof(struct sof_manifest_tlv); i++)
270c72fcc34Sopenharmony_ci		*dst++ = *top_p++;
271c72fcc34Sopenharmony_ci
272c72fcc34Sopenharmony_ci	*manifest_buffer = byte_buffer;
273c72fcc34Sopenharmony_ci
274c72fcc34Sopenharmony_ci	return 0;
275c72fcc34Sopenharmony_ci}
276c72fcc34Sopenharmony_ci
277c72fcc34Sopenharmony_cistatic int nhlt_get_flat_buffer(struct nhlt *blob, struct endpoint_descriptor **eps,
278c72fcc34Sopenharmony_ci				uint32_t eps_count, uint32_t *size, uint8_t **nhlt_buffer)
279c72fcc34Sopenharmony_ci{
280c72fcc34Sopenharmony_ci	uint8_t *top_p = (uint8_t *)blob;
281c72fcc34Sopenharmony_ci	struct endpoint_descriptor *ep;
282c72fcc34Sopenharmony_ci	uint8_t *byte_buffer;
283c72fcc34Sopenharmony_ci	uint32_t nhlt_size;
284c72fcc34Sopenharmony_ci	uint8_t *ep_p;
285c72fcc34Sopenharmony_ci	uint8_t *dst;
286c72fcc34Sopenharmony_ci	unsigned int i, j;
287c72fcc34Sopenharmony_ci
288c72fcc34Sopenharmony_ci	/* get blob total size */
289c72fcc34Sopenharmony_ci	nhlt_size = sizeof(struct nhlt);
290c72fcc34Sopenharmony_ci	for (i = 0; i < eps_count; i++) {
291c72fcc34Sopenharmony_ci		if (eps[i])
292c72fcc34Sopenharmony_ci			nhlt_size += eps[i]->length;
293c72fcc34Sopenharmony_ci	}
294c72fcc34Sopenharmony_ci
295c72fcc34Sopenharmony_ci	*size = nhlt_size;
296c72fcc34Sopenharmony_ci
297c72fcc34Sopenharmony_ci	byte_buffer = calloc(nhlt_size, sizeof(uint8_t));
298c72fcc34Sopenharmony_ci	if (!byte_buffer)
299c72fcc34Sopenharmony_ci		return -ENOMEM;
300c72fcc34Sopenharmony_ci
301c72fcc34Sopenharmony_ci	dst = byte_buffer;
302c72fcc34Sopenharmony_ci	for (i = 0; i < sizeof(struct nhlt); i++)
303c72fcc34Sopenharmony_ci		*dst++ = *top_p++;
304c72fcc34Sopenharmony_ci
305c72fcc34Sopenharmony_ci	for (i = 0; i < blob->endpoint_count; i++) {
306c72fcc34Sopenharmony_ci		ep = eps[i];
307c72fcc34Sopenharmony_ci		ep_p = (uint8_t *)ep;
308c72fcc34Sopenharmony_ci		for (j = 0; j < ep->length; j++)
309c72fcc34Sopenharmony_ci			*dst++ = *ep_p++;
310c72fcc34Sopenharmony_ci	}
311c72fcc34Sopenharmony_ci
312c72fcc34Sopenharmony_ci	*nhlt_buffer = byte_buffer;
313c72fcc34Sopenharmony_ci
314c72fcc34Sopenharmony_ci	return 0;
315c72fcc34Sopenharmony_ci}
316c72fcc34Sopenharmony_ci
317c72fcc34Sopenharmony_ci/* called at the end of topology pre-processing, create flat buffer from variable size nhlt */
318c72fcc34Sopenharmony_cistatic int nhlt_create(struct intel_nhlt_params *nhlt, snd_config_t *input,
319c72fcc34Sopenharmony_ci		       snd_config_t *output ATTRIBUTE_UNUSED,
320c72fcc34Sopenharmony_ci		       uint8_t **nhlt_buffer, uint32_t *nhlt_size)
321c72fcc34Sopenharmony_ci{
322c72fcc34Sopenharmony_ci	struct endpoint_descriptor *eps[MAX_ENDPOINT_COUNT];
323c72fcc34Sopenharmony_ci	int eps_count = 0;
324c72fcc34Sopenharmony_ci	struct nhlt blob;
325c72fcc34Sopenharmony_ci	uint32_t size;
326c72fcc34Sopenharmony_ci	uint8_t dir;
327c72fcc34Sopenharmony_ci	int ret;
328c72fcc34Sopenharmony_ci	int i;
329c72fcc34Sopenharmony_ci
330c72fcc34Sopenharmony_ci	for (i = 0; i < MAX_ENDPOINT_COUNT; i++)
331c72fcc34Sopenharmony_ci		eps[i] = NULL;
332c72fcc34Sopenharmony_ci
333c72fcc34Sopenharmony_ci	/* we always have only 0 or 1 dmic ep */
334c72fcc34Sopenharmony_ci	for (i = 0; i < nhlt_dmic_get_ep_count(nhlt); i++) {
335c72fcc34Sopenharmony_ci		ret = nhlt_dmic_get_ep(nhlt, &eps[eps_count], i);
336c72fcc34Sopenharmony_ci		if (ret < 0)
337c72fcc34Sopenharmony_ci			return -EINVAL;
338c72fcc34Sopenharmony_ci		eps_count++;
339c72fcc34Sopenharmony_ci	}
340c72fcc34Sopenharmony_ci
341c72fcc34Sopenharmony_ci	/* we can have 0 to several ssp eps */
342c72fcc34Sopenharmony_ci	for (i = 0; i < nhlt_ssp_get_ep_count(nhlt); i++) {
343c72fcc34Sopenharmony_ci		nhlt_ssp_get_dir(nhlt, i, &dir);
344c72fcc34Sopenharmony_ci		/* duplicate endpoint for duplex dai */
345c72fcc34Sopenharmony_ci		if (dir > NHLT_ENDPOINT_DIRECTION_FEEDBACK_FOR_RENDER) {
346c72fcc34Sopenharmony_ci			ret = nhlt_ssp_get_ep(nhlt, &eps[eps_count], i,
347c72fcc34Sopenharmony_ci					      NHLT_ENDPOINT_DIRECTION_RENDER);
348c72fcc34Sopenharmony_ci			if (ret < 0)
349c72fcc34Sopenharmony_ci				goto err;
350c72fcc34Sopenharmony_ci			eps_count++;
351c72fcc34Sopenharmony_ci			ret = nhlt_ssp_get_ep(nhlt, &eps[eps_count], i,
352c72fcc34Sopenharmony_ci					      NHLT_ENDPOINT_DIRECTION_CAPTURE);
353c72fcc34Sopenharmony_ci		} else {
354c72fcc34Sopenharmony_ci			ret = nhlt_ssp_get_ep(nhlt, &eps[eps_count], i, dir);
355c72fcc34Sopenharmony_ci		}
356c72fcc34Sopenharmony_ci		if (ret < 0)
357c72fcc34Sopenharmony_ci			goto err;
358c72fcc34Sopenharmony_ci		eps_count++;
359c72fcc34Sopenharmony_ci	}
360c72fcc34Sopenharmony_ci
361c72fcc34Sopenharmony_ci	/* we don't have endpoints */
362c72fcc34Sopenharmony_ci	if (!eps_count)
363c72fcc34Sopenharmony_ci		return 0;
364c72fcc34Sopenharmony_ci
365c72fcc34Sopenharmony_ci	uint8_t sig[4] = {'N', 'H', 'L', 'T'};
366c72fcc34Sopenharmony_ci	blob.efi_acpi.signature = *((uint32_t *)sig);
367c72fcc34Sopenharmony_ci	blob.efi_acpi.length = 0;
368c72fcc34Sopenharmony_ci	blob.efi_acpi.revision = 0;
369c72fcc34Sopenharmony_ci	blob.efi_acpi.checksum = 0;
370c72fcc34Sopenharmony_ci	for (i = 0; i < 6; i++)
371c72fcc34Sopenharmony_ci		blob.efi_acpi.oem_id[i] = 0;
372c72fcc34Sopenharmony_ci	blob.efi_acpi.oem_table_id = 0;
373c72fcc34Sopenharmony_ci	blob.efi_acpi.oem_revision = 0;
374c72fcc34Sopenharmony_ci	blob.efi_acpi.creator_id = 0;
375c72fcc34Sopenharmony_ci	blob.efi_acpi.creator_revision = 0;
376c72fcc34Sopenharmony_ci
377c72fcc34Sopenharmony_ci	blob.endpoint_count = eps_count;
378c72fcc34Sopenharmony_ci
379c72fcc34Sopenharmony_ci	/* get blob total size */
380c72fcc34Sopenharmony_ci	size = sizeof(struct nhlt);
381c72fcc34Sopenharmony_ci	for (i = 0; i < eps_count; i++) {
382c72fcc34Sopenharmony_ci		if (eps[i])
383c72fcc34Sopenharmony_ci			size += eps[i]->length;
384c72fcc34Sopenharmony_ci	}
385c72fcc34Sopenharmony_ci
386c72fcc34Sopenharmony_ci	/* add the total length to top level struct */
387c72fcc34Sopenharmony_ci	blob.efi_acpi.length = size;
388c72fcc34Sopenharmony_ci
389c72fcc34Sopenharmony_ci	debug_print_nhlt(&blob, eps);
390c72fcc34Sopenharmony_ci
391c72fcc34Sopenharmony_ci	save_nhlt_binary(&blob, eps, input);
392c72fcc34Sopenharmony_ci
393c72fcc34Sopenharmony_ci	ret = nhlt_get_flat_buffer(&blob, eps, eps_count, nhlt_size, nhlt_buffer);
394c72fcc34Sopenharmony_ci
395c72fcc34Sopenharmony_cierr:
396c72fcc34Sopenharmony_ci	/* remove all enpoints */
397c72fcc34Sopenharmony_ci	for (i = 0; i < eps_count; i++)
398c72fcc34Sopenharmony_ci		free(eps[i]);
399c72fcc34Sopenharmony_ci
400c72fcc34Sopenharmony_ci	return ret;
401c72fcc34Sopenharmony_ci}
402c72fcc34Sopenharmony_ci
403c72fcc34Sopenharmony_cistatic int do_nhlt(struct intel_nhlt_params *nhlt, snd_config_t *input, snd_config_t *output)
404c72fcc34Sopenharmony_ci{
405c72fcc34Sopenharmony_ci	uint8_t *manifest_buffer = NULL;
406c72fcc34Sopenharmony_ci	uint8_t *nhlt_buffer = NULL;
407c72fcc34Sopenharmony_ci	uint32_t manifest_size;
408c72fcc34Sopenharmony_ci	uint32_t nhlt_size = 0;
409c72fcc34Sopenharmony_ci	int ret = 0;
410c72fcc34Sopenharmony_ci
411c72fcc34Sopenharmony_ci	ret = nhlt_create(nhlt, input, output, &nhlt_buffer, &nhlt_size);
412c72fcc34Sopenharmony_ci	if (ret) {
413c72fcc34Sopenharmony_ci		fprintf(stderr, "can't create nhlt blob, err %d\n", ret);
414c72fcc34Sopenharmony_ci		return ret;
415c72fcc34Sopenharmony_ci	}
416c72fcc34Sopenharmony_ci
417c72fcc34Sopenharmony_ci	ret = manifest_create(output, &manifest_buffer, &manifest_size, nhlt_size);
418c72fcc34Sopenharmony_ci	if (ret) {
419c72fcc34Sopenharmony_ci		fprintf(stderr, "can't re-create manifest, err %d\n", ret);
420c72fcc34Sopenharmony_ci		goto err;
421c72fcc34Sopenharmony_ci	}
422c72fcc34Sopenharmony_ci
423c72fcc34Sopenharmony_ci	ret = merge_manifest_data(output, manifest_buffer, manifest_size, nhlt_buffer, nhlt_size);
424c72fcc34Sopenharmony_ci	if (ret)
425c72fcc34Sopenharmony_ci		fprintf(stderr, "can't merge manifest data, err %d\n", ret);
426c72fcc34Sopenharmony_ci
427c72fcc34Sopenharmony_cierr:
428c72fcc34Sopenharmony_ci	if (manifest_buffer)
429c72fcc34Sopenharmony_ci		free(manifest_buffer);
430c72fcc34Sopenharmony_ci	if (nhlt_buffer)
431c72fcc34Sopenharmony_ci		free(nhlt_buffer);
432c72fcc34Sopenharmony_ci
433c72fcc34Sopenharmony_ci	return ret;
434c72fcc34Sopenharmony_ci}
435c72fcc34Sopenharmony_ci
436c72fcc34Sopenharmony_ciSND_TOPOLOGY_PLUGIN_DEFINE_FUNC(nhlt)
437c72fcc34Sopenharmony_ci{
438c72fcc34Sopenharmony_ci	snd_config_iterator_t i, i2, next, next2;
439c72fcc34Sopenharmony_ci	struct intel_nhlt_params nhlt;
440c72fcc34Sopenharmony_ci	snd_config_t *n, *n2;
441c72fcc34Sopenharmony_ci	snd_config_t *items;
442c72fcc34Sopenharmony_ci	const char *id, *id2;
443c72fcc34Sopenharmony_ci	int ret;
444c72fcc34Sopenharmony_ci
445c72fcc34Sopenharmony_ci	/* initialize the internal structs */
446c72fcc34Sopenharmony_ci	ret = nhlt_ssp_init_params(&nhlt);
447c72fcc34Sopenharmony_ci	if (ret < 0)
448c72fcc34Sopenharmony_ci		return ret;
449c72fcc34Sopenharmony_ci
450c72fcc34Sopenharmony_ci	ret = nhlt_dmic_init_params(&nhlt);
451c72fcc34Sopenharmony_ci	if (ret < 0)
452c72fcc34Sopenharmony_ci		return ret;
453c72fcc34Sopenharmony_ci
454c72fcc34Sopenharmony_ci	/* find DAIs and set internal parameters */
455c72fcc34Sopenharmony_ci	ret = snd_config_search(input, "Object.Dai", &items);
456c72fcc34Sopenharmony_ci	if (ret < 0)
457c72fcc34Sopenharmony_ci		return ret;
458c72fcc34Sopenharmony_ci
459c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, items) {
460c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
461c72fcc34Sopenharmony_ci
462c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
463c72fcc34Sopenharmony_ci			continue;
464c72fcc34Sopenharmony_ci
465c72fcc34Sopenharmony_ci		snd_config_for_each(i2, next2, n) {
466c72fcc34Sopenharmony_ci			n2 = snd_config_iterator_entry(i2);
467c72fcc34Sopenharmony_ci
468c72fcc34Sopenharmony_ci			if (snd_config_get_id(n2, &id2) < 0)
469c72fcc34Sopenharmony_ci				continue;
470c72fcc34Sopenharmony_ci
471c72fcc34Sopenharmony_ci			/* set dai parameters here */
472c72fcc34Sopenharmony_ci			if (!strncmp(id, "DMIC", 4)) {
473c72fcc34Sopenharmony_ci				ret = nhlt_dmic_set_params(&nhlt, n2, input);
474c72fcc34Sopenharmony_ci				if (ret < 0)
475c72fcc34Sopenharmony_ci					return ret;
476c72fcc34Sopenharmony_ci			}
477c72fcc34Sopenharmony_ci
478c72fcc34Sopenharmony_ci			if (!strncmp(id, "SSP", 3)) {
479c72fcc34Sopenharmony_ci				ret = nhlt_ssp_set_params(&nhlt, n2, input);
480c72fcc34Sopenharmony_ci				if (ret < 0)
481c72fcc34Sopenharmony_ci					return ret;
482c72fcc34Sopenharmony_ci			}
483c72fcc34Sopenharmony_ci		}
484c72fcc34Sopenharmony_ci	}
485c72fcc34Sopenharmony_ci
486c72fcc34Sopenharmony_ci	/* create the nhlt blob from internal structs */
487c72fcc34Sopenharmony_ci	ret = do_nhlt(&nhlt, input, output);
488c72fcc34Sopenharmony_ci	if (ret)
489c72fcc34Sopenharmony_ci		fprintf(stderr, "error in nhlt processing\n");
490c72fcc34Sopenharmony_ci
491c72fcc34Sopenharmony_ci	free(nhlt.ssp_params);
492c72fcc34Sopenharmony_ci	free(nhlt.dmic_params);
493c72fcc34Sopenharmony_ci
494c72fcc34Sopenharmony_ci	return 0;
495c72fcc34Sopenharmony_ci}
496