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 <daniel.leung@intel.com>
This commit is contained in:
parent
492e890cd6
commit
0ba204083d
14 changed files with 389 additions and 7 deletions
|
@ -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()
|
||||
|
|
32
boards/xtensa/intel_s1000_crb/support/all_gdb.txt
Normal file
32
boards/xtensa/intel_s1000_crb/support/all_gdb.txt
Normal file
|
@ -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
|
32
boards/xtensa/intel_s1000_crb/support/dsp1_gdb.txt
Normal file
32
boards/xtensa/intel_s1000_crb/support/dsp1_gdb.txt
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<configuration>
|
||||
<controller id='Controller0' module='ft2232' probe='flyswatter2' speed='10MHz' />
|
||||
<driver id='XtensaDriver0' cust-idcode='00140101,LX6' module='xtensa' step-intr='mask,stepover,setps' />
|
||||
|
||||
<driver id='TraxDriver0' module='trax' />
|
||||
<chain controller='Controller0'>
|
||||
<tap id='TAP2' irwidth='8' />
|
||||
<tap id='TAP0' irwidth='5' />
|
||||
<tap id='TAP1' irwidth='5' />
|
||||
</chain>
|
||||
|
||||
<system module='jtag'>
|
||||
<component id='Component0' tap='TAP0' config='trax' />
|
||||
<component id='Component1' tap='TAP1' config='trax' />
|
||||
</system>
|
||||
<device id='Xtensa0' component='Component0' driver='XtensaDriver0' />
|
||||
<device id='Xtensa1' component='Component1' driver='XtensaDriver0' />
|
||||
|
||||
<application id='GDBStub0' module='gdbstub' port='20000'>
|
||||
<target device='Xtensa0' sync-group='1' loose-sync='1' />
|
||||
<target device='Xtensa1' sync-group='1' loose-sync='1' />
|
||||
</application>
|
||||
|
||||
</configuration>
|
|
@ -0,0 +1,21 @@
|
|||
<configuration>
|
||||
<controller id='Controller0' module='ft2232' probe='flyswatter2' speed='10MHz' />
|
||||
<driver id='XtensaDriver0' cust-idcode='00140101,LX6' module='xtensa' step-intr='mask,stepover,setps' />
|
||||
|
||||
<driver id='TraxDriver0' module='trax' />
|
||||
<chain controller='Controller0'>
|
||||
<tap id='TAP2' irwidth='8' />
|
||||
<tap id='TAP1' irwidth='5' />
|
||||
</chain>
|
||||
|
||||
<system module='jtag'>
|
||||
<component id='Component1' tap='TAP1' config='trax' />
|
||||
|
||||
</system>
|
||||
<device id='Xtensa1' component='Component1' driver='XtensaDriver0' />
|
||||
|
||||
<application id='GDBStub0' module='gdbstub' port='20001'>
|
||||
<target device='Xtensa1' />
|
||||
</application>
|
||||
|
||||
</configuration>
|
|
@ -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>;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -21,6 +21,8 @@ OUTPUT_ARCH(xtensa)
|
|||
#include <linker/linker-defs.h>
|
||||
#include <linker/linker-tool.h>
|
||||
|
||||
#include <xtensa/config/core-isa.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
204
soc/xtensa/intel_s1000/soc_mp.c
Normal file
204
soc/xtensa/intel_s1000/soc_mp.c
Normal file
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <init.h>
|
||||
#include <kernel.h>
|
||||
#include <kernel_structs.h>
|
||||
#include <sys/sys_io.h>
|
||||
#include <sys/__assert.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(soc_mp, CONFIG_SOC_LOG_LEVEL);
|
||||
|
||||
#include "soc.h"
|
||||
#include "memory.h"
|
||||
|
||||
#ifdef CONFIG_SCHED_IPI_SUPPORTED
|
||||
#include <drivers/ipm.h>
|
||||
#include <ipm/ipm_cavs_idc.h>
|
||||
|
||||
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
|
Loading…
Add table
Add a link
Reference in a new issue