forked from thesofproject/sof
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <andyross@google.com>
- Loading branch information
Showing
3 changed files
with
219 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
|
||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#!/bin/sh | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
# Copyright(c) 2024 Google LLC. All rights reserved. | ||
# Author: Andy Ross <andyross@google.com> | ||
set -ex | ||
|
||
PLATFORMS="$*" | ||
if [ -z "$PLATFORMS" ]; then | ||
PLATFORMS="mt8195 mt8188 mt8186 mt8196" | ||
fi | ||
|
||
SOF=`cd ../../../..; /bin/pwd` | ||
|
||
for p in $PLATFORMS; do | ||
|
||
SRCS="$SOF/src/platform/$p/lib/dai.c $SOF/src/platform/$p/afe-platform.c" | ||
|
||
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" | ||
|
||
DEFS="-DRELATIVE_FILE=\"mt-dai-gen.c\" -DCONFIG_CORE_COUNT=1 -DCONFIG_IPC_MAJOR_3=1" | ||
|
||
touch uuid-registry.h | ||
INCS="$INCS -I." | ||
|
||
gcc -g -Wall -Werror -m32 -o mt-dai-gen mt-dai-gen.c $SRCS $INCS $DEFS | ||
|
||
./mt-dai-gen > afe-${p}.dts | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
// Copyright(c) 2024 Google LLC. All rights reserved. | ||
// Author: Andy Ross <andyross@google.com> | ||
#include <sof/lib/dai-legacy.h> | ||
#include <sof/drivers/afe-drv.h> | ||
#include <stdio.h> | ||
|
||
/* DIY assertion, an "assert()" is already defined in platform headers */ | ||
#define CHECK(expr) if(!(expr)) { \ | ||
printf("FAILED: " #expr " at line %d\n", __LINE__); *(int*)0=0; } | ||
|
||
/* These are the symbols we need to enumerate */ | ||
extern struct mtk_base_afe_platform mtk_afe_platform; | ||
extern const struct dai_info lib_dai; | ||
|
||
/* Call this to initialize the dai arrays */ | ||
int dai_init(struct sof *sof); | ||
|
||
/* Debug hook in some versions of MTK firmware */ | ||
void printf_(void) {} | ||
|
||
/* Just need a pointer to a symbol with this name */ | ||
int afe_dai_driver; | ||
|
||
/* So dai_init() can write to something */ | ||
struct sof sof; | ||
|
||
unsigned int afe_base_addr; | ||
|
||
void symify(char *s) | ||
{ | ||
for(; *s; s++) { | ||
if (*s >= 'A' && *s <= 'Z') | ||
*s += 'a' - 'A'; | ||
CHECK((*s >= 'a' && *s <= 'z') || (*s >= '0' && *s <= '9') || *s == '_'); | ||
} | ||
} | ||
|
||
/* The AFE driver has some... idiosyncratic defaulting. The existing | ||
* configurations have a varying set of conventions to encode "no | ||
* value is set": | ||
* | ||
* ch_num is skipped if the stored reg value is negative | ||
* quad_ch is skipped if the mask is zero | ||
* int_odd: <=0 reg | ||
* mono: <=0 reg OR <=0 shift | ||
* msb: <=0 reg | ||
* msb2: <=0 reg | ||
* agent_disable: <=0 reg | ||
* fs: never skipped | ||
* hd: never skipped | ||
* enable: never skipped | ||
* | ||
* We detect the union of those conditions and elide the setting (it | ||
* will be defaulted to reg=-1/shift=0/mask=0 in the driver DTS macros) | ||
*/ | ||
void print_fld(const char *name, int reg, int shift, int lomask) | ||
{ | ||
if (reg <= 0 || shift < 0 || lomask == 0) { | ||
return; | ||
} | ||
|
||
int bits = __builtin_ffs(lomask + 1) - 1; | ||
|
||
CHECK(((lomask + 1) & lomask) == 0); // must be power of two | ||
CHECK(lomask); // and not zero | ||
CHECK(shift >= 0 && (shift + bits) <= 32); // and shift doesn't overrun | ||
|
||
printf("\t\t" "%s = <0x%8.8x %d %d>;\n", | ||
name, reg + afe_base_addr, shift, bits); | ||
} | ||
|
||
unsigned int msbaddr(int val) | ||
{ | ||
return val ? val + afe_base_addr : 0; | ||
} | ||
|
||
int main(void) | ||
{ | ||
dai_init(&sof); | ||
|
||
afe_base_addr = mtk_afe_platform.base_addr; | ||
|
||
// The DAI order here is immutable: the indexes are known to and | ||
// used by the kernel driver. And these point to the memif array | ||
// via an index stored in the low byte (?!) of the first fifo's | ||
// "handshake" (it's not a DMA handshake value at all). So we | ||
// invert the mapping and store the dai index along with the AFE | ||
// record. | ||
int dai_memif[64]; | ||
int num_dais = 0; | ||
for (int t = 0; t < lib_dai.num_dai_types; t++) { | ||
for (int i = 0; i < lib_dai.dai_type_array[t].num_dais; i++) { | ||
int idx = lib_dai.dai_type_array[t].dai_array[i].index; | ||
int hs = lib_dai.dai_type_array[t].dai_array[i].plat_data.fifo[0].handshake; | ||
|
||
CHECK(idx == num_dais); | ||
dai_memif[num_dais++] = hs >> 16; | ||
} | ||
} | ||
|
||
// Quick check that the dai/memif mapping is unique | ||
for(int i=0; i<num_dais; i++) { | ||
int n = 0; | ||
for(int j=0; j<num_dais; j++) | ||
if(dai_memif[j] == i) | ||
n++; | ||
CHECK(n == 1); | ||
} | ||
|
||
for (int i = 0; i < mtk_afe_platform.memif_size; i++) { | ||
const struct mtk_base_memif_data *m = &mtk_afe_platform.memif_datas[i]; | ||
|
||
int dai_id = -1; | ||
for (int j = 0; j < num_dais; j++) { | ||
if (dai_memif[j] == i) { | ||
dai_id = j; | ||
break; | ||
} | ||
} | ||
CHECK(dai_id >= 0); | ||
|
||
// We use the UL/DL naming to detect direction, make sure it isn't broken | ||
bool uplink = !!strstr(m->name, "UL"); | ||
bool downlink = !!strstr(m->name, "DL"); | ||
CHECK(uplink != downlink); | ||
|
||
// Validate and lower-case the name to make a DTS symbol | ||
char sym[64]; | ||
CHECK(strlen(m->name) < sizeof(sym)); | ||
strcpy(sym, m->name); | ||
symify(sym); | ||
|
||
//printf("memif %d %s dai %d %s\n", i, sym, dai_id, downlink ? "downlink" : ""); | ||
|
||
printf("\t" "afe_%s: afe_%s {\n", sym, sym); | ||
printf("\t\t" "compatible = \"mediatek,afe\";\n"); | ||
printf("\t\t" "afe_name = \"%s\";\n", m->name); | ||
printf("\t\t" "dai_id = <%d>;\n", dai_id); | ||
if (downlink) | ||
printf("\t\t" "downlink;\n"); | ||
|
||
/* Register pairs containing the high and low words of | ||
* bus/host addresses. The first (high) register is allowed | ||
* to be zero indicating all addresses will be 32 bit. | ||
*/ | ||
printf("\t\t" "base = <0x%8.8x 0x%8.8x>;\n", | ||
msbaddr(m->reg_ofs_base_msb), m->reg_ofs_base + afe_base_addr); | ||
printf("\t\t" "cur = <0x%8.8x 0x%8.8x>;\n", | ||
msbaddr(m->reg_ofs_cur_msb), m->reg_ofs_cur + afe_base_addr); | ||
printf("\t\t" "end = <0x%8.8x 0x%8.8x>;\n", | ||
msbaddr(m->reg_ofs_end_msb), m->reg_ofs_end + afe_base_addr); | ||
|
||
print_fld("fs", m->fs_reg, m->fs_shift, m->fs_maskbit); | ||
print_fld("mono", m->mono_reg, m->mono_shift, 1); | ||
if (m->mono_invert) | ||
printf("\t\t" "mono_invert;\n"); | ||
print_fld("quad_ch", m->quad_ch_reg, m->quad_ch_shift, m->quad_ch_mask); | ||
print_fld("int_odd", m->int_odd_flag_reg, m->int_odd_flag_shift, 1); | ||
print_fld("enable", m->enable_reg, m->enable_shift, 1); | ||
print_fld("hd", m->hd_reg, m->hd_shift, 1); | ||
print_fld("msb", m->msb_reg, m->msb_shift, 1); | ||
print_fld("msb2", m->msb2_reg, m->msb2_shift, 1); | ||
print_fld("agent_disable", m->agent_disable_reg, m->agent_disable_shift, 1); | ||
print_fld("ch_num", m->ch_num_reg, m->ch_num_shift, m->ch_num_maskbit); | ||
|
||
// Note: there are also "pbuf" and "minlen" registers defined | ||
// in the memif_data struct, but they are unused by the | ||
// existing driver. | ||
|
||
printf("\t" "};\n\n"); | ||
} | ||
} | ||
|