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