From 0ba204083ddfdd9c49d967e8247b0d218c2fcb2f Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 21 Feb 2019 15:05:30 -0800 Subject: [PATCH] soc: intel_s1000: add SMP support This adds SMP support for Intel S1000 SoC. Some of the start-up code is borrowed from ESP32. Signed-off-by: Daniel Leung --- boards/xtensa/intel_s1000_crb/board.cmake | 9 + .../intel_s1000_crb/support/all_gdb.txt | 32 +++ .../intel_s1000_crb/support/dsp1_gdb.txt | 32 +++ .../intel_s1000_crb/support/load_elf.txt | 3 + .../support/topology_all_flyswatter2.xml | 24 +++ .../support/topology_dsp1_flyswatter2.xml | 21 ++ dts/xtensa/intel/intel_s1000.dtsi | 8 + soc/xtensa/intel_s1000/CMakeLists.txt | 4 + soc/xtensa/intel_s1000/Kconfig.defconfig | 22 ++ soc/xtensa/intel_s1000/linker.ld | 12 ++ soc/xtensa/intel_s1000/memory.h | 6 +- soc/xtensa/intel_s1000/soc.c | 3 +- soc/xtensa/intel_s1000/soc.h | 16 +- soc/xtensa/intel_s1000/soc_mp.c | 204 ++++++++++++++++++ 14 files changed, 389 insertions(+), 7 deletions(-) create mode 100644 boards/xtensa/intel_s1000_crb/support/all_gdb.txt create mode 100644 boards/xtensa/intel_s1000_crb/support/dsp1_gdb.txt create mode 100644 boards/xtensa/intel_s1000_crb/support/topology_all_flyswatter2.xml create mode 100644 boards/xtensa/intel_s1000_crb/support/topology_dsp1_flyswatter2.xml create mode 100644 soc/xtensa/intel_s1000/soc_mp.c diff --git a/boards/xtensa/intel_s1000_crb/board.cmake b/boards/xtensa/intel_s1000_crb/board.cmake index 6e5e996f782..58c03a3e23a 100644 --- a/boards/xtensa/intel_s1000_crb/board.cmake +++ b/boards/xtensa/intel_s1000_crb/board.cmake @@ -3,9 +3,18 @@ board_set_flasher_ifnset(intel_s1000) board_set_debugger_ifnset(intel_s1000) +if(CONFIG_SMP) +board_finalize_runner_args(intel_s1000 + "--xt-ocd-dir=/opt/tensilica/xocd-12.0.4/xt-ocd" + "--ocd-topology=topology_all_flyswatter2.xml" + "--ocd-jtag-instr=all_gdb.txt" + "--gdb-flash-file=load_elf.txt" +) +else() board_finalize_runner_args(intel_s1000 "--xt-ocd-dir=/opt/tensilica/xocd-12.0.4/xt-ocd" "--ocd-topology=topology_dsp0_flyswatter2.xml" "--ocd-jtag-instr=dsp0_gdb.txt" "--gdb-flash-file=load_elf.txt" ) +endif() diff --git a/boards/xtensa/intel_s1000_crb/support/all_gdb.txt b/boards/xtensa/intel_s1000_crb/support/all_gdb.txt new file mode 100644 index 00000000000..f182671d520 --- /dev/null +++ b/boards/xtensa/intel_s1000_crb/support/all_gdb.txt @@ -0,0 +1,32 @@ +#Initialization script format +#COMMAND LENGTH DATA +# +#COMMAND: 1 - Scan DR branch +# 2 - Scan IR branch +# 3 - Send TRST +# +#LENGTH: Number of bits to send out (in decimal format). +# +#DATA: Data to send out. A sequence of bytes separated by space. +# The rightmost bit is scanned out first. E.g. (B4 B3 B2 B1 B0) +# +## Examples +# +# Perform TAP Reset: +3 +## all stap disable +2 8 12 +1 6 0 +# Scan out MTAP IDCODE command (0x2) a265013h +## all stap enable +2 8 12 +1 6 05 +# +# +# Scan out (2 cores): +# Send Trax Access IR command to 1st core and bypass to 2nd +#2 10 3 9F +# Write to DOSR register of 1st core (NAR part) +#1 9 1 07 +# Write 32 bits to DOSR register (NDR part) +#1 33 1 98 13 45 ab diff --git a/boards/xtensa/intel_s1000_crb/support/dsp1_gdb.txt b/boards/xtensa/intel_s1000_crb/support/dsp1_gdb.txt new file mode 100644 index 00000000000..fccecac20c3 --- /dev/null +++ b/boards/xtensa/intel_s1000_crb/support/dsp1_gdb.txt @@ -0,0 +1,32 @@ +#Initialization script format +#COMMAND LENGTH DATA +# +#COMMAND: 1 - Scan DR branch +# 2 - Scan IR branch +# 3 - Send TRST +# +#LENGTH: Number of bits to send out (in decimal format). +# +#DATA: Data to send out. A sequence of bytes separated by space. +# The rightmost bit is scanned out first. E.g. (B4 B3 B2 B1 B0) +# +## Examples +# +# Perform TAP Reset: +3 +## all stap disable +2 8 12 +1 6 0 +# Scan out MTAP IDCODE command (0x2) a265013h +## all stap enable +2 8 12 +1 6 04 +# +# +# Scan out (2 cores): +# Send Trax Access IR command to 1st core and bypass to 2nd +#2 10 3 9F +# Write to DOSR register of 1st core (NAR part) +#1 9 1 07 +# Write 32 bits to DOSR register (NDR part) +#1 33 1 98 13 45 ab diff --git a/boards/xtensa/intel_s1000_crb/support/load_elf.txt b/boards/xtensa/intel_s1000_crb/support/load_elf.txt index f92eab026f6..6351783c8bb 100644 --- a/boards/xtensa/intel_s1000_crb/support/load_elf.txt +++ b/boards/xtensa/intel_s1000_crb/support/load_elf.txt @@ -7,6 +7,9 @@ set *(0x71d20) = 0 # disable xtensa core power saving set *(0x71F90) = 0x71 +# stall/reset second core +set *(0x81C14) = 0x0202 + set pagination off set confirm off load zephyr/zephyr.elf diff --git a/boards/xtensa/intel_s1000_crb/support/topology_all_flyswatter2.xml b/boards/xtensa/intel_s1000_crb/support/topology_all_flyswatter2.xml new file mode 100644 index 00000000000..3504ff9ae9e --- /dev/null +++ b/boards/xtensa/intel_s1000_crb/support/topology_all_flyswatter2.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/boards/xtensa/intel_s1000_crb/support/topology_dsp1_flyswatter2.xml b/boards/xtensa/intel_s1000_crb/support/topology_dsp1_flyswatter2.xml new file mode 100644 index 00000000000..0dfc3f67bc8 --- /dev/null +++ b/boards/xtensa/intel_s1000_crb/support/topology_dsp1_flyswatter2.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/dts/xtensa/intel/intel_s1000.dtsi b/dts/xtensa/intel/intel_s1000.dtsi index d37974f85c3..06e5cb901a9 100644 --- a/dts/xtensa/intel/intel_s1000.dtsi +++ b/dts/xtensa/intel/intel_s1000.dtsi @@ -87,6 +87,14 @@ interrupt-parent = <&core_intc>; }; + idc: idc@1200 { + compatible = "intel,cavs-idc"; + label = "CAVS_IDC"; + reg = <0x1200 0x80>; + interrupts = <8 0 0>; + interrupt-parent = <&cavs0>; + }; + dw_intc: intc@81800 { compatible = "snps,designware-intc"; reg = <0x00081800 0x400>; diff --git a/soc/xtensa/intel_s1000/CMakeLists.txt b/soc/xtensa/intel_s1000/CMakeLists.txt index ae8aa2050e4..252f85f6188 100644 --- a/soc/xtensa/intel_s1000/CMakeLists.txt +++ b/soc/xtensa/intel_s1000/CMakeLists.txt @@ -7,3 +7,7 @@ zephyr_library_sources(soc.c) if("${ZEPHYR_TOOLCHAIN_VARIANT}" STREQUAL "xcc") add_subdirectory(xcc) endif() + +if(CONFIG_SMP) +zephyr_library_sources(soc_mp.c) +endif() diff --git a/soc/xtensa/intel_s1000/Kconfig.defconfig b/soc/xtensa/intel_s1000/Kconfig.defconfig index e0e813aa0af..2724148c34c 100644 --- a/soc/xtensa/intel_s1000/Kconfig.defconfig +++ b/soc/xtensa/intel_s1000/Kconfig.defconfig @@ -23,4 +23,26 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC default 400000000 if XTENSA_TIMER default 38400000 if CAVS_TIMER +if SMP + +config MP_NUM_CPUS + default 2 + +config XTENSA_TIMER + default n + +config CAVS_TIMER + default y + +config IPM + default y + +config IPM_CAVS_IDC + default y if IPM + +config SCHED_IPI_SUPPORTED + default y if IPM_CAVS_IDC + +endif + endif diff --git a/soc/xtensa/intel_s1000/linker.ld b/soc/xtensa/intel_s1000/linker.ld index 000a053abc1..671a2e2e869 100644 --- a/soc/xtensa/intel_s1000/linker.ld +++ b/soc/xtensa/intel_s1000/linker.ld @@ -21,6 +21,8 @@ OUTPUT_ARCH(xtensa) #include #include +#include + #define RAMABLE_REGION ram :ram_phdr #define ROMABLE_REGION ram :ram_phdr #define LPRAM_REGION lpram @@ -179,7 +181,17 @@ _memmap_cacheattr_bp_allvalid = 0x22222222; * as cacheattr_set macro sets them both to the same set of * attributes. */ +#ifndef CONFIG_SMP _memmap_cacheattr_intel_s1000 = 0x1212fff2; +#else +/* + * Since there is no cache coherence between cores, + * set the data section (0xA0000000 - 0xBFFFFFFF) to be + * non-cacheable, for now. Until we have proper support + * to manipulate cache lines. + */ +_memmap_cacheattr_intel_s1000 = 0x1222fff2; +#endif PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_intel_s1000); SECTIONS diff --git a/soc/xtensa/intel_s1000/memory.h b/soc/xtensa/intel_s1000/memory.h index 8117c16406f..53e9639bda6 100644 --- a/soc/xtensa/intel_s1000/memory.h +++ b/soc/xtensa/intel_s1000/memory.h @@ -47,9 +47,6 @@ #define MEM_VECT_SIZE (MEM_VECT_TEXT_SIZE +\ MEM_VECT_LIT_SIZE) -/* The memerror vector address is copied as is from core-isa.h */ -#define XCHAL_MEMERROR_VECTOR_PADDR 0xBEFE0400 - #define MEM_ERROR_TEXT_SIZE 0x180 #define MEM_ERROR_LIT_SIZE 0x8 @@ -72,4 +69,7 @@ #define LPRAM_BASE (DT_LP_SRAM_BASE) #define LPRAM_SIZE (DT_LP_SRAM_SIZE) +/* Boot vector resideing in LP-SRAM for core #1 */ +#define LPSRAM_BOOT_VECTOR_ADDR (DT_LP_SRAM_BASE + 0x08) + #endif /* __INC_MEMORY_H */ diff --git a/soc/xtensa/intel_s1000/soc.c b/soc/xtensa/intel_s1000/soc.c index ba0c4eaca7a..46480db82eb 100644 --- a/soc/xtensa/intel_s1000/soc.c +++ b/soc/xtensa/intel_s1000/soc.c @@ -284,8 +284,7 @@ static inline void soc_set_power_and_clock(void) dsp_shim_regs->clkctl |= SOC_CLKCTL_REQ_FAST_CLK | SOC_CLKCTL_OCS_FAST_CLK; - dsp_shim_regs->pwrctl |= SOC_PWRCTL_DISABLE_PWR_GATING_DSP1 | - SOC_PWRCTL_DISABLE_PWR_GATING_DSP0; + dsp_shim_regs->pwrctl |= SOC_PWRCTL_DISABLE_PWR_GATING_DSP0; soc_set_dmic_power(); soc_set_gna_power(); diff --git a/soc/xtensa/intel_s1000/soc.h b/soc/xtensa/intel_s1000/soc.h index 820b1c41888..6e43e945980 100644 --- a/soc/xtensa/intel_s1000/soc.h +++ b/soc/xtensa/intel_s1000/soc.h @@ -134,6 +134,11 @@ struct soc_resource_alloc_regs { u32_t geno; }; +/* L2 Local Memory Registers */ +#define SOC_L2RAM_LOCAL_MEM_REG_BASE 0x00071D00 +#define SOC_L2RAM_LOCAL_MEM_REG_LSPGCTL \ + (SOC_L2RAM_LOCAL_MEM_REG_BASE + 0x50) + /* DMIC SHIM Registers */ #define SOC_DMIC_SHIM_REG_BASE 0x00071E80 #define SOC_DMIC_SHIM_DMICLCTL_SPA BIT(0) @@ -198,15 +203,22 @@ struct soc_dsp_shim_regs { #define SOC_GNA_POWER_CONTROL_CPA (BIT(8)) #define SOC_GNA_POWER_CONTROL_CLK_EN (BIT(16)) +#define SOC_S1000_GLB_CTRL_DSP1_PWRCTL_CRST BIT(1) +#define SOC_S1000_GLB_CTRL_DSP1_PWRCTL_CSTALL BIT(9) +#define SOC_S1000_GLB_CTRL_DSP1_PWRCTL_SPA BIT(17) +#define SOC_S1000_GLB_CTRL_DSP1_PWRCTL_CPA BIT(25) + #define SOC_S1000_STRAP_REF_CLK (BIT_MASK(2) << 3) #define SOC_S1000_STRAP_REF_CLK_38P4 (0 << 3) #define SOC_S1000_STRAP_REF_CLK_19P2 (1 << 3) #define SOC_S1000_STRAP_REF_CLK_24P576 (2 << 3) struct soc_global_regs { - u32_t reserved1[8]; + u32_t reserved1[5]; + u32_t cavs_dsp1power_control; + u32_t reserved2[2]; u32_t gna_power_control; - u32_t reserved2[7]; + u32_t reserved3[7]; u32_t straps; }; diff --git a/soc/xtensa/intel_s1000/soc_mp.c b/soc/xtensa/intel_s1000/soc_mp.c new file mode 100644 index 00000000000..c9d6529b141 --- /dev/null +++ b/soc/xtensa/intel_s1000/soc_mp.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2018-2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(soc_mp, CONFIG_SOC_LOG_LEVEL); + +#include "soc.h" +#include "memory.h" + +#ifdef CONFIG_SCHED_IPI_SUPPORTED +#include +#include + +static struct device *idc; +#endif +extern void __start(void); + +struct cpustart_rec { + u32_t cpu; + arch_cpustart_t fn; + char *stack_top; + void *arg; + u32_t vecbase; + u32_t alive; + /* padding to cache line */ + u8_t padding[XCHAL_DCACHE_LINESIZE - 6 * 4]; +}; + +static __aligned(XCHAL_DCACHE_LINESIZE) +struct cpustart_rec start_rec; + +static void *mp_top; + +static void mp_entry2(void) +{ + volatile int ps, ie; + + /* Copy over VECBASE from the main CPU for an initial value + * (will need to revisit this if we ever allow a user API to + * change interrupt vectors at runtime). Make sure interrupts + * are locally disabled, then synthesize a PS value that will + * enable them for the user code to pass to irq_unlock() + * later. + */ + __asm__ volatile("rsr.PS %0" : "=r"(ps)); + ps &= ~(PS_EXCM_MASK | PS_INTLEVEL_MASK); + __asm__ volatile("wsr.PS %0" : : "r"(ps)); + + ie = 0; + __asm__ volatile("wsr.INTENABLE %0" : : "r"(ie)); + __asm__ volatile("wsr.VECBASE %0" : : "r"(start_rec.vecbase)); + __asm__ volatile("rsync"); + + /* Set up the CPU pointer. */ + _cpu_t *cpu = &_kernel.cpus[start_rec.cpu]; + + __asm__ volatile( + "wsr." CONFIG_XTENSA_KERNEL_CPU_PTR_SR " %0" : : "r"(cpu)); + +#ifdef CONFIG_IPM_CAVS_IDC + /* Interrupt must be enabled while running on current core */ + irq_enable(XTENSA_IRQ_NUMBER(DT_INST_0_INTEL_CAVS_IDC_IRQ_0)); +#endif /* CONFIG_IPM_CAVS_IDC */ + + start_rec.alive = 1; + SOC_DCACHE_FLUSH(&start_rec, sizeof(start_rec)); + + start_rec.fn(start_rec.arg); + +#if CONFIG_MP_NUM_CPUS == 1 + /* CPU#1 can be under manual control running custom functions + * instead of participating in general thread execution. + * Put the CPU into idle after those functions return + * so this won't return. + */ + for (;;) { + k_cpu_idle(); + } +#endif +} + +/* Defines a locally callable "function" named mp_stack_switch(). The + * first argument (in register a2 post-ENTRY) is the new stack pointer + * to go into register a1. The second (a3) is the entry point. + * Because this never returns, a0 is used as a scratch register then + * set to zero for the called function (a null return value is the + * signal for "top of stack" to the debugger). + */ +void mp_stack_switch(void *stack, void *entry); +__asm__("\n" + ".align 4 \n" + "mp_stack_switch: \n\t" + + "entry a1, 16 \n\t" + + "movi a0, 0 \n\t" + + "jx a3 \n\t"); + +/* Carefully constructed to use no stack beyond compiler-generated ABI + * instructions. Stack pointer is pointing to __stack at this point. + */ +void z_mp_entry(void) +{ + mp_stack_switch(mp_top, mp_entry2); +} + +void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, + arch_cpustart_t fn, void *arg) +{ + volatile struct soc_dsp_shim_regs *dsp_shim_regs = + (volatile struct soc_dsp_shim_regs *)SOC_DSP_SHIM_REG_BASE; + volatile struct soc_global_regs *soc_glb_regs = + (volatile struct soc_global_regs *)SOC_S1000_GLB_CTRL_BASE; + u32_t vecbase; + + __ASSERT(cpu_num == 1, "Intel S1000 supports only two CPUs!"); + + /* Setup data to boot core #1 */ + __asm__ volatile("rsr.VECBASE %0\n\t" : "=r"(vecbase)); + + start_rec.cpu = cpu_num; + start_rec.fn = fn; + start_rec.stack_top = Z_THREAD_STACK_BUFFER(stack) + sz; + start_rec.arg = arg; + start_rec.vecbase = vecbase; + start_rec.alive = 0; + + mp_top = Z_THREAD_STACK_BUFFER(stack) + sz; + + SOC_DCACHE_FLUSH(&start_rec, sizeof(start_rec)); + +#ifdef CONFIG_SCHED_IPI_SUPPORTED + idc = device_get_binding(DT_INST_0_INTEL_CAVS_IDC_LABEL); +#endif + + /* + * SoC Boot ROM has hard-coded address for boot vector in LP-SRAM, + * and will jump unconditionally to it. So power up the LP-SRAM + * and set the vector. + */ + sys_write32(0x0, SOC_L2RAM_LOCAL_MEM_REG_LSPGCTL); + *((u32_t *)LPSRAM_BOOT_VECTOR_ADDR) = (u32_t)__start; + + /* Disable power gating for DSP core #cpu_num */ + dsp_shim_regs->pwrctl |= SOC_PWRCTL_DISABLE_PWR_GATING_DSP1; + + /* + * Since we do not know the status of the core, + * power it down and force it into reset and stall. + */ + soc_glb_regs->cavs_dsp1power_control |= + SOC_S1000_GLB_CTRL_DSP1_PWRCTL_CRST | + SOC_S1000_GLB_CTRL_DSP1_PWRCTL_CSTALL; + + soc_glb_regs->cavs_dsp1power_control &= + ~SOC_S1000_GLB_CTRL_DSP1_PWRCTL_SPA; + + /* Wait for core power down */ + while ((soc_glb_regs->cavs_dsp1power_control & + SOC_S1000_GLB_CTRL_DSP1_PWRCTL_CPA) != 0) { + }; + + /* Now power up the core */ + soc_glb_regs->cavs_dsp1power_control |= + SOC_S1000_GLB_CTRL_DSP1_PWRCTL_SPA; + + /* Wait for core power up*/ + while ((soc_glb_regs->cavs_dsp1power_control & + SOC_S1000_GLB_CTRL_DSP1_PWRCTL_CPA) == 0) { + }; + + /* Then step out of reset, and un-stall */ + soc_glb_regs->cavs_dsp1power_control &= + ~SOC_S1000_GLB_CTRL_DSP1_PWRCTL_CRST; + + soc_glb_regs->cavs_dsp1power_control &= + ~SOC_S1000_GLB_CTRL_DSP1_PWRCTL_CSTALL; + + do { + SOC_DCACHE_INVALIDATE(&start_rec, sizeof(start_rec)); + } while (start_rec.alive == 0); +} + +#ifdef CONFIG_SCHED_IPI_SUPPORTED +FUNC_ALIAS(soc_sched_ipi, arch_sched_ipi, void); +void soc_sched_ipi(void) +{ + if (likely(idc != NULL)) { + ipm_send(idc, 0, IPM_CAVS_IDC_MSG_SCHED_IPI_ID, + IPM_CAVS_IDC_MSG_SCHED_IPI_DATA, 0); + } +} +#endif