diff --git a/arch/xtensa/core/prep_c.c b/arch/xtensa/core/prep_c.c index 990915c5a461..6dbab69f50f5 100644 --- a/arch/xtensa/core/prep_c.c +++ b/arch/xtensa/core/prep_c.c @@ -13,6 +13,13 @@ extern FUNC_NORETURN void z_cstart(void); /* defined by the SoC in case of CONFIG_SOC_HAS_RUNTIME_NUM_CPUS=y */ extern void soc_num_cpus_init(void); +/* Make sure the platform configuration matches what the toolchain + * thinks the hardware is doing. + */ +#ifdef CONFIG_DCACHE_LINE_SIZE +BUILD_ASSERT(CONFIG_DCACHE_LINE_SIZE == XCHAL_DCACHE_LINESIZE); +#endif + /** * * @brief Prepare to and run C code diff --git a/boards/mediatek/mt8186/mt8186_adsp.dts b/boards/mediatek/mt8186/mt8186_adsp.dts index a04aac1ffbf7..23f637cff4b6 100644 --- a/boards/mediatek/mt8186/mt8186_adsp.dts +++ b/boards/mediatek/mt8186/mt8186_adsp.dts @@ -37,12 +37,12 @@ #interrupt-cells = <3>; }; - intc2: intc@10680010 { + intc2: intc@10680050 { compatible = "mediatek,adsp_intc"; interrupt-controller; #interrupt-cells = <3>; - reg = <0x10680010 4>; - status-reg = <0x10680050>; + reg = <0x10680050 4>; + status-reg = <0x10680010>; interrupts = <2 0 0>; mask = <0x3f>; interrupt-parent = <&core_intc>; diff --git a/boards/mediatek/mt8188/mt8188_adsp.dts b/boards/mediatek/mt8188/mt8188_adsp.dts index 1796bb7f4478..5f676bf11585 100644 --- a/boards/mediatek/mt8188/mt8188_adsp.dts +++ b/boards/mediatek/mt8188/mt8188_adsp.dts @@ -38,12 +38,12 @@ #interrupt-cells = <3>; }; - intc2: intc@10b80010 { + intc2: intc@10b80050 { compatible = "mediatek,adsp_intc"; interrupt-controller; #interrupt-cells = <3>; - reg = <0x10b80010 4>; - status-reg = <0x10b80050>; + reg = <0x10b80050 4>; + status-reg = <0x10b80010>; interrupts = <2 0 0>; mask = <0x3f>; interrupt-parent = <&core_intc>; diff --git a/boards/mediatek/mt8195/mt8195_adsp.dts b/boards/mediatek/mt8195/mt8195_adsp.dts index a21d81693fa3..76a2b94415ad 100644 --- a/boards/mediatek/mt8195/mt8195_adsp.dts +++ b/boards/mediatek/mt8195/mt8195_adsp.dts @@ -18,7 +18,13 @@ dram0: memory@60000000 { device_type = "memory"; compatible = "mmio-sram"; - reg = <0x60000000 DT_SIZE_M(17)>; + reg = <0x60000000 DT_SIZE_K(13824)>; + }; + + dram1: memory@60e80000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x60e80000 DT_SIZE_K(2560)>; }; soc { diff --git a/boards/mediatek/mt8196/mt8196_adsp.dts b/boards/mediatek/mt8196/mt8196_adsp.dts index ea3bfdf4f98a..27fc2f0048a3 100644 --- a/boards/mediatek/mt8196/mt8196_adsp.dts +++ b/boards/mediatek/mt8196/mt8196_adsp.dts @@ -21,10 +21,10 @@ reg = <0x90000000 DT_SIZE_M(6)>; }; - dram1: memory@90700000 { + dram1: memory@90800000 { device_type = "memory"; compatible = "mmio-sram"; - reg = <0x90700000 DT_SIZE_M(1)>; + reg = <0x90800000 DT_SIZE_M(1)>; }; soc { @@ -88,16 +88,16 @@ interrupts = <8 0 0>; }; - mbox0: mbox@1a360100 { + mbox0: mbox@1a350100 { compatible = "mediatek,mbox"; - reg = <0x1a360100 16>; + reg = <0x1a350100 16>; interrupt-parent = <&intc_g2>; interrupts = <6 0 0>; }; - mbox1: mbox@1a370100 { + mbox1: mbox@1a360100 { compatible = "mediatek,mbox"; - reg = <0x1a370100 16>; + reg = <0x1a360100 16>; interrupt-parent = <&intc_g2>; interrupts = <7 0 0>; }; diff --git a/boards/qemu/xtensa/Kconfig.defconfig b/boards/qemu/xtensa/Kconfig.defconfig index 081971b5e810..c94da322385b 100644 --- a/boards/qemu/xtensa/Kconfig.defconfig +++ b/boards/qemu/xtensa/Kconfig.defconfig @@ -9,4 +9,8 @@ config BUILD_OUTPUT_BIN config IPM_CONSOLE_STACK_SIZE default 2048 if IPM_CONSOLE_RECEIVER +# Must match XCHAL_DCACHE_LINESIZE form core-isa.h +config DCACHE_LINE_SIZE + default 32 + endif # BOARD_QEMU_XTENSA diff --git a/drivers/console/Kconfig b/drivers/console/Kconfig index 2fd0111a9dd5..98ae6f7f8430 100644 --- a/drivers/console/Kconfig +++ b/drivers/console/Kconfig @@ -284,4 +284,20 @@ config WINSTREAM_CONSOLE See the WINSTREAM Kconfig help for more information. +config WINSTREAM_CONSOLE_STATIC + bool "Use static/linkable memory for the winstream console" + default y if !SOC_FAMILY_INTEL_ADSP + help + The winstream console can be configured to use simple linker + memory which can help avoid manual memory management at the + platform layer. The memory should be pointed to by the + symbol "_winstream_console_buf" and have size set by + CONFIG_WINSTREAM_CONSOLE_SIZE. + +config WINSTREAM_CONSOLE_STATIC_SIZE + int "Size of winstream console buffer" + default 32768 + help + Size of winstream console buffer, in bytes + endif # CONSOLE diff --git a/drivers/console/winstream_console.c b/drivers/console/winstream_console.c index 79794068ce81..08b0206a4d8d 100644 --- a/drivers/console/winstream_console.c +++ b/drivers/console/winstream_console.c @@ -12,8 +12,10 @@ #include #include +#ifdef SOC_FAMILY_INTEL_ADSP #include #include +#endif struct k_spinlock trace_lock; @@ -58,19 +60,70 @@ static void winstream_console_hook_install(void) #endif } +/* This gets optionally defined by the platform layer as it needs (it + * might want to go in a special location to coordinate with linux + * userspace, etc...) + */ +extern char _winstream_console_buf[]; + +/* This descriptor with a 96-bit magic number gets linked into the + * binary when enabled so that external tooling can easily find it at + * runtime (e.g. by searching the binary image file, etc...) + */ +#define WINSTREAM_CONSOLE_MAGIC1 0xd06a5f74U +#define WINSTREAM_CONSOLE_MAGIC2 0x004fe279U +#define WINSTREAM_CONSOLE_MAGIC3 0xf9bdb8cdU + +struct winstream_console_desc { + uint32_t magic1; + uint32_t magic2; + uint32_t magic3; + uint32_t buf_addr; + uint32_t size; +}; + +static const __used struct winstream_console_desc wsdesc = { + .magic1 = WINSTREAM_CONSOLE_MAGIC1, + .magic2 = WINSTREAM_CONSOLE_MAGIC2, + .magic3 = WINSTREAM_CONSOLE_MAGIC3, + .buf_addr = (uint32_t) &_winstream_console_buf, + .size = CONFIG_WINSTREAM_CONSOLE_STATIC_SIZE, +}; static int winstream_console_init(void) { + void *buf = NULL; + size_t size = 0; + +#ifdef SOC_FAMILY_INTEL_ADSP + /* These have a SOC-specific "mem_window" device. FIXME: The + * type handling is backwards here. We shouldn't be grabbing + * an arbitrary DTS alias and assuming it's a mem_window at + * runtime, that's not safe. The mem_window init code (which + * is typesafe by construction) should be detecting that it's + * supposed to be the console and starting the console hook + * registration process. + */ const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); if (!device_is_ready(dev)) { return -ENODEV; } const struct mem_win_config *config = dev->config; - void *buf = - sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *)config->mem_base); + buf = sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *)config->mem_base); + size = config->size; +#endif + +#ifdef CONFIG_WINSTREAM_CONSOLE_STATIC + /* Dirty trick to prevent linker garbage collection */ + _winstream_console_buf[0] = ((volatile char*) &wsdesc)[0]; + + buf = &_winstream_console_buf; + size = CONFIG_WINSTREAM_CONSOLE_STATIC_SIZE; +#endif - winstream = sys_winstream_init(buf, config->size); + __ASSERT_NO_MSG(buf != NULL && size != 0); + winstream = sys_winstream_init(buf, size); winstream_console_hook_install(); return 0; diff --git a/soc/mediatek/mt8xxx/Kconfig.defconfig b/soc/mediatek/mt8xxx/Kconfig.defconfig index dd429d36bbf4..d8ebe43c402d 100644 --- a/soc/mediatek/mt8xxx/Kconfig.defconfig +++ b/soc/mediatek/mt8xxx/Kconfig.defconfig @@ -31,11 +31,32 @@ config IRQ_OFFLOAD_NESTED default n if SOC_SERIES_MT818X default y +config CPU_HAS_DCACHE + default y +config DCACHE + default y +config CACHE_MANAGEMENT + default y +config DCACHE_LINE_SIZE + default 128 + +config NOCACHE_MEMORY + default y + config MTK_ADSP_TIMER default y config XTENSA_TIMER default n +config CONSOLE + default y +config WINSTREAM_CONSOLE + default y +config WINSTREAM + default y +config LOG_BACKEND_ADSP + default y if LOG + config XTENSA_CCOUNT_HZ default 720000000 if SOC_MT8195 default 400000000 if SOC_MT8186 diff --git a/soc/mediatek/mt8xxx/linker.ld b/soc/mediatek/mt8xxx/linker.ld index 9ed61873abde..1593c0d3b337 100644 --- a/soc/mediatek/mt8xxx/linker.ld +++ b/soc/mediatek/mt8xxx/linker.ld @@ -65,6 +65,15 @@ SECTIONS { *(.gnu.linkonce.h.*) } > dram + /* SOF extended manifest */ + . = ALIGN(16); + _fw_metadata_start = .; + .fw_metadata : { + KEEP (*(.fw_metadata)) + . = ALIGN(16); + } > dram + _fw_metadata_end = .; + #include #include @@ -101,6 +110,11 @@ SECTIONS { _end = .; _mtk_adsp_dram_end = .; + .nocache (NOLOAD) : { + . = ALIGN(4096); + *(.nocache .nocache.*) + } > dram + /* Non-runtime-loaded sections below */ #include diff --git a/soc/mediatek/mt8xxx/mbox.c b/soc/mediatek/mt8xxx/mbox.c index 4e0cbb905a63..448cb3b96a59 100644 --- a/soc/mediatek/mt8xxx/mbox.c +++ b/soc/mediatek/mt8xxx/mbox.c @@ -57,7 +57,6 @@ struct mtk_mbox { struct mbox_cfg { volatile struct mtk_mbox *mbox; - uint32_t irq; }; struct mbox_data { @@ -85,7 +84,12 @@ void mtk_adsp_mbox_signal(const struct device *mbox, uint32_t chan) } } -static void mbox_isr(const void *arg) +#define DEF_DEVPTR(N) DEVICE_DT_INST_GET(N), +const struct device * const mbox_devs[] = { + DT_INST_FOREACH_STATUS_OKAY(DEF_DEVPTR) +}; + +static void mbox_handle(const void *arg) { const struct mbox_cfg *cfg = ((struct device *)arg)->config; struct mbox_data *data = ((struct device *)arg)->data; @@ -101,11 +105,17 @@ static void mbox_isr(const void *arg) cfg->mbox->in_cmd_clr = cfg->mbox->in_cmd; /* ACK */ } +static void mbox_isr(const void *arg) +{ + for (int i = 0; i < ARRAY_SIZE(mbox_devs); i++) { + mbox_handle(mbox_devs[i]); + } +} + #define DEF_IRQ(N) \ { IRQ_CONNECT(DT_INST_IRQN(N), 0, mbox_isr, DEVICE_DT_INST_GET(N), 0); \ irq_enable(DT_INST_IRQN(N)); } - static int mbox_init(void) { DT_INST_FOREACH_STATUS_OKAY(DEF_IRQ); @@ -117,7 +127,7 @@ SYS_INIT(mbox_init, POST_KERNEL, 0); #define DEF_DEV(N) \ static struct mbox_data dev_data##N; \ static const struct mbox_cfg dev_cfg##N = \ - { .irq = DT_INST_IRQN(N), .mbox = (void *)DT_INST_REG_ADDR(N), }; \ + { .mbox = (void *)DT_INST_REG_ADDR(N), }; \ DEVICE_DT_INST_DEFINE(N, NULL, NULL, &dev_data##N, &dev_cfg##N, \ POST_KERNEL, 0, NULL); diff --git a/soc/mediatek/mt8xxx/mtk_adsp_load.py b/soc/mediatek/mt8xxx/mtk_adsp_load.py index ba3e4dbaddde..03efcd2f1cc7 100755 --- a/soc/mediatek/mt8xxx/mtk_adsp_load.py +++ b/soc/mediatek/mt8xxx/mtk_adsp_load.py @@ -171,7 +171,7 @@ def start(self, boot_vector): # 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): +def old_log(dev): msg = b'' dram = maps["dram1"] for i in dev.logrange(): @@ -218,6 +218,93 @@ def le4(bstr): return struct.unpack(" 0x2000000 or (r.START >= r.WLEN) or (r.END >= r.WLEN): + raise RuntimeError("Invalid winstream") + self.regs = r + self.data = (ctypes.c_char * r.WLEN).from_address(addr + 16) + self.msg = bytearray(r.WLEN) + self.seq = 0 + + def read(self): + ws, msg, data = self.regs, self.msg, self.data + last_seq = self.seq + wlen = ws.WLEN + while True: + start, end, seq = ws.START, ws.END, ws.SEQ + self.seq = seq + if seq == last_seq or start == end: + return "" + behind = seq - last_seq + if behind > ((end - start) % wlen): + return "" + copy = (end - behind) % wlen + suffix = min(behind, wlen - copy) + for i in range(suffix): + msg[i] = data[copy + i][0] + msglen = suffix + l2 = behind - suffix + if l2 > 0: + for i in range(l2): + msg[msglen + i] = data[i][0] + msglen += l2 + if start == ws.START and seq == ws.SEQ: + return msg[0:msglen].decode("utf-8", "replace") + + +# Locates a winstream descriptor in the firmware via its 96-bit magic +# number and returns the address and size fields it finds there. +def find_winstream(maps): + magic = b'\x74\x5f\x6a\xd0\x79\xe2\x4f\x00\xcd\xb8\xbd\xf9' + for m in maps: + if "dram" in m: + magoff = maps[m].find(magic) + if magoff >= 0: + addr = le4(maps[m][magoff + 12 : magoff + 16]) + return addr + raise RuntimeError("Cannot find winstream descriptor in firmware runtime") + + +def winstream_localaddr(globaddr, mmio, maps): + for m in mmio: + off = globaddr - mmio[m][0] + if 0 <= off < mmio[m][1]: + return ctypes.addressof(ctypes.c_int.from_buffer(maps[m])) + off + raise RuntimeError("Winstream address not inside DSP memory") + + +def winstream_log(mmio, maps): + physaddr = find_winstream(maps) + regsbase = winstream_localaddr(physaddr, mmio, maps) + ws = Winstream(regsbase) + while True: + msg = ws.read() + if msg: + sys.stdout.write(msg) + sys.stdout.flush() + else: + time.sleep(0.1) + + def main(): dsp = detect() assert dsp @@ -272,10 +359,18 @@ def main(): for i in range(len(dram), mmio["dram1"][1]): maps["dram1"][i] = 0 dev.start(boot_vector) - log(dev) + winstream_log(mmio, maps) elif sys.argv[1] == "log": - log(dev) + winstream_log(mmio, maps) + + elif sys.argv[1] == "oldlog": + old_log(dev) + + elif sys.argv[1] == "mem": + print("Memory Regions:") + for m in mmio: + print(f" {m}: {mmio[m][1]} @ 0x{mmio[m][0]:08x}") elif sys.argv[1] == "dump": sz = mmio[sys.argv[2]][1] diff --git a/soc/mediatek/mt8xxx/soc.c b/soc/mediatek/mt8xxx/soc.c index 128e7cad9968..2b375ccf3951 100644 --- a/soc/mediatek/mt8xxx/soc.c +++ b/soc/mediatek/mt8xxx/soc.c @@ -19,6 +19,11 @@ extern char _mtk_adsp_dram_end[]; #define DRAM_SIZE DT_REG_SIZE(DT_NODELABEL(dram0)) #define DRAM_END (DRAM_START + DRAM_SIZE) +#define DMA_START DT_REG_ADDR(DT_NODELABEL(dram1)) +#define DMA_SIZE DT_REG_SIZE(DT_NODELABEL(dram1)) +#define DMA_END (DMA_START + DMA_SIZE) + + #ifdef CONFIG_SOC_MT8196 #define INIT_STACK "0x90400000" #define LOG_BASE 0x90580000 @@ -197,6 +202,8 @@ static void enable_mpu(void) { DRAM_START, 0xf7f00 }, /* cached DRAM */ { (uint32_t)&_mtk_adsp_dram_end, 0x06f00 }, /* uncached DRAM */ { DRAM_END, 0x06000 }, /* inaccessible top of mem */ + { DMA_START, 0x06f00 }, /* uncached host "DMA" area */ + { DMA_END, 0x06000 }, /* inaccessible top of mem */ }; /* Must write BACKWARDS FROM THE END to avoid introducing a @@ -244,6 +251,7 @@ static void enable_mpu(void) * dram clear and also set buf[0] to 0 manually (as it isn't affected * by device reset). */ +#ifndef CONFIG_WINSTREAM_CONSOLE int arch_printk_char_out(int c) { char volatile * const buf = (void *)LOG_BASE; @@ -256,6 +264,10 @@ int arch_printk_char_out(int c) } return 0; } +#endif + +/* Define this here as a simple uncached array, no special linkage requirements */ +__nocache char _winstream_console_buf[CONFIG_WINSTREAM_CONSOLE_STATIC_SIZE]; void c_boot(void) {