Skip to content

Commit 46779a5

Browse files
Jaska UimonenJaska Uimonen
authored andcommitted
topology: add nhlt generation into topology2.0 pre-processing
Add optional generation of nhlt acpi table into topology2.0 processing. Nhlt internal structure is defined in: https://01.org/sites/default/files/595976_intel_sst_nhlt.pdf Nhlt acpi table contain vendor specific binary data blobs that are used in some Intel dsp platforms for configuring the dmic and ssp hardware. The beef in this code is to generate the vendor specific binary blobs, but as there is existing nhlt parser in kernel there's no point of re-inventing the container: just use the existing nhlt acpi table format. Basically this code is creating similar nhlt acpi table that you would get from: cat /sys/firmware/acpi/tables/NHLT Nhlt generation can be enabled with a alsatplg switch -l. Nhlt generation is done by adding auto attribute function for topology2.0 dai processing, saving parameters and generating the nhlt struct after parsing. Nhlt struct is added into the manifest as bytes field. Nhlt processing uses a private data in tplg_pre_processor struct and needs to be initialized before parsing starts. After all dais have been parsed the nhlt can be created. Nhtl structs are almost direct copy from related kernel header. Vendor specific blob generation will be added in later commits. Signed-off-by: Jaska Uimonen <[email protected]>
1 parent e2b167c commit 46779a5

File tree

9 files changed

+588
-11
lines changed

9 files changed

+588
-11
lines changed

topology/Makefile.am

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ endif
99
rst2man $< > $@
1010

1111
alsatplg_SOURCES = topology.c pre-processor.c pre-process-class.c pre-process-object.c \
12-
pre-process-dapm.c pre-process-dai.c
12+
pre-process-dapm.c pre-process-dai.c nhlt/nhlt-processor.c
1313

14-
noinst_HEADERS = topology.h pre-processor.h
14+
noinst_HEADERS = topology.h pre-processor.h \
15+
nhlt/nhlt-processor.h nhlt/nhlt.h
1516

1617
AM_CPPFLAGS = \
1718
-Wall -I$(top_srcdir)/include

topology/nhlt/nhlt-processor.c

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/*
2+
Copyright(c) 2021 Intel Corporation
3+
All rights reserved.
4+
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of version 2 of the GNU General Public License as
7+
published by the Free Software Foundation.
8+
9+
This program is distributed in the hope that it will be useful, but
10+
WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17+
The full GNU General Public License is included in this distribution
18+
in the file called LICENSE.GPL.
19+
*/
20+
21+
#include <errno.h>
22+
#include <stdio.h>
23+
#include <alsa/input.h>
24+
#include <alsa/output.h>
25+
#include <alsa/conf.h>
26+
#include <alsa/error.h>
27+
#include "pre-processor.h"
28+
#include "nhlt-processor.h"
29+
#include "nhlt.h"
30+
31+
#define MAX_ENDPOINT_COUNT 20
32+
33+
static int add_bytes_to_data_section(struct tplg_pre_processor *tplg_pp, char *src)
34+
{
35+
const char *data_name = "nhlt";
36+
snd_config_t *top_data_section;
37+
snd_config_t *bytes;
38+
snd_config_t *nhlt;
39+
int ret;
40+
41+
/* add the nhlt bytes as new config into existing SectionData*/
42+
ret = snd_config_search(tplg_pp->output_cfg, "SectionData", &top_data_section);
43+
if (ret < 0)
44+
return ret;
45+
46+
ret = tplg_config_make_add(&nhlt, data_name, SND_CONFIG_TYPE_COMPOUND, top_data_section);
47+
if (ret < 0)
48+
return ret;
49+
50+
ret = tplg_config_make_add(&bytes, "bytes", SND_CONFIG_TYPE_STRING, nhlt);
51+
if (ret < 0) {
52+
snd_config_delete(nhlt);
53+
return ret;
54+
}
55+
56+
ret = snd_config_set_string(bytes, src);
57+
if (ret < 0) {
58+
snd_config_delete(nhlt);
59+
snd_config_delete(bytes);
60+
return ret;
61+
}
62+
63+
return 0;
64+
}
65+
66+
static int add_to_manifest(struct tplg_pre_processor *tplg_pp, char *src)
67+
{
68+
const char *data_name = "nhlt";
69+
snd_config_t *manifest;
70+
snd_config_t *man_inst;
71+
snd_config_t *n;
72+
snd_config_t *cfg_new;
73+
snd_config_t *data;
74+
snd_config_iterator_t i, next;
75+
const char *id;
76+
char *id_name;
77+
int ret, id_num = 0;
78+
79+
/* find manifest section and its named instance */
80+
ret = snd_config_search(tplg_pp->output_cfg, "SectionManifest", &manifest);
81+
if (ret < 0)
82+
return 0;
83+
84+
snd_config_for_each(i, next, manifest) {
85+
86+
n = snd_config_iterator_entry(i);
87+
88+
if (snd_config_get_id(n, &id) < 0)
89+
continue;
90+
91+
if (!strcmp(id, "sof_manifest"))
92+
man_inst = n;
93+
}
94+
95+
/* if manifest not found, just exit */
96+
if (!man_inst)
97+
return 0;
98+
99+
ret = add_bytes_to_data_section(tplg_pp, src);
100+
if (ret < 0)
101+
return ret;
102+
103+
/* add the reference to the bytes into manifest data */
104+
ret = snd_config_search(man_inst, "data", &data);
105+
if (ret < 0)
106+
return ret;
107+
108+
snd_config_for_each(i, next, data) {
109+
const char *name;
110+
111+
n = snd_config_iterator_entry(i);
112+
if (snd_config_get_string(n, &name) < 0)
113+
continue;
114+
115+
/* item already exists */
116+
if (!strcmp(name, data_name))
117+
return 0;
118+
id_num++;
119+
}
120+
121+
/* add new item */
122+
id_name = tplg_snprintf("%d", id_num);
123+
if (!id_name)
124+
return -ENOMEM;
125+
126+
ret = snd_config_make(&cfg_new, id_name, SND_CONFIG_TYPE_STRING);
127+
free(id_name);
128+
if (ret < 0)
129+
return ret;
130+
131+
ret = snd_config_set_string(cfg_new, data_name);
132+
if (ret < 0)
133+
return ret;
134+
135+
ret = snd_config_add(data, cfg_new);
136+
if (ret < 0)
137+
snd_config_delete(cfg_new);
138+
139+
return 0;
140+
}
141+
142+
static int print_nhlt_as_hex_bytes(struct nhlt *blob, struct endpoint_descriptor **eps, char *dst)
143+
{
144+
uint8_t *top_p = (uint8_t *)blob;
145+
struct endpoint_descriptor *ep;
146+
uint8_t *ep_p;
147+
int i, j;
148+
149+
for (i = 0; i < sizeof(struct nhlt); i++) {
150+
snprintf(dst, 6, "0x%02x,", *top_p);
151+
dst += 5;
152+
top_p++;
153+
}
154+
155+
for (i = 0; i < blob->endpoint_count; i++) {
156+
ep = eps[i];
157+
ep_p = (uint8_t *)ep;
158+
printf("ep %i length is %u\n", i, ep->length);
159+
for (j = 0; j < ep->length; j++) {
160+
snprintf(dst, 6, "0x%02x,", *ep_p);
161+
dst += 5;
162+
ep_p++;
163+
}
164+
}
165+
166+
/* remove the last comma... */
167+
dst--;
168+
*dst = '\0';
169+
170+
return 0;
171+
}
172+
173+
/* called at the beginning of topology pre-processing */
174+
int nhlt_init(struct tplg_pre_processor *tplg_pp)
175+
{
176+
if (!tplg_pp)
177+
return -EINVAL;
178+
179+
return 0;
180+
}
181+
182+
/* called when exiting topology pre-processing */
183+
int nhlt_delete(struct tplg_pre_processor *tplg_pp)
184+
{
185+
if (!tplg_pp)
186+
return -EINVAL;
187+
188+
if(tplg_pp->private_data)
189+
free(tplg_pp->private_data);
190+
191+
return 0;
192+
}
193+
194+
/* called at the end of topology pre-processing */
195+
int nhlt_create(struct tplg_pre_processor *tplg_pp)
196+
{
197+
struct endpoint_descriptor *eps[MAX_ENDPOINT_COUNT];
198+
struct intel_nhlt_params *nhlt;
199+
char *bytes_string_buffer;
200+
int eps_count = 0;
201+
struct nhlt blob;
202+
size_t nhlt_size;
203+
int ret;
204+
int i;
205+
206+
nhlt = (struct intel_nhlt_params *)tplg_pp->private_data;
207+
if (!nhlt)
208+
return -EINVAL;
209+
210+
for (i = 0; i < MAX_ENDPOINT_COUNT; i++)
211+
eps[i] = NULL;
212+
213+
/* we always have only 0 or 1 dmic ep */
214+
if (nhlt_dmic_get_ep_count(tplg_pp)) {
215+
/* the index is always 0 in dmic case */
216+
ret = nhlt_dmic_get_ep(tplg_pp, &eps[eps_count], 0);
217+
if (ret < 0)
218+
return ret;
219+
eps_count++;
220+
}
221+
222+
/* we can have 0 to several ssp eps */
223+
for (i = 0; i < nhlt_ssp_get_ep_count(tplg_pp); i++) {
224+
ret = nhlt_ssp_get_ep(tplg_pp, &eps[eps_count], i);
225+
if (ret < 0)
226+
goto err;
227+
eps_count++;
228+
}
229+
230+
/* we don't have endpoints */
231+
if (!eps_count)
232+
return 0;
233+
234+
blob.efi_acpi.signature = 0;
235+
blob.efi_acpi.length = 0;
236+
blob.efi_acpi.revision = 0;
237+
blob.efi_acpi.checksum = 0;
238+
blob.efi_acpi.oem_id[6] = 0;
239+
blob.efi_acpi.oem_table_id = 0;
240+
blob.efi_acpi.oem_revision = 0;
241+
blob.efi_acpi.creator_id = 0;
242+
blob.efi_acpi.creator_revision = 0;
243+
244+
blob.endpoint_count = eps_count;
245+
246+
/* get blob total size */
247+
nhlt_size = sizeof(struct nhlt);
248+
for (i = 0; i < eps_count; i++) {
249+
if (eps[i])
250+
nhlt_size += eps[i]->length;
251+
}
252+
253+
/* add the total length to top level struct */
254+
blob.efi_acpi.length = nhlt_size;
255+
256+
/* allocate the bytes string, every byte is alsa conf byte string format "0xA1," */
257+
bytes_string_buffer = calloc(nhlt_size * 5, sizeof(uint8_t));
258+
if (!bytes_string_buffer) {
259+
ret = -ENOMEM;
260+
goto err;
261+
}
262+
263+
/* print the whole thing in hex characters */
264+
print_nhlt_as_hex_bytes(&blob, eps, bytes_string_buffer);
265+
266+
ret = add_to_manifest(tplg_pp, bytes_string_buffer);
267+
268+
err:
269+
/* remove all enpoints */
270+
for (i = 0; i < eps_count; i++)
271+
free(eps[i]);
272+
273+
free(bytes_string_buffer);
274+
275+
return ret;
276+
}
277+
278+
/* called from pre-processor deferred dai processing */
279+
int nhlt_set_dai(struct tplg_pre_processor *tplg_pp,
280+
snd_config_t *cfg, snd_config_t *parent)
281+
{
282+
const char *id;
283+
284+
if (snd_config_get_id(cfg, &id) < 0)
285+
return -EINVAL;
286+
287+
/* set dai parameters here */
288+
289+
return 0;
290+
}

topology/nhlt/nhlt-processor.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Copyright(c) 2021 Intel Corporation
3+
All rights reserved.
4+
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of version 2 of the GNU General Public License as
7+
published by the Free Software Foundation.
8+
9+
This program is distributed in the hope that it will be useful, but
10+
WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17+
The full GNU General Public License is included in this distribution
18+
in the file called LICENSE.GPL.
19+
*/
20+
21+
#ifndef __NHLT_PROCESSOR_H
22+
#define __NHLT_PROCESSOR_H
23+
24+
#include "pre-processor.h"
25+
26+
int nhlt_init(struct tplg_pre_processor *tplg_pp);
27+
int nhlt_set_dai(struct tplg_pre_processor *tplg_pp, snd_config_t *cfg, snd_config_t *parent);
28+
int nhlt_create(struct tplg_pre_processor *tplg_pp);
29+
int nhlt_delete(struct tplg_pre_processor *tplg_pp);
30+
31+
#endif

0 commit comments

Comments
 (0)