From fe5c11db05382261fb32bb0a7aee5e469744da70 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Wed, 30 Oct 2024 11:06:05 -0700 Subject: [PATCH] boards/mediatek: Add mt8196_adsp Add Zephyr support for the Audio DSP on the MT8196 SOC. This is a very similar device to previous designs. Most of this patch is just DTS. The biggest delta is the more complicated second level interrupt controller, though it is still able to be represented using some vaguely clever DTS config over the older intc_mtk_adsp driver. Also the memory layout is slightly different, requiring a little indirection to set the initial boot stack address and log output buffer. And the timer "irq_ack" register bits moved. Signed-off-by: Andy Ross --- boards/mediatek/mt8196/Kconfig.mt8196 | 5 + boards/mediatek/mt8196/board.yml | 5 + boards/mediatek/mt8196/mt8196_adsp.dts | 109 +++++++++++++++++++ boards/mediatek/twister.yaml | 2 + drivers/timer/mtk_adsp_timer.c | 5 + soc/mediatek/mt8xxx/Kconfig.soc | 11 ++ soc/mediatek/mt8xxx/irq.c | 10 ++ soc/mediatek/mt8xxx/mt8196/Kconfig.defconfig | 18 +++ soc/mediatek/mt8xxx/mt8196/linker.ld | 5 + soc/mediatek/mt8xxx/mt8196/soc.h | 10 ++ soc/mediatek/mt8xxx/mtk_adsp_load.py | 35 ++++++ soc/mediatek/mt8xxx/soc.c | 21 +++- soc/mediatek/mt8xxx/soc.yml | 5 + 13 files changed, 235 insertions(+), 6 deletions(-) create mode 100644 boards/mediatek/mt8196/Kconfig.mt8196 create mode 100644 boards/mediatek/mt8196/board.yml create mode 100644 boards/mediatek/mt8196/mt8196_adsp.dts create mode 100644 soc/mediatek/mt8xxx/mt8196/Kconfig.defconfig create mode 100644 soc/mediatek/mt8xxx/mt8196/linker.ld create mode 100644 soc/mediatek/mt8xxx/mt8196/soc.h diff --git a/boards/mediatek/mt8196/Kconfig.mt8196 b/boards/mediatek/mt8196/Kconfig.mt8196 new file mode 100644 index 00000000000..7167a092755 --- /dev/null +++ b/boards/mediatek/mt8196/Kconfig.mt8196 @@ -0,0 +1,5 @@ +# Copyright 2024 The ChromiumOS Authors +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_MT8196 + select SOC_MT8196 diff --git a/boards/mediatek/mt8196/board.yml b/boards/mediatek/mt8196/board.yml new file mode 100644 index 00000000000..cf5a2e27699 --- /dev/null +++ b/boards/mediatek/mt8196/board.yml @@ -0,0 +1,5 @@ +boards: + - name: mt8196 + vendor: mediatek + socs: + - name: mt8196 diff --git a/boards/mediatek/mt8196/mt8196_adsp.dts b/boards/mediatek/mt8196/mt8196_adsp.dts new file mode 100644 index 00000000000..ea3bfdf4f98 --- /dev/null +++ b/boards/mediatek/mt8196/mt8196_adsp.dts @@ -0,0 +1,109 @@ +/* Copyright 2024 The ChromiumOS Authors + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/dts-v1/; +/ { + + #address-cells = <1>; + #size-cells = <1>; + + sram0: memory@4e100000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x4e100000 DT_SIZE_K(512)>; + }; + + dram0: memory@90000000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x90000000 DT_SIZE_M(6)>; + }; + + dram1: memory@90700000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x90700000 DT_SIZE_M(1)>; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + + core_intc: core_intc@0 { + compatible = "cdns,xtensa-core-intc"; + reg = <0 4>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + /* The 8196 interrupt controller is actually more complicated + * than the driver here supports. There are 64 total + * interrupt inputs, each of which is a associated with one of + * 16 "groups", each of which is wired to a separate Xtensa + * architectural interrupt. (Whether the mapping of external + * interrupts to groups is mutable is an open question, the + * values here appear to be hardware defaults). We represent + * each group (strictly each of the high and low 32 interrupts + * of each group) as a separate adsp_intc controller, pointing + * at the same status and enable registers, but with disjoint + * masks. Note that this disallows configurations where a + * single controller needs to manage interrupts in both the + * high and low 32 bits of the set, but no current drivers + * rely on such a configuration. + */ + + intc_g1: intc_g1@1a014010 { + compatible = "mediatek,adsp_intc"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0x1a014010 4>; + status-reg = <0x1a014008>; + mask = <0x00007f3f>; + interrupts = <1 0 0>; + interrupt-parent = <&core_intc>; + }; + + intc_g2: intc_g2@1a014010 { + compatible = "mediatek,adsp_intc"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0x1a014010 4>; + status-reg = <0x1a014008>; + mask = <0x000000c0>; + interrupts = <2 0 0>; + interrupt-parent = <&core_intc>; + }; + + ostimer64: ostimer64@1a00b080 { + compatible = "mediatek,ostimer64"; + reg = <0x1a00b080 28>; + }; + + ostimer0: ostimer@1a00b000 { + compatible = "mediatek,ostimer"; + reg = <0x1a00b000 16>; + interrupt-parent = <&intc_g1>; + interrupts = <8 0 0>; + }; + + mbox0: mbox@1a360100 { + compatible = "mediatek,mbox"; + reg = <0x1a360100 16>; + interrupt-parent = <&intc_g2>; + interrupts = <6 0 0>; + }; + + mbox1: mbox@1a370100 { + compatible = "mediatek,mbox"; + reg = <0x1a370100 16>; + interrupt-parent = <&intc_g2>; + interrupts = <7 0 0>; + }; + }; /* soc */ + + chosen { }; + aliases { }; + +}; diff --git a/boards/mediatek/twister.yaml b/boards/mediatek/twister.yaml index dba7a14c3e8..e941f640048 100644 --- a/boards/mediatek/twister.yaml +++ b/boards/mediatek/twister.yaml @@ -14,3 +14,5 @@ variants: name: MediaTek MT8188 Audio DSP mt8186/mt8186/adsp: name: MediaTek MT8186 Audio DSP + mt8196/mt8196/adsp: + name: MediaTek MT8196 Audio DSP diff --git a/drivers/timer/mtk_adsp_timer.c b/drivers/timer/mtk_adsp_timer.c index 7a6c06d9e61..995236f0346 100644 --- a/drivers/timer/mtk_adsp_timer.c +++ b/drivers/timer/mtk_adsp_timer.c @@ -56,8 +56,13 @@ struct mtk_ostimer64 { #define OSTIMER_CON_CLKSRC_BCLK 0x20 /* CPU speed, 720 MHz */ #define OSTIMER_CON_CLKSRC_PCLK 0x30 /* ~312 MHz experimentally */ +#ifndef CONFIG_SOC_MT8196 #define OSTIMER_IRQ_ACK_ENABLE BIT(4) /* read = status, write = enable */ #define OSTIMER_IRQ_ACK_CLEAR BIT(5) +#else +#define OSTIMER_IRQ_ACK_ENABLE BIT(0) +#define OSTIMER_IRQ_ACK_CLEAR BIT(5) +#endif #define OST64_HZ 13000000U #define OST_HZ 26000000U diff --git a/soc/mediatek/mt8xxx/Kconfig.soc b/soc/mediatek/mt8xxx/Kconfig.soc index 0b26f92abc7..ba52c9eb574 100644 --- a/soc/mediatek/mt8xxx/Kconfig.soc +++ b/soc/mediatek/mt8xxx/Kconfig.soc @@ -16,6 +16,12 @@ config SOC_SERIES_MT818X help Mediatek MT818x Audio DSPs +config SOC_SERIES_MT8196 + bool + select SOC_FAMILY_MTK + help + Mediatek MT8196 Audio DSPs + config SOC_MT8195 bool select SOC_SERIES_MT8195 @@ -28,7 +34,12 @@ config SOC_MT8188 bool select SOC_SERIES_MT818X +config SOC_MT8196 + bool + select SOC_SERIES_MT8196 + config SOC default "mt8195" if SOC_MT8195 default "mt8186" if SOC_MT8186 default "mt8188" if SOC_MT8188 + default "mt8196" if SOC_MT8196 diff --git a/soc/mediatek/mt8xxx/irq.c b/soc/mediatek/mt8xxx/irq.c index 28b9fad6337..792e31d360f 100644 --- a/soc/mediatek/mt8xxx/irq.c +++ b/soc/mediatek/mt8xxx/irq.c @@ -25,6 +25,16 @@ static const struct device *irq_dev(unsigned int *irq_inout) __ASSERT_NO_MSG((*irq_inout & 0xff) == 23); *irq_inout = (*irq_inout >> 8) - 1; return DEVICE_DT_GET(DT_INST(1, mediatek_adsp_intc)); +#elif defined(CONFIG_SOC_SERIES_MT8196) + /* Two subcontrollers on core IRQs 1 and 2 */ + uint32_t lvl1 = *irq_inout & 0xff; + + *irq_inout = (*irq_inout >> 8) - 1; + if (lvl1 == 1) { + return DEVICE_DT_GET(DT_INST(0, mediatek_adsp_intc)); + } + __ASSERT_NO_MSG(lvl1 == 2); + return DEVICE_DT_GET(DT_INST(1, mediatek_adsp_intc)); #else /* Only one on 818x */ return DEVICE_DT_GET(DT_INST(0, mediatek_adsp_intc)); diff --git a/soc/mediatek/mt8xxx/mt8196/Kconfig.defconfig b/soc/mediatek/mt8xxx/mt8196/Kconfig.defconfig new file mode 100644 index 00000000000..e406dce76a5 --- /dev/null +++ b/soc/mediatek/mt8xxx/mt8196/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright 2024 The ChromiumOS Authors +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MT8196 + +config LEGACY_MULTI_LEVEL_TABLE_GENERATION + default n + +config NUM_2ND_LEVEL_AGGREGATORS + default 2 + +config 2ND_LVL_INTR_00_OFFSET + default 1 + +config 2ND_LVL_INTR_01_OFFSET + default 2 + +endif diff --git a/soc/mediatek/mt8xxx/mt8196/linker.ld b/soc/mediatek/mt8xxx/mt8196/linker.ld new file mode 100644 index 00000000000..3d086aecb1a --- /dev/null +++ b/soc/mediatek/mt8xxx/mt8196/linker.ld @@ -0,0 +1,5 @@ +/* Copyright 2024 The ChromiumOS Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../linker.ld" diff --git a/soc/mediatek/mt8xxx/mt8196/soc.h b/soc/mediatek/mt8xxx/mt8196/soc.h new file mode 100644 index 00000000000..5c7734b9e6a --- /dev/null +++ b/soc/mediatek/mt8xxx/mt8196/soc.h @@ -0,0 +1,10 @@ +/* Copyright 2024 The ChromiumOS Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_MT8196_SOC_H +#define ZEPHYR_SOC_MT8196_SOC_H + +#include "../soc.h" + +#endif /* ZEPHYR_SOC_MT8196_SOC_H */ diff --git a/soc/mediatek/mt8xxx/mtk_adsp_load.py b/soc/mediatek/mt8xxx/mtk_adsp_load.py index 9317761a7b6..84526465ec3 100755 --- a/soc/mediatek/mt8xxx/mtk_adsp_load.py +++ b/soc/mediatek/mt8xxx/mtk_adsp_load.py @@ -129,6 +129,39 @@ class MT818x(): self.cfg.SW_RSTN &= 0xffffffee # Release reset self.cfg.IO_CONFIG &= 0x7fffffff # Clear RUNSTALL +class MT8196(): + def __init__(self, maps): + cfg_base = ctypes.addressof(ctypes.c_int.from_buffer(maps["cfg"])) + sec_base = ctypes.addressof(ctypes.c_int.from_buffer(maps["sec"])) + self.cfg = Regs(cfg_base) + self.cfg.CFGREG_SW_RSTN = 0x0000 + self.cfg.MBOX_IRQ_EN = 0x009c + self.cfg.HIFI_RUNSTALL = 0x0108 + self.cfg.freeze() + self.sec = Regs(sec_base) + self.sec.ALTVEC_C0 = 0x04 + self.sec.ALTVECSEL = 0x0c + self.sec.freeze() + + def logrange(self): + return range(0x580000, 0x600000) + + def stop(self): + self.cfg.HIFI_RUNSTALL |= 0x1000 + self.cfg.CFGREG_SW_RSTN |= 0x11 + + def start(self, boot_vector): + self.sec.ALTVEC_C0 = 0 + self.sec.ALTVECSEL = 0 + self.sec.ALTVEC_C0 = boot_vector + self.sec.ALTVECSEL = 1 + self.cfg.HIFI_RUNSTALL |= 0x1000 + self.cfg.MBOX_IRQ_EN |= 3 + self.cfg.CFGREG_SW_RSTN |= 0x11 + time.sleep(0.1) + self.cfg.CFGREG_SW_RSTN &= ~0x11 + self.cfg.HIFI_RUNSTALL &= ~0x1000 + # Temporary logging protocol: watch the 1M null-terminated log # stream at 0x60700000 -- the top of the linkable region of # existing SOF firmware, before the heap. Nothing uses this @@ -193,6 +226,8 @@ def main(): dev = MT8195(maps) elif dsp in ("mt8186", "mt8188"): dev = MT818x(maps) + elif dsp == "mt8196": + dev = MT8196(maps) if sys.argv[1] == "load": dat = open(sys.argv[2], "rb").read() diff --git a/soc/mediatek/mt8xxx/soc.c b/soc/mediatek/mt8xxx/soc.c index 1ac91ac4aaa..744980f084a 100644 --- a/soc/mediatek/mt8xxx/soc.c +++ b/soc/mediatek/mt8xxx/soc.c @@ -19,14 +19,23 @@ extern char _mtk_adsp_dram_end[]; #define DRAM_SIZE DT_REG_SIZE(DT_NODELABEL(dram0)) #define DRAM_END (DRAM_START + DRAM_SIZE) +#ifdef CONFIG_SOC_MT8196 +#define INIT_STACK "0x90400000" +#define LOG_BASE 0x90580000 +#define LOG_LEN 0x80000 +#else +#define INIT_STACK "0x60e00000" +#define LOG_BASE 0x60700000 +#define LOG_LEN 0x100000 +#endif + /* This is the true boot vector. This device allows for direct * setting of the alternate reset vector, so we let it link wherever * it lands and extract its address in the loader. This represents * the minimum amount of effort required to successfully call a C * function (and duplicates a few versions elsewhere in the tree: - * really this should move to the arch layer). Note that the stack - * used is 15MB into the DRAM region and safe/unused by all devices. - * But really this should be z_interrupt_stacks[0]. + * really this should move to the arch layer). The initial stack + * really should be the end of _interrupt_stacks[0] */ __asm__(".align 4\n\t" ".global mtk_adsp_boot_entry\n\t" @@ -38,7 +47,7 @@ __asm__(".align 4\n\t" " movi a0, 1\n\t" " wsr a0, WINDOWSTART\n\t" " rsync\n\t" - " movi a1, 0x60e00000\n\t" + " movi a1, " INIT_STACK "\n\t" " call4 c_boot\n\t"); /* Initial MPU configuration, needed to enable caching */ @@ -109,8 +118,8 @@ static void enable_mpu(void) */ int arch_printk_char_out(int c) { - char volatile * const buf = (void *)0x60700000; - const size_t max = 0x100000 - 4; + char volatile * const buf = (void *)LOG_BASE; + const size_t max = LOG_LEN - 4; int volatile * const len = (int *)&buf[max]; if (*len < max) { diff --git a/soc/mediatek/mt8xxx/soc.yml b/soc/mediatek/mt8xxx/soc.yml index 2f8e56639bb..fd5cd68b04e 100644 --- a/soc/mediatek/mt8xxx/soc.yml +++ b/soc/mediatek/mt8xxx/soc.yml @@ -14,3 +14,8 @@ family: - name: mt8188 cpuclusters: - name: adsp + - name: mt8196 + socs: + - name: mt8196 + cpuclusters: + - name: adsp