From: Rander Wang rander.wang@linux.intel.com
Add platform initialisation and drivers for Intel Cannonlake platform.
Signed-off-by: Rander Wang rander.wang@linux.intel.com --- src/platform/cannonlake/Makefile.am | 35 ++ src/platform/cannonlake/base_module.c | 52 +++ src/platform/cannonlake/boot_ldr.x.in | 431 ++++++++++++++++++++++ src/platform/cannonlake/boot_module.c | 52 +++ src/platform/cannonlake/cannonlake.x.in | 542 ++++++++++++++++++++++++++++ src/platform/cannonlake/clk.c | 206 +++++++++++ src/platform/cannonlake/dai.c | 108 ++++++ src/platform/cannonlake/dma.c | 175 +++++++++ src/platform/cannonlake/include/Makefile.am | 1 + src/platform/cannonlake/interrupt.c | 304 ++++++++++++++++ src/platform/cannonlake/platform.c | 272 ++++++++++++++ src/platform/cannonlake/timer.c | 134 +++++++ 12 files changed, 2312 insertions(+) create mode 100644 src/platform/cannonlake/Makefile.am create mode 100644 src/platform/cannonlake/base_module.c create mode 100644 src/platform/cannonlake/boot_ldr.x.in create mode 100644 src/platform/cannonlake/boot_module.c create mode 100644 src/platform/cannonlake/cannonlake.x.in create mode 100644 src/platform/cannonlake/clk.c create mode 100644 src/platform/cannonlake/dai.c create mode 100644 src/platform/cannonlake/dma.c create mode 100644 src/platform/cannonlake/include/Makefile.am create mode 100644 src/platform/cannonlake/interrupt.c create mode 100644 src/platform/cannonlake/platform.c create mode 100644 src/platform/cannonlake/timer.c
diff --git a/src/platform/cannonlake/Makefile.am b/src/platform/cannonlake/Makefile.am new file mode 100644 index 0000000..9f3d591 --- /dev/null +++ b/src/platform/cannonlake/Makefile.am @@ -0,0 +1,35 @@ +SUBDIRS = include + +noinst_LIBRARIES = libplatform.a + +libplatform_a_SOURCES = \ + platform.c \ + dai.c \ + dma.c \ + clk.c \ + timer.c \ + interrupt.c + +libplatform_a_CFLAGS = \ + $(ARCH_CFLAGS) \ + $(ARCH_INCDIR) \ + $(REEF_INCDIR) \ + $(PLATFORM_INCDIR) + +noinst_PROGRAMS = module boot_module + +module_SOURCES = \ + base_module.c + +module_CFLAGS = \ + $(ARCH_INCDIR) \ + $(REEF_INCDIR) \ + $(PLATFORM_INCDIR) + +boot_module_SOURCES = \ + boot_module.c + +boot_module_CFLAGS = \ + $(ARCH_INCDIR) \ + $(REEF_INCDIR) \ + $(PLATFORM_INCDIR) \ No newline at end of file diff --git a/src/platform/cannonlake/base_module.c b/src/platform/cannonlake/base_module.c new file mode 100644 index 0000000..dd5d719 --- /dev/null +++ b/src/platform/cannonlake/base_module.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood liam.r.girdwood@linux.intel.com + */ + +#include <uapi/manifest.h> +#include <platform/memory.h> + +/* + * Each module has an entry in the FW manifest header. This is NOT part of + * the SOF executable image but is inserted by object copy as a ELF section + * for parsing by rimage (to genrate the manifest). + */ +struct sof_man_module cnl_manifest = { + .name = "BASEFW", + .uuid = {0x32, 0x8c, 0x39, 0x0e, 0xde, 0x5a, 0x4b, 0xba, + 0x93, 0xb1, 0xc5, 0x04, 0x32, 0x28, 0x0e, 0xe4}, + .entry_point = REEF_TEXT_START, + .type = { + .load_type = SOF_MAN_MOD_TYPE_MODULE, + .domain_ll = 1, + }, + .affinity_mask = 3, +}; + +/* not used, but stops linker complaining */ +int _start; diff --git a/src/platform/cannonlake/boot_ldr.x.in b/src/platform/cannonlake/boot_ldr.x.in new file mode 100644 index 0000000..cc7a2dc --- /dev/null +++ b/src/platform/cannonlake/boot_ldr.x.in @@ -0,0 +1,431 @@ +/* + * Linker Script for Cannonlake Bootloader. + * + * This script is run through the GNU C preprocessor to align the memory + * offsets with headers. + * + * Use spaces for formatting as cpp ignore tab sizes. + */ + +#include <platform/memory.h> +#include <xtensa/config/core-isa-boot.h> + +OUTPUT_ARCH(xtensa) + +MEMORY +{ + boot_entry_text : + org = IMR_BOOT_LDR_TEXT_ENTRY_BASE, + len = IMR_BOOT_LDR_TEXT_ENTRY_SIZE + boot_entry_lit : + org = IMR_BOOT_LDR_LIT_BASE, + len = IMR_BOOT_LDR_LIT_SIZE + reef_text : + org = IMR_BOOT_LDR_TEXT_BASE, + len = IMR_BOOT_LDR_TEXT_SIZE, + vector_base_text : + org = XCHAL_VECBASE_RESET_PADDR, + len = REEF_MEM_VECBASE_LIT_SIZE + vector_int2_lit : + org = XCHAL_INTLEVEL2_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int2_text : + org = XCHAL_INTLEVEL2_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_int3_lit : + org = XCHAL_INTLEVEL3_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int3_text : + org = XCHAL_INTLEVEL3_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_int4_lit : + org = XCHAL_INTLEVEL4_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int4_text : + org = XCHAL_INTLEVEL4_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_int5_lit : + org = XCHAL_INTLEVEL5_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int5_text : + org = XCHAL_INTLEVEL5_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_int6_lit : + org = XCHAL_INTLEVEL6_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int6_text : + org = XCHAL_INTLEVEL6_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_int7_lit : + org = XCHAL_INTLEVEL7_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int7_text : + org = XCHAL_INTLEVEL7_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_kernel_lit : + org = XCHAL_KERNEL_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_kernel_text : + org = XCHAL_KERNEL_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_user_lit : + org = XCHAL_USER_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_user_text : + org = XCHAL_USER_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_double_lit : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_double_text : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + reef_data : + org = IMR_BOOT_LDR_DATA_BASE, + len = IMR_BOOT_LDR_DATA_SIZE + reef_bss_data : + org = IMR_BOOT_LDR_BSS_BASE, + len = IMR_BOOT_LDR_BSS_SIZE +} + +PHDRS +{ + boot_entry_text_phdr PT_LOAD; + boot_entry_lit_phdr PT_LOAD; + reef_text_phdr PT_LOAD; + vector_base_text_phdr PT_LOAD; + vector_int2_lit_phdr PT_LOAD; + vector_int2_text_phdr PT_LOAD; + vector_int3_lit_phdr PT_LOAD; + vector_int3_text_phdr PT_LOAD; + vector_int4_lit_phdr PT_LOAD; + vector_int4_text_phdr PT_LOAD; + vector_int5_lit_phdr PT_LOAD; + vector_int5_text_phdr PT_LOAD; + vector_int6_lit_phdr PT_LOAD; + vector_int6_text_phdr PT_LOAD; + vector_int7_lit_phdr PT_LOAD; + vector_int7_text_phdr PT_LOAD; + vector_kernel_lit_phdr PT_LOAD; + vector_kernel_text_phdr PT_LOAD; + vector_user_lit_phdr PT_LOAD; + vector_user_text_phdr PT_LOAD; + vector_double_lit_phdr PT_LOAD; + vector_double_text_phdr PT_LOAD; + reef_data_phdr PT_LOAD; + reef_bss_data_phdr PT_LOAD; +} + +/* Default entry point: */ +ENTRY(boot_entry) +EXTERN(reset_vector) + +SECTIONS +{ + .boot_entry.text : ALIGN(4) + { + _boot_entry_text_start = ABSOLUTE(.); + KEEP (*(.boot_entry.text)) + _boot_entry_text_end = ABSOLUTE(.); + } >boot_entry_text :boot_entry_text_phdr + + .boot_entry.literal : ALIGN(4) + { + _boot_entry_literal_start = ABSOLUTE(.); + *(.boot_entry.literal) + *(.literal .literal.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + _boot_entry_literal_end = ABSOLUTE(.); + } >boot_entry_lit :boot_entry_lit_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.entry.text) + *(.init.literal) + KEEP(*(.init)) + *( .text .text.*) + *(.fini.literal) + KEEP(*(.fini)) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >reef_text :reef_text_phdr + + .WindowVectors.text : ALIGN(4) + { + _WindowVectors_text_start = ABSOLUTE(.); + KEEP (*(.WindowVectors.text)) + _WindowVectors_text_end = ABSOLUTE(.); + } >vector_base_text :vector_base_text_phdr + + .Level2InterruptVector.literal : ALIGN(4) + { + _Level2InterruptVector_literal_start = ABSOLUTE(.); + *(.Level2InterruptVector.literal) + _Level2InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int2_lit :vector_int2_lit_phdr + + .Level2InterruptVector.text : ALIGN(4) + { + _Level2InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level2InterruptVector.text)) + _Level2InterruptVector_text_end = ABSOLUTE(.); + } >vector_int2_text :vector_int2_text_phdr + + .Level3InterruptVector.literal : ALIGN(4) + { + _Level3InterruptVector_literal_start = ABSOLUTE(.); + *(.Level3InterruptVector.literal) + _Level3InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int3_lit :vector_int3_lit_phdr + + .Level3InterruptVector.text : ALIGN(4) + { + _Level3InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level3InterruptVector.text)) + _Level3InterruptVector_text_end = ABSOLUTE(.); + } >vector_int3_text :vector_int3_text_phdr + + .Level4InterruptVector.literal : ALIGN(4) + { + _Level4InterruptVector_literal_start = ABSOLUTE(.); + *(.Level4InterruptVector.literal) + _Level4InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int4_lit :vector_int4_lit_phdr + + .Level4InterruptVector.text : ALIGN(4) + { + _Level4InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level4InterruptVector.text)) + _Level4InterruptVector_text_end = ABSOLUTE(.); + } >vector_int4_text :vector_int4_text_phdr + + .Level5InterruptVector.literal : ALIGN(4) + { + _Level5InterruptVector_literal_start = ABSOLUTE(.); + *(.Level5InterruptVector.literal) + _Level5InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int5_lit :vector_int5_lit_phdr + + .Level5InterruptVector.text : ALIGN(4) + { + _Level5InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level5InterruptVector.text)) + _Level5InterruptVector_text_end = ABSOLUTE(.); + } >vector_int5_text :vector_int5_text_phdr + + .DebugExceptionVector.literal : ALIGN(4) + { + _DebugExceptionVector_literal_start = ABSOLUTE(.); + *(.DebugExceptionVector.literal) + _DebugExceptionVector_literal_end = ABSOLUTE(.); + } >vector_int6_lit :vector_int6_lit_phdr + + .DebugExceptionVector.text : ALIGN(4) + { + _DebugExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.DebugExceptionVector.text)) + _DebugExceptionVector_text_end = ABSOLUTE(.); + } >vector_int6_text :vector_int6_text_phdr + + .NMIExceptionVector.literal : ALIGN(4) + { + _NMIExceptionVector_literal_start = ABSOLUTE(.); + *(.NMIExceptionVector.literal) + _NMIExceptionVector_literal_end = ABSOLUTE(.); + } >vector_int7_lit :vector_int7_lit_phdr + + .NMIExceptionVector.text : ALIGN(4) + { + _NMIExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.NMIExceptionVector.text)) + _NMIExceptionVector_text_end = ABSOLUTE(.); + } >vector_int7_text :vector_int7_text_phdr + + .KernelExceptionVector.literal : ALIGN(4) + { + _KernelExceptionVector_literal_start = ABSOLUTE(.); + *(.KernelExceptionVector.literal) + _KernelExceptionVector_literal_end = ABSOLUTE(.); + } >vector_kernel_lit :vector_kernel_lit_phdr + + .KernelExceptionVector.text : ALIGN(4) + { + _KernelExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.KernelExceptionVector.text)) + _KernelExceptionVector_text_end = ABSOLUTE(.); + } >vector_kernel_text :vector_kernel_text_phdr + + .UserExceptionVector.literal : ALIGN(4) + { + _UserExceptionVector_literal_start = ABSOLUTE(.); + *(.UserExceptionVector.literal) + _UserExceptionVector_literal_end = ABSOLUTE(.); + } >vector_user_lit :vector_user_lit_phdr + + .UserExceptionVector.text : ALIGN(4) + { + _UserExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.UserExceptionVector.text)) + _UserExceptionVector_text_end = ABSOLUTE(.); + } >vector_user_text :vector_user_text_phdr + + .DoubleExceptionVector.literal : ALIGN(4) + { + _DoubleExceptionVector_literal_start = ABSOLUTE(.); + *(.DoubleExceptionVector.literal) + _DoubleExceptionVector_literal_end = ABSOLUTE(.); + } >vector_double_lit :vector_double_lit_phdr + + .DoubleExceptionVector.text : ALIGN(4) + { + _DoubleExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.DoubleExceptionVector.text)) + _DoubleExceptionVector_text_end = ABSOLUTE(.); + } >vector_double_text :vector_double_text_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + KEEP (*(.xt_except_table)) + KEEP (*(.gcc_except_table)) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + KEEP (*(.eh_frame)) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >reef_data :reef_data_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + KEEP(*(.gnu.linkonce.d.*personality*)) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + KEEP(*(.jcr)) + _data_end = ABSOLUTE(.); + } >reef_data :reef_data_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >reef_data :reef_data_phdr + + .bss (NOLOAD) : ALIGN(8) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + } >reef_bss_data :reef_bss_data_phdr + + _man = 0x1234567; + + PROVIDE(_memmap_vecbase_reset = HP_SRAM_VECBASE_RESET); + + _memmap_cacheattr_wbna_trapnull = 0x25222222; + PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wbna_trapnull); + + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .xt.insn 0 : + { + KEEP (*(.xt.insn)) + KEEP (*(.gnu.linkonce.x.*)) + } + .xt.prop 0 : + { + KEEP (*(.xt.prop)) + KEEP (*(.xt.prop.*)) + KEEP (*(.gnu.linkonce.prop.*)) + } + .xt.lit 0 : + { + KEEP (*(.xt.lit)) + KEEP (*(.xt.lit.*)) + KEEP (*(.gnu.linkonce.p.*)) + } + .xt.profile_range 0 : + { + KEEP (*(.xt.profile_range)) + KEEP (*(.gnu.linkonce.profile_range.*)) + } + .xt.profile_ranges 0 : + { + KEEP (*(.xt.profile_ranges)) + KEEP (*(.gnu.linkonce.xt.profile_ranges.*)) + } + .xt.profile_files 0 : + { + KEEP (*(.xt.profile_files)) + KEEP (*(.gnu.linkonce.xt.profile_files.*)) + } +} diff --git a/src/platform/cannonlake/boot_module.c b/src/platform/cannonlake/boot_module.c new file mode 100644 index 0000000..7d965f5 --- /dev/null +++ b/src/platform/cannonlake/boot_module.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood liam.r.girdwood@linux.intel.com + */ + +#include <uapi/manifest.h> +#include <platform/memory.h> + +/* + * Each module has an entry in the FW manifest header. This is NOT part of + * the SOF executable image but is inserted by object copy as a ELF section + * for parsing by rimage (to genrate the manifest). + */ +struct sof_man_module cnl_bootldr_manifest = { + .name = "BRNGUP", + .uuid = {0xf3, 0xe4, 0x79, 0x2b, 0x75, 0x46, 0x49, 0xf6, + 0x89, 0xdf, 0x3b, 0xc1, 0x94, 0xa9, 0x1a, 0xeb}, + .entry_point = IMR_BOOT_LDR_TEXT_ENTRY_BASE, + .type = { + .load_type = SOF_MAN_MOD_TYPE_MODULE, + .domain_ll = 1, + }, + .affinity_mask = 3, +}; + +/* not used, but stops linker complaining */ +int _start; diff --git a/src/platform/cannonlake/cannonlake.x.in b/src/platform/cannonlake/cannonlake.x.in new file mode 100644 index 0000000..9ca28f0 --- /dev/null +++ b/src/platform/cannonlake/cannonlake.x.in @@ -0,0 +1,542 @@ +/* + * Linker Script for Apololake. + * + * This script is run through the GNU C preprocessor to align the memory + * offsets with headers. + * + * Use spaces for formatting as cpp ignore tab sizes. + */ + +#include <platform/memory.h> +#include <xtensa/config/core-isa.h> + +OUTPUT_ARCH(xtensa) + +MEMORY +{ + vector_reset_text : + org = XCHAL_RESET_VECTOR0_PADDR, + len = REEF_MEM_RESET_TEXT_SIZE + vector_reset_lit : + org = XCHAL_RESET_VECTOR0_PADDR + REEF_MEM_RESET_TEXT_SIZE, + len = REEF_MEM_RESET_LIT_SIZE + vector_memory_lit : + org = XCHAL_MEMERROR_VECTOR_PADDR + REEF_MEM_ERROR_LIT_SIZE, + len = REEF_MEM_ERROR_LIT_SIZE + vector_memory_text : + org = XCHAL_MEMERROR_VECTOR_PADDR, + len = REEF_MEM_ERROR_TEXT_SIZE + vector_base_text : + org = XCHAL_VECBASE_RESET_PADDR, + len = REEF_MEM_VECBASE_LIT_SIZE + vector_int2_lit : + org = XCHAL_INTLEVEL2_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int2_text : + org = XCHAL_INTLEVEL2_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_int3_lit : + org = XCHAL_INTLEVEL3_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int3_text : + org = XCHAL_INTLEVEL3_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_int4_lit : + org = XCHAL_INTLEVEL4_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int4_text : + org = XCHAL_INTLEVEL4_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_int5_lit : + org = XCHAL_INTLEVEL5_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int5_text : + org = XCHAL_INTLEVEL5_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_int6_lit : + org = XCHAL_INTLEVEL6_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int6_text : + org = XCHAL_INTLEVEL6_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_int7_lit : + org = XCHAL_INTLEVEL7_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_int7_text : + org = XCHAL_INTLEVEL7_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_kernel_lit : + org = XCHAL_KERNEL_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_kernel_text : + org = XCHAL_KERNEL_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_user_lit : + org = XCHAL_USER_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_user_text : + org = XCHAL_USER_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + vector_double_lit : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR - REEF_MEM_VECT_LIT_SIZE, + len = REEF_MEM_VECT_LIT_SIZE + vector_double_text : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR, + len = REEF_MEM_VECT_TEXT_SIZE + reef_text_start : + org = REEF_TEXT_START, + len = REEF_TEXT_START_SIZE, + reef_text : + org = REEF_TEXT_BASE, + len = REEF_TEXT_SIZE, + reef_data : + org = REEF_TEXT_BASE + REEF_TEXT_SIZE, + len = REEF_DATA_SIZE + reef_bss_data : + org = REEF_TEXT_BASE + REEF_TEXT_SIZE + REEF_DATA_SIZE, + len = REEF_BSS_DATA_SIZE + system_heap : + org = HEAP_SYSTEM_BASE, + len = HEAP_SYSTEM_SIZE + runtime_heap : + org = HEAP_RUNTIME_BASE, + len = HEAP_RUNTIME_SIZE + buffer_heap : + org = HEAP_BUFFER_BASE, + len = HEAP_BUFFER_SIZE + reef_stack : + org = REEF_STACK_END, + len = REEF_STACK_BASE - REEF_STACK_END +} + +PHDRS +{ + vector_reset_text_phdr PT_LOAD; + vector_reset_lit_phdr PT_LOAD; + vector_memory_lit_phdr PT_LOAD; + vector_memory_text_phdr PT_LOAD; + vector_base_text_phdr PT_LOAD; + vector_int2_lit_phdr PT_LOAD; + vector_int2_text_phdr PT_LOAD; + vector_int3_lit_phdr PT_LOAD; + vector_int3_text_phdr PT_LOAD; + vector_int4_lit_phdr PT_LOAD; + vector_int4_text_phdr PT_LOAD; + vector_int5_lit_phdr PT_LOAD; + vector_int5_text_phdr PT_LOAD; + vector_int6_lit_phdr PT_LOAD; + vector_int6_text_phdr PT_LOAD; + vector_int7_lit_phdr PT_LOAD; + vector_int7_text_phdr PT_LOAD; + vector_kernel_lit_phdr PT_LOAD; + vector_kernel_text_phdr PT_LOAD; + vector_user_lit_phdr PT_LOAD; + vector_user_text_phdr PT_LOAD; + vector_double_lit_phdr PT_LOAD; + vector_double_text_phdr PT_LOAD; + reef_text_start_phdr PT_LOAD; + reef_text_phdr PT_LOAD; + reef_data_phdr PT_LOAD; + reef_bss_data_phdr PT_LOAD; + system_heap_phdr PT_LOAD; + runtime_heap_phdr PT_LOAD; + buffer_heap_phdr PT_LOAD; + reef_stack_phdr PT_LOAD; +} + +/* Default entry point: */ +ENTRY(_MainEntry) +_rom_store_table = 0; + +/* ABI0 does not use Window base */ +PROVIDE(_memmap_vecbase_reset = XCHAL_VECBASE_RESET_PADDR); + +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x44024000; +_memmap_cacheattr_wt_base = 0x11021000; +_memmap_cacheattr_bp_base = 0x22022000; +_memmap_cacheattr_unused_mask = 0x00F00FFF; +_memmap_cacheattr_wb_trapnull = 0x4422422F; +_memmap_cacheattr_wba_trapnull = 0x4422422F; +_memmap_cacheattr_wbna_trapnull = 0x25222222; +_memmap_cacheattr_wt_trapnull = 0x1122122F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0x44F24FFF; +_memmap_cacheattr_wt_strict = 0x11F21FFF; +_memmap_cacheattr_bp_strict = 0x22F22FFF; +_memmap_cacheattr_wb_allvalid = 0x44224222; +_memmap_cacheattr_wt_allvalid = 0x11221222; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wbna_trapnull); + +SECTIONS +{ + .ResetVector.text : ALIGN(4) + { + _ResetVector_text_start = ABSOLUTE(.); + KEEP (*(.ResetVector.text)) + _ResetVector_text_end = ABSOLUTE(.); + } >vector_reset_text :vector_reset_text_phdr + + .ResetVector.literal : ALIGN(4) + { + _ResetVector_literal_start = ABSOLUTE(.); + *(.ResetVector.literal) + _ResetVector_literal_end = ABSOLUTE(.); + } >vector_reset_lit :vector_reset_lit_phdr + + .MemoryExceptionVector.literal : ALIGN(4) + { + _MemoryExceptionVector_literal_start = ABSOLUTE(.); + KEEP (*(.MemoryExceptionVector.literal)) + _MemoryExceptionVector_literal_end = ABSOLUTE(.); + } >vector_memory_lit :vector_memory_lit_phdr + + .MemoryExceptionVector.text : ALIGN(4) + { + _MemoryExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.MemoryExceptionVector.text)) + _MemoryExceptionVector_text_end = ABSOLUTE(.); + } >vector_memory_text :vector_memory_text_phdr + + .WindowVectors.text : ALIGN(4) + { + _WindowVectors_text_start = ABSOLUTE(.); + KEEP (*(.WindowVectors.text)) + _WindowVectors_text_end = ABSOLUTE(.); + } >vector_base_text :vector_base_text_phdr + + .Level2InterruptVector.literal : ALIGN(4) + { + _Level2InterruptVector_literal_start = ABSOLUTE(.); + *(.Level2InterruptVector.literal) + _Level2InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int2_lit :vector_int2_lit_phdr + + .Level2InterruptVector.text : ALIGN(4) + { + _Level2InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level2InterruptVector.text)) + _Level2InterruptVector_text_end = ABSOLUTE(.); + } >vector_int2_text :vector_int2_text_phdr + + .Level3InterruptVector.literal : ALIGN(4) + { + _Level3InterruptVector_literal_start = ABSOLUTE(.); + *(.Level3InterruptVector.literal) + _Level3InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int3_lit :vector_int3_lit_phdr + + .Level3InterruptVector.text : ALIGN(4) + { + _Level3InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level3InterruptVector.text)) + _Level3InterruptVector_text_end = ABSOLUTE(.); + } >vector_int3_text :vector_int3_text_phdr + + .Level4InterruptVector.literal : ALIGN(4) + { + _Level4InterruptVector_literal_start = ABSOLUTE(.); + *(.Level4InterruptVector.literal) + _Level4InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int4_lit :vector_int4_lit_phdr + + .Level4InterruptVector.text : ALIGN(4) + { + _Level4InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level4InterruptVector.text)) + _Level4InterruptVector_text_end = ABSOLUTE(.); + } >vector_int4_text :vector_int4_text_phdr + + .Level5InterruptVector.literal : ALIGN(4) + { + _Level5InterruptVector_literal_start = ABSOLUTE(.); + *(.Level5InterruptVector.literal) + _Level5InterruptVector_literal_end = ABSOLUTE(.); + } >vector_int5_lit :vector_int5_lit_phdr + + .Level5InterruptVector.text : ALIGN(4) + { + _Level5InterruptVector_text_start = ABSOLUTE(.); + KEEP (*(.Level5InterruptVector.text)) + _Level5InterruptVector_text_end = ABSOLUTE(.); + } >vector_int5_text :vector_int5_text_phdr + + .DebugExceptionVector.literal : ALIGN(4) + { + _DebugExceptionVector_literal_start = ABSOLUTE(.); + *(.DebugExceptionVector.literal) + _DebugExceptionVector_literal_end = ABSOLUTE(.); + } >vector_int6_lit :vector_int6_lit_phdr + + .DebugExceptionVector.text : ALIGN(4) + { + _DebugExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.DebugExceptionVector.text)) + _DebugExceptionVector_text_end = ABSOLUTE(.); + } >vector_int6_text :vector_int6_text_phdr + + .NMIExceptionVector.literal : ALIGN(4) + { + _NMIExceptionVector_literal_start = ABSOLUTE(.); + *(.NMIExceptionVector.literal) + _NMIExceptionVector_literal_end = ABSOLUTE(.); + } >vector_int7_lit :vector_int7_lit_phdr + + .NMIExceptionVector.text : ALIGN(4) + { + _NMIExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.NMIExceptionVector.text)) + _NMIExceptionVector_text_end = ABSOLUTE(.); + } >vector_int7_text :vector_int7_text_phdr + + .KernelExceptionVector.literal : ALIGN(4) + { + _KernelExceptionVector_literal_start = ABSOLUTE(.); + *(.KernelExceptionVector.literal) + _KernelExceptionVector_literal_end = ABSOLUTE(.); + } >vector_kernel_lit :vector_kernel_lit_phdr + + .KernelExceptionVector.text : ALIGN(4) + { + _KernelExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.KernelExceptionVector.text)) + _KernelExceptionVector_text_end = ABSOLUTE(.); + } >vector_kernel_text :vector_kernel_text_phdr + + .UserExceptionVector.literal : ALIGN(4) + { + _UserExceptionVector_literal_start = ABSOLUTE(.); + *(.UserExceptionVector.literal) + _UserExceptionVector_literal_end = ABSOLUTE(.); + } >vector_user_lit :vector_user_lit_phdr + + .UserExceptionVector.text : ALIGN(4) + { + _UserExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.UserExceptionVector.text)) + _UserExceptionVector_text_end = ABSOLUTE(.); + } >vector_user_text :vector_user_text_phdr + + .DoubleExceptionVector.literal : ALIGN(4) + { + _DoubleExceptionVector_literal_start = ABSOLUTE(.); + *(.DoubleExceptionVector.literal) + _DoubleExceptionVector_literal_end = ABSOLUTE(.); + } >vector_double_lit :vector_double_lit_phdr + + .DoubleExceptionVector.text : ALIGN(4) + { + _DoubleExceptionVector_text_start = ABSOLUTE(.); + KEEP (*(.DoubleExceptionVector.text)) + _DoubleExceptionVector_text_end = ABSOLUTE(.); + } >vector_double_text :vector_double_text_phdr + + .MainEntry.text : ALIGN(4) + { + _MainEntry_text_start = ABSOLUTE(.); + KEEP (*(.MainEntry.text)) + _MainEntry_text_end = ABSOLUTE(.); + } >reef_text_start :reef_text_start_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.entry.text) + *(.init.literal) + KEEP(*(.init)) + *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + KEEP(*(.fini)) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >reef_text :reef_text_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + KEEP (*(.xt_except_table)) + KEEP (*(.gcc_except_table)) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + KEEP (*(.eh_frame)) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >reef_data :reef_data_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + KEEP(*(.gnu.linkonce.d.*personality*)) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + KEEP(*(.jcr)) + _data_end = ABSOLUTE(.); + } >reef_data :reef_data_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >reef_data :reef_data_phdr + + .bss (NOLOAD) : ALIGN(8) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + } >reef_bss_data :reef_bss_data_phdr + + /* stack */ + _end = REEF_STACK_END; + PROVIDE(end = REEF_STACK_END); + _stack_sentry = REEF_STACK_END; + __stack = REEF_STACK_BASE; + + /* System Heap */ + _system_heap = HEAP_SYSTEM_BASE; + + + /* module heap */ + _module_heap = HEAP_RUNTIME_BASE; + + /* buffer heap */ + _buffer_heap = HEAP_BUFFER_BASE; + _buffer_heap_end = _stack_sentry; + + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .xt.insn 0 : + { + KEEP (*(.xt.insn)) + KEEP (*(.gnu.linkonce.x.*)) + } + .xt.prop 0 : + { + KEEP (*(.xt.prop)) + KEEP (*(.xt.prop.*)) + KEEP (*(.gnu.linkonce.prop.*)) + } + .xt.lit 0 : + { + KEEP (*(.xt.lit)) + KEEP (*(.xt.lit.*)) + KEEP (*(.gnu.linkonce.p.*)) + } + .xt.profile_range 0 : + { + KEEP (*(.xt.profile_range)) + KEEP (*(.gnu.linkonce.profile_range.*)) + } + .xt.profile_ranges 0 : + { + KEEP (*(.xt.profile_ranges)) + KEEP (*(.gnu.linkonce.xt.profile_ranges.*)) + } + .xt.profile_files 0 : + { + KEEP (*(.xt.profile_files)) + KEEP (*(.gnu.linkonce.xt.profile_files.*)) + } + + .system_heap (NOLOAD) : ALIGN(8) + { + . = ALIGN (32); + _system_heap_start = ABSOLUTE(.); + . = . + HEAP_SYSTEM_SIZE; + _system_heap_end = ABSOLUTE(.); + } >system_heap :system_heap_phdr + + .runtime_heap (NOLOAD) : ALIGN(8) + { + . = ALIGN (32); + _runtime_heap_start = ABSOLUTE(.); + . = . + HEAP_RUNTIME_SIZE; + _runtime_heap_end = ABSOLUTE(.); + } >runtime_heap :runtime_heap_phdr + + .buffer_heap (NOLOAD) : ALIGN(8) + { + . = ALIGN (32); + _system_heap_start = ABSOLUTE(.); + . = . + HEAP_BUFFER_SIZE; + _system_heap_end = ABSOLUTE(.); + } >buffer_heap :buffer_heap_phdr + + .reef_stack (NOLOAD) : ALIGN(8) + { + . = ALIGN (4096); + _reef_stack_start = ABSOLUTE(.); + . = . + REEF_STACK_SIZE; + _reef_stack_end = ABSOLUTE(.); + } >reef_stack :reef_stack_phdr +} diff --git a/src/platform/cannonlake/clk.c b/src/platform/cannonlake/clk.c new file mode 100644 index 0000000..bcce20d --- /dev/null +++ b/src/platform/cannonlake/clk.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Rander Wang rander.wang@intel.com + */ + +#include <reef/clock.h> +#include <reef/io.h> +#include <reef/reef.h> +#include <reef/list.h> +#include <reef/alloc.h> +#include <reef/notifier.h> +#include <reef/lock.h> +#include <platform/clk.h> +#include <platform/shim.h> +#include <platform/timer.h> +#include <config.h> +#include <stdint.h> +#include <limits.h> + +#define NUM_CLOCKS 2 + +struct clk_data { + uint32_t freq; + uint32_t ticks_per_usec; + spinlock_t lock; +}; + +struct clk_pdata { + struct clk_data clk[NUM_CLOCKS]; +}; + +struct freq_table { + uint32_t freq; + uint32_t ticks_per_usec; + uint32_t enc; +}; + +static struct clk_pdata *clk_pdata; + +/* increasing frequency order */ +static const struct freq_table cpu_freq[] = { + {120000000, 120, 0x0}, + {400000000, 400, 0x4}, +}; + +static const struct freq_table ssp_freq[] = { + {19200000, 19,}, + {25000000, 25,}, /* default */ +}; + +#define CPU_DEFAULT_IDX 2 +#define SSP_DEFAULT_IDX 1 + +static inline uint32_t get_freq(const struct freq_table *table, int size, + unsigned int hz) +{ + uint32_t i; + + /* find lowest available frequency that is >= requested hz */ + for (i = 0; i < size; i++) { + if (hz <= table[i].freq) + return i; + } + + /* not found, so return max frequency */ + return size - 1; +} + +void clock_enable(int clock) +{ + switch (clock) { + case CLK_CPU: + break; + case CLK_SSP: + default: + break; + } +} + +void clock_disable(int clock) +{ + switch (clock) { + case CLK_CPU: + break; + case CLK_SSP: + default: + break; + } +} + +uint32_t clock_set_freq(int clock, uint32_t hz) +{ + struct clock_notify_data notify_data; + uint32_t idx; + uint32_t flags; + + notify_data.old_freq = clk_pdata->clk[clock].freq; + notify_data.old_ticks_per_usec = clk_pdata->clk[clock].ticks_per_usec; + + /* atomic context for chaning clocks */ + spin_lock_irq(&clk_pdata->clk[clock].lock, flags); + + switch (clock) { + case CLK_CPU: + /* get nearest frequency that is >= requested Hz */ + idx = get_freq(cpu_freq, ARRAY_SIZE(cpu_freq), hz); + notify_data.freq = cpu_freq[idx].freq; + + /* tell anyone interested we are about to change CPU freq */ + notifier_event(NOTIFIER_ID_CPU_FREQ, CLOCK_NOTIFY_PRE, + ¬ify_data); + + /* set CPU frequency request for CCU */ + io_reg_update_bits(SHIM_BASE + SHIM_CLKCTL, + SHIM_CLKCTL_DPCS_MASK(0), cpu_freq[idx].enc); + + /* tell anyone interested we have now changed CPU freq */ + notifier_event(NOTIFIER_ID_CPU_FREQ, CLOCK_NOTIFY_POST, + ¬ify_data); + break; + case CLK_SSP: + default: + break; + } + + spin_unlock_irq(&clk_pdata->clk[clock].lock, flags); + return clk_pdata->clk[clock].freq; +} + +uint32_t clock_get_freq(int clock) +{ + return clk_pdata->clk[clock].freq; +} + +uint64_t clock_us_to_ticks(int clock, uint64_t us) +{ + return clk_pdata->clk[clock].ticks_per_usec * us; +} + +uint64_t clock_time_elapsed(int clock, uint64_t previous, uint64_t *current) +{ + uint64_t _current; + + // TODO: change timer APIs to clk APIs ?? + switch (clock) { + case CLK_CPU: + _current = arch_timer_get_system(NULL); + break; + case CLK_SSP: + _current = platform_timer_get(platform_timer); + break; + default: + return 0; + } + + *current = _current; + if (_current >= previous) + return (_current - previous) / + clk_pdata->clk[clock].ticks_per_usec; + else + return (_current + (ULONG_LONG_MAX - previous)) / + clk_pdata->clk[clock].ticks_per_usec; +} + +void init_platform_clocks(void) +{ + clk_pdata = rmalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*clk_pdata)); + + spinlock_init(&clk_pdata->clk[0].lock); + spinlock_init(&clk_pdata->clk[1].lock); + + /* set defaults */ + clk_pdata->clk[CLK_CPU].freq = cpu_freq[CPU_DEFAULT_IDX].freq; + clk_pdata->clk[CLK_CPU].ticks_per_usec = + cpu_freq[CPU_DEFAULT_IDX].ticks_per_usec; + clk_pdata->clk[CLK_SSP].freq = ssp_freq[SSP_DEFAULT_IDX].freq; + clk_pdata->clk[CLK_SSP].ticks_per_usec = + ssp_freq[SSP_DEFAULT_IDX].ticks_per_usec; +} diff --git a/src/platform/cannonlake/dai.c b/src/platform/cannonlake/dai.c new file mode 100644 index 0000000..1ca5c29 --- /dev/null +++ b/src/platform/cannonlake/dai.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Rander Wang rander.wang@intel.com + */ + +#include <reef/reef.h> +#include <reef/dai.h> +#include <reef/ssp.h> +#include <reef/stream.h> +#include <reef/audio/component.h> +#include <platform/memory.h> +#include <platform/interrupt.h> +#include <platform/dma.h> +#include <stdint.h> +#include <string.h> +#include <config.h> + +static struct dai ssp[] = { +{ + .type = SOF_DAI_INTEL_SSP, + .index = 0, + .plat_data = { + .base = SSP_BASE(0), + .irq = IRQ_EXT_SSP0_LVL5(0), + .fifo[SOF_IPC_STREAM_PLAYBACK] = { + .offset = SSP_BASE(0) + SSDR, + .handshake = DMA_HANDSHAKE_SSP0_TX, + }, + .fifo[SOF_IPC_STREAM_CAPTURE] = { + .offset = SSP_BASE(0) + SSDR, + .handshake = DMA_HANDSHAKE_SSP0_RX, + } + }, + .ops = &ssp_ops, +}, +{ + .type = SOF_DAI_INTEL_SSP, + .index = 1, + .plat_data = { + .base = SSP_BASE(1), + .irq = IRQ_EXT_SSP1_LVL5(0), + .fifo[SOF_IPC_STREAM_PLAYBACK] = { + .offset = SSP_BASE(1) + SSDR, + .handshake = DMA_HANDSHAKE_SSP1_TX, + }, + .fifo[SOF_IPC_STREAM_CAPTURE] = { + .offset = SSP_BASE(1) + SSDR, + .handshake = DMA_HANDSHAKE_SSP1_RX, + } + }, + .ops = &ssp_ops, +}, +{ + .type = SOF_DAI_INTEL_SSP, + .index = 2, + .plat_data = { + .base = SSP_BASE(2), + .irq = IRQ_EXT_SSP2_LVL5(0), + .fifo[SOF_IPC_STREAM_PLAYBACK] = { + .offset = SSP_BASE(2) + SSDR, + .handshake = DMA_HANDSHAKE_SSP2_TX, + }, + .fifo[SOF_IPC_STREAM_CAPTURE] = { + .offset = SSP_BASE(2) + SSDR, + .handshake = DMA_HANDSHAKE_SSP2_RX, + } + }, + .ops = &ssp_ops, +},}; + +struct dai *dai_get(uint32_t type, uint32_t index) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ssp); i++) { + if (ssp[i].type == type && ssp[i].index == index) + return &ssp[i]; + } + + return NULL; +} diff --git a/src/platform/cannonlake/dma.c b/src/platform/cannonlake/dma.c new file mode 100644 index 0000000..45bdee3 --- /dev/null +++ b/src/platform/cannonlake/dma.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Rander Wang rander.wang@intel.com + */ + +#include <reef/dma.h> +#include <reef/dw-dma.h> +#include <platform/memory.h> +#include <platform/interrupt.h> +#include <platform/dma.h> +#include <stdint.h> +#include <string.h> + +static struct dw_drv_plat_data dmac0 = { + .chan[0] = { + .class = 6, + .weight = 0, + }, + .chan[1] = { + .class = 6, + .weight = 0, + }, + .chan[2] = { + .class = 6, + .weight = 0, + }, + .chan[3] = { + .class = 6, + .weight = 0, + }, + .chan[4] = { + .class = 6, + .weight = 0, + }, + .chan[5] = { + .class = 6, + .weight = 0, + }, + .chan[6] = { + .class = 6, + .weight = 0, + }, + .chan[7] = { + .class = 6, + .weight = 0, + }, +}; + +static struct dw_drv_plat_data dmac1 = { + .chan[0] = { + .class = 7, + .weight = 0, + }, + .chan[1] = { + .class = 7, + .weight = 0, + }, + .chan[2] = { + .class = 7, + .weight = 0, + }, + .chan[3] = { + .class = 7, + .weight = 0, + }, + .chan[4] = { + .class = 7, + .weight = 0, + }, + .chan[5] = { + .class = 7, + .weight = 0, + }, + .chan[6] = { + .class = 7, + .weight = 0, + }, + .chan[7] = { + .class = 7, + .weight = 0, + }, +}; + +static struct dma dma[] = { +{ /* Low Power GP DMAC 0 */ + .plat_data = { + .id = DMA_GP_LP_DMAC0, + .base = LP_GP_DMA_BASE(0), + .channels = 8, + .irq = IRQ_EXT_LP_GPDMA0_LVL5(0, 0), + .drv_plat_data = &dmac0, + }, + .ops = &dw_dma_ops, +}, +{ /* Low Power GP DMAC 1 */ + .plat_data = { + .id = DMA_GP_LP_DMAC1, + .base = LP_GP_DMA_BASE(1), + .channels = 8, + .irq = IRQ_EXT_LP_GPDMA1_LVL4(0, 0), + .drv_plat_data = &dmac1, + }, + .ops = &dw_dma_ops, +}, +{ /* Host In DMAC */ + .plat_data = { + .id = DMA_HOST_IN_DMAC, + .base = GTW_HOST_IN_STREAM_BASE(0), + .channels = 7, + .irq = IRQ_EXT_HOST_DMA_IN_LVL3(0, 0), + }, +}, +{ /* Host out DMAC */ + .plat_data = { + .id = DMA_HOST_OUT_DMAC, + .base = GTW_HOST_OUT_STREAM_BASE(0), + .channels = 6, + .irq = IRQ_EXT_HOST_DMA_OUT_LVL3(0, 0), + }, +}, +{ /* Link In DMAC */ + .plat_data = { + .id = DMA_LINK_IN_DMAC, + .base = GTW_LINK_IN_STREAM_BASE(0), + .channels = 8, + .irq = IRQ_EXT_LINK_DMA_IN_LVL4(0, 0), + }, +}, +{ /* Link out DMAC */ + .plat_data = { + .id = DMA_LINK_OUT_DMAC, + .base = GTW_LINK_OUT_STREAM_BASE(0), + .channels = 8, + .irq = IRQ_EXT_LINK_DMA_OUT_LVL4(0, 0), + }, +},}; + +struct dma *dma_get(int dmac_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dma); i++) { + if (dma[i].plat_data.id == dmac_id) + return &dma[i]; + } + + return NULL; +} diff --git a/src/platform/cannonlake/include/Makefile.am b/src/platform/cannonlake/include/Makefile.am new file mode 100644 index 0000000..19f40eb --- /dev/null +++ b/src/platform/cannonlake/include/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = platform xtensa diff --git a/src/platform/cannonlake/interrupt.c b/src/platform/cannonlake/interrupt.c new file mode 100644 index 0000000..3268362 --- /dev/null +++ b/src/platform/cannonlake/interrupt.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Keyon Jie yang.jie@linux.intel.com + * Liam Girdwood liam.r.girdwood@linux.intel.com + * Rander Wang rander.wang@intel.com + */ + +#include <reef/reef.h> +#include <reef/interrupt.h> +#include <reef/interrupt-map.h> +#include <arch/interrupt.h> +#include <platform/interrupt.h> +#include <platform/shim.h> +#include <stdint.h> +#include <stdlib.h> + +static void parent_level2_handler(void *data) +{ + struct irq_parent *parent = (struct irq_parent *)data; + struct irq_child * child = NULL; + uint32_t status; + uint32_t i = 0; + + /* mask the parent IRQ */ + arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL2); + + /* mask all child interrupts */ + status = irq_read(REG_IRQ_IL2SD(0)); + irq_write(REG_IRQ_IL2MSD(0), status); + + /* handle each child */ + while (status) { + + /* any IRQ for this child bit ? */ + if ((status & 0x1) == 0) + goto next; + + /* get child if any and run handler */ + child = parent->child[i]; + if (child && child->handler) { + child->handler(child->handler_arg); + + /* unmask this bit i interrupt */ + irq_write(REG_IRQ_IL2MCD(0), 0x1 << i); + } else { + /* nobody cared ? */ + trace_irq_error("nbc"); + } + +next: + status >>= 1; + i++; + } + + /* clear parent and unmask */ + arch_interrupt_clear(IRQ_NUM_EXT_LEVEL2); + arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL2); +} + +static void parent_level3_handler(void *data) +{ + struct irq_parent *parent = (struct irq_parent *)data; + struct irq_child * child = NULL; + uint32_t status; + uint32_t i = 0; + + /* mask the parent IRQ */ + arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL3); + + /* mask all child interrupts */ + status = irq_read(REG_IRQ_IL3SD(0)); + irq_write(REG_IRQ_IL3MSD(0), status); + + /* handle each child */ + while (status) { + + /* any IRQ for this child bit ? */ + if ((status & 0x1) == 0) + goto next; + + /* get child if any and run handler */ + child = parent->child[i]; + if (child && child->handler) { + child->handler(child->handler_arg); + + /* unmask this bit i interrupt */ + irq_write(REG_IRQ_IL3MCD(0), 0x1 << i); + } else { + /* nobody cared ? */ + trace_irq_error("nbc"); + } + +next: + status >>= 1; + i++; + } + + /* clear parent and unmask */ + arch_interrupt_clear(IRQ_NUM_EXT_LEVEL3); + arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL3); +} + +static void parent_level4_handler(void *data) +{ + struct irq_parent *parent = (struct irq_parent *)data; + struct irq_child * child = NULL; + uint32_t status; + uint32_t i = 0; + + /* mask the parent IRQ */ + arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL4); + + /* mask all child interrupts */ + status = irq_read(REG_IRQ_IL4SD(0)); + irq_write(REG_IRQ_IL4MSD(0), status); + + /* handle each child */ + while (status) { + + /* any IRQ for this child bit ? */ + if ((status & 0x1) == 0) + goto next; + + /* get child if any and run handler */ + child = parent->child[i]; + if (child && child->handler) { + child->handler(child->handler_arg); + + /* unmask this bit i interrupt */ + irq_write(REG_IRQ_IL4MCD(0), 0x1 << i); + } else { + /* nobody cared ? */ + trace_irq_error("nbc"); + } + +next: + status >>= 1; + i++; + } + + /* clear parent and unmask */ + arch_interrupt_clear(IRQ_NUM_EXT_LEVEL4); + arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL4); +} + +static void parent_level5_handler(void *data) +{ + struct irq_parent *parent = (struct irq_parent *)data; + struct irq_child * child = NULL; + uint32_t status; + uint32_t i = 0; + + /* mask the parent IRQ */ + arch_interrupt_disable_mask(1 << IRQ_NUM_EXT_LEVEL5); + + /* mask all child interrupts */ + status = irq_read(REG_IRQ_IL5SD(0)); + irq_write(REG_IRQ_IL5MSD(0), status); + + /* handle each child */ + while (status) { + + /* any IRQ for this child bit ? */ + if ((status & 0x1) == 0) + goto next; + + /* get child if any and run handler */ + child = parent->child[i]; + if (child && child->handler) { + child->handler(child->handler_arg); + + /* unmask this bit i interrupt */ + irq_write(REG_IRQ_IL5MCD(0), 0x1 << i); + } else { + /* nobody cared ? */ + trace_irq_error("nbc"); + } + +next: + status >>= 1; + i++; + } + + /* clear parent and unmask */ + arch_interrupt_clear(IRQ_NUM_EXT_LEVEL5); + arch_interrupt_enable_mask(1 << IRQ_NUM_EXT_LEVEL5); +} + +/* DSP internal interrupts */ +static struct irq_parent dsp_irq[4] = { + {IRQ_NUM_EXT_LEVEL2, parent_level2_handler, }, + {IRQ_NUM_EXT_LEVEL3, parent_level3_handler, }, + {IRQ_NUM_EXT_LEVEL4, parent_level4_handler, }, + {IRQ_NUM_EXT_LEVEL5, parent_level5_handler, }, +}; + +struct irq_parent *platform_irq_get_parent(uint32_t irq) +{ + switch (REEF_IRQ_NUMBER(irq)) { + case IRQ_NUM_EXT_LEVEL2: + return &dsp_irq[0]; + case IRQ_NUM_EXT_LEVEL3: + return &dsp_irq[1]; + case IRQ_NUM_EXT_LEVEL4: + return &dsp_irq[2]; + case IRQ_NUM_EXT_LEVEL5: + return &dsp_irq[3]; + default: + return NULL; + } +} + +uint32_t platform_interrupt_get_enabled(void) +{ + return 0; +} + +void platform_interrupt_mask(uint32_t irq, uint32_t mask) +{ + /* mask external interrupt bit */ + switch (REEF_IRQ_NUMBER(irq)) { + case IRQ_NUM_EXT_LEVEL5: + irq_write(REG_IRQ_IL5MSD(0), 1 << REEF_IRQ_BIT(irq)); + break; + case IRQ_NUM_EXT_LEVEL4: + irq_write(REG_IRQ_IL4MSD(0), 1 << REEF_IRQ_BIT(irq)); + break; + case IRQ_NUM_EXT_LEVEL3: + irq_write(REG_IRQ_IL3MSD(0), 1 << REEF_IRQ_BIT(irq)); + break; + case IRQ_NUM_EXT_LEVEL2: + irq_write(REG_IRQ_IL2MSD(0), 1 << REEF_IRQ_BIT(irq)); + break; + default: + break; + } + +} + +void platform_interrupt_unmask(uint32_t irq, uint32_t mask) +{ + /* unmask external interrupt bit */ + switch (REEF_IRQ_NUMBER(irq)) { + case IRQ_NUM_EXT_LEVEL5: + irq_write(REG_IRQ_IL5MCD(0), 1 << REEF_IRQ_BIT(irq)); + break; + case IRQ_NUM_EXT_LEVEL4: + irq_write(REG_IRQ_IL4MCD(0), 1 << REEF_IRQ_BIT(irq)); + break; + case IRQ_NUM_EXT_LEVEL3: + irq_write(REG_IRQ_IL3MCD(0), 1 << REEF_IRQ_BIT(irq)); + break; + case IRQ_NUM_EXT_LEVEL2: + irq_write(REG_IRQ_IL2MCD(0), 1 << REEF_IRQ_BIT(irq)); + break; + default: + break; + } + +} + +void platform_interrupt_clear(uint32_t irq, uint32_t mask) +{ +} + +void platform_interrupt_init(void) +{ + int i; + + /* mask all external IRQs by default */ + irq_write(REG_IRQ_IL2MSD(0), REG_IRQ_IL2MD_ALL); + irq_write(REG_IRQ_IL3MSD(0), REG_IRQ_IL3MD_ALL); + irq_write(REG_IRQ_IL4MSD(0), REG_IRQ_IL4MD_ALL); + irq_write(REG_IRQ_IL5MSD(0), REG_IRQ_IL5MD_ALL); + + for (i = 0; i < ARRAY_SIZE(dsp_irq); i++) { + spinlock_init(&dsp_irq[i].lock); + } +} diff --git a/src/platform/cannonlake/platform.c b/src/platform/cannonlake/platform.c new file mode 100644 index 0000000..729364f --- /dev/null +++ b/src/platform/cannonlake/platform.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Rander Wang rander.wang@intel.com + */ + +#include <platform/memory.h> +#include <platform/mailbox.h> +#include <platform/shim.h> +#include <platform/dma.h> +#include <platform/clk.h> +#include <platform/timer.h> +#include <platform/interrupt.h> +#include <uapi/ipc.h> +#include <reef/mailbox.h> +#include <reef/dai.h> +#include <reef/dma.h> +#include <reef/reef.h> +#include <reef/work.h> +#include <reef/clock.h> +#include <reef/ipc.h> +#include <reef/agent.h> +#include <reef/io.h> +#include <reef/trace.h> +#include <reef/audio/component.h> +#include <config.h> +#include <string.h> +#include <version.h> + +static const struct sof_ipc_fw_ready ready = { + .hdr = { + .cmd = SOF_IPC_FW_READY, + .size = sizeof(struct sof_ipc_fw_ready), + }, + .version = { + .build = REEF_BUILD, + .minor = REEF_MINOR, + .major = REEF_MAJOR, + .date = __DATE__, + .time = __TIME__, + .tag = REEF_TAG, + }, +}; + +#define SRAM_WINDOW_HOST_OFFSET(x) (0x80000 + x * 0x20000) + +#define NUM_CNL_WINDOWS 5 + +static const struct sof_ipc_window sram_window = { + .ext_hdr = { + .hdr.cmd = SOF_IPC_FW_READY, + .hdr.size = sizeof(struct sof_ipc_window) + + sizeof(struct sof_ipc_window_elem) * NUM_CNL_WINDOWS, + .type = SOF_IPC_EXT_WINDOW, + }, + .num_windows = NUM_CNL_WINDOWS, + .window[0] = { + .type = SOF_IPC_REGION_REGS, + .id = 0, /* map to host window 0 */ + .flags = 0, // TODO: set later + .size = MAILBOX_SW_REG_SIZE, + .offset = 0, + }, + .window[1] = { + .type = SOF_IPC_REGION_UPBOX, + .id = 0, /* map to host window 0 */ + .flags = 0, // TODO: set later + .size = MAILBOX_DSPBOX_SIZE, + .offset = MAILBOX_SW_REG_SIZE, + }, + .window[2] = { + .type = SOF_IPC_REGION_DOWNBOX, + .id = 1, /* map to host window 1 */ + .flags = 0, // TODO: set later + .size = MAILBOX_HOSTBOX_SIZE, + .offset = 0, + }, + .window[3] = { + .type = SOF_IPC_REGION_DEBUG, + .id = 2, /* map to host window 2 */ + .flags = 0, // TODO: set later + .size = SRAM_DEBUG_SIZE, + .offset = 0, + }, + .window[4] = { + .type = SOF_IPC_REGION_TRACE, + .id = 3, /* map to host window 3 */ + .flags = 0, // TODO: set later + .size = MAILBOX_TRACE_SIZE, + .offset = 0, + }, + +}; + +static struct work_queue_timesource platform_generic_queue = { + .timer = { + .id = TIMER3, /* external timer */ + .irq = IRQ_EXT_TSTAMP0_LVL2(0), + }, + .clk = CLK_CPU, + .notifier = NOTIFIER_ID_CPU_FREQ, + .timer_set = platform_timer_set, + .timer_clear = platform_timer_clear, + .timer_get = platform_timer_get, +}; + +struct timer *platform_timer = &platform_generic_queue.timer; + +int platform_boot_complete(uint32_t boot_message) +{ + mailbox_dspbox_write(0, &ready, sizeof(ready)); + mailbox_dspbox_write(sizeof(ready), &sram_window, + sram_window.ext_hdr.hdr.size); + + /* boot now complete so we can relax the CPU */ + clock_set_freq(CLK_CPU, CLK_DEFAULT_CPU_HZ); + + /* tell host we are ready */ + ipc_write(IPC_DIPCIDD, SRAM_WINDOW_HOST_OFFSET(0) >> 12); + ipc_write(IPC_DIPCIDR, 0x80000000 | SOF_IPC_FW_READY); + + return 0; +} + +static void platform_memory_windows_init(void) +{ + /* window0, for fw status & outbox/uplink mbox */ + io_reg_write(DMWLO(0), HP_SRAM_WIN0_SIZE | 0x7); + io_reg_write(DMWBA(0), HP_SRAM_WIN0_BASE + | DMWBA_READONLY | DMWBA_ENABLE); + + /* window1, for inbox/downlink mbox */ + io_reg_write(DMWLO(1), HP_SRAM_WIN1_SIZE | 0x7); + io_reg_write(DMWBA(1), HP_SRAM_WIN1_BASE + | DMWBA_ENABLE); + + /* window2, for debug */ + io_reg_write(DMWLO(2), HP_SRAM_WIN2_SIZE | 0x7); + io_reg_write(DMWBA(2), HP_SRAM_WIN2_BASE + | DMWBA_READONLY | DMWBA_ENABLE); + + /* window3, for trace */ + io_reg_write(DMWLO(3), HP_SRAM_WIN3_SIZE | 0x7); + io_reg_write(DMWBA(3), HP_SRAM_WIN3_BASE + | DMWBA_READONLY | DMWBA_ENABLE); +} + +/* init HW */ +static void platform_init_hw(void) +{ + io_reg_write(DSP_INIT_GENO, + GENO_MDIVOSEL | GENO_DIOPTOSEL); + + io_reg_write(DSP_INIT_IOPO, + IOPO_DMIC_FLAG |IOPO_I2S_FLAG); + + io_reg_write(DSP_INIT_ALHO, + ALHO_ASO_FLAG | ALHO_CSO_FLAG | ALHO_CFO_FLAG); + + io_reg_write(DSP_INIT_LPGPDMA(0), + LPGPDMA_CHOSEL_FLAG | LPGPDMA_CTLOSEL_FLAG); + io_reg_write(DSP_INIT_LPGPDMA(1), + LPGPDMA_CHOSEL_FLAG | LPGPDMA_CTLOSEL_FLAG); +} + +static struct timer platform_ext_timer = { + .id = TIMER3, + .irq = IRQ_EXT_TSTAMP0_LVL2(0), +}; + +int platform_init(struct reef *reef) +{ + struct dma *dmac0; + struct dma *dmac1; + struct dai *ssp; + int i; + + trace_point(TRACE_BOOT_PLATFORM_ENTRY); + platform_init_hw(); + + platform_interrupt_init(); + + trace_point(TRACE_BOOT_PLATFORM_MBOX); + platform_memory_windows_init(); + + trace_point(TRACE_BOOT_PLATFORM_SHIM); + + /* init work queues and clocks */ + trace_point(TRACE_BOOT_PLATFORM_TIMER); + platform_timer_start(&platform_ext_timer); + + trace_point(TRACE_BOOT_PLATFORM_CLOCK); + init_platform_clocks(); + + trace_point(TRACE_BOOT_SYS_WORK); + init_system_workq(&platform_generic_queue); + + /* init the system agent */ + sa_init(reef); + + /* Set CPU to default frequency for booting */ + trace_point(TRACE_BOOT_SYS_CPU_FREQ); + clock_set_freq(CLK_CPU, CLK_MAX_CPU_HZ); + + /* set SSP clock to 25M */ + trace_point(TRACE_BOOT_PLATFORM_SSP_FREQ); + clock_set_freq(CLK_SSP, 25000000); + + /* initialise the host IPC mechanisms */ + trace_point(TRACE_BOOT_PLATFORM_IPC); + ipc_init(reef); + + /* prevent Core0 clock gating. */ + shim_write(SHIM_CLKCTL, shim_read(SHIM_CLKCTL) | + SHIM_CLKCTL_TCPLCG(0)); + + /* prevent LP GPDMA 0&1 clock gating */ + io_reg_write(GPDMA_CLKCTL(0), GPDMA_FDCGB); + io_reg_write(GPDMA_CLKCTL(1), GPDMA_FDCGB); + + /* prevent DSP Common power gating */ + shim_write16(SHIM_PWRCTL, SHIM_PWRCTL_TCPDSP0PG); + + /* init DMACs */ + trace_point(TRACE_BOOT_PLATFORM_DMA); + dmac0 = dma_get(DMA_GP_LP_DMAC0); + if (dmac0 == NULL) + return -ENODEV; + dma_probe(dmac0); + + dmac1 = dma_get(DMA_GP_LP_DMAC1); + if (dmac1 == NULL) + return -ENODEV; + dma_probe(dmac1); + + /* init SSP ports */ + trace_point(TRACE_BOOT_PLATFORM_SSP); + for(i = 0; i < PLATFORM_SSP_COUNT; i++) { + ssp = dai_get(SOF_DAI_INTEL_SSP, i); + if (ssp == NULL) + return -ENODEV; + dai_probe(ssp); + } + + return 0; +} diff --git a/src/platform/cannonlake/timer.c b/src/platform/cannonlake/timer.c new file mode 100644 index 0000000..d2ee870 --- /dev/null +++ b/src/platform/cannonlake/timer.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Rander Wang rander.wang@intel.com + */ + +#include <platform/timer.h> +#include <platform/shim.h> +#include <reef/debug.h> +#include <reef/audio/component.h> +#include <stdint.h> + +void platform_timer_start(struct timer *timer) +{ + /* run timer */ + shim_write64(SHIM_DSPWCT0C, 0); + shim_write(SHIM_DSPWCTCS, + shim_read(SHIM_DSPWCTCS) | SHIM_DSPWCTCS_T0A); +} + +void platform_timer_stop(struct timer *timer) +{ + /* stop timer */ + shim_write64(SHIM_DSPWCT0C, 0); + shim_write(SHIM_DSPWCTCS, + shim_read(SHIM_DSPWCTCS) & ~SHIM_DSPWCTCS_T0A); +} + +int platform_timer_set(struct timer *timer, uint64_t ticks) +{ + /* a tick value of 0 will not generate an IRQ */ + if (ticks == 0) + ticks = 1; + + /* set new value and run */ + shim_write64(SHIM_DSPWCT0C, ticks); + shim_write(SHIM_DSPWCTCS, + shim_read(SHIM_DSPWCTCS) | SHIM_DSPWCTCS_T0A); + + return 0; +} + +void platform_timer_clear(struct timer *timer) +{ + /* write 1 to clear the timer interrupt */ + shim_write(SHIM_DSPWCTCS, + shim_read(SHIM_DSPWCTCS) | SHIM_DSPWCTCS_T0T); +} + +uint64_t platform_timer_get(struct timer *timer) +{ +// return arch_timer_get_system(timer); + return (uint64_t)shim_read64(SHIM_DSPWC); +} + +/* get timestamp for host stream DMA position */ +void platform_host_timestamp(struct comp_dev *host, + struct sof_ipc_stream_posn *posn) +{ + int err; + + /* get host postion */ + err = comp_position(host, posn); + if (err == 0) + posn->flags |= SOF_TIME_HOST_VALID; +} + +/* get timestamp for DAI stream DMA position */ +void platform_dai_timestamp(struct comp_dev *dai, + struct sof_ipc_stream_posn *posn) +{ + int err; + + /* get DAI postion */ + err = comp_position(dai, posn); + if (err == 0) + posn->flags |= SOF_TIME_DAI_VALID; + + /* get SSP wallclock - DAI sets this to stream start value */ + posn->wallclock = shim_read64(SHIM_DSPWC) - posn->wallclock; + posn->flags |= SOF_TIME_WALL_VALID; +} + +/* get current wallclock for componnent */ +void platform_dai_wallclock(struct comp_dev *dai, uint64_t *wallclock) +{ + *wallclock = shim_read64(SHIM_DSPWC); +} + +int platform_timer_register(struct timer *timer, + void (*handler)(void *arg), void *arg) +{ + return interrupt_register(timer->irq, handler, arg); +} + +int timer_register(struct timer *timer, void(*handler)(void *arg), void *arg) +{ + switch (timer->id) { + case TIMER0: + case TIMER1: + case TIMER2: + return arch_timer_register(timer, handler, arg); + case TIMER3: + return platform_timer_register(timer, handler, arg); + default: + return -EINVAL; + } +}