diff --git a/app/boards/mt8186_mt8186_adsp.conf b/app/boards/mt8186_mt8186_adsp.conf new file mode 100644 index 000000000000..0d44864b6144 --- /dev/null +++ b/app/boards/mt8186_mt8186_adsp.conf @@ -0,0 +1,6 @@ +# Boilerplate. Because the "Platform" is a kconfig "choice" (of which +# "MTK" is an member), it can't be selected automatically from other +# kconfigs, nor expressed as a default. Don't put anything else here. +# Board-level config goes in Zephyr (and ideally in DTS). App-level +# config goes in prj.conf. +CONFIG_MTK=y diff --git a/app/boards/mt8188_mt8188_adsp.conf b/app/boards/mt8188_mt8188_adsp.conf new file mode 100644 index 000000000000..0d44864b6144 --- /dev/null +++ b/app/boards/mt8188_mt8188_adsp.conf @@ -0,0 +1,6 @@ +# Boilerplate. Because the "Platform" is a kconfig "choice" (of which +# "MTK" is an member), it can't be selected automatically from other +# kconfigs, nor expressed as a default. Don't put anything else here. +# Board-level config goes in Zephyr (and ideally in DTS). App-level +# config goes in prj.conf. +CONFIG_MTK=y diff --git a/app/boards/mt8195_mt8195_adsp.conf b/app/boards/mt8195_mt8195_adsp.conf new file mode 100644 index 000000000000..0d44864b6144 --- /dev/null +++ b/app/boards/mt8195_mt8195_adsp.conf @@ -0,0 +1,6 @@ +# Boilerplate. Because the "Platform" is a kconfig "choice" (of which +# "MTK" is an member), it can't be selected automatically from other +# kconfigs, nor expressed as a default. Don't put anything else here. +# Board-level config goes in Zephyr (and ideally in DTS). App-level +# config goes in prj.conf. +CONFIG_MTK=y diff --git a/app/boards/mt8196_mt8196_adsp.conf b/app/boards/mt8196_mt8196_adsp.conf new file mode 100644 index 000000000000..0d44864b6144 --- /dev/null +++ b/app/boards/mt8196_mt8196_adsp.conf @@ -0,0 +1,6 @@ +# Boilerplate. Because the "Platform" is a kconfig "choice" (of which +# "MTK" is an member), it can't be selected automatically from other +# kconfigs, nor expressed as a default. Don't put anything else here. +# Board-level config goes in Zephyr (and ideally in DTS). App-level +# config goes in prj.conf. +CONFIG_MTK=y diff --git a/scripts/xtensa-build-zephyr.py b/scripts/xtensa-build-zephyr.py index 5ce0c633ae7c..3463c64ec083 100755 --- a/scripts/xtensa-build-zephyr.py +++ b/scripts/xtensa-build-zephyr.py @@ -104,6 +104,28 @@ class PlatformConfig: "rmb_LX7_HiFi5_PROD", RIMAGE_KEY = "key param ignored by acp_6_0" ), + # MediaTek platforms + # (move to platform_configs_all on next Zephyr SDK release after 0.17.0) + "mt8195" : PlatformConfig( + "mtk", "mt8195/mt8195/adsp", + f"RJ-2024.3{xtensa_tools_version_postfix}", + "hifi4_8195_PROD", + ), + "mt8186" : PlatformConfig( + "mtk", "mt8186/mt8186/adsp", + f"RJ-2024.3{xtensa_tools_version_postfix}", + "hifi5_7stg_I64D128", + ), + "mt8188" : PlatformConfig( + "mtk", "mt8188/mt8188/adsp", + f"RJ-2024.3{xtensa_tools_version_postfix}", + "hifi5_7stg_I64D128", + ), + "mt8196" : PlatformConfig( + "mtk", "mt8196/mt8196/adsp", + f"RJ-2024.3{xtensa_tools_version_postfix}", + "HiFi5_MPU_lock_2023_11", + ), } # These can all be built out of the box. --all builds all these. @@ -1173,7 +1195,7 @@ def gzip_compress(fname, gzdst=None): RI_INFO_UNSUPPORTED += ['imx8', 'imx8x', 'imx8m', 'imx8ulp', 'imx95'] RI_INFO_UNSUPPORTED += ['rn', 'acp_6_0'] -RI_INFO_UNSUPPORTED += ['mt8186', 'mt8195'] +RI_INFO_UNSUPPORTED += ['mt8186', 'mt8188', 'mt8195', 'mt8196'] # For temporary workarounds. Unlike _UNSUPPORTED above, the platforms below will print a warning. RI_INFO_FIXME = [ ] diff --git a/src/drivers/mediatek/afe/afe-dai.c b/src/drivers/mediatek/afe/afe-dai.c index a0b3450515a9..b8225471e5f0 100644 --- a/src/drivers/mediatek/afe/afe-dai.c +++ b/src/drivers/mediatek/afe/afe-dai.c @@ -27,6 +27,7 @@ SOF_DEFINE_REG_UUID(afe_dai); DECLARE_TR_CTX(afe_dai_tr, SOF_UUID(afe_dai_uuid), LOG_LEVEL_INFO); +LOG_MODULE_DECLARE(mtk_afe, CONFIG_SOF_LOG_LEVEL); static int afe_dai_drv_trigger(struct dai *dai, int cmd, int direction) { diff --git a/src/drivers/mediatek/afe/afe-drv.c b/src/drivers/mediatek/afe/afe-drv.c index b9cf29eaa654..c5b27f772b7b 100644 --- a/src/drivers/mediatek/afe/afe-drv.c +++ b/src/drivers/mediatek/afe/afe-drv.c @@ -29,6 +29,7 @@ static struct mtk_base_afe mtk_afe; SOF_DEFINE_REG_UUID(afedrv); DECLARE_TR_CTX(afedrv_tr, SOF_UUID(afedrv_uuid), LOG_LEVEL_INFO); +LOG_MODULE_DECLARE(mtk_afe, CONFIG_SOF_LOG_LEVEL); static inline void afe_reg_read(struct mtk_base_afe *afe, uint32_t reg, uint32_t *value) { diff --git a/src/drivers/mediatek/afe/afe-memif.c b/src/drivers/mediatek/afe/afe-memif.c index 5fdba9b17fd9..9fb691622a92 100644 --- a/src/drivers/mediatek/afe/afe-memif.c +++ b/src/drivers/mediatek/afe/afe-memif.c @@ -29,6 +29,7 @@ SOF_DEFINE_REG_UUID(memif); DECLARE_TR_CTX(memif_tr, SOF_UUID(memif_uuid), LOG_LEVEL_INFO); +LOG_MODULE_REGISTER(mtk_afe, CONFIG_SOF_LOG_LEVEL); struct afe_memif_dma { int direction; /* 1 downlink, 0 uplink */ diff --git a/src/platform/Kconfig b/src/platform/Kconfig index 684f775049aa..f476d0610683 100644 --- a/src/platform/Kconfig +++ b/src/platform/Kconfig @@ -231,7 +231,7 @@ config ACP_7_0 Select if your target platform is acp_7_0-compatible config MT8186 - bool "Build for MTK MT8186" + bool "Build for MTK MT8186 (XTOS)" select XT_INTERRUPT_LEVEL_1 select XT_INTERRUPT_LEVEL_2 select XT_INTERRUPT_LEVEL_3 @@ -244,9 +244,10 @@ config MT8186 select SCHEDULE_DMA_MULTI_CHANNEL help Select if your target platform is mt8186-compatible + Builds legacy/xtos firmware config MT8188 - bool "Build for MTK MT8188" + bool "Build for MTK MT8188 (XTOS)" select XT_INTERRUPT_LEVEL_1 select XT_INTERRUPT_LEVEL_2 select XT_INTERRUPT_LEVEL_3 @@ -259,9 +260,10 @@ config MT8188 select SCHEDULE_DMA_MULTI_CHANNEL help Select if your target platform is mt8188-compatible. + Builds legacy/xtos firmware config MT8195 - bool "Build for MTK MT8195" + bool "Build for MTK MT8195 (XTOS)" select XT_INTERRUPT_LEVEL_1 select XT_INTERRUPT_LEVEL_2 select XT_INTERRUPT_LEVEL_3 @@ -272,6 +274,14 @@ config MT8195 select SCHEDULE_DMA_MULTI_CHANNEL help Select if your target platform is mt8195-compatible + Builds legacy/xtos firmware + +config MTK + bool "Build for Mediatek (Zephyr)" + select SCHEDULE_DMA_MULTI_CHANNEL + select HOST_PTABLE + help + Select if your target is a Mediatek DSP. Builds Zephyr firmware. endchoice diff --git a/src/platform/mtk/dai.c b/src/platform/mtk/dai.c new file mode 100644 index 000000000000..0cc22445ca2f --- /dev/null +++ b/src/platform/mtk/dai.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright(c) 2024 Google LLC. All rights reserved. +// Author: Andy Ross +#include +#include +#include + +/* The legacy driver stores register addresses as an offset from an + * arbitrary base address (which is not actually a unified block of + * AFE-related registers), where DTS naturally wants to provide full + * addresses. We store the base here, pending a Zephyrized driver. + */ +#if defined(CONFIG_SOC_MT8186) +#define MTK_AFE_BASE 0x11210000 +#elif defined(CONFIG_SOC_SERIES_MT818X) +#define MTK_AFE_BASE 0x10b10000 +#elif defined(CONFIG_SOC_MT8195) +#define MTK_AFE_BASE 0x10890000 +#elif defined(CONFIG_SOC_MT8196) +#define MTK_AFE_BASE 0x1a110000 +#else +#error Unrecognized device +#endif + +/* Bitfield register: address, left shift amount, and number of bits */ +struct afe_bitfld { + uint32_t reg; + uint8_t shift; + uint8_t bits; +}; + +/* Pair of registers to store a 64 bit host/bus address */ +struct afe_busreg { + uint32_t hi; + uint32_t lo; +}; + +/* Config struct for a DTS-defined AFE device */ +struct afe_cfg { + char afe_name[32]; + int dai_id; + bool downlink; + bool mono_invert; + struct afe_busreg base; + struct afe_busreg end; + struct afe_busreg cur; + struct afe_bitfld fs; + struct afe_bitfld hd; + struct afe_bitfld enable; + struct afe_bitfld mono; + struct afe_bitfld quad_ch; + struct afe_bitfld int_odd; + struct afe_bitfld msb; + struct afe_bitfld msb2; + struct afe_bitfld agent_disable; + struct afe_bitfld ch_num; +}; + +/* Converts the DTS_derived afe_cfg struct to a runtime memif_data for + * use by the legacy driver. This is temporary, pending a + * Zephyrization port that will get the driver using the config struct + * directly. + * + * Note the preprocessor trickery to help mapping the regularized DTS + * data to the "almost but not quite convention-conforming" original + * naming. Mostly just some naming quirks. The only semantic + * differences are that the register addresses in DTS become offsets + * from MTK_AFE_BASE, that default/unset register addresses are stored + * as -1 and not NULL. + */ +static void cfg_convert(const struct afe_cfg *src, struct mtk_base_memif_data *dst) +{ +#define REGCVT(R) (((R) > 0) ? ((R) - MTK_AFE_BASE) : -1) + +#define COPYBIT(S, Dr, Ds) do { \ + dst->Dr = REGCVT(src->S.reg); \ + dst->Ds = src->S.shift; \ + } while (0) + +#define COPYFLD(S, Dr, Ds, Dm) do { \ + COPYBIT(S, Dr, Ds); \ + dst->Dm = BIT(src->S.bits) - 1; \ + } while (0) + +#define COPY2(F) COPYBIT(F, F##_reg, F##_shift) +#define COPY3(F) COPYFLD(F, F##_reg, F##_shift, F##_mask) + + dst->name = src->afe_name; /* DTS values are string literals */ + dst->reg_ofs_base = REGCVT(src->base.lo); + dst->reg_ofs_cur = REGCVT(src->cur.lo); + dst->reg_ofs_end = REGCVT(src->end.lo); + dst->reg_ofs_base_msb = REGCVT(src->base.hi); + dst->reg_ofs_cur_msb = REGCVT(src->cur.hi); + dst->reg_ofs_end_msb = REGCVT(src->end.hi); + dst->mono_invert = src->mono_invert; + + COPYFLD(fs, fs_reg, fs_shift, fs_maskbit); + COPY2(mono); + COPY3(quad_ch); + COPYBIT(int_odd, int_odd_flag_reg, int_odd_flag_shift); + COPY2(enable); + COPY2(hd); + COPY2(msb); + COPY2(msb2); + COPY2(agent_disable); + COPYFLD(ch_num, ch_num_reg, ch_num_shift, ch_num_maskbit); + +#undef REGCVT +#undef COPYBIT +#undef COPYFLD +#undef COPY2 +#undef COPY3 +} + +/* Some properties may be skipped/defaulted in DTS, leave them zero-filled */ +#define COND_PROP(n, prop) \ + IF_ENABLED(DT_NODE_HAS_PROP(n, prop), (.prop = DT_PROP(n, prop),)) + +#define GENAFE(n) { \ + .afe_name = DT_PROP(n, afe_name), \ + .dai_id = DT_PROP(n, dai_id), \ + .downlink = DT_PROP(n, downlink), \ + .mono_invert = DT_PROP(n, mono_invert), \ + .base = DT_PROP(n, base), \ + .end = DT_PROP(n, end), \ + .cur = DT_PROP(n, cur), \ + .fs = DT_PROP(n, fs), \ + .hd = DT_PROP(n, hd), \ + .enable = DT_PROP(n, enable), \ + COND_PROP(n, mono) \ + COND_PROP(n, quad_ch) \ + COND_PROP(n, int_odd) \ + COND_PROP(n, msb) \ + COND_PROP(n, msb2) \ + COND_PROP(n, agent_disable) \ + COND_PROP(n, ch_num) \ + }, + +static const struct afe_cfg afes[] = { + DT_FOREACH_STATUS_OKAY(mediatek_afe, GENAFE) +}; + +#define EMPTY_STRUCT(n) {}, + +static struct mtk_base_memif_data afe_memifs[] = { + DT_FOREACH_STATUS_OKAY(mediatek_afe, EMPTY_STRUCT) +}; + +static struct dai mtk_dais[] = { + DT_FOREACH_STATUS_OKAY(mediatek_afe, EMPTY_STRUCT) +}; + +extern const struct dma_ops memif_ops; +extern const struct dma_ops dummy_dma_ops; + +// FIXME: remove this ID field? Nothing seems to use it +enum dma_id { + DMA_ID_AFE_MEMIF, + DMA_ID_HOST, +}; + +static struct dma mtk_dma[] = { + { + .plat_data = { + .id = DMA_ID_HOST, + .dir = DMA_DIR_HMEM_TO_LMEM | DMA_DIR_LMEM_TO_HMEM, + .devs = DMA_DEV_HOST, + .channels = 16, + }, + .ops = &dummy_dma_ops, + }, + { + .plat_data = { + .id = DMA_ID_AFE_MEMIF, + .dir = DMA_DIR_MEM_TO_DEV | DMA_DIR_DEV_TO_MEM, + .devs = SOF_DMA_DEV_AFE_MEMIF, + .base = MTK_AFE_BASE, + .channels = ARRAY_SIZE(mtk_dais), + }, + .ops = &memif_ops, + }, +}; + +static const struct dma_info mtk_dma_info = { + .dma_array = mtk_dma, + .num_dmas = ARRAY_SIZE(mtk_dma), +}; + +static const struct dai_type_info mtk_dai_types[] = { + { + .type = SOF_DAI_MEDIATEK_AFE, + .dai_array = mtk_dais, + .num_dais = ARRAY_SIZE(mtk_dais), + }, +}; + +static const struct dai_info mtk_dai_info = { + .dai_type_array = mtk_dai_types, + .num_dai_types = ARRAY_SIZE(mtk_dai_types), +}; + +/* Static table of fs register values. TODO: binary search */ +static unsigned int mtk_afe_fs_timing(unsigned int rate) +{ + static const struct { int hz, reg; } rate2reg[] = { + { 8000, 0 }, + { 11025, 1 }, + { 12000, 2 }, + { 16000, 4 }, + { 22050, 5 }, + { 24000, 6 }, + { 32000, 8 }, + { 44100, 9 }, + { 48000, 10 }, + { 88200, 13 }, + { 96000, 14 }, + { 176400, 17 }, + { 192000, 18 }, + { 352800, 21 }, + { 384000, 22 }, + }; + + for (int i = 0; i < ARRAY_SIZE(rate2reg); i++) + if (rate2reg[i].hz == rate) + return rate2reg[i].reg; + return -EINVAL; +} + +static unsigned int mtk_afe_fs(unsigned int rate, int aud_blk) +{ + return mtk_afe_fs_timing(rate); +} + +/* Global symbol referenced by AFE driver */ +struct mtk_base_afe_platform mtk_afe_platform = { + .base_addr = MTK_AFE_BASE, + .memif_datas = afe_memifs, + .memif_size = ARRAY_SIZE(afe_memifs), + .memif_32bit_supported = 0, + .irq_datas = NULL, + .irqs_size = 0, + .dais_size = ARRAY_SIZE(mtk_dais), + .afe_fs = mtk_afe_fs, + .irq_fs = mtk_afe_fs_timing, +}; + +int mtk_dai_init(struct sof *sof) +{ + int i; + + /* Convert our DTS-defined AFE devices to legacy memif structs */ + for (i = 0; i < ARRAY_SIZE(afes); i++) { + afe_memifs[i].id = i; + cfg_convert(&afes[i], &afe_memifs[i]); + + /* Also initialize the dais array */ + extern const struct dai_driver afe_dai_driver; + + mtk_dais[i].index = i; + mtk_dais[i].drv = &afe_dai_driver; + + /* Also construct the mtk_dais[] array, which is the + * mapping from the host-visible DAI index to a driver + * defined in afe_memifs[]. The mapping is ad-hoc, + * and stored, bitpacked, in the "handshake" variable + * in plat data. The DAI index is the low byte, the + * AFE index is in the third byte. There is an IRQ + * traditionally defined in the middle byte but unused + * here because the driver doesn't support + * interrupts. + */ + int di = afes[i].dai_id; + int hs = (i << 16) | di; + + mtk_dais[di].plat_data.fifo[0].handshake = hs; + } + + /* DTS stores the direction as a boolean property, but the + * legacy driver wants all the DL devices at the start of the + * array. Compute memif_dl_num (and validate the order!). + */ + for (i = 0; i < ARRAY_SIZE(afes); i++) { + if (!afes[i].downlink) { + mtk_afe_platform.memif_dl_num = i; + break; + } + } + for (/**/; i < ARRAY_SIZE(afes); i++) + __ASSERT_NO_MSG(!afes[i].downlink); + + sof->dai_info = &mtk_dai_info; + sof->dma_info = &mtk_dma_info; + return 0; +} diff --git a/src/platform/mtk/include/platform/lib/clk.h b/src/platform/mtk/include/platform/lib/clk.h new file mode 100644 index 000000000000..de604ef4001d --- /dev/null +++ b/src/platform/mtk/include/platform/lib/clk.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Google LLC. All rights reserved. + * Author: Andy Ross + */ +#ifndef _SOF_PLATFORM_MTK_LIB_CLK_H +#define _SOF_PLATFORM_MTK_LIB_CLK_H + +#define CLK_CPU(x) (x) + +// FIXME: set correctly from mtk_adsp layer! +#define CLK_MAX_CPU_HZ CONFIG_XTENSA_CCOUNT_HZ + +#endif /* _SOF_PLATFORM_MTK_LIB_CLK_H */ diff --git a/src/platform/mtk/include/platform/lib/cpu.h b/src/platform/mtk/include/platform/lib/cpu.h new file mode 100644 index 000000000000..bd2b0c29640d --- /dev/null +++ b/src/platform/mtk/include/platform/lib/cpu.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Google LLC. All rights reserved. + * Author: Andy Ross + */ +#ifndef _SOF_PLATFORM_MTK_LIB_CPU_H +#define _SOF_PLATFORM_MTK_LIB_CPU_H + +#define PLATFORM_PRIMARY_CORE_ID 0 + +#endif /* _SOF_PLATFORM_MTK_LIB_CPU_H */ diff --git a/src/platform/mtk/include/platform/lib/dai.h b/src/platform/mtk/include/platform/lib/dai.h new file mode 100644 index 000000000000..82fca579236c --- /dev/null +++ b/src/platform/mtk/include/platform/lib/dai.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Google LLC. All rights reserved. + * Author: Andy Ross + */ +#ifndef _SOF_PLATFORM_MTK_LIB_DAI_H +#define _SOF_PLATFORM_MTK_LIB_DAI_H + +/* No symbols needed from this header, but included anyway */ + +#endif /* _SOF_PLATFORM_MTK_LIB_DAI_H */ diff --git a/src/platform/mtk/include/platform/lib/dma.h b/src/platform/mtk/include/platform/lib/dma.h new file mode 100644 index 000000000000..42f8adc4190b --- /dev/null +++ b/src/platform/mtk/include/platform/lib/dma.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Google LLC. All rights reserved. + * Author: Andy Ross + */ +#ifndef _SOF_PLATFORM_MTK_DMA_H +#define _SOF_PLATFORM_MTK_DMA_H + +/* Only needed in dma_multi_chan_domain.c */ +#define PLATFORM_NUM_DMACS 2 +#define PLATFORM_MAX_DMA_CHAN 32 + +#define dma_chan_irq(dma, chan) dma_irq(dma) +#define dma_chan_irq_name(dma, chan) dma_irq_name(dma) + +#endif /* _SOF_PLATFORM_MTK_DMA_H */ diff --git a/src/platform/mtk/include/platform/lib/mailbox.h b/src/platform/mtk/include/platform/lib/mailbox.h new file mode 100644 index 000000000000..1157730ead57 --- /dev/null +++ b/src/platform/mtk/include/platform/lib/mailbox.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Google LLC. All rights reserved. + * Author: Andy Ross + */ +#ifndef _SOF_PLATFORM_MTK_LIB_MAILBOX_H +#define _SOF_PLATFORM_MTK_LIB_MAILBOX_H + +#include "memory.h" + +#define MAILBOX_DSPBOX_BASE MTK_IPC_WIN_BASE(UPBOX) +#define MAILBOX_DSPBOX_SIZE MTK_IPC_WIN_SIZE(UPBOX) + +#define MAILBOX_HOSTBOX_BASE MTK_IPC_WIN_BASE(DOWNBOX) +#define MAILBOX_HOSTBOX_SIZE MTK_IPC_WIN_SIZE(DOWNBOX) + +#define MAILBOX_STREAM_BASE MTK_IPC_WIN_BASE(STREAM) +#define MAILBOX_STREAM_SIZE MTK_IPC_WIN_SIZE(STREAM) + +#endif /* _SOF_PLATFORM_MTK_LIB_MAILBOX_H */ diff --git a/src/platform/mtk/include/platform/lib/memory.h b/src/platform/mtk/include/platform/lib/memory.h new file mode 100644 index 000000000000..a84809bf2d48 --- /dev/null +++ b/src/platform/mtk/include/platform/lib/memory.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Google LLC. All rights reserved. + * Author: Andy Ross + */ +#ifndef _SOF_PLATFORM_MTK_LIB_MEMORY_H +#define _SOF_PLATFORM_MTK_LIB_MEMORY_H + +#include +#include + +#define PLATFORM_DCACHE_ALIGN 128 + +/* Sigh, too many ways to get this wrong... */ +BUILD_ASSERT(PLATFORM_DCACHE_ALIGN == XCHAL_DCACHE_LINESIZE); + +#define uncache_to_cache(addr) (addr) +#define cache_to_uncache(addr) (addr) + +static inline void *platform_shared_get(void *ptr, int bytes) +{ + return ptr; +} + +#define host_to_local(addr) (addr) + +#define PLATFORM_HEAP_SYSTEM 1 +#define PLATFORM_HEAP_SYSTEM_RUNTIME 1 +#define PLATFORM_HEAP_RUNTIME 1 +#define PLATFORM_HEAP_BUFFER 1 + +#define SHARED_DATA /* no special section attribute needed */ + +/* Mailbox window addresses for the rimage extended manifest. The + * struct is optimized out in generated code, it's just here to be a + * little clearer than the pages of #defines used traditionally. + * + * 8195 puts the window region at 8M into the DRAM memory space, + * everything else at 5M. Note that these are linkable addresses! + * There's nothing preventing a symbol from ending up here except the + * fact that SOF isn't (remotely) that big. Long term we should move + * this stuff into regular .bss/.noinit symbols, but that requires + * validation that the kernel driver interprets the manifest + * correctly. Right now we're using the historical addresses. + */ +#ifdef CONFIG_SOC_MT8195 +#define MTK_IPC_BASE (DT_REG_ADDR(DT_NODELABEL(dram0)) + 0x800000) +#else +#define MTK_IPC_BASE (DT_REG_ADDR(DT_NODELABEL(dram0)) + 0x500000) +#endif + +/* Beware: the first two buffers are variously labelled UP/DOWN OUT/IN + * and DSP/HOST, and the correspondance isn't as clear as one would + * want. + */ +#define _MTK_WIN_SZ_K_UPBOX 4 +#define _MTK_WIN_SZ_K_DOWNBOX 4 +#define _MTK_WIN_SZ_K_DEBUG 2 +#define _MTK_WIN_SZ_K_EXCEPTION 2 +#define _MTK_WIN_SZ_K_STREAM 4 +#define _MTK_WIN_SZ_K_TRACE 4 + +#define _MTK_WIN_OFF_K_UPBOX 0 +#define _MTK_WIN_OFF_K_DOWNBOX (_MTK_WIN_SZ_K_UPBOX) +#define _MTK_WIN_OFF_K_DEBUG (_MTK_WIN_SZ_K_DOWNBOX + _MTK_WIN_OFF_K_DOWNBOX) +#define _MTK_WIN_OFF_K_EXCEPTION (_MTK_WIN_SZ_K_DEBUG + _MTK_WIN_OFF_K_DEBUG) +#define _MTK_WIN_OFF_K_STREAM (_MTK_WIN_SZ_K_EXCEPTION + _MTK_WIN_OFF_K_EXCEPTION) +#define _MTK_WIN_OFF_K_TRACE (_MTK_WIN_SZ_K_STREAM + _MTK_WIN_OFF_K_STREAM) + +#define MTK_IPC_WIN_OFF(reg) (1024 * _MTK_WIN_OFF_K_##reg) +#define MTK_IPC_WIN_SIZE(reg) (1024 * _MTK_WIN_SZ_K_##reg) +#define MTK_IPC_WIN_BASE(reg) (MTK_IPC_BASE + MTK_IPC_WIN_OFF(reg)) + +#endif /* _SOF_PLATFORM_MTK_LIB_MEMORY_H */ diff --git a/src/platform/mtk/include/platform/lib/pm_runtime.h b/src/platform/mtk/include/platform/lib/pm_runtime.h new file mode 100644 index 000000000000..4d3bc1b3e1ef --- /dev/null +++ b/src/platform/mtk/include/platform/lib/pm_runtime.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Google LLC. All rights reserved. + * Author: Andy Ross + */ +#ifndef _SOF_PLATFORM_MTK_LIB_PM_RUNTIME_H +#define _SOF_PLATFORM_MTK_LIB_PM_RUNTIME_H + +#include + +struct pm_runtime_data; + +static inline void platform_pm_runtime_init(struct pm_runtime_data *prd) +{ +} + +static inline void platform_pm_runtime_get(uint32_t context, uint32_t index, uint32_t flags) +{ +} + +static inline void platform_pm_runtime_put(uint32_t context, uint32_t index, uint32_t flags) +{ +} + +static inline void platform_pm_runtime_enable(uint32_t context, uint32_t index) +{ +} + +static inline void platform_pm_runtime_disable(uint32_t context, uint32_t index) +{ +} + +static inline bool platform_pm_runtime_is_active(uint32_t context, uint32_t index) +{ + return false; +} + +#endif /* _SOF_PLATFORM_MTK_LIB_PM_RUNTIME_H */ diff --git a/src/platform/mtk/include/platform/platform.h b/src/platform/mtk/include/platform/platform.h new file mode 100644 index 000000000000..df4a4ca1ddfc --- /dev/null +++ b/src/platform/mtk/include/platform/platform.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Google LLC. All rights reserved. + * Author: Andy Ross + */ +#ifndef _SOF_PLATFORM_MTK_PLATFORM_H +#define _SOF_PLATFORM_MTK_PLATFORM_H + +#include + +#define PLATFORM_MAX_CHANNELS 4 +#define PLATFORM_MAX_STREAMS 5 + +#define HOST_PAGE_SIZE 4096 + +#define PLATFORM_DEFAULT_CLOCK CLK_CPU(0) + +#endif /* _SOF_PLATFORM_MTK_PLATFORM_H */ diff --git a/src/platform/mtk/include/platform/trace/trace.h b/src/platform/mtk/include/platform/trace/trace.h new file mode 100644 index 000000000000..bac2cd302ef3 --- /dev/null +++ b/src/platform/mtk/include/platform/trace/trace.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Google LLC. All rights reserved. + * Author: Andy Ross + */ +#ifndef _SOF_PLATFORM_MTK_TRACE_H +#define _SOF_PLATFORM_MTK_TRACE_H + +/* No legacy trace defined for this platform, but header required anyway */ + +#endif /* _SOF_PLATFORM_MTK_TRACE_H */ diff --git a/src/platform/mtk/platform.c b/src/platform/mtk/platform.c new file mode 100644 index 000000000000..53b48f12b6e9 --- /dev/null +++ b/src/platform/mtk/platform.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright(c) 2024 Google LLC. All rights reserved. +// Author: Andy Ross +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* General platform glue code. In a Zephyr build, most of this is + * vestigial or degenerate, or at least evolving in that direction. + */ + +void mtk_dai_init(struct sof *sof); + +#define MBOX0 DEVICE_DT_GET(DT_INST(0, mediatek_mbox)) +#define MBOX1 DEVICE_DT_GET(DT_INST(1, mediatek_mbox)) + +/* Use the same UUID as in "ipc-zephyr.c", which is actually an Intel driver */ +SOF_DEFINE_REG_UUID(zipc_task); + +static void mbox_cmd_fn(const struct device *mbox, void *arg) +{ + /* We're in ISR context. This unblocks the IPC task thread, + * which calls ipc_do_cmd(), which calls back into + * ipc_platform_do_cmd() below, which then calls ipc_cmd(). + */ + ipc_schedule_process(ipc_get()); +} + +enum task_state ipc_platform_do_cmd(struct ipc *ipc) +{ + /* mailbox_validate() checks the command length (that's all it + * vaildates) and copies the incoming command from the host + * window to the comp_data buffer in the IPC object. + */ + struct ipc_cmd_hdr *hdr = mailbox_validate(); + + if (hdr) + ipc_cmd(hdr); + return SOF_TASK_STATE_COMPLETED; +} + +void ipc_platform_complete_cmd(struct ipc *ipc) +{ + mtk_adsp_mbox_signal(MBOX0, 1); +} + +static void mtk_ipc_send(const void *msg, size_t sz) +{ + mailbox_dspbox_write(0, msg, sz); + mtk_adsp_mbox_signal(MBOX1, 0); +} + +int ipc_platform_send_msg(const struct ipc_msg *msg) +{ + struct ipc *ipc = ipc_get(); + + if (ipc->is_notification_pending) + return -EBUSY; + + ipc->is_notification_pending = true; + mtk_ipc_send(msg->tx_data, msg->tx_size); + return 0; +} + +static void mbox_reply_fn(const struct device *mbox, void *arg) +{ + ipc_get()->is_notification_pending = false; +} + +/* "Host Page Table" support. The platform is responsible for + * providing a buffer into which the IPC layer reads a DMA "page + * table" from the host. This isn't really a page table, it's a + * packed array of PPN addresses (basically a scatter/gather list) + * used to configure the buffer used for dummy_dma, which is a "DMA" + * driver that works by directly copying data in shared memory. And + * somewhat confusingly, it's itself configured at runtime by "DMA" + * over the same mechanism (instead of e.g. by a IPC command, which + * would fit just fine!). All of this is degenerate with MTK anyway, + * because the actual addresses being passed are in a DRAM region + * dedicated for the purpose and are AFAICT guaranteed contiguous. + * + * Note: the 256 byte page table size is fixed by protocol in the + * linux driver, but here in SOF it's always been a platform symbol. + * But it's not tunable! Don't touch it. + */ +static uint8_t hostbuf_ptable[256]; +static struct ipc_data_host_buffer mtk_host_buffer; + +struct ipc_data_host_buffer *ipc_platform_get_host_buffer(struct ipc *ipc) +{ + return &mtk_host_buffer; +} + +/* Called out of ipc_init(), which is called out of platform_init() below */ +int platform_ipc_init(struct ipc *ipc) +{ + mtk_host_buffer.page_table = hostbuf_ptable; + mtk_host_buffer.dmac = dma_get(DMA_DIR_HMEM_TO_LMEM, 0, DMA_DEV_HOST, + DMA_ACCESS_SHARED); + + schedule_task_init_edf(&ipc->ipc_task, SOF_UUID(zipc_task_uuid), + &ipc_task_ops, ipc, 0, 0); + + mtk_adsp_mbox_set_handler(MBOX0, 0, mbox_cmd_fn, NULL); + mtk_adsp_mbox_set_handler(MBOX1, 1, mbox_reply_fn, NULL); + return 0; +} + +int platform_context_save(struct sof *sof) +{ + return 0; +} + +static int set_cpuclk(int clock, int hz) +{ + return clock == 0 && hz == CONFIG_XTENSA_CCOUNT_HZ ? 0 : -EINVAL; +} + +/* This is required out of dma_multi_chan_domain but nothing + * defines it in Zephyr builds. Stub with a noop here, + * knowing that MTK "DMA" "devices" don't have interrupts. + */ +void interrupt_clear_mask(uint32_t irq, uint32_t mask) +{ +} + +/* Dummy CPU clock driver that supports one known frequency. This + * hardware has clock scaling support, but it hasn't historically been + * exercised so we have nothing to test against. + */ +void clocks_init(struct sof *sof) +{ + static const struct freq_table freqs[] = { + { .freq = CONFIG_XTENSA_CCOUNT_HZ, + .ticks_per_msec = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000, } + }; + static struct clock_info clks[] = { + { .freqs_num = ARRAY_SIZE(freqs), + .freqs = freqs, + .notification_id = NOTIFIER_ID_CPU_FREQ, + .notification_mask = NOTIFIER_TARGET_CORE_MASK(0), + .set_freq = set_cpuclk, }, + }; + sof->clocks = clks; +} + +int platform_init(struct sof *sof) +{ + clocks_init(sof); + sof->platform_timer_domain = zephyr_domain_init(PLATFORM_DEFAULT_CLOCK); + mtk_dai_init(sof); + ipc_init(sof); + scheduler_init_edf(); + scheduler_init_ll(sof->platform_timer_domain); + sof->platform_dma_domain = + dma_multi_chan_domain_init(&sof->dma_info->dma_array[0], + sof->dma_info->num_dmas, + PLATFORM_DEFAULT_CLOCK, false); + sa_init(sof, CONFIG_SYSTICK_PERIOD); + return 0; +} + +int platform_boot_complete(uint32_t boot_message) +{ + static const struct sof_ipc_fw_ready fw_ready_cmd = { + .hdr.cmd = SOF_IPC_FW_READY, + .hdr.size = sizeof(struct sof_ipc_fw_ready), + .version = { + .hdr.size = sizeof(struct sof_ipc_fw_version), + .micro = SOF_MICRO, + .minor = SOF_MINOR, + .major = SOF_MAJOR, + .tag = SOF_TAG, + .abi_version = SOF_ABI_VERSION, + .src_hash = SOF_SRC_HASH, + }, + .flags = DEBUG_SET_FW_READY_FLAGS, + }; + + mtk_ipc_send(&fw_ready_cmd, sizeof(fw_ready_cmd)); + return 0; +} + +/* Extended manifest window record. Note the alignment attribute is + * critical as rimage demands allocation in units of 16 bytes, yet the + * C struct records emitted into the section are not in general padded + * and will pack tighter than that! (Really this is an rimage bug, it + * should separately validate each symbol in the section and re-pack + * the array instead of relying on the poor linker to do it). + */ +#define WINDOW(region) \ + { .type = SOF_IPC_REGION_##region, \ + .size = MTK_IPC_WIN_SIZE(region), \ + . offset = MTK_IPC_WIN_OFF(region), } +struct ext_man_windows mtk_man_win __section(".fw_metadata") __aligned(EXT_MAN_ALIGN) = { + .hdr = { + .type = EXT_MAN_ELEM_WINDOW, + .elem_size = ROUND_UP(sizeof(struct ext_man_windows), EXT_MAN_ALIGN) + }, + .window = { + .ext_hdr = { + .hdr.cmd = SOF_IPC_FW_READY, + .hdr.size = sizeof(struct sof_ipc_window), + .type = SOF_IPC_EXT_WINDOW, + }, + .num_windows = 6, + .window = { + // Order doesn't match memory layout for historical + // reasons. Shouldn't matter, but don't rock the boat... + WINDOW(UPBOX), + WINDOW(DOWNBOX), + WINDOW(DEBUG), + WINDOW(TRACE), + WINDOW(STREAM), + WINDOW(EXCEPTION), + }, + }, +}; diff --git a/src/platform/mtk/tools/README.txt b/src/platform/mtk/tools/README.txt new file mode 100644 index 000000000000..a7b35f464e96 --- /dev/null +++ b/src/platform/mtk/tools/README.txt @@ -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-.dts files can be included directly in +Zephyr board config. diff --git a/src/platform/mtk/tools/build.sh b/src/platform/mtk/tools/build.sh new file mode 100755 index 000000000000..1b17c8e38cf8 --- /dev/null +++ b/src/platform/mtk/tools/build.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2024 Google LLC. All rights reserved. +# Author: Andy Ross +set -ex + +PLATFORMS="$*" +if [ -z "$PLATFORMS" ]; then + PLATFORMS="mt8195 mt8188 mt8186" +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" + INCS="$INCS -I$SOF/src/arch/host/include -I$SOF/src/platform/$p/include/platform" + INCS="$INCS -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 diff --git a/src/platform/mtk/tools/mt-dai-gen.c b/src/platform/mtk/tools/mt-dai-gen.c new file mode 100644 index 000000000000..9c3ae67013a8 --- /dev/null +++ b/src/platform/mtk/tools/mt-dai-gen.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright(c) 2024 Google LLC. All rights reserved. +// Author: Andy Ross +#include +#include +#include + +/* DIY assertion, an "assert()" is already defined in platform headers */ +#define CHECK(expr) do { if (!(expr)) { \ + printf("FAILED: " #expr " at line %d\n", __LINE__); \ + *(int *)0 = 0; } \ + } while (false) + +/* 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: reg <=0 + * mono: reg <=0 OR shift <=0 + * msb: reg <=0 + * msb2: reg <=0 + * agent_disable: reg <=0 + * 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 proper mask in low bits */ + 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("\tafe_%s: afe_%s {\n", sym, sym); + printf("\t\tcompatible = \"mediatek,afe\";\n"); + printf("\t\tafe_name = \"%s\";\n", m->name); + printf("\t\tdai_id = <%d>;\n", dai_id); + if (downlink) + printf("\t\tdownlink;\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\tbase = <0x%8.8x 0x%8.8x>;\n", + msbaddr(m->reg_ofs_base_msb), m->reg_ofs_base + afe_base_addr); + printf("\t\tcur = <0x%8.8x 0x%8.8x>;\n", + msbaddr(m->reg_ofs_cur_msb), m->reg_ofs_cur + afe_base_addr); + printf("\t\tend = <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\tmono_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"); + } +} diff --git a/tools/rimage/config/mt8196.toml b/tools/rimage/config/mt8196.toml new file mode 100644 index 000000000000..1e66bab0b538 --- /dev/null +++ b/tools/rimage/config/mt8196.toml @@ -0,0 +1,15 @@ +version = [1, 0] # use simple file write + +[adsp] +name = "mt8196" + +[[adsp.mem_zone]] +type = "IRAM" +base = "0x4e100000" +size = "0x00080000" +host_offset = "0x0" +[[adsp.mem_zone]] +type = "SRAM" +base = "0x90000000" +size = "0x00600000" +host_offset = "0x0" diff --git a/tools/topology/topology1/CMakeLists.txt b/tools/topology/topology1/CMakeLists.txt index 5c9d9926d0c4..1431124d08d2 100644 --- a/tools/topology/topology1/CMakeLists.txt +++ b/tools/topology/topology1/CMakeLists.txt @@ -98,6 +98,7 @@ set(TPLGS "sof-mt8186-mt6366\;sof-mt8186-mt6366-rt1019-rt5682s-waves\;-DWAVES=1" "sof-mt8188-mt6359\;sof-mt8188" "sof-mt8188-mt6359\;sof-mt8188-waves\;-DWAVES=1" + "sof-mt8196-mt6681\;sof-mt8196" "sof-acp-renoir\;sof-acp" "sof-rn-rt5682-rt1019\;sof-rn-rt5682-rt1019" diff --git a/tools/topology/topology1/platform/mediatek/mt8196.m4 b/tools/topology/topology1/platform/mediatek/mt8196.m4 new file mode 100644 index 000000000000..74cdd252f024 --- /dev/null +++ b/tools/topology/topology1/platform/mediatek/mt8196.m4 @@ -0,0 +1,23 @@ +# +# MT8196 differentiation for pipelines and components +# + +include(`memory.m4') + +define(`PLATFORM_DAI_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE)) +define(`PLATFORM_HOST_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE)) +define(`PLATFORM_PASS_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_DMA, MEM_CAP_CACHE)) +define(`PLATFORM_COMP_MEM_CAP', MEMCAPS(MEM_CAP_RAM, MEM_CAP_CACHE)) + +# Low Latency PCM Configuration +W_VENDORTUPLES(pipe_ll_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "50000"')) +W_DATA(pipe_ll_schedule_plat, pipe_ll_schedule_plat_tokens) + +# Media PCM Configuration +W_VENDORTUPLES(pipe_media_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "100000"')) +W_DATA(pipe_media_schedule_plat, pipe_media_schedule_plat_tokens) + +# DAI schedule Configuration - scheduled by IRQ +W_VENDORTUPLES(pipe_dai_schedule_plat_tokens, sof_sched_tokens, LIST(` ', `SOF_TKN_SCHED_MIPS "5000"')) +W_DATA(pipe_dai_schedule_plat, pipe_dai_schedule_plat_tokens) + diff --git a/tools/topology/topology1/sof-mt8196-mt6681.m4 b/tools/topology/topology1/sof-mt8196-mt6681.m4 new file mode 100644 index 000000000000..e52c8c84fa0e --- /dev/null +++ b/tools/topology/topology1/sof-mt8196-mt6681.m4 @@ -0,0 +1,148 @@ +# +# Topology for MT8196 board with mt6681 +# + +# Include topology builder +include(`utils.m4') +include(`dai.m4') +include(`pipeline.m4') +include(`afe.m4') +include(`pcm.m4') +include(`buffer.m4') + +# Include TLV library +include(`common/tlv.m4') + +# Include Token library +include(`sof/tokens.m4') + +# Include DSP configuration +include(`platform/mediatek/mt8196.m4') + +# +# Define the pipelines +# +# PCM0 ---> AFE (Speaker - nau8318) +# PCM1 ---> AFE (Headset playback - nau88l25) +# PCM2 <--- AFE (DMIC0 - AP) +# PCM3 <--- AFE (Headset record - nau88l25) +# PCM4 <--- AFE (DMIC1 - AP) + +dnl PIPELINE_PCM_ADD(pipeline, +dnl pipe id, pcm, max channels, format, +dnl period, priority, core, +dnl pcm_min_rate, pcm_max_rate, pipeline_rate, +dnl time_domain, sched_comp) + +define(`ENDPOINT_NAME', `Speakers') +# Low Latency playback pipeline 1 on PCM 16 using max 2 channels of s16le +# Set 1000us deadline with priority 0 on core 0 +PIPELINE_PCM_ADD(ifdef(`WAVES', sof/pipe-waves-codec-playback.m4, sof/pipe-passthrough-playback.m4), + 1, 0, 2, s16le, + 1000, 0, 0, + 48000, 48000, 48000) +undefine(`ENDPOINT_NAME') + +define(`ENDPOINT_NAME', `Headphones') +# Low Latency playback pipeline 2 on PCM 17 using max 2 channels of s16le +# Set 1000us deadline with priority 0 on core 0 +PIPELINE_PCM_ADD(ifdef(`WAVES', sof/pipe-waves-codec-playback.m4, sof/pipe-passthrough-playback.m4), + 2, 1, 2, s16le, + 1000, 0, 0, + 48000, 48000, 48000) +undefine(`ENDPOINT_NAME') +# Low Latency capture pipeline 3 on PCM 18 using max 2 channels of s16le +# Set 2000us deadline with priority 0 on core 0 +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 3, 2, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Low Latency capture pipeline 4 on PCM 19 using max 2 channels of s16le +# Set 2000us deadline with priority 0 on core 0 +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 4, 3, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + +# Low Latency capture pipeline 4 on PCM 20 using max 2 channels of s16le +# Set 2000us deadline with priority 0 on core 0 +PIPELINE_PCM_ADD(sof/pipe-passthrough-capture.m4, + 5, 4, 2, s16le, + 2000, 0, 0, + 48000, 48000, 48000) + + + +# +# DAIs configuration +# + +dnl DAI_ADD(pipeline, +dnl pipe id, dai type, dai_index, dai_be, +dnl buffer, periods, format, +dnl deadline, priority, core) + + +# playback DAI is AFE using 2 periods +# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0 +DAI_ADD(sof/pipe-dai-playback.m4, + 1, AFE, 0, AFE_SOF_DL_24CH, + PIPELINE_SOURCE_1, 2, s16le, + 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +# playback DAI is AFE using 2 periods +# Buffers use s16le format, with 48 frame per 1000us on core 0 with priority 0 +DAI_ADD(sof/pipe-dai-playback.m4, + 2, AFE, 1, AFE_SOF_DL1, + PIPELINE_SOURCE_2, 2, s16le, + 1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) +# capture DAI is AFE using 2 periods +# Buffers use s16le format, with 48 frame per 2000us on core 0 with priority 0 +DAI_ADD(sof/pipe-dai-capture.m4, + 3, AFE, 2, AFE_SOF_UL0, + PIPELINE_SINK_3, 2, s16le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +# capture DAI is AFE using 2 periods +# Buffers use s16le format, with 48 frame per 2000us on core 0 with priority 0 +DAI_ADD(sof/pipe-dai-capture.m4, + 4, AFE, 3, AFE_SOF_UL1, + PIPELINE_SINK_4, 2, s16le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +# capture DAI is AFE using 2 periods +# Buffers use s16le format, with 48 frame per 2000us on core 0 with priority 0 +DAI_ADD(sof/pipe-dai-capture.m4, + 5, AFE, 4, AFE_SOF_UL2, + PIPELINE_SINK_5, 2, s16le, + 2000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER) + +#SCHEDULE_TIME_DOMAIN_DMA +dnl PCM_PLAYBACK_ADD(name, pcm_id, playback) + +# PCM Low Latency, id 0 +PCM_PLAYBACK_ADD(SOF_DL_24CH, 0, PIPELINE_PCM_1) +PCM_PLAYBACK_ADD(SOF_DL1, 1, PIPELINE_PCM_2) +PCM_CAPTURE_ADD(SOF_UL0, 2, PIPELINE_PCM_3) +PCM_CAPTURE_ADD(SOF_UL1, 3, PIPELINE_PCM_4) +PCM_CAPTURE_ADD(SOF_UL2, 4, PIPELINE_PCM_5) + + +dnl DAI_CONFIG(type, dai_index, link_id, name, afe_config) + +DAI_CONFIG(AFE, 0, 0, AFE_SOF_DL_24CH, + AFE_CONFIG(AFE_CONFIG_DATA(AFE, 0, 48000, 2, s16le))) + +DAI_CONFIG(AFE, 1, 0, AFE_SOF_DL1, + AFE_CONFIG(AFE_CONFIG_DATA(AFE, 1, 48000, 2, s16le))) + +DAI_CONFIG(AFE, 2, 0, AFE_SOF_UL0, + AFE_CONFIG(AFE_CONFIG_DATA(AFE, 2, 48000, 2, s16le))) + +DAI_CONFIG(AFE, 3, 0, AFE_SOF_UL1, + AFE_CONFIG(AFE_CONFIG_DATA(AFE, 3, 48000, 2, s16le))) + +DAI_CONFIG(AFE, 4, 0, AFE_SOF_UL2, + AFE_CONFIG(AFE_CONFIG_DATA(AFE, 4, 48000, 2, s16le))) + diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 2e96668e119b..61a92251dc24 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -455,6 +455,20 @@ if (CONFIG_SOC_ACP_6_0) set(PLATFORM "acp_6_0") endif() +if (CONFIG_SOC_FAMILY_MTK) + set(PLATFORM "mtk") + + zephyr_library_sources( + ${SOF_PLATFORM_PATH}/mtk/platform.c + ${SOF_PLATFORM_PATH}/mtk/dai.c + ${SOF_SRC_PATH}/schedule/zephyr_ll.c + ${SOF_DRIVERS_PATH}/generic/dummy-dma.c + ${SOF_SRC_PATH}/drivers/mediatek/afe/afe-memif.c + ${SOF_SRC_PATH}/drivers/mediatek/afe/afe-dai.c + ${SOF_SRC_PATH}/drivers/mediatek/afe/afe-drv.c + ) +endif() + # Building for native_posix-based whole-OS host emulator zephyr_library_sources_ifdef(CONFIG_ZEPHYR_POSIX ${SOF_SRC_PATH}/schedule/zephyr_ll.c diff --git a/zephyr/lib/alloc.c b/zephyr/lib/alloc.c index f525618d7c15..8bfe3155477d 100644 --- a/zephyr/lib/alloc.c +++ b/zephyr/lib/alloc.c @@ -105,6 +105,15 @@ __section(".heap_mem") static uint8_t __aligned(PLATFORM_DCACHE_ALIGN) heapmem[H #define HEAPMEM_SIZE (256 * 1024) char __aligned(8) heapmem[HEAPMEM_SIZE]; +#elif defined(CONFIG_SOC_FAMILY_MTK) + +extern char _mtk_adsp_sram_end; +#define SRAM_START DT_REG_ADDR(DT_NODELABEL(sram0)) +#define SRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sram0)) +#define SRAM_END (SRAM_START + SRAM_SIZE) +#define heapmem ((uint8_t *)ALIGN_UP((uintptr_t)&_mtk_adsp_sram_end, PLATFORM_DCACHE_ALIGN)) +#define HEAPMEM_SIZE ((uint8_t *)SRAM_END - heapmem) + #else extern char _end[], _heap_sentry[];