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