diff --git a/arch/Kconfig b/arch/Kconfig
index 27dbbc0b10cf7..db9c5b8924ea1 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -50,7 +50,6 @@ config ARM64
select ARCH_HAS_THREAD_LOCAL_STORAGE
select USE_SWITCH
select USE_SWITCH_SUPPORTED
- select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD
select BARRIER_OPERATIONS_ARCH
select ARCH_HAS_DIRECTED_IPIS
select ARCH_HAS_DEMAND_PAGING
@@ -95,7 +94,6 @@ config X86
select ARCH_HAS_THREAD_LOCAL_STORAGE
select ARCH_HAS_DEMAND_PAGING if !X86_64
select ARCH_HAS_DEMAND_MAPPING if ARCH_HAS_DEMAND_PAGING
- select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD
select NEED_LIBC_MEM_PARTITION if USERSPACE && TIMING_FUNCTIONS \
&& !BOARD_HAS_TIMING_FUNCTIONS \
&& !SOC_HAS_TIMING_FUNCTIONS
@@ -123,7 +121,6 @@ config RISCV
select ARCH_SUPPORTS_EMPTY_IRQ_SPURIOUS
select ARCH_HAS_CODE_DATA_RELOCATION
select ARCH_HAS_THREAD_LOCAL_STORAGE
- select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD
select USE_SWITCH_SUPPORTED
select USE_SWITCH
select SCHED_IPI_SUPPORTED if SMP
@@ -138,7 +135,6 @@ config XTENSA
select ARCH_IS_SET
select USE_SWITCH
select USE_SWITCH_SUPPORTED
- select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD
select ARCH_HAS_CODE_DATA_RELOCATION
select ARCH_HAS_TIMING_FUNCTIONS
select ARCH_MEM_DOMAIN_DATA if USERSPACE
@@ -581,11 +577,12 @@ config IRQ_OFFLOAD
config IRQ_OFFLOAD_NESTED
bool "irq_offload() supports nested IRQs"
depends on IRQ_OFFLOAD
+ default y if ARM64 || X86 || RISCV || XTENSA
help
- When set by the arch layer, indicates that irq_offload() may
- legally be called in interrupt context to cause a
- synchronous nested interrupt on the current CPU. Not all
- hardware is capable.
+ When set by the platform layers, indicates that
+ irq_offload() may legally be called in interrupt context to
+ cause a synchronous nested interrupt on the current CPU.
+ Not all hardware is capable.
config EXCEPTION_DEBUG
bool "Unhandled exception debugging"
diff --git a/boards/mediatek/index.rst b/boards/mediatek/index.rst
new file mode 100644
index 0000000000000..4c41e0b4d8637
--- /dev/null
+++ b/boards/mediatek/index.rst
@@ -0,0 +1,166 @@
+.. _boards-mtk_adsp:
+
+Mediatek Audio DSPs
+###################
+
+Zephyr can be built and run on the Audio DSPs included in various
+members of the Mediatek MT8xxx series of ARM SOCs used in Chromebooks
+from various manufacturers.
+
+Two of these DSPs are in the market already, implemented via the
+MT8195 ("Kompanio 1380") and MT8186 ("Kompanio 520") SOCs.
+Development has been done on and validation performed on at least
+these devices, though more exist:
+
+ ====== ============= =================================== =================
+ SOC Product Name Example Device ChromeOS Codename
+ ====== ============= =================================== =================
+ MT8195 Kompanio 1380 HP Chromebook x360 13b dojo
+ MT8186 Kompanio 520 Lenovo 300e Yoga Chromebook Gen 4 steelix
+ ====== ============= =================================== =================
+
+Hardware
+********
+
+These devices are Xtensa DSP cores, very similar to the Intel ADSP
+series in concept (with the notable difference that these are all
+single-core devices, no parallel SMP is available, but at the same
+time there are fewer worries about the incoherent cache).
+
+Their memory space is split between dedicated, fast SRAM and ~16MB of
+much slower system DRAM. Zephyr currently loads and links into the
+DRAM area, a convention it inherits from SOF (these devices have
+comparatively large caches which are used for all accesses, unlike
+with intel_adsp). SRAM is used for interrupt vectors and stacks,
+currently.
+
+There is comparatively little on-device hardware. The architecture is
+that interaction with the off-chip audio hardware (e.g. I2S codecs,
+DMIC inputs, etc...) is managed by the host kernel. The DSP receives
+its data via a single array of custom DMA controllers.
+
+Beyond that the Zephyr-visible hardware is limited to a bounty of
+timer devices (of which Zephyr uses two), and a "mailbox"
+bidirectional interrupt source it uses to communicate with the host
+kernel.
+
+Programming and Debugging
+*************************
+
+These devices work entirely in RAM, so there is no "flash" process as
+such. Their memory state is initialized by the host Linux
+environment. This process works under the control of a
+``mtk_adsp_load.py`` python script, which has no dependencies outside
+the standard library and can be run (as root, of course) on any
+reasonably compatible Linux environment with a Python 3.8 or later
+interpreter. A chromebook in development mode with the dev packages
+installed works great. See the ChromiumOS developer library for more
+detail:
+
+* `Developer mode `__
+* `Dev-Install: Installing Developer and Test packages onto a Chrome OS device `__
+
+Once you have the device set up, the process is as simple as copying
+the ``zephyr.img`` file from the build directory to the device
+(typically via ssh) and running it with the script. For example for
+my mt8186 device named "steelix":
+
+.. code-block:: console
+
+ user@dev_host:~$ west build -b mt8186//adsp samples/hello_world
+ ...
+ ... # build output
+ ...
+ user@dev_host:~$ scp build/zephyr/zephyr.img root@steelix:
+ user@dev_host:~$ scp soc/mediatek/mt8xxx/mtk_adsp_load.py root@steelix:
+ user@dev_host:~$ ssh steelix
+
+ root@steelix:~ # ./mtk_adsp_load.py load zephyr.img
+ *** Booting Zephyr OS build v3.6.0-5820-gd2a89b3c089e ***
+ Hello World! mt8186_adsp/mt8186_adsp
+
+Debugging
+=========
+
+Given the limited I/O facilities, debugging support remains limited on
+these platforms. Users with access to hardware-level debug and trace
+tools (e.g. from Cadence) will be able to use them as-is. Zephyr
+debugging itself is limited to printk/logging techniques at the
+moment. In theory a bidirectional console like winstream can be used
+with gdb_stub, which has support on Xtensa and via the SDK debuggers,
+but this is still unintegrated.
+
+Toolchains
+**********
+
+The MT8195 toolchain is already part of the Zephyr SDK, so builds for
+the ``mt8195//adsp`` board should work out of the box simply following
+the generic Zephyr build instructions in the Getting Started guide.
+
+The MT8186 toolchain is not, and given the proliferation of Xtensa
+toolchains in the SDK may not be. The overlay files for the device
+are maintained by the SOF project, however, and building a toolchain
+yourself using crosstools-ng is not difficult or time-consuming. This
+script should work for most users:
+
+.. code-block:: shell
+
+ #!/bin/sh
+
+ TC=mtk_mt818x_adsp
+
+ # Grab source (these are small)
+ git clone https://github.com/crosstool-ng/crosstool-ng
+ git clone https://github.com/thesofproject/xtensa-overlay
+
+ # Build ct-ng itself
+ cd crosstool-ng
+ ./bootstrap
+ ./configure --enable-local
+ make -j$(nproc)
+
+ mkdir overlays
+ (cd overlays; ln -s ../../xtensa-overlay/xtensa_mt8186.tar.gz xtensa_${TC}.tar.gz)
+
+ # Construct a .config file
+ cat >.config <
+
+/dts-v1/;
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sram0: memory@4e100000 {
+ device_type = "memory";
+ compatible = "mmio-sram";
+ reg = <0x4e100000 DT_SIZE_K(1024)>;
+ };
+
+ dram0: memory@60000000 {
+ device_type = "memory";
+ compatible = "mmio-sram";
+ reg = <0x60000000 DT_SIZE_M(16)>;
+ };
+
+ dram1: memory@61000000 {
+ device_type = "memory";
+ compatible = "mmio-sram";
+ reg = <0x61000000 DT_SIZE_K(1024)>;
+ };
+
+ 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>;
+ };
+
+ intc2: intc@10680010 {
+ compatible = "mediatek,adsp_intc";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0x10680010 4>;
+ status-reg = <0x10680050>;
+ interrupts = <2 0 0>;
+ mask = <0x3f>;
+ interrupt-parent = <&core_intc>;
+ };
+
+ ostimer64: ostimer64@10683080 {
+ compatible = "mediatek,ostimer64";
+ reg = <0x10683080 28>;
+ };
+
+ ostimer0: ostimer@10683000 {
+ compatible = "mediatek,ostimer";
+ reg = <0x10683000 16>;
+ interrupt-parent = <&core_intc>;
+ interrupts = <18 0 0>;
+ };
+
+ mbox0: mbox@10686100 {
+ compatible = "mediatek,mbox";
+ reg = <0x10686100 16>;
+ interrupt-parent = <&intc2>;
+ interrupts = <1 0 0>;
+ };
+
+ mbox1: mbox@10687100 {
+ compatible = "mediatek,mbox";
+ reg = <0x10687100 16>;
+ interrupt-parent = <&intc2>;
+ interrupts = <2 0 0>;
+ };
+ }; /* soc */
+
+ chosen { };
+ aliases { };
+};
diff --git a/boards/mediatek/mt8188/Kconfig.mt8188 b/boards/mediatek/mt8188/Kconfig.mt8188
new file mode 100644
index 0000000000000..cc549945b91bd
--- /dev/null
+++ b/boards/mediatek/mt8188/Kconfig.mt8188
@@ -0,0 +1,5 @@
+# Copyright 2024 The ChromiumOS Authors
+# SPDX-License-Identifier: Apache-2.0
+
+config BOARD_MT8188
+ select SOC_MT8188
diff --git a/boards/mediatek/mt8188/board.yml b/boards/mediatek/mt8188/board.yml
new file mode 100644
index 0000000000000..f50e9227a82cd
--- /dev/null
+++ b/boards/mediatek/mt8188/board.yml
@@ -0,0 +1,5 @@
+boards:
+ - name: mt8188
+ vendor: mediatek
+ socs:
+ - name: mt8188
diff --git a/boards/mediatek/mt8188/mt8188_adsp.dts b/boards/mediatek/mt8188/mt8188_adsp.dts
new file mode 100644
index 0000000000000..1796bb7f44785
--- /dev/null
+++ b/boards/mediatek/mt8188/mt8188_adsp.dts
@@ -0,0 +1,81 @@
+/* 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@60000000 {
+ device_type = "memory";
+ compatible = "mmio-sram";
+ reg = <0x60000000 DT_SIZE_M(15)>;
+ };
+
+ dram1: memory@61000000 {
+ device_type = "memory";
+ compatible = "mmio-sram";
+ reg = <0x61000000 DT_SIZE_K(1024)>;
+ };
+
+ 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>;
+ };
+
+ intc2: intc@10b80010 {
+ compatible = "mediatek,adsp_intc";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0x10b80010 4>;
+ status-reg = <0x10b80050>;
+ interrupts = <2 0 0>;
+ mask = <0x3f>;
+ interrupt-parent = <&core_intc>;
+ };
+
+ ostimer64: ostimer64@10b83080 {
+ compatible = "mediatek,ostimer64";
+ reg = <0x10b83080 28>;
+ };
+
+ ostimer0: ostimer@10b83000 {
+ compatible = "mediatek,ostimer";
+ reg = <0x10b83000 16>;
+ interrupt-parent = <&core_intc>;
+ interrupts = <18 0 0>;
+ };
+
+ mbox0: mbox@10b86100 {
+ compatible = "mediatek,mbox";
+ reg = <0x10b86100 16>;
+ interrupt-parent = <&intc2>;
+ interrupts = <1 0 0>;
+ };
+
+ mbox1: mbox@10b87100 {
+ compatible = "mediatek,mbox";
+ reg = <0x10b87100 16>;
+ interrupt-parent = <&intc2>;
+ interrupts = <2 0 0>;
+ };
+ }; /* soc */
+
+ chosen { };
+ aliases { };
+};
diff --git a/boards/mediatek/mt8195_adsp/Kconfig.mt8195_adsp b/boards/mediatek/mt8195/Kconfig.mt8195
similarity index 71%
rename from boards/mediatek/mt8195_adsp/Kconfig.mt8195_adsp
rename to boards/mediatek/mt8195/Kconfig.mt8195
index 43a3a49f9e1c9..0fb211185c9d2 100644
--- a/boards/mediatek/mt8195_adsp/Kconfig.mt8195_adsp
+++ b/boards/mediatek/mt8195/Kconfig.mt8195
@@ -1,7 +1,7 @@
# Copyright 2023 The ChromiumOS Authors
# SPDX-License-Identifier: Apache-2.0
-config BOARD_MT8195_ADSP
- select SOC_MT8195_ADSP
+config BOARD_MT8195
+ select SOC_MT8195
help
Board with Mediatek MT8195 Audio DSP
diff --git a/boards/mediatek/mt8195_adsp/board.yml b/boards/mediatek/mt8195/board.yml
similarity index 57%
rename from boards/mediatek/mt8195_adsp/board.yml
rename to boards/mediatek/mt8195/board.yml
index a58b33ecf8d95..7a9bb707c1d50 100644
--- a/boards/mediatek/mt8195_adsp/board.yml
+++ b/boards/mediatek/mt8195/board.yml
@@ -1,6 +1,6 @@
boards:
- - name: mt8195_adsp
+ - name: mt8195
full_name: MT8195 ADSP
vendor: mediatek
socs:
- - name: mt8195_adsp
+ - name: mt8195
diff --git a/boards/mediatek/mt8195/mt8195_adsp.dts b/boards/mediatek/mt8195/mt8195_adsp.dts
new file mode 100644
index 0000000000000..a21d81693fa39
--- /dev/null
+++ b/boards/mediatek/mt8195/mt8195_adsp.dts
@@ -0,0 +1,94 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include
+
+/dts-v1/;
+/ {
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ sram0: memory@40000000 {
+ device_type = "memory";
+ compatible = "mmio-sram";
+ reg = <0x40000000 DT_SIZE_K(256)>;
+ };
+
+ dram0: memory@60000000 {
+ device_type = "memory";
+ compatible = "mmio-sram";
+ reg = <0x60000000 DT_SIZE_M(17)>;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpuclk: cpuclk@10000000 {
+ compatible = "mediatek,mt8195_cpuclk";
+ reg = <0x10000000 380>;
+ cg_reg = <0x10720180>;
+ pll_ctrl_reg = <0x1000c7e0>;
+ freqs_mhz = <26 370 540 720>;
+ };
+
+ core_intc: core_intc@0 {
+ compatible = "cdns,xtensa-core-intc";
+ reg = <0 4>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ };
+
+ intc1: intc@10680130 {
+ compatible = "mediatek,adsp_intc";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0x10680130 4>;
+ status-reg = <0x10680150>;
+ interrupts = <1 0 0>;
+ mask = <0x3ffffff0>;
+ interrupt-parent = <&core_intc>;
+ };
+
+ intc23: intc@108030f4 {
+ compatible = "mediatek,adsp_intc";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0x108030f4 4>;
+ status-reg = <0x108030fc>;
+ interrupts = <23 0 0>;
+ mask = <0xffff>;
+ interrupt-parent = <&core_intc>;
+ };
+
+ ostimer64: ostimer64@1080d080 {
+ compatible = "mediatek,ostimer64";
+ reg = <0x1080d080 28>;
+ };
+
+ ostimer0: ostimer@1080d000 {
+ compatible = "mediatek,ostimer";
+ reg = <0x1080d000 16>;
+ interrupt-parent = <&intc23>;
+ interrupts = <11 0 0>;
+ };
+
+ mbox0: mbox@10816000 {
+ compatible = "mediatek,mbox";
+ reg = <0x10816000 56>;
+ interrupt-parent = <&intc23>;
+ interrupts = <0 0 0>;
+ };
+
+ mbox1: mbox@10817000 {
+ compatible = "mediatek,mbox";
+ reg = <0x10817000 56>;
+ interrupt-parent = <&intc23>;
+ interrupts = <1 0 0>;
+ };
+ }; /* soc */
+
+ chosen { };
+ aliases { };
+};
diff --git a/boards/mediatek/mt8195_adsp/Kconfig.defconfig b/boards/mediatek/mt8195_adsp/Kconfig.defconfig
deleted file mode 100644
index 31f557670b15f..0000000000000
--- a/boards/mediatek/mt8195_adsp/Kconfig.defconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2023 The ChromiumOS Authors
-# SPDX-License-Identifier: Apache-2.0
-
-if BOARD_MT8195_ADSP
-
-config BOARD
- default "mt8195_adsp"
-
-endif # BOARD_MT8195_ADSP
diff --git a/boards/mediatek/mt8195_adsp/mt8195_adsp.dts b/boards/mediatek/mt8195_adsp/mt8195_adsp.dts
deleted file mode 100644
index c26e2dd0f4017..0000000000000
--- a/boards/mediatek/mt8195_adsp/mt8195_adsp.dts
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Copyright 2023 The ChromiumOS Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-#include
-
-/dts-v1/;
-/ {
-
-#address-cells = <1>;
-#size-cells = <1>;
-
-sram0: memory@40000000 {
- device_type = "memory";
- compatible = "mmio-sram";
- reg = <0x40000000 DT_SIZE_K(256)>;
-};
-
-dram0: memory@60000000 {
- device_type = "memory";
- compatible = "mmio-sram";
- reg = <0x60000000 DT_SIZE_M(17)>;
-};
-
-soc {
- #address-cells = <1>;
- #size-cells = <1>;
-
- cpuclk: cpuclk@10000000 {
- compatible = "mediatek,mt8195_cpuclk";
- reg = <0x10000000 380>;
- cg_reg = <0x10720180>;
- pll_ctrl_reg = <0x1000c7e0>;
- freqs_mhz = <26 370 540 720>;
- };
-
- core_intc: core_intc@0 {
- compatible = "cdns,xtensa-core-intc";
- reg = <0 4>;
- interrupt-controller;
- #interrupt-cells = <3>;
- };
-
- intc1: intc@10680130 {
- compatible = "mediatek,adsp_intc";
- interrupt-controller;
- #interrupt-cells = <3>;
- reg = <0x10680130 4>;
- status-reg = <0x10680150>;
- interrupts = <1 0 0>;
- mask = <0x3ffffff0>;
- interrupt-parent = <&core_intc>;
- };
-
- intc23: intc@108030f4 {
- compatible = "mediatek,adsp_intc";
- interrupt-controller;
- #interrupt-cells = <3>;
- reg = <0x108030f4 4>;
- status-reg = <0x108030fc>;
- interrupts = <23 0 0>;
- mask = <0xffff>;
- interrupt-parent = <&core_intc>;
- };
-
- ostimer64: ostimer64@1080d080 {
- compatible = "mediatek,ostimer64";
- reg = <0x1080d080 28>;
- };
-
- ostimer0: ostimer@1080d000 {
- compatible = "mediatek,ostimer";
- reg = <0x1080d000 16>;
- interrupt-parent = <&intc23>;
- interrupts = <11 0 0>;
- };
-
- mbox0: mbox@10816000 {
- compatible = "mediatek,mbox";
- reg = <0x10816000 56>;
- interrupt-parent = <&intc23>;
- interrupts = <0 0 0>;
- };
-
- mbox1: mbox@10817000 {
- compatible = "mediatek,mbox";
- reg = <0x10817000 56>;
- interrupt-parent = <&intc23>;
- interrupts = <1 0 0>;
- };
-}; /* soc */
-
-chosen { };
-aliases { };
-
-};
diff --git a/boards/mediatek/mt8195_adsp/mt8195_adsp_defconfig b/boards/mediatek/mt8195_adsp/mt8195_adsp_defconfig
deleted file mode 100644
index 1110a4cfeb1cc..0000000000000
--- a/boards/mediatek/mt8195_adsp/mt8195_adsp_defconfig
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright 2023 The ChromiumOS Authors
-# SPDX-License-Identifier: Apache-2.0
-
-CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=13000000
diff --git a/boards/mediatek/mt8196/Kconfig.mt8196 b/boards/mediatek/mt8196/Kconfig.mt8196
new file mode 100644
index 0000000000000..7167a09275533
--- /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 0000000000000..cf5a2e276992e
--- /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 0000000000000..ea3bfdf4f98a2
--- /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
new file mode 100644
index 0000000000000..e941f64004818
--- /dev/null
+++ b/boards/mediatek/twister.yaml
@@ -0,0 +1,18 @@
+arch: xtensa
+type: mcu
+toolchain:
+ - xt-clang
+testing:
+ ignore_tags:
+ - net
+ - bluetooth
+ - mcumgr
+variants:
+ mt8195/mt8195/adsp:
+ name: MediaTek MT8195 Audio DSP
+ mt8188/mt8188/adsp:
+ 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 7a6c06d9e61ac..995236f034674 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/dts/bindings/timer/mediatek,ostimer64.yaml b/dts/bindings/timer/mediatek,ostimer64.yaml
new file mode 100644
index 0000000000000..6431caef53cc7
--- /dev/null
+++ b/dts/bindings/timer/mediatek,ostimer64.yaml
@@ -0,0 +1,15 @@
+# Copyright 2024 The ChromiumOS Authors
+# SPDX-License-Identifier: Apache-2.0
+
+include: base.yaml
+
+# This clock hardware is almost fully described by its register block,
+# but needs a binding for the frequency property below (which is
+# architecturally fixed at 13 MHz on all known devices)
+
+description: MediaTek Audio DSP Core Clock
+compatible: "mediatek,ostimer64"
+properties:
+ freq-hz:
+ type: int
+ default: 13000000
diff --git a/soc/mediatek/mtk_adsp/CMakeLists.txt b/soc/mediatek/mt8xxx/CMakeLists.txt
similarity index 78%
rename from soc/mediatek/mtk_adsp/CMakeLists.txt
rename to soc/mediatek/mt8xxx/CMakeLists.txt
index fb2d3b5933d06..96d0ae468b14a 100644
--- a/soc/mediatek/mtk_adsp/CMakeLists.txt
+++ b/soc/mediatek/mt8xxx/CMakeLists.txt
@@ -1,7 +1,9 @@
# Copyright 2023 The ChromiumOS Authors
# SPDX-License-Identifier: Apache-2.0
-zephyr_library_sources(soc.c irq.c cpuclk.c mbox.c)
+zephyr_library_sources(soc.c irq.c mbox.c)
+
+zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_MT8195 cpuclk.c)
set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/${CONFIG_SOC}/linker.ld CACHE INTERNAL "")
diff --git a/soc/mediatek/mtk_adsp/Kconfig b/soc/mediatek/mt8xxx/Kconfig
similarity index 81%
rename from soc/mediatek/mtk_adsp/Kconfig
rename to soc/mediatek/mt8xxx/Kconfig
index a2887dff32851..87f4f24faecf2 100644
--- a/soc/mediatek/mtk_adsp/Kconfig
+++ b/soc/mediatek/mt8xxx/Kconfig
@@ -1,6 +1,6 @@
# Copyright 2024 The ChromiumOS Authors
# SPDX-License-Identifier: Apache-2.0
-config SOC_FAMILY_MTK_ADSP
+config SOC_FAMILY_MTK
select XTENSA
select XTENSA_GEN_HANDLERS
diff --git a/soc/mediatek/mtk_adsp/Kconfig.defconfig b/soc/mediatek/mt8xxx/Kconfig.defconfig
similarity index 74%
rename from soc/mediatek/mtk_adsp/Kconfig.defconfig
rename to soc/mediatek/mt8xxx/Kconfig.defconfig
index b25781651b4b0..8603103104427 100644
--- a/soc/mediatek/mtk_adsp/Kconfig.defconfig
+++ b/soc/mediatek/mt8xxx/Kconfig.defconfig
@@ -3,7 +3,7 @@
orsource "*/Kconfig.defconfig"
-if SOC_FAMILY_MTK_ADSP
+if SOC_FAMILY_MTK
config INTC_MTK_ADSP
default y
@@ -23,11 +23,22 @@ config MAX_IRQ_PER_AGGREGATOR
config 2ND_LVL_ISR_TBL_OFFSET
default 32
+# The 8186/8188 core has only one software interrupt that lives at
+# level 2, underneath other hardware interrupts like timer, so it
+# can't reliably do this. Unselect so the tests don't try to exercise
+# it.
+config IRQ_OFFLOAD_NESTED
+ default n if SOC_SERIES_MT818X
+ default y
+
config MTK_ADSP_TIMER
default y
config XTENSA_TIMER
default n
+config SYS_CLOCK_HW_CYCLES_PER_SEC
+ default $(dt_node_int_prop_int,$(dt_nodelabel_path,ostimer64),freq-hz)
+
config MAIN_STACK_SIZE
default 2048
@@ -48,7 +59,8 @@ config XTENSA_HAL
default y
config SOC_TOOLCHAIN_NAME
- default "mtk_mt8195_adsp"
+ default "mtk_mt8195_adsp" if SOC_SERIES_MT8195
+ default "mtk_mt818x_adsp" if SOC_SERIES_MT818X
config XTENSA_RESET_VECTOR
default n
@@ -69,4 +81,4 @@ config GEN_SW_ISR_TABLE
config GEN_IRQ_VECTOR_TABLE
default n
-endif # SOC_FAMILY_MTK_ADSP
+endif # SOC_FAMILY_MTK
diff --git a/soc/mediatek/mt8xxx/Kconfig.soc b/soc/mediatek/mt8xxx/Kconfig.soc
new file mode 100644
index 0000000000000..ba52c9eb57465
--- /dev/null
+++ b/soc/mediatek/mt8xxx/Kconfig.soc
@@ -0,0 +1,45 @@
+# Copyright 2024 The ChromiumOS Authors
+# SPDX-License-Identifier: Apache-2.0
+
+config SOC_FAMILY_MTK
+ bool
+
+config SOC_SERIES_MT8195
+ bool
+ select SOC_FAMILY_MTK
+ help
+ Mediatek MT8195 Audio DSP
+
+config SOC_SERIES_MT818X
+ bool
+ select SOC_FAMILY_MTK
+ 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
+
+config SOC_MT8186
+ bool
+ select SOC_SERIES_MT818X
+
+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/mtk_adsp/cpuclk.c b/soc/mediatek/mt8xxx/cpuclk.c
similarity index 100%
rename from soc/mediatek/mtk_adsp/cpuclk.c
rename to soc/mediatek/mt8xxx/cpuclk.c
diff --git a/soc/mediatek/mt8xxx/gen_img.py b/soc/mediatek/mt8xxx/gen_img.py
new file mode 100755
index 0000000000000..83b69ec1b9a05
--- /dev/null
+++ b/soc/mediatek/mt8xxx/gen_img.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+# Copyright 2023 The ChromiumOS Authors
+# SPDX-License-Identifier: Apache-2.0
+import struct
+import sys
+
+import elftools.elf.elffile
+import elftools.elf.sections
+
+# Converts a zephyr.elf file into an extremely simple "image format"
+# for device loading. Really we should just load the ELF file
+# directly, but the python ChromeOS test image lacks elftools. Longer
+# term we should probably just use rimage, but that's significantly
+# harder to parse.
+#
+# Format:
+#
+# 1. Three LE 32 bit words: MagicNumber, SRAM len, BootAddress
+# 2. Two byte arrays: SRAM (length specified), and DRAM (remainder of file)
+#
+# No padding or uninterpreted bytes.
+
+FILE_MAGIC = 0xE463BE95
+
+elf_file = sys.argv[1]
+out_file = sys.argv[2]
+
+sram = bytearray()
+dram = bytearray()
+
+# Returns the offset of a segment within the sram region, or -1 if it
+# doesn't appear to be SRAM. SRAM is mapped differently for different
+# SOCs, but it's always a <=1M region in 0x4xxxxxxx. Just use what we
+# get, but validate that it fits.
+sram_block = 0
+
+
+def sram_off(addr):
+ global sram_block
+ if addr < 0x40000000 or addr >= 0x50000000:
+ return -1
+ block = addr & ~0xFFFFF
+ assert sram_block in (0, block)
+
+ sram_block = block
+ off = addr - sram_block
+ assert off < 0x100000
+ return off
+
+
+# Similar heuristics: current platforms put DRAM either at 0x60000000
+# or 0x90000000 with no more than 16M of range
+def dram_off(addr):
+ if (addr >> 28 not in [6, 9]) or (addr & 0x0F000000 != 0):
+ return -1
+ return addr & 0xFFFFFF
+
+
+def read_elf(efile):
+ ef = elftools.elf.elffile.ELFFile(efile)
+
+ for seg in ef.iter_segments():
+ h = seg.header
+ if h.p_type == "PT_LOAD":
+ soff = sram_off(h.p_paddr)
+ doff = dram_off(h.p_paddr)
+ if soff >= 0:
+ buf = sram
+ off = soff
+ elif doff >= 0:
+ buf = dram
+ off = doff
+ else:
+ print(f"Invalid PT_LOAD address {h.p_paddr:x}")
+ sys.exit(1)
+
+ dat = seg.data()
+ end = off + len(dat)
+ if end > len(buf):
+ buf.extend(b'\x00' * (end - len(buf)))
+
+ # pylint: disable=consider-using-enumerate
+ for i in range(len(dat)):
+ buf[i + off] = dat[i]
+
+ for sec in ef.iter_sections():
+ if isinstance(sec, elftools.elf.sections.SymbolTableSection):
+ for sym in sec.iter_symbols():
+ if sym.name == "mtk_adsp_boot_entry":
+ boot_vector = sym.entry['st_value']
+
+ with open(out_file, "wb") as of:
+ of.write(struct.pack(">= 8;
@@ -24,6 +25,20 @@ 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));
+#endif
}
void z_soc_irq_enable(unsigned int irq)
diff --git a/soc/mediatek/mtk_adsp/mt8195_adsp/linker.ld b/soc/mediatek/mt8xxx/linker.ld
similarity index 97%
rename from soc/mediatek/mtk_adsp/mt8195_adsp/linker.ld
rename to soc/mediatek/mt8xxx/linker.ld
index b58b91e5dc97f..47a72aae2a81a 100644
--- a/soc/mediatek/mtk_adsp/mt8195_adsp/linker.ld
+++ b/soc/mediatek/mt8xxx/linker.ld
@@ -1,4 +1,4 @@
-/* Copyright 2023 The ChromiumOS Authors
+/* Copyright 2024 The ChromiumOS Authors
* SPDX-License-Identifier: Apache-2.0
*/
@@ -61,6 +61,7 @@ SECTIONS {
} > dram
#include
+#include
__rodata_region_end = .;
@@ -139,4 +140,5 @@ SECTIONS {
#ifdef CONFIG_LLEXT
#include
#endif
+
} /* SECTIONS */
diff --git a/soc/mediatek/mtk_adsp/mbox.c b/soc/mediatek/mt8xxx/mbox.c
similarity index 80%
rename from soc/mediatek/mtk_adsp/mbox.c
rename to soc/mediatek/mt8xxx/mbox.c
index e2906b8fa29d4..69fc7b0839346 100644
--- a/soc/mediatek/mtk_adsp/mbox.c
+++ b/soc/mediatek/mt8xxx/mbox.c
@@ -28,20 +28,31 @@
*
* In practice: The first device (mbox0) is for IPC commands in both
* directions. The cmd register is written with a 1 ("IPI_OP_REQ")
- * and the command is placed in shared DRAM. The message registers
- * are ignored. The second device (mbox1) is for responses to IPC
- * commands, writing a 2 (IPI_OP_RSP) to the command register. (Yes,
- * this is redundant, and the actual value is ignored by the ISRs on
- * both sides).
+ * and the command is placed in shared DRAM.
+ *
+ * Note that the 8195 has ten "msg" registers. These only exist on
+ * this version of the hardware, and act as uninspected r/w scratch
+ * registers to both the host and DSP, with no other behavior. They
+ * aren't used by the Linux kernel at all (which has a single driver
+ * for all these DSPs), so are described here for completeness but
+ * otherwise ignored. In practice they don't do anything that simple
+ * shared memory can't.
*/
struct mtk_mbox {
+#ifdef SOC_SERIES_MT8195
uint32_t in_cmd;
uint32_t in_cmd_clr;
uint32_t in_msg[5];
uint32_t out_cmd;
uint32_t out_cmd_clr;
uint32_t out_msg[5];
+#else
+ uint32_t in_cmd;
+ uint32_t out_cmd;
+ uint32_t in_cmd_clr;
+ uint32_t out_cmd_clr;
+#endif
};
struct mbox_cfg {
@@ -65,25 +76,6 @@ void mtk_adsp_mbox_set_handler(const struct device *mbox, uint32_t chan,
}
}
-void mtk_adsp_mbox_set_msg(const struct device *mbox, uint32_t idx, uint32_t val)
-{
- const struct mbox_cfg *cfg = ((struct device *)mbox)->config;
-
- if (idx < MTK_ADSP_MBOX_MSG_WORDS) {
- cfg->mbox->out_msg[idx] = val;
- }
-}
-
-uint32_t mtk_adsp_mbox_get_msg(const struct device *mbox, uint32_t idx)
-{
- const struct mbox_cfg *cfg = ((struct device *)mbox)->config;
-
- if (idx < MTK_ADSP_MBOX_MSG_WORDS) {
- return cfg->mbox->in_msg[idx];
- }
- return 0;
-}
-
void mtk_adsp_mbox_signal(const struct device *mbox, uint32_t chan)
{
const struct mbox_cfg *cfg = ((struct device *)mbox)->config;
diff --git a/soc/mediatek/mt8xxx/mt8186/Kconfig.defconfig b/soc/mediatek/mt8xxx/mt8186/Kconfig.defconfig
new file mode 100644
index 0000000000000..763e0c2ddd0b8
--- /dev/null
+++ b/soc/mediatek/mt8xxx/mt8186/Kconfig.defconfig
@@ -0,0 +1,13 @@
+# Copyright 2024 The ChromiumOS Authors
+# SPDX-License-Identifier: Apache-2.0
+
+if SOC_MT8186
+
+# FIXME: move this to 818x series code to share w/8188
+config NUM_2ND_LEVEL_AGGREGATORS
+ default 1
+
+config 2ND_LVL_INTR_00_OFFSET
+ default 2
+
+endif
diff --git a/soc/mediatek/mt8xxx/mt8186/linker.ld b/soc/mediatek/mt8xxx/mt8186/linker.ld
new file mode 100644
index 0000000000000..3d086aecb1abc
--- /dev/null
+++ b/soc/mediatek/mt8xxx/mt8186/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/mt8186/soc.h b/soc/mediatek/mt8xxx/mt8186/soc.h
new file mode 100644
index 0000000000000..5b5613517fb9c
--- /dev/null
+++ b/soc/mediatek/mt8xxx/mt8186/soc.h
@@ -0,0 +1,10 @@
+/* Copyright 2024 The ChromiumOS Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_SOC_MT8186_SOC_H
+#define ZEPHYR_SOC_MT8186_SOC_H
+
+#include "../soc.h"
+
+#endif /* ZEPHYR_SOC_MT8186_SOC_H */
diff --git a/soc/mediatek/mt8xxx/mt8188/Kconfig.defconfig b/soc/mediatek/mt8xxx/mt8188/Kconfig.defconfig
new file mode 100644
index 0000000000000..b79e1caac3677
--- /dev/null
+++ b/soc/mediatek/mt8xxx/mt8188/Kconfig.defconfig
@@ -0,0 +1,12 @@
+# Copyright 2024 The ChromiumOS Authors
+# SPDX-License-Identifier: Apache-2.0
+
+if SOC_MT8188
+
+config NUM_2ND_LEVEL_AGGREGATORS
+ default 1
+
+config 2ND_LVL_INTR_00_OFFSET
+ default 2
+
+endif
diff --git a/soc/mediatek/mt8xxx/mt8188/linker.ld b/soc/mediatek/mt8xxx/mt8188/linker.ld
new file mode 100644
index 0000000000000..3d086aecb1abc
--- /dev/null
+++ b/soc/mediatek/mt8xxx/mt8188/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/mt8188/soc.h b/soc/mediatek/mt8xxx/mt8188/soc.h
new file mode 100644
index 0000000000000..381f5686c8fb5
--- /dev/null
+++ b/soc/mediatek/mt8xxx/mt8188/soc.h
@@ -0,0 +1,10 @@
+/* Copyright 2024 The ChromiumOS Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_SOC_MT8188_SOC_H
+#define ZEPHYR_SOC_MT8188_SOC_H
+
+#include "../soc.h"
+
+#endif /* ZEPHYR_SOC_MT8188_SOC_H */
diff --git a/soc/mediatek/mtk_adsp/mt8195_adsp/Kconfig.defconfig b/soc/mediatek/mt8xxx/mt8195/Kconfig.defconfig
similarity index 78%
rename from soc/mediatek/mtk_adsp/mt8195_adsp/Kconfig.defconfig
rename to soc/mediatek/mt8xxx/mt8195/Kconfig.defconfig
index e50e98f004c3d..15e030beb35a6 100644
--- a/soc/mediatek/mtk_adsp/mt8195_adsp/Kconfig.defconfig
+++ b/soc/mediatek/mt8xxx/mt8195/Kconfig.defconfig
@@ -1,7 +1,7 @@
# Copyright 2023 The ChromiumOS Authors
# SPDX-License-Identifier: Apache-2.0
-if SOC_SERIES_MT8195_ADSP
+if SOC_SERIES_MT8195
config NUM_2ND_LEVEL_AGGREGATORS
default 2
@@ -10,4 +10,4 @@ config 2ND_LVL_INTR_00_OFFSET
config 2ND_LVL_INTR_01_OFFSET
default 23
-endif # SOC_SERIES_MT8195_ADSP
+endif # SOC_SERIES_MT8195
diff --git a/soc/mediatek/mt8xxx/mt8195/linker.ld b/soc/mediatek/mt8xxx/mt8195/linker.ld
new file mode 100644
index 0000000000000..3d086aecb1abc
--- /dev/null
+++ b/soc/mediatek/mt8xxx/mt8195/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/mt8195/soc.h b/soc/mediatek/mt8xxx/mt8195/soc.h
new file mode 100644
index 0000000000000..cfd8c56ad5ebe
--- /dev/null
+++ b/soc/mediatek/mt8xxx/mt8195/soc.h
@@ -0,0 +1,10 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_SOC_MT8195_SOC_H
+#define ZEPHYR_SOC_MT8195_SOC_H
+
+#include "../soc.h"
+
+#endif /* ZEPHYR_SOC_MT8195_SOC_H */
diff --git a/soc/mediatek/mt8xxx/mt8196/Kconfig.defconfig b/soc/mediatek/mt8xxx/mt8196/Kconfig.defconfig
new file mode 100644
index 0000000000000..e406dce76a5be
--- /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 0000000000000..3d086aecb1abc
--- /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 0000000000000..5c7734b9e6a96
--- /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
new file mode 100755
index 0000000000000..ba3e4dbaddde1
--- /dev/null
+++ b/soc/mediatek/mt8xxx/mtk_adsp_load.py
@@ -0,0 +1,290 @@
+#!/usr/bin/env python
+# Copyright 2023 The ChromiumOS Authors
+# SPDX-License-Identifier: Apache-2.0
+import ctypes
+import mmap
+import os
+import re
+import struct
+import sys
+import time
+from glob import glob
+
+# MT8195 audio firmware load/debug gadget
+
+# Note that the hardware handling here is only partial: in practice
+# the audio DSP depends on clock and power well devices whose drivers
+# live elsewhere in the kernel. Those aren't duplicated here. Make
+# sure the DSP has been started by a working kernel driver first.
+#
+# See gen_img.py for docs on the image format itself. The way this
+# script works is to map the device memory regions and registers via
+# /dev/mem and copy the two segments while resetting the DSP.
+#
+# In the kernel driver, the address/size values come from devicetree.
+# But currently the MediaTek architecture is one kernel driver per SOC
+# (i.e. the devicetree values in the kenrel source are tied to the
+# specific SOC anyway), so it really doesn't matter and we hard-code
+# the addresses for simplicity.
+#
+# (For future reference: in /proc/device-tree on current ChromeOS
+# kernels, the host registers are a "cfg" platform resource on the
+# "adsp@10803000" node. The sram is likewise the "sram" resource on
+# that device node, and the two dram areas are "memory-region"
+# phandles pointing to "adsp_mem_region" and "adsp_dma_mem_region"
+# nodes under "/reserved-memory").
+
+FILE_MAGIC = 0xE463BE95
+
+# Runtime mmap objects for each MAPPINGS entry
+maps = {}
+
+
+# Returns a string (e.g. "mt8195", "mt8186", "mt8188") if a supported
+# adsp is detected, or None if not
+def detect():
+ compat = readfile(glob("/proc/device-tree/**/adsp@*/compatible", recursive=True)[0], "r")
+ m = re.match(r'.*(mt\d{4})-dsp', compat)
+ if m:
+ return m.group(1)
+
+
+# Parse devicetree to find the MMIO mappings: there is an "adsp" node
+# (in various locations) with an array of named "reg" mappings. It
+# also refers by reference to reserved-memory regions of system
+# DRAM. Those don't have names, call them dram0/1 (dram1 is the main
+# region to which code is linked, dram0 is presumably a dma pool but
+# unused by current firmware). Returns a dict mapping name to a
+# (addr, size) tuple.
+def mappings():
+ path = glob("/proc/device-tree/**/adsp@*/", recursive=True)[0]
+ rnames = readfile(path + "reg-names", "r").split('\0')[:-1]
+ regs = struct.unpack(f">{2 * len(rnames)}Q", readfile(path + "reg"))
+ maps = {n: (regs[2 * i], regs[2 * i + 1]) for i, n in enumerate(rnames)}
+ for i, ph in enumerate(struct.unpack(">II", readfile(path + "memory-region"))):
+ for rmem in glob("/proc/device-tree/reserved-memory/*/"):
+ phf = rmem + "phandle"
+ if os.path.exists(phf) and struct.unpack(">I", readfile(phf))[0] == ph:
+ (addr, sz) = struct.unpack(">QQ", readfile(rmem + "reg"))
+ maps[f"dram{i}"] = (addr, sz)
+ break
+ return maps
+
+
+# Register API for 8195
+class MT8195:
+ def __init__(self, maps):
+ # Create a Regs object for the registers
+ r = Regs(ctypes.addressof(ctypes.c_int.from_buffer(maps["cfg"])))
+ r.ALTRESETVEC = 0x0004 # Xtensa boot address
+ r.RESET_SW = 0x0024 # Xtensa halt/reset/boot control
+ r.PDEBUGBUS0 = 0x000C # Unclear, enabled by host, unused by SOF?
+ r.SRAM_POOL_CON = 0x0930 # SRAM power control: low 4 bits (banks?) enable
+ r.EMI_MAP_ADDR = 0x981C # == host SRAM mapping - 0x40000000 (controls MMIO map?)
+ r.freeze()
+ self.cfg = r
+
+ def logrange(self):
+ return range(0x700000, 0x800000)
+
+ def stop(self):
+ self.cfg.RESET_SW |= 8 # Set RUNSTALL: halt CPU
+ self.cfg.RESET_SW |= 3 # Set low two bits: "BRESET|DRESET"
+
+ def start(self, boot_vector):
+ self.stop()
+ self.cfg.RESET_SW |= 0x10 # Enable "alternate reset" boot vector
+ self.cfg.ALTRESETVEC = boot_vector
+ self.cfg.RESET_SW &= ~3 # Release reset bits
+ self.cfg.RESET_SW &= ~8 # Clear RUNSTALL: go!
+
+
+# Register API for 8186/8188
+class MT818x:
+ def __init__(self, maps):
+ # These have registers spread across two blocks
+ 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.SW_RSTN = 0x00
+ self.cfg.IO_CONFIG = 0x0C
+ 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(0x700000, 0x800000)
+
+ def stop(self):
+ self.cfg.IO_CONFIG |= 1 << 31 # Set RUNSTALL to stop core
+ time.sleep(0.1)
+ self.cfg.SW_RSTN |= 0x11 # Assert reset: SW_RSTN_C0|SW_DBG_RSTN_C0
+
+ # Note: 8186 and 8188 use different bits in ALTVECSEC, but
+ # it's safe to write both to enable the alternate boot vector
+ def start(self, boot_vector):
+ self.cfg.IO_CONFIG |= 1 << 31 # Set RUNSTALL
+ self.sec.ALTVEC_C0 = boot_vector
+ self.sec.ALTVECSEL = 0x03 # Enable alternate vector
+ self.cfg.SW_RSTN |= 0x00000011 # Assert reset
+ 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
+# currently. Will be replaced by winstream very soon.
+def log(dev):
+ msg = b''
+ dram = maps["dram1"]
+ for i in dev.logrange():
+ x = dram[i]
+ if x == 0:
+ sys.stdout.buffer.write(msg)
+ sys.stdout.buffer.flush()
+ msg = b''
+ while x == 0:
+ time.sleep(0.1)
+ x = dram[i]
+ msg += x.to_bytes(1, "little")
+ sys.stdout.buffer.write(msg)
+ sys.stdout.buffer.flush()
+
+
+# (Cribbed from cavstool.py)
+class Regs:
+ def __init__(self, base_addr):
+ vars(self)["base_addr"] = base_addr
+ vars(self)["ptrs"] = {}
+ vars(self)["frozen"] = False
+
+ def freeze(self):
+ vars(self)["frozen"] = True
+
+ def __setattr__(self, name, val):
+ if not self.frozen and name not in self.ptrs:
+ addr = self.base_addr + val
+ self.ptrs[name] = ctypes.c_uint32.from_address(addr)
+ else:
+ self.ptrs[name].value = val
+
+ def __getattr__(self, name):
+ return self.ptrs[name].value
+
+
+def readfile(f, mode="rb"):
+ return open(f, mode).read()
+
+
+def le4(bstr):
+ assert len(bstr) == 4
+ return struct.unpack("")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/soc/mediatek/mtk_adsp/soc.c b/soc/mediatek/mt8xxx/soc.c
similarity index 90%
rename from soc/mediatek/mtk_adsp/soc.c
rename to soc/mediatek/mt8xxx/soc.c
index a94d5bbc5568f..744980f084a3e 100644
--- a/soc/mediatek/mtk_adsp/soc.c
+++ b/soc/mediatek/mt8xxx/soc.c
@@ -3,6 +3,7 @@
*/
#include
+#include
#include
#include
@@ -18,12 +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).
+ * 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"
@@ -35,7 +47,7 @@ __asm__(".align 4\n\t"
" movi a0, 1\n\t"
" wsr a0, WINDOWSTART\n\t"
" rsync\n\t"
- " movi a1, 0x40040000\n\t"
+ " movi a1, " INIT_STACK "\n\t"
" call4 c_boot\n\t");
/* Initial MPU configuration, needed to enable caching */
@@ -106,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) {
@@ -147,7 +159,9 @@ void c_boot(void)
*/
__asm__ volatile("wsr %0, VECBASE; rsync" :: "r"(&z_xtensa_vecbase));
+#ifdef CONFIG_SOC_SERIES_MT8195
mtk_adsp_cpu_freq_init();
+#endif
/* Likewise, memory power is external to the device, and the
* kernel SOF loader doesn't zero it, so zero our unlinked
@@ -171,5 +185,9 @@ void c_boot(void)
val = 0xffffffff;
__asm__ volatile("wsr %0, INTCLEAR" :: "r"(val));
+ /* Default console, a driver can override this later */
+ __stdout_hook_install(arch_printk_char_out);
+
+ void z_prep_c(void);
z_prep_c();
}
diff --git a/soc/mediatek/mtk_adsp/soc.h b/soc/mediatek/mt8xxx/soc.h
similarity index 63%
rename from soc/mediatek/mtk_adsp/soc.h
rename to soc/mediatek/mt8xxx/soc.h
index 8b6247b79108c..6857547ea2afb 100644
--- a/soc/mediatek/mtk_adsp/soc.h
+++ b/soc/mediatek/mt8xxx/soc.h
@@ -2,8 +2,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
-#ifndef ZEPHYR_SOC_MTK_ADSP_SOC_H
-#define ZEPHYR_SOC_MTK_ADSP_SOC_H
+#ifndef ZEPHYR_SOC_MTK_SOC_H
+#define ZEPHYR_SOC_MTK_SOC_H
#include
@@ -23,14 +23,7 @@ typedef void (*mtk_adsp_mbox_handler_t)(const struct device *mbox, void *arg);
void mtk_adsp_mbox_set_handler(const struct device *mbox, uint32_t chan,
mtk_adsp_mbox_handler_t handler, void *arg);
-/* Mailbox hardware has an array of unstructured "message" data in
- * each direction. Any value can be placed in the registers.
- */
-#define MTK_ADSP_MBOX_MSG_WORDS 5
-void mtk_adsp_mbox_set_msg(const struct device *mbox, uint32_t idx, uint32_t val);
-uint32_t mtk_adsp_mbox_get_msg(const struct device *mbox, uint32_t idx);
-
/* Signal an interrupt on the specified channel for the other side */
void mtk_adsp_mbox_signal(const struct device *mbox, uint32_t chan);
-#endif /* ZEPHYR_SOC_MTK_ADSP_SOC_H */
+#endif /* ZEPHYR_SOC_MTK_SOC_H */
diff --git a/soc/mediatek/mt8xxx/soc.yml b/soc/mediatek/mt8xxx/soc.yml
new file mode 100644
index 0000000000000..fd5cd68b04e0b
--- /dev/null
+++ b/soc/mediatek/mt8xxx/soc.yml
@@ -0,0 +1,21 @@
+family:
+ - name: mt8xxx
+ series:
+ - name: mt8195
+ socs:
+ - name: mt8195
+ cpuclusters:
+ - name: adsp
+ - name: mt818x
+ socs:
+ - name: mt8186
+ cpuclusters:
+ - name: adsp
+ - name: mt8188
+ cpuclusters:
+ - name: adsp
+ - name: mt8196
+ socs:
+ - name: mt8196
+ cpuclusters:
+ - name: adsp
diff --git a/soc/mediatek/mtk_adsp/Kconfig.soc b/soc/mediatek/mtk_adsp/Kconfig.soc
deleted file mode 100644
index 37e4f45228795..0000000000000
--- a/soc/mediatek/mtk_adsp/Kconfig.soc
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2024 The ChromiumOS Authors
-# SPDX-License-Identifier: Apache-2.0
-
-config SOC_FAMILY_MTK_ADSP
- bool
- help
- Mediatek MT8xxx Series Audio DSPs
-
-config SOC_SERIES_MT8195_ADSP
- bool
- select SOC_FAMILY_MTK_ADSP
- help
- Mediatek MT8195 Audio DSP
-
-config SOC_MT8195_ADSP
- bool
- select SOC_SERIES_MT8195_ADSP
-
-config SOC_FAMILY
- default "mtk_adsp" if SOC_FAMILY_MTK_ADSP
-
-config SOC_SERIES
- default "mt8195_adsp" if SOC_SERIES_MT8195_ADSP
-
-config SOC
- default "mt8195_adsp" if SOC_MT8195_ADSP
diff --git a/soc/mediatek/mtk_adsp/gen_img.py b/soc/mediatek/mtk_adsp/gen_img.py
deleted file mode 100755
index 5d14f5e9d13fb..0000000000000
--- a/soc/mediatek/mtk_adsp/gen_img.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2023 The ChromiumOS Authors
-# SPDX-License-Identifier: Apache-2.0
-import sys
-import struct
-import elftools.elf.elffile
-import elftools.elf.sections
-
-# Converts a zephyr.elf file into an extremely simple "image format"
-# for device loading. Really we should just load the ELF file
-# directly, but the python ChromeOS test image lacks elftools. Longer
-# term we should probably just use rimage, but that's significantly
-# harder to parse.
-#
-# Format:
-#
-# 1. Three LE 32 bit words: MagicNumber, SRAM len, BootAddress
-# 2. Two byte arrays: SRAM (length specified), and DRAM (remainder of file)
-#
-# No padding or uninterpreted bytes.
-
-FILE_MAGIC = 0xe463be95
-
-SRAM_START = 0x40000000
-SRAM_END = 0x40040000
-DRAM_START = 0x60000000
-DRAM_END = 0x61100000
-
-elf_file = sys.argv[1]
-out_file = sys.argv[2]
-
-ef = elftools.elf.elffile.ELFFile(open(elf_file, "rb"))
-
-sram = bytearray()
-dram = bytearray()
-
-for seg in ef.iter_segments():
- h = seg.header
- if h.p_type == "PT_LOAD":
- if h.p_paddr in range(SRAM_START, SRAM_END):
- buf = sram
- off = h.p_paddr - SRAM_START
- elif h.p_paddr in range(DRAM_START, DRAM_END):
- buf = dram
- off = h.p_paddr - DRAM_START
- else:
- print(f"Invalid PT_LOAD address {h.p_paddr:x}")
- sys.exit(1)
-
- dat = seg.data()
- end = off + len(dat)
- if end > len(buf):
- buf.extend(b'\x00' * (end - len(buf)))
-
- for i in range(len(dat)):
- buf[i + off] = dat[i]
-
-for sec in ef.iter_sections():
- if isinstance(sec, elftools.elf.sections.SymbolTableSection):
- for sym in sec.iter_symbols():
- if sym.name == "mtk_adsp_boot_entry":
- boot_vector = sym.entry['st_value']
-
-assert len(sram) < SRAM_END - SRAM_START
-assert len(dram) < DRAM_END - DRAM_START
-assert (SRAM_START <= boot_vector < SRAM_END) or (DRAM_START <= boot_vector < DRAM_END)
-
-of = open(out_file, "wb")
-of.write(struct.pack("")
-
-# (Cribbed from cavstool.py)
-class Regs:
- def __init__(self, base_addr):
- vars(self)["base_addr"] = base_addr
- vars(self)["ptrs"] = {}
- vars(self)["frozen"] = False
- def freeze(self):
- vars(self)["frozen"] = True
- def __setattr__(self, name, val):
- if not self.frozen and name not in self.ptrs:
- addr = self.base_addr + val
- self.ptrs[name] = ctypes.c_uint32.from_address(addr)
- else:
- self.ptrs[name].value = val
- def __getattr__(self, name):
- return self.ptrs[name].value
-
-if __name__ == "__main__":
- main()
diff --git a/soc/mediatek/mtk_adsp/soc.yml b/soc/mediatek/mtk_adsp/soc.yml
deleted file mode 100644
index c042b9bd2ae35..0000000000000
--- a/soc/mediatek/mtk_adsp/soc.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-family:
- - name: mtk_adsp
- series:
- - name: mtk_adsp
- socs:
- - name: mt8195_adsp
diff --git a/tests/boards/mtk_adsp/src/main.c b/tests/boards/mtk_adsp/src/main.c
index 63b87f89f8ec7..95efbffd47ce0 100644
--- a/tests/boards/mtk_adsp/src/main.c
+++ b/tests/boards/mtk_adsp/src/main.c
@@ -35,6 +35,7 @@ static uint32_t cpu_hz(void)
ZTEST(mtk_adsp, cpu_freq)
{
+#ifdef CONFIG_SOC_SERIES_MT8195
int freqs[] = { 26, 370, 540, 720 };
for (int i = 0; i < ARRAY_SIZE(freqs); i++) {
@@ -49,6 +50,9 @@ ZTEST(mtk_adsp, cpu_freq)
zassert_true(err > 200);
}
+#else
+ (void)cpu_hz();
+#endif
}
#define MBOX0 DEVICE_DT_GET(DT_INST(0, mediatek_mbox))
@@ -69,23 +73,16 @@ static void mbox_fn(const struct device *mbox, void *arg)
/* Test in/out interrupts from the host. This relies on a SOF driver
* on the host, which has the behavior of "replying" with an interrupt
* on mbox1 after receiving a "command" on mbox0 (you can also see it
- * whine about the invalid IPC message in the kernel logs). SOF
- * ignores the message bytes (it uses a DRAM area instead), so we just
- * write them blindly. It's only a partial test of the hardware, but
- * easy to run and exercises the core functionality.
+ * whine about the invalid IPC message in the kernel logs).
*
- * Note that there's a catch: SOF's "reply" comes after a timeout
- * (it's an invalid command, afterall) which is 165 seconds! But the
- * test does pass.
+ * Note that there's a catch: on older kernels, SOF's "reply" comes
+ * after a timeout (it's an invalid command, afterall) which is 165
+ * seconds! But the test does pass.
*/
ZTEST(mtk_adsp, mbox)
{
mtk_adsp_mbox_set_handler(MBOX1, 1, mbox_fn, NULL);
- for (int i = 0; i < MTK_ADSP_MBOX_MSG_WORDS; i++) {
- mtk_adsp_mbox_set_msg(MBOX0, i, 0x01010100 | i);
- }
-
/* First signal the host with a reply on the second channel,
* that effects a reply to anything it thinks it might have
* sent us