Skip to content

Commit 6b08512

Browse files
committed
src/platform/mtk: MTK AFE Generator tool
Early versions of the AFE driver were published with large C struct definitions tied to platform headers. Zephyr strongly prefers Devicetree for configuration and not C code. So this is a somewhat klugey C program that builds and runs the AFE platform code on a Linux host CPU, producing valid DTS output that can be included in a board devicetree file in Zephyr. Just run ./build.sh from inside this directory. The only required host software is a working gcc that supports the "-m32" flag. The resulting afe-<platform>.dts files can be included directly in Zephyr board config. Signed-off-by: Andy Ross <[email protected]>
1 parent 25f5a6d commit 6b08512

File tree

3 files changed

+219
-0
lines changed

3 files changed

+219
-0
lines changed

src/platform/mtk/tools/README.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
MTK AFE Generator tool
3+
======================
4+
5+
Early versions of the AFE driver were published with large C struct
6+
definitions tied to platform headers. Zephyr strongly prefers
7+
Devicetree for configuration and not C code.
8+
9+
So this is a somewhat klugey C program that builds and runs the AFE
10+
platform code on a Linux host CPU, producing valid DTS output that can
11+
be included in a board devicetree file in Zephyr.
12+
13+
Just run ./build.sh from inside this directory. The only required
14+
host software is a working gcc that supports the "-m32" flag.
15+
16+
The resulting afe-<platform>.dts files can be included directly in
17+
Zephyr board config.

src/platform/mtk/tools/build.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/bin/sh
2+
# SPDX-License-Identifier: BSD-3-Clause
3+
# Copyright(c) 2024 Google LLC. All rights reserved.
4+
# Author: Andy Ross <[email protected]>
5+
set -ex
6+
7+
PLATFORMS="$*"
8+
if [ -z "$PLATFORMS" ]; then
9+
PLATFORMS="mt8195 mt8188 mt8186 mt8196"
10+
fi
11+
12+
SOF=`cd ../../../..; /bin/pwd`
13+
14+
for p in $PLATFORMS; do
15+
16+
SRCS="$SOF/src/platform/$p/lib/dai.c $SOF/src/platform/$p/afe-platform.c"
17+
18+
INCS="-I$SOF/src/include -I$SOF/src/platform/posix/include -I$SOF/posix/include -I$SOF/src/arch/host/include -I$SOF/src/platform/$p/include/platform -I$SOF/src/platform/$p/include"
19+
20+
DEFS="-DRELATIVE_FILE=\"mt-dai-gen.c\" -DCONFIG_CORE_COUNT=1 -DCONFIG_IPC_MAJOR_3=1"
21+
22+
touch uuid-registry.h
23+
INCS="$INCS -I."
24+
25+
gcc -g -Wall -Werror -m32 -o mt-dai-gen mt-dai-gen.c $SRCS $INCS $DEFS
26+
27+
./mt-dai-gen > afe-${p}.dts
28+
done
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
// Copyright(c) 2024 Google LLC. All rights reserved.
3+
// Author: Andy Ross <[email protected]>
4+
#include <sof/lib/dai-legacy.h>
5+
#include <sof/drivers/afe-drv.h>
6+
#include <stdio.h>
7+
8+
/* DIY assertion, an "assert()" is already defined in platform headers */
9+
#define CHECK(expr) if(!(expr)) { \
10+
printf("FAILED: " #expr " at line %d\n", __LINE__); *(int*)0=0; }
11+
12+
/* These are the symbols we need to enumerate */
13+
extern struct mtk_base_afe_platform mtk_afe_platform;
14+
extern const struct dai_info lib_dai;
15+
16+
/* Call this to initialize the dai arrays */
17+
int dai_init(struct sof *sof);
18+
19+
/* Debug hook in some versions of MTK firmware */
20+
void printf_(void) {}
21+
22+
/* Just need a pointer to a symbol with this name */
23+
int afe_dai_driver;
24+
25+
/* So dai_init() can write to something */
26+
struct sof sof;
27+
28+
unsigned int afe_base_addr;
29+
30+
void symify(char *s)
31+
{
32+
for(; *s; s++) {
33+
if (*s >= 'A' && *s <= 'Z')
34+
*s += 'a' - 'A';
35+
CHECK((*s >= 'a' && *s <= 'z') || (*s >= '0' && *s <= '9') || *s == '_');
36+
}
37+
}
38+
39+
/* The AFE driver has some... idiosyncratic defaulting. The existing
40+
* configurations have a varying set of conventions to encode "no
41+
* value is set":
42+
*
43+
* ch_num is skipped if the stored reg value is negative
44+
* quad_ch is skipped if the mask is zero
45+
* int_odd: <=0 reg
46+
* mono: <=0 reg OR <=0 shift
47+
* msb: <=0 reg
48+
* msb2: <=0 reg
49+
* agent_disable: <=0 reg
50+
* fs: never skipped
51+
* hd: never skipped
52+
* enable: never skipped
53+
*
54+
* We detect the union of those conditions and elide the setting (it
55+
* will be defaulted to reg=-1/shift=0/mask=0 in the driver DTS macros)
56+
*/
57+
void print_fld(const char *name, int reg, int shift, int lomask)
58+
{
59+
if (reg <= 0 || shift < 0 || lomask == 0) {
60+
return;
61+
}
62+
63+
int bits = __builtin_ffs(lomask + 1) - 1;
64+
65+
CHECK(((lomask + 1) & lomask) == 0); // must be power of two
66+
CHECK(lomask); // and not zero
67+
CHECK(shift >= 0 && (shift + bits) <= 32); // and shift doesn't overrun
68+
69+
printf("\t\t" "%s = <0x%8.8x %d %d>;\n",
70+
name, reg + afe_base_addr, shift, bits);
71+
}
72+
73+
unsigned int msbaddr(int val)
74+
{
75+
return val ? val + afe_base_addr : 0;
76+
}
77+
78+
int main(void)
79+
{
80+
dai_init(&sof);
81+
82+
afe_base_addr = mtk_afe_platform.base_addr;
83+
84+
// The DAI order here is immutable: the indexes are known to and
85+
// used by the kernel driver. And these point to the memif array
86+
// via an index stored in the low byte (?!) of the first fifo's
87+
// "handshake" (it's not a DMA handshake value at all). So we
88+
// invert the mapping and store the dai index along with the AFE
89+
// record.
90+
int dai_memif[64];
91+
int num_dais = 0;
92+
for (int t = 0; t < lib_dai.num_dai_types; t++) {
93+
for (int i = 0; i < lib_dai.dai_type_array[t].num_dais; i++) {
94+
int idx = lib_dai.dai_type_array[t].dai_array[i].index;
95+
int hs = lib_dai.dai_type_array[t].dai_array[i].plat_data.fifo[0].handshake;
96+
97+
CHECK(idx == num_dais);
98+
dai_memif[num_dais++] = hs >> 16;
99+
}
100+
}
101+
102+
// Quick check that the dai/memif mapping is unique
103+
for(int i=0; i<num_dais; i++) {
104+
int n = 0;
105+
for(int j=0; j<num_dais; j++)
106+
if(dai_memif[j] == i)
107+
n++;
108+
CHECK(n == 1);
109+
}
110+
111+
for (int i = 0; i < mtk_afe_platform.memif_size; i++) {
112+
const struct mtk_base_memif_data *m = &mtk_afe_platform.memif_datas[i];
113+
114+
int dai_id = -1;
115+
for (int j = 0; j < num_dais; j++) {
116+
if (dai_memif[j] == i) {
117+
dai_id = j;
118+
break;
119+
}
120+
}
121+
CHECK(dai_id >= 0);
122+
123+
// We use the UL/DL naming to detect direction, make sure it isn't broken
124+
bool uplink = !!strstr(m->name, "UL");
125+
bool downlink = !!strstr(m->name, "DL");
126+
CHECK(uplink != downlink);
127+
128+
// Validate and lower-case the name to make a DTS symbol
129+
char sym[64];
130+
CHECK(strlen(m->name) < sizeof(sym));
131+
strcpy(sym, m->name);
132+
symify(sym);
133+
134+
//printf("memif %d %s dai %d %s\n", i, sym, dai_id, downlink ? "downlink" : "");
135+
136+
printf("\t" "afe_%s: afe_%s {\n", sym, sym);
137+
printf("\t\t" "compatible = \"mediatek,afe\";\n");
138+
printf("\t\t" "afe_name = \"%s\";\n", m->name);
139+
printf("\t\t" "dai_id = <%d>;\n", dai_id);
140+
if (downlink)
141+
printf("\t\t" "downlink;\n");
142+
143+
/* Register pairs containing the high and low words of
144+
* bus/host addresses. The first (high) register is allowed
145+
* to be zero indicating all addresses will be 32 bit.
146+
*/
147+
printf("\t\t" "base = <0x%8.8x 0x%8.8x>;\n",
148+
msbaddr(m->reg_ofs_base_msb), m->reg_ofs_base + afe_base_addr);
149+
printf("\t\t" "cur = <0x%8.8x 0x%8.8x>;\n",
150+
msbaddr(m->reg_ofs_cur_msb), m->reg_ofs_cur + afe_base_addr);
151+
printf("\t\t" "end = <0x%8.8x 0x%8.8x>;\n",
152+
msbaddr(m->reg_ofs_end_msb), m->reg_ofs_end + afe_base_addr);
153+
154+
print_fld("fs", m->fs_reg, m->fs_shift, m->fs_maskbit);
155+
print_fld("mono", m->mono_reg, m->mono_shift, 1);
156+
if (m->mono_invert)
157+
printf("\t\t" "mono_invert;\n");
158+
print_fld("quad_ch", m->quad_ch_reg, m->quad_ch_shift, m->quad_ch_mask);
159+
print_fld("int_odd", m->int_odd_flag_reg, m->int_odd_flag_shift, 1);
160+
print_fld("enable", m->enable_reg, m->enable_shift, 1);
161+
print_fld("hd", m->hd_reg, m->hd_shift, 1);
162+
print_fld("msb", m->msb_reg, m->msb_shift, 1);
163+
print_fld("msb2", m->msb2_reg, m->msb2_shift, 1);
164+
print_fld("agent_disable", m->agent_disable_reg, m->agent_disable_shift, 1);
165+
print_fld("ch_num", m->ch_num_reg, m->ch_num_shift, m->ch_num_maskbit);
166+
167+
// Note: there are also "pbuf" and "minlen" registers defined
168+
// in the memif_data struct, but they are unused by the
169+
// existing driver.
170+
171+
printf("\t" "};\n\n");
172+
}
173+
}
174+

0 commit comments

Comments
 (0)