diff options
94 files changed, 9368 insertions, 102 deletions
@@ -27,7 +27,16 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # +#check gcc tools chain +arm_toolchain_check=$(strip $(shell if [ -d ../toolchain/gcc-arm -a -d ../toolchain/gcc-aarch64 ]; then echo yes; fi ) ) +ifneq ("$(arm_toolchain_check)", "yes") + $(info "gcc tools chain not exist") + $(info "Please run ./build.sh -t under brandy directory at the first time") + $(error "") +endif +CROSS_COMPILE = ../toolchain/gcc-aarch64/bin/aarch64-linux-gnu- +BL33= # # Trusted Firmware Version # @@ -41,11 +50,11 @@ VERSION_MINOR := 0 # Build verbosity V := 0 # Debug build -DEBUG := 0 +DEBUG := 1 # Build architecture ARCH := aarch64 # Build platform -DEFAULT_PLAT := fvp +DEFAULT_PLAT := sun50iw1p1 PLAT := ${DEFAULT_PLAT} # SPD choice SPD := none @@ -227,14 +236,13 @@ ASFLAGS += -nostdinc -ffreestanding -Wa,--fatal-warnings \ -Werror -Wmissing-include-dirs \ -mgeneral-regs-only -D__ASSEMBLY__ \ ${DEFINES} ${INCLUDES} -CFLAGS += -nostdinc -pedantic -ffreestanding -Wall \ +CFLAGS += -nostdinc -ffreestanding -Wall \ -Werror -Wmissing-include-dirs \ -mgeneral-regs-only -std=c99 -c -Os \ ${DEFINES} ${INCLUDES} CFLAGS += -ffunction-sections -fdata-sections - LDFLAGS += --fatal-warnings -O1 -LDFLAGS += --gc-sections +LDFLAGS += --gc-sections --fix-cortex-a53-843419 CC := ${CROSS_COMPILE}gcc @@ -249,7 +257,7 @@ PP := ${CROSS_COMPILE}gcc -E ${CFLAGS} # Variables for use with Firmware Image Package FIPTOOLPATH ?= tools/fip_create -FIPTOOL ?= ${FIPTOOLPATH}/fip_create +FIPTOOL ?= ${FIPTOOLPATH}/fip_create fiptool: ${FIPTOOL} fip: ${BUILD_PLAT}/fip.bin @@ -421,6 +429,11 @@ $(BIN) : $(ELF) @echo @echo "Built $$@ successfully" @echo +ifeq (bl31.bin,$(notdir ${BIN})) + $${Q}git show HEAD --pretty=format:"%H" | head -n 1 > cur.log + $${Q}./tools/add_hash_bl31.sh -f $$@ -m bl31 +endif + @cp -v $$@ ../../tools/pack/chips/$(DEFAULT_PLAT)/bin/ .PHONY : bl$(1) bl$(1) : $(BUILD_DIR) $(BIN) $(DUMP) @@ -482,6 +495,10 @@ cscope: ${Q}find ${CURDIR} -name "*.[chsS]" > cscope.files ${Q}cscope -b -q -k +ctag: + ctags -R --c++-kinds=+p --fields=+iaS --extra=+q -w -o ctags `find $(CURDIR) \ + -name '*.[chS]' -print` + help: @echo "usage: ${MAKE} PLAT=<${HELP_PLATFORMS}> <all|bl1|bl2|bl31|distclean|clean|checkcodebase|checkpatch>" @echo "" diff --git a/bl31/aarch64/bl31_arch_setup.c b/bl31/aarch64/bl31_arch_setup.c index a88b029..97d98d9 100644 --- a/bl31/aarch64/bl31_arch_setup.c +++ b/bl31/aarch64/bl31_arch_setup.c @@ -33,7 +33,10 @@ #include <assert.h> #include <bl_common.h> #include <bl31.h> +#include <cpu_data.h> #include <platform.h> +#include <debug.h> + /******************************************************************************* * This duplicates what the primary cpu did after a cold boot in BL1. The same @@ -47,4 +50,8 @@ void bl31_arch_setup(void) /* Program the counter frequency */ write_cntfrq_el0(plat_get_syscnt_freq()); + + /* Initialize the cpu_ops pointer. */ + init_cpu_ops(); + } diff --git a/bl31/aarch64/bl31_entrypoint.S b/bl31/aarch64/bl31_entrypoint.S index 04063e1..6f5a7c0 100644 --- a/bl31/aarch64/bl31_entrypoint.S +++ b/bl31/aarch64/bl31_entrypoint.S @@ -40,7 +40,6 @@ * executed only by the primary cpu. * ----------------------------------------------------- */ - func bl31_entrypoint /* --------------------------------------------------------------- * Preceding bootloader has populated x0 with a pointer to a @@ -49,8 +48,16 @@ func bl31_entrypoint * --------------------------------------------------------------- */ #if !RESET_TO_BL31 - mov x20, x0 - mov x21, x1 + /* + *AA32 warmreset to AA64, the high 32bit in reg R0,R1 is unpredictable + */ + /*mov x20, x0*/ + /*mov x21, x1*/ + + mov x20, 0 + mov x21, 0 + mov w20, w0 + mov w21, w1 #else /* --------------------------------------------- * Set the CPU endianness before doing anything @@ -153,11 +160,6 @@ func bl31_entrypoint ldr x1, =__COHERENT_RAM_UNALIGNED_SIZE__ bl zeromem16 - /* --------------------------------------------- - * Initialize the cpu_ops pointer. - * --------------------------------------------- - */ - bl init_cpu_ops /* --------------------------------------------- * Use SP_EL0 for the C runtime stack. diff --git a/bl31/aarch64/crash_reporting.S b/bl31/aarch64/crash_reporting.S index 68fe256..79d7457 100644 --- a/bl31/aarch64/crash_reporting.S +++ b/bl31/aarch64/crash_reporting.S @@ -342,7 +342,7 @@ func do_crash_reporting plat_print_gic_regs /* Print the interconnect registers */ - plat_print_interconnect_regs + /*plat_print_interconnect_regs*/ /* Done reporting */ b crash_panic diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S index add65b8..b7a867f 100644 --- a/bl31/bl31.ld.S +++ b/bl31/bl31.ld.S @@ -32,7 +32,6 @@ OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) OUTPUT_ARCH(PLATFORM_LINKER_ARCH) -ENTRY(bl31_entrypoint) MEMORY { @@ -48,7 +47,9 @@ SECTIONS ro . : { __RO_START__ = .; - *bl31_entrypoint.o(.text*) + KEEP(*head_data.o(.head_data*)) + KEEP(*bl31_hash.o(.hash_data*)) + KEEP(*bl31_entrypoint.o(.text*)) *(.text*) *(.rodata*) diff --git a/bl31/bl31.mk b/bl31/bl31.mk index f53a41f..cbeac94 100644 --- a/bl31/bl31.mk +++ b/bl31/bl31.mk @@ -28,7 +28,9 @@ # POSSIBILITY OF SUCH DAMAGE. # -BL31_SOURCES += bl31/bl31_main.c \ +BL31_SOURCES+= bl31/head_data.c \ + bl31/bl31_hash.c \ + bl31/bl31_main.c \ bl31/context_mgmt.c \ bl31/cpu_data_array.c \ bl31/runtime_svc.c \ diff --git a/bl31/bl31_hash.c b/bl31/bl31_hash.c new file mode 100644 index 0000000..2722d64 --- /dev/null +++ b/bl31/bl31_hash.c @@ -0,0 +1,25 @@ +/* + * (C) Copyright 2007-2013 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Jerry Wang <wangflord@allwinnertech.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + char bl31_hash_value[64] __attribute__ ((section(".hash_data"))) = {0x38}; diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c index 19f3774..cab46d7 100644 --- a/bl31/bl31_main.c +++ b/bl31/bl31_main.c @@ -71,8 +71,11 @@ void bl31_lib_init(void) ******************************************************************************/ void bl31_main(void) { + extern char bl31_hash_value[64]; + NOTICE("BL3-1: %s\n", version_string); NOTICE("BL3-1: %s\n", build_message); + NOTICE("BL3-1 commit: %s\n", bl31_hash_value); /* Perform remaining generic architectural setup from EL3 */ bl31_arch_setup(); @@ -89,7 +92,7 @@ void bl31_main(void) /* Clean caches before re-entering normal world */ dcsw_op_all(DCCSW); - + /* * All the cold boot actions on the primary cpu are done. We now need to * decide which is the next image (BL32 or BL33) and how to execute it. @@ -105,8 +108,9 @@ void bl31_main(void) */ if (bl32_init) { INFO("BL3-1: Initializing BL3-2\n"); - (*bl32_init)(); + //(*bl32_init)(); } + //__asm__ __volatile__ ("b ."); /* * We are ready to enter the next EL. Prepare entry into the image * corresponding to the desired security state after the next ERET. diff --git a/bl31/context_mgmt.c b/bl31/context_mgmt.c index 489d454..56b6a0a 100644 --- a/bl31/context_mgmt.c +++ b/bl31/context_mgmt.c @@ -183,6 +183,13 @@ void cm_init_context(uint64_t mpidr, const entry_point_info_t *ep) */ sctlr_elx = EP_GET_EE(ep->h.attr) ? SCTLR_EE_BIT : 0; sctlr_elx |= SCTLR_EL1_RES1; + + //if use AA32 SVC + if(GET_M32(ep->spsr) == MODE32_svc) + { + sctlr_elx |= 1<<5;//AArch32 CP15 barrier operations enabled + } + write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_elx); if ((GET_RW(ep->spsr) == MODE_RW_64 diff --git a/bl31/head_data.c b/bl31/head_data.c new file mode 100644 index 0000000..d14dd86 --- /dev/null +++ b/bl31/head_data.c @@ -0,0 +1,23 @@ +/*
+ *
+ * Header for semelis
+ *
+ */
+
+#include <head_data.h>
+#include <platform_def.h>
+
+extern char bl31_hash_value[64]; + +struct spare_boot_ctrl_head monitor_head __attribute__ ((section(".head_data"))) =
+{
+ (0x14000000 |(((sizeof(struct spare_boot_ctrl_head)+sizeof(bl31_hash_value)) / sizeof(int)) & 0x00FFFFFF)), + "monitor",
+ 0,
+ 0,
+ 0,
+ 0,
+ "2.0",
+ "monitor",
+ {BL31_BASE}
+};
diff --git a/common/tf_printf.c b/common/tf_printf.c index 02461c0..d39711f 100644 --- a/common/tf_printf.c +++ b/common/tf_printf.c @@ -115,6 +115,14 @@ loop: unsigned_num_print(unum, 16); break; + case 'p': + unum =(uint64_t)va_arg(args, void *); + unsigned_num_print(unum, 16); + break; + case 'z': + fmt++; + bit64 = sizeof(long) == 0x8 ? 1:0; + goto loop; case 'l': bit64 = 1; fmt++; @@ -134,6 +142,11 @@ loop: fmt++; continue; } + //for windos newline"\r\n" + else if (*fmt == '\n') + { + putchar('\r'); + } putchar(*fmt++); } exit: diff --git a/drivers/arm/gic/arm_gic.c b/drivers/arm/gic/arm_gic.c index 86aaa9a..0600af8 100644 --- a/drivers/arm/gic/arm_gic.c +++ b/drivers/arm/gic/arm_gic.c @@ -47,6 +47,9 @@ static unsigned long g_gicr_base; static const unsigned int *g_irq_sec_ptr; static unsigned int g_num_irqs; +void gic_sunxi_distributor_init(void); +void gic_sunxi_cpuif_init(void); + /******************************************************************************* * This function does some minimal GICv3 configuration. The Firmware itself does @@ -161,6 +164,7 @@ static void gicv3_cpuif_deactivate(void) ******************************************************************************/ void arm_gic_cpuif_setup(void) { + unsigned int val; assert(g_gicc_base); @@ -174,11 +178,13 @@ void arm_gic_cpuif_setup(void) if (((val >> GICC_IIDR_ARCH_SHIFT) & GICC_IIDR_ARCH_MASK) >= 3) gicv3_cpuif_setup(); + val = ENABLE_GRP0 | FIQ_EN | FIQ_BYP_DIS_GRP0; val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1; gicc_write_pmr(g_gicc_base, GIC_PRI_MASK); gicc_write_ctlr(g_gicc_base, val); + } /******************************************************************************* @@ -238,6 +244,7 @@ void arm_gic_pcpu_distif_setup(void) ******************************************************************************/ static void arm_gic_distif_setup(void) { + unsigned int num_ints, ctlr, index, irq_num; /* Disable the distributor before going further */ @@ -273,6 +280,7 @@ static void arm_gic_distif_setup(void) arm_gic_pcpu_distif_setup(); gicd_write_ctlr(g_gicd_base, ctlr | ENABLE_GRP0); + } /******************************************************************************* @@ -301,8 +309,16 @@ void arm_gic_init(unsigned int gicc_base, ******************************************************************************/ void arm_gic_setup(void) { - arm_gic_cpuif_setup(); - arm_gic_distif_setup(); + if(0) + { + arm_gic_cpuif_setup(); + arm_gic_distif_setup(); + }else + { + gic_sunxi_cpuif_init(); + gic_sunxi_distributor_init(); + } + } /******************************************************************************* diff --git a/include/bl31/cpu_data.h b/include/bl31/cpu_data.h index ba7ae06..859a8d4 100644 --- a/include/bl31/cpu_data.h +++ b/include/bl31/cpu_data.h @@ -104,6 +104,7 @@ static inline struct cpu_data *_cpu_data(void) *************************************************************************/ void init_cpu_data_ptr(void); +void init_cpu_ops(void); #define get_cpu_data(_m) _cpu_data()->_m #define set_cpu_data(_m, _v) _cpu_data()->_m = _v @@ -115,6 +116,10 @@ void init_cpu_data_ptr(void); #define flush_cpu_data(_m) flush_dcache_range((uint64_t) \ &(_cpu_data()->_m), \ sizeof(_cpu_data()->_m)) +#define flush_cpu_data_by_index(_ix, _m) \ + flush_dcache_range((uint64_t) \ + &(_cpu_data_by_index(_ix)->_m), \ + sizeof(_cpu_data_by_index(_ix)->_m)) #endif /* __ASSEMBLY__ */ diff --git a/include/bl31/head_data.h b/include/bl31/head_data.h new file mode 100644 index 0000000..9c5223f --- /dev/null +++ b/include/bl31/head_data.h @@ -0,0 +1,27 @@ +/*
+ *
+ * Header for system
+ *
+ */
+
+#ifndef __HEAD_H__
+#define __HEAD_H__
+
+/******************************************************************************/
+/* the control information stored in file head */
+/******************************************************************************/
+struct spare_boot_ctrl_head {
+ unsigned int jump_instruction; // one intruction jumping to real code
+ unsigned char magic[8]; // ="u-boot"
+ unsigned int check_sum; // generated by PC
+ unsigned int align_size; // align size in byte
+ unsigned int length; // the size of all file
+ unsigned int uboot_length; // the size of uboot
+ unsigned char version[8]; // uboot version
+ unsigned char platform[8]; // platform information
+ int reserved[1]; //stamp space, 16bytes align
+} ;
+
+
+
+#endif /* __HEAD_H__ */
diff --git a/include/bl31/services/std_svc.h b/include/bl31/services/std_svc.h index cbd5b62..329cee2 100644 --- a/include/bl31/services/std_svc.h +++ b/include/bl31/services/std_svc.h @@ -38,6 +38,7 @@ /* 0x8400ff02 is reserved */ #define ARM_STD_SVC_VERSION 0x8400ff03 + /* ARM Standard Service Calls version numbers */ #define STD_SVC_VERSION_MAJOR 0x0 #define STD_SVC_VERSION_MINOR 0x1 diff --git a/include/drivers/console.h b/include/drivers/console.h index f144ab9..6b0fe35 100644 --- a/include/drivers/console.h +++ b/include/drivers/console.h @@ -33,6 +33,7 @@ int console_init(unsigned long base_addr, unsigned int uart_clk, unsigned int baud_rate); +int console_exit(void); int console_putc(int c); int console_getc(void); diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h index 09365fb..9b238d1 100644 --- a/include/lib/aarch64/arch_helpers.h +++ b/include/lib/aarch64/arch_helpers.h @@ -40,24 +40,24 @@ * registers *********************************************************************/ -#define _DEFINE_SYSREG_READ_FUNC(_name, _reg_name) \ -static inline uint64_t read_ ## _name(void) \ -{ \ - uint64_t v; \ - __asm__ ("mrs %0, " #_reg_name : "=r" (v)); \ - return v; \ +#define _DEFINE_SYSREG_READ_FUNC(_name, _reg_name) \ +static inline uint64_t read_ ## _name(void) \ +{ \ + uint64_t v; \ + __asm__ volatile ("mrs %0, " #_reg_name : "=r" (v)); \ + return v; \ } -#define _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name) \ -static inline void write_ ## _name(uint64_t v) \ -{ \ - __asm__ ("msr " #_reg_name ", %0" : : "r" (v)); \ +#define _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name) \ +static inline void write_ ## _name(uint64_t v) \ +{ \ + __asm__ volatile ("msr " #_reg_name ", %0" : : "r" (v)); \ } #define _DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _reg_name) \ -static inline void write_ ## _name(const uint64_t v) \ -{ \ - __asm__ ("msr " #_reg_name ", %0" : : "i" (v)); \ +static inline void write_ ## _name(const uint64_t v) \ +{ \ + __asm__ volatile ("msr " #_reg_name ", %0" : : "i" (v)); \ } /* Define read function for system register */ diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index 69bb749..bedff9e 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -191,4 +191,6 @@ void bl31_plat_enable_mmu(uint32_t flags); ******************************************************************************/ void bl32_plat_enable_mmu(uint32_t flags); +void platform_smp_init(void); + #endif /* __PLATFORM_H__ */ diff --git a/lib/aarch64/xlat_tables.c b/lib/aarch64/xlat_tables.c index ddc9ba8..82ae898 100644 --- a/lib/aarch64/xlat_tables.c +++ b/lib/aarch64/xlat_tables.c @@ -35,7 +35,7 @@ #include <platform_def.h> #include <string.h> #include <xlat_tables.h> - +#include <stdio.h> #ifndef DEBUG_XLAT_TABLE #define DEBUG_XLAT_TABLE 0 @@ -349,3 +349,58 @@ DEFINE_ENABLE_MMU_EL(1, DEFINE_ENABLE_MMU_EL(3, TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT), tlbialle3) + +#if 0 +void enable_mmu_el3(uint32_t flags) +{ + uint64_t mair, tcr, ttbr; + uint32_t sctlr; + uint32_t _tcr_extra = TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT); + + + assert(IS_IN_EL(_el)); + assert((read_sctlr_el3() & SCTLR_M_BIT) == 0); + + /* Set attributes in the right indices of the MAIR */ + mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX); + mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, + ATTR_IWBWA_OWBWA_NTR_INDEX); + write_mair_el3(mair); + + /* Invalidate TLBs at the current exception level */ + tlbialle3(); + + /* Set TCR bits as well. */ + /* Inner & outer WBWA & shareable + T0SZ = 32 */ + tcr = TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WBA | + TCR_RGN_INNER_WBA | + (64 - __builtin_ctzl(ADDR_SPACE_SIZE)); + tcr |= _tcr_extra; + write_tcr_el3(tcr); + + /* Set TTBR bits as well */ + ttbr = (uint64_t) l1_xlation_table; + write_ttbr0_el3(ttbr); + + /* Ensure all translation table writes have drained */ + /* into memory, the TLB invalidation is complete, */ + /* and translation register writes are committed */ + /* before enabling the MMU */ + dsb(); + isb(); + + sctlr = read_sctlr_el3(); + sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT; + + if (flags & DISABLE_DCACHE) + sctlr &= ~SCTLR_C_BIT; + else + sctlr |= SCTLR_C_BIT; + + write_sctlr_el3(sctlr); + + /* Ensure the MMU enable takes effect immediately */ + isb(); +} +#endif + diff --git a/lib/cpus/aarch64/cpu_helpers.S b/lib/cpus/aarch64/cpu_helpers.S index 46584b3..ecc2088 100644 --- a/lib/cpus/aarch64/cpu_helpers.S +++ b/lib/cpus/aarch64/cpu_helpers.S @@ -105,7 +105,8 @@ func prepare_cluster_pwr_dwn /* * Initializes the cpu_ops_ptr if not already initialized - * in cpu_data. This can be called without a runtime stack. + * in cpu_data. This can be called without a runtime stack, but may + * only be called after the MMU is enabled. * clobbers: x0 - x6, x10 */ .globl init_cpu_ops @@ -119,7 +120,7 @@ func init_cpu_ops cmp x0, #0 ASM_ASSERT(ne) #endif - str x0, [x6, #CPU_DATA_CPU_OPS_PTR] + str x0, [x6, #CPU_DATA_CPU_OPS_PTR]! mov x30, x10 1: ret diff --git a/lib/locks/bakery/bakery_lock.c b/lib/locks/bakery/bakery_lock.c index 877f526..7e71dec 100644 --- a/lib/locks/bakery/bakery_lock.c +++ b/lib/locks/bakery/bakery_lock.c @@ -107,6 +107,7 @@ static unsigned int bakery_get_ticket(bakery_lock_t *bakery, unsigned int me) ++my_ticket; bakery->number[me] = my_ticket; bakery->entering[me] = 0; + dsb(); sev(); return my_ticket; @@ -189,5 +190,6 @@ void bakery_lock_release(bakery_lock_t *bakery) */ bakery->owner = NO_OWNER; bakery->number[me] = 0; + dsb(); sev(); } diff --git a/lib/stdlib/assert.c b/lib/stdlib/assert.c index 90a1afe..b6570da 100644 --- a/lib/stdlib/assert.c +++ b/lib/stdlib/assert.c @@ -36,6 +36,5 @@ void __assert (const char *function, const char *file, unsigned int line, const char *assertion) { - tf_printf("ASSERT: %s <%d> : %s\n", function, line, assertion); while(1); } diff --git a/plat/fvp/platform.mk b/plat/fvp/platform.mk index e7c06a8..73d6052 100644 --- a/plat/fvp/platform.mk +++ b/plat/fvp/platform.mk @@ -71,7 +71,8 @@ PLAT_BL_COMMON_SOURCES := drivers/arm/pl011/pl011_console.S \ lib/semihosting/semihosting.c \ lib/semihosting/aarch64/semihosting_call.S \ plat/common/aarch64/plat_common.c \ - plat/fvp/fvp_io_storage.c + plat/fvp/fvp_io_storage.c + BL1_SOURCES += drivers/arm/cci400/cci400.c \ lib/cpus/aarch64/aem_generic.S \ diff --git a/plat/sun50iw1p1/aarch64/plat_helpers.S b/plat/sun50iw1p1/aarch64/plat_helpers.S new file mode 100644 index 0000000..1bb225f --- /dev/null +++ b/plat/sun50iw1p1/aarch64/plat_helpers.S @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <arch.h> +#include <asm_macros.S> +#include <bl_common.h> +#include <cortex_a57.h> +#include <cpu_macros.S> +#include <platform_def.h> +#include "../sunxi_def.h" + + .globl plat_crash_console_init + .globl plat_crash_console_putc + .globl plat_report_exception + .globl plat_reset_handler + .globl platform_get_core_pos + .globl platform_mem_init + .globl platform_smp_init + + /* Define a crash console for the plaform */ +#define JUNO_CRASH_CONSOLE_BASE 0 + + /* --------------------------------------------- + * void plat_report_exception(unsigned int type) + * Function to report an unhandled exception + * with platform-specific means. + * On Juno platform, it updates the LEDs + * to indicate where we are + * --------------------------------------------- + */ +func plat_report_exception + + ret + + /* + * Return 0 to 3 for the A53s and 4 or 5 for the A57s + */ +func platform_get_core_pos + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + add x0, x1, x0, LSR #6 + ret + + + /* ----------------------------------------------------- + * void platform_mem_init(void); + * + * We don't need to carry out any memory initialization + * on Juno. The Secure RAM is accessible straight away. + * ----------------------------------------------------- + */ +func platform_mem_init + ret + + /* ----------------------------------------------------- + * void plat_reset_handler(void); + * + * Implement workaround for defect id 831273 by enabling + * an event stream every 65536 cycles and set the L2 RAM + * latencies for Cortex-A57. + * ----------------------------------------------------- + */ +func plat_reset_handler + /* Read the MIDR_EL1 */ + mrs x0, midr_el1 + ubfx x1, x0, MIDR_PN_SHIFT, #12 + cmp w1, #((CORTEX_A57_MIDR >> MIDR_PN_SHIFT) & MIDR_PN_MASK) + b.ne 1f + + /* Change the L2 Data and Tag Ram latency to 3 cycles */ + mov x0, #(L2_DATA_RAM_LATENCY_3_CYCLES | \ + (L2_TAG_RAM_LATENCY_3_CYCLES << \ + L2CTLR_TAG_RAM_LATENCY_SHIFT)) + msr L2CTLR_EL1, x0 + +1: + /* --------------------------------------------- + * Enable the event stream every 65536 cycles + * --------------------------------------------- + */ + mov x0, #(0xf << EVNTI_SHIFT) + orr x0, x0, #EVNTEN_BIT + msr CNTKCTL_EL1, x0 + isb + ret + +func platform_smp_init + mrs x0, ACTLR_EL3 // Read ACTLR_EL3 + orr x0, x0, #(1 << 1) // Set CPUECTLR_EL1 access control bit + msr ACTLR_EL3, x0 // Write ACTLR_EL3 + mrs x0, ACTLR_EL2 // Read ACTLR_EL2 + orr x0, x0, #(1 << 1) // Set CPUECTLR_EL1 access control bit + msr ACTLR_EL2, x0 // Write ACTLR_EL2 + mrs x0, S3_1_c15_c2_1 // Read CPUECTLR_EL1 + orr x0, x0, #(1 << 6) // Set the SMPEN bit + msr S3_1_c15_c2_1, x0 // Write CPUECTLR_EL1 + mov x0, #0x0 + msr cntvoff_el2, x0 + ret + +func console_core_putc + ldr x1, =0x01c28000 +1: + ldr w2, [x1,#20] + tbz w2, #6, 1b + str w0, [x1,#0] + ret + +func plat_crash_console_init + mov w0, #1 + ret + +func plat_crash_console_putc + b console_core_putc + + + diff --git a/plat/sun50iw1p1/aarch64/sunxi_common.c b/plat/sun50iw1p1/aarch64/sunxi_common.c new file mode 100644 index 0000000..b7de9d0 --- /dev/null +++ b/plat/sun50iw1p1/aarch64/sunxi_common.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <arm_gic.h> +#include <bl_common.h> +#include <cci400.h> +#include <debug.h> +#include <mmio.h> +#include <platform.h> +#include <plat_config.h> +#include <xlat_tables.h> +#include "../sunxi_def.h" +#include "../sunxi_private.h" + +/******************************************************************************* + * plat_config holds the characteristics of the differences between the three + * FVP platforms (Base, A53_A57 & Foundation). It will be populated during cold + * boot at each boot stage by the primary before enabling the MMU (to allow cci + * configuration) & used thereafter. Each BL will have its own copy to allow + * independent operation. + ******************************************************************************/ +plat_config_t plat_config; + +/* + * Table of regions to map using the MMU. + * This doesn't include TZRAM as the 'mem_layout' argument passed to + * configure_mmu_elx() will give the available subset of that, + */ +const mmap_region_t sunxi_mmap[] = { + + //1G + { 0, 0, DRAM1_BASE, MT_DEVICE | MT_RW | MT_SECURE }, + //2G + { DRAM1_BASE, DRAM1_BASE, SUNXI_MAX_DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS}, + //TRUSTED dram for secure os and shared memory + { SUNXI_TRUSTED_DRAM_BASE, SUNXI_TRUSTED_DRAM_BASE, SUNXI_TRUSTED_DRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE }, + { MEMRES_BASE, MEMRES_BASE, MEMRES_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, + {0} +}; + + + + +/******************************************************************************* + * Macro generating the code for the function setting up the pagetables as per + * the platform memory map & initialize the mmu, for the given exception level + ******************************************************************************/ +#define DEFINE_CONFIGURE_MMU_EL(_el) \ + void sunxi_configure_mmu_el##_el(unsigned long total_base, \ + unsigned long total_size, \ + unsigned long ro_start, \ + unsigned long ro_limit, \ + unsigned long coh_start, \ + unsigned long coh_limit) \ + { \ + mmap_add_region(total_base, total_base, \ + total_size, \ + MT_MEMORY | MT_RW | MT_SECURE); \ + mmap_add_region(ro_start, ro_start, \ + ro_limit - ro_start, \ + MT_MEMORY | MT_RO | MT_SECURE); \ + mmap_add_region(coh_start, coh_start, \ + coh_limit - coh_start, \ + MT_DEVICE | MT_RW | MT_SECURE); \ + mmap_add(sunxi_mmap); \ + init_xlat_tables(); \ + \ + enable_mmu_el##_el(0); \ + } + +void sunxi_configure_mmu_el3(unsigned long total_base, + unsigned long total_size, + unsigned long ro_start, + unsigned long ro_limit, + unsigned long coh_start, + unsigned long coh_limit) +{ + mmap_add_region(total_base, total_base, + total_size, + MT_MEMORY | MT_RW | MT_SECURE); + mmap_add_region(ro_start, ro_start, + ro_limit - ro_start, + MT_MEMORY | MT_RO | MT_SECURE); + mmap_add_region(coh_start, coh_start, + coh_limit - coh_start, + MT_DEVICE | MT_RW | MT_SECURE); + mmap_add(sunxi_mmap); + init_xlat_tables(); + + enable_mmu_el3(0); +} + +void sunxi_configure_mmu_el1(unsigned long total_base, + unsigned long total_size, + unsigned long ro_start, + unsigned long ro_limit, + unsigned long coh_start, + unsigned long coh_limit) +{ + mmap_add_region(total_base, total_base, + total_size, + MT_MEMORY | MT_RW | MT_SECURE); + mmap_add_region(ro_start, ro_start, + ro_limit - ro_start, + MT_MEMORY | MT_RO | MT_SECURE); + mmap_add_region(coh_start, coh_start, + coh_limit - coh_start, + MT_DEVICE | MT_RW | MT_SECURE); + mmap_add(sunxi_mmap); + init_xlat_tables(); + + enable_mmu_el1(0); +} + + +/* Define EL1 and EL3 variants of the function initialising the MMU */ +//DEFINE_CONFIGURE_MMU_EL(1) +//DEFINE_CONFIGURE_MMU_EL(3) + +/******************************************************************************* + * A single boot loader stack is expected to work on both the Foundation FVP + * models and the two flavours of the Base FVP models (AEMv8 & Cortex). The + * SYS_ID register provides a mechanism for detecting the differences between + * these platforms. This information is stored in a per-BL array to allow the + * code to take the correct path.Per BL platform configuration. + ******************************************************************************/ +int sunxi_config_setup(void) +{ + + return 0; +} + +unsigned long plat_get_ns_image_entrypoint(void) +{ + return NS_IMAGE_OFFSET; +} + +uint64_t plat_get_syscnt_freq(void) +{ + uint64_t counter_base_frequency; + + /* Read the frequency from Frequency modes table */ + counter_base_frequency = 24<<20;//mmio_read_32(SYS_CNTCTL_BASE + CNTFID_OFF); + + /* The first entry of the frequency modes table must not be 0 */ + if (counter_base_frequency == 0) + panic(); + + return counter_base_frequency; +} + +void sunxi_cci_init(void) +{ + /* + * Initialize CCI-400 driver + */ + +} + +void sunxi_cci_enable(void) +{ + /* + * Enable CCI-400 coherency for this cluster. No need + * for locks as no other cpu is active at the + * moment + */ + +} + + +void sunxi_gic_init(void) +{ + gic_setup(); +} + + +/******************************************************************************* + * Gets SPSR for BL32 entry + ******************************************************************************/ +uint32_t sunxi_get_spsr_for_bl32_entry(void) +{ + /* + * The Secure Payload Dispatcher service is responsible for + * setting the SPSR prior to entry into the BL32 image. + */ + return 0; +} + +/******************************************************************************* + * Gets SPSR for BL33 entry + ******************************************************************************/ +uint32_t sunxi_get_spsr_for_bl33_entry(void) +{ + #if 0 + unsigned long el_status; + unsigned int mode; + uint32_t spsr; + + /* Figure out what mode we enter the non-secure world in */ + el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; + el_status &= ID_AA64PFR0_ELX_MASK; + + if (el_status) + mode = MODE_EL2; + else + mode = MODE_EL1; + + /* + * TODO: Consider the possibility of specifying the SPSR in + * the FIP ToC and allowing the platform to have a say as + * well. + */ + spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); + return spsr; + #endif + return SPSR_MODE32(MODE32_svc,SPSR_T_ARM,SPSR_E_LITTLE,DISABLE_ALL_EXCEPTIONS); +} diff --git a/plat/sun50iw1p1/bl1_sunxi_setup.c b/plat/sun50iw1p1/bl1_sunxi_setup.c new file mode 100644 index 0000000..b1205d4 --- /dev/null +++ b/plat/sun50iw1p1/bl1_sunxi_setup.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <debug.h> +#include <console.h> +#include <mmio.h> +#include <platform.h> +#include <platform_def.h> +#include "../../bl1/bl1_private.h" +#include "fvp_def.h" +#include "fvp_private.h" + +/******************************************************************************* + * Declarations of linker defined symbols which will help us find the layout + * of trusted SRAM + ******************************************************************************/ +extern unsigned long __COHERENT_RAM_START__; +extern unsigned long __COHERENT_RAM_END__; + +/* + * The next 2 constants identify the extents of the coherent memory region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to + * page-aligned addresses. + */ +#define BL1_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__) +#define BL1_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__) + +/* Data structure which holds the extents of the trusted SRAM for BL1*/ +static meminfo_t bl1_tzram_layout; + +meminfo_t *bl1_plat_sec_mem_layout(void) +{ + return &bl1_tzram_layout; +} + +/******************************************************************************* + * Perform any BL1 specific platform actions. + ******************************************************************************/ +void bl1_early_platform_setup(void) +{ + const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE; + + /* Initialize the console to provide early debug support */ + console_init(PL011_UART0_BASE, PL011_UART0_CLK_IN_HZ, PL011_BAUDRATE); + + /* Allow BL1 to see the whole Trusted RAM */ + bl1_tzram_layout.total_base = FVP_TRUSTED_SRAM_BASE; + bl1_tzram_layout.total_size = FVP_TRUSTED_SRAM_SIZE; + + /* Calculate how much RAM BL1 is using and how much remains free */ + bl1_tzram_layout.free_base = FVP_TRUSTED_SRAM_BASE; + bl1_tzram_layout.free_size = FVP_TRUSTED_SRAM_SIZE; + reserve_mem(&bl1_tzram_layout.free_base, + &bl1_tzram_layout.free_size, + BL1_RAM_BASE, + bl1_size); + + /* Initialize the platform config for future decision making */ + fvp_config_setup(); +} + +/******************************************************************************* + * Function which will evaluate how much of the trusted ram has been gobbled + * up by BL1 and return the base and size of whats available for loading BL2. + * Its called after coherency and the MMU have been turned on. + ******************************************************************************/ +void bl1_platform_setup(void) +{ + /* Initialise the IO layer and register platform IO devices */ + fvp_io_setup(); +} + + +/******************************************************************************* + * Perform the very early platform specific architecture setup here. At the + * moment this only does basic initialization. Later architectural setup + * (bl1_arch_setup()) does not do anything platform specific. + ******************************************************************************/ +void bl1_plat_arch_setup(void) +{ + fvp_cci_init(); + fvp_cci_enable(); + + fvp_configure_mmu_el3(bl1_tzram_layout.total_base, + bl1_tzram_layout.total_size, + BL1_RO_BASE, + BL1_RO_LIMIT, + BL1_COHERENT_RAM_BASE, + BL1_COHERENT_RAM_LIMIT); +} + + +/******************************************************************************* + * Before calling this function BL2 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL2 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl1_plat_set_bl2_ep_info(image_info_t *bl2_image, + entry_point_info_t *bl2_ep) +{ + SET_SECURITY_STATE(bl2_ep->h.attr, SECURE); + bl2_ep->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); +} diff --git a/plat/sun50iw1p1/bl2_sunxi_setup.c b/plat/sun50iw1p1/bl2_sunxi_setup.c new file mode 100644 index 0000000..d4fa4cb --- /dev/null +++ b/plat/sun50iw1p1/bl2_sunxi_setup.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <console.h> +#include <platform.h> +#include <platform_def.h> +#include <string.h> +#include "fvp_def.h" +#include "fvp_private.h" + +/******************************************************************************* + * Declarations of linker defined symbols which will help us find the layout + * of trusted SRAM + ******************************************************************************/ +extern unsigned long __RO_START__; +extern unsigned long __RO_END__; + +extern unsigned long __COHERENT_RAM_START__; +extern unsigned long __COHERENT_RAM_END__; + +/* + * The next 2 constants identify the extents of the code & RO data region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses. + */ +#define BL2_RO_BASE (unsigned long)(&__RO_START__) +#define BL2_RO_LIMIT (unsigned long)(&__RO_END__) + +/* + * The next 2 constants identify the extents of the coherent memory region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to + * page-aligned addresses. + */ +#define BL2_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__) +#define BL2_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__) + +/* Data structure which holds the extents of the trusted SRAM for BL2 */ +static meminfo_t bl2_tzram_layout +__attribute__ ((aligned(PLATFORM_CACHE_LINE_SIZE), + section("tzfw_coherent_mem"))); + +/* Assert that BL3-1 parameters fit in shared memory */ +CASSERT((PARAMS_BASE + sizeof(bl2_to_bl31_params_mem_t)) < + (FVP_SHARED_RAM_BASE + FVP_SHARED_RAM_SIZE), + assert_bl31_params_do_not_fit_in_shared_memory); + +/******************************************************************************* + * Reference to structures which holds the arguments which need to be passed + * to BL31 + ******************************************************************************/ +static bl31_params_t *bl2_to_bl31_params; +static entry_point_info_t *bl31_ep_info; + +meminfo_t *bl2_plat_sec_mem_layout(void) +{ + return &bl2_tzram_layout; +} + +/******************************************************************************* + * This function assigns a pointer to the memory that the platform has kept + * aside to pass platform specific and trusted firmware related information + * to BL31. This memory is allocated by allocating memory to + * bl2_to_bl31_params_mem_t structure which is a superset of all the + * structure whose information is passed to BL31 + * NOTE: This function should be called only once and should be done + * before generating params to BL31 + ******************************************************************************/ +bl31_params_t *bl2_plat_get_bl31_params(void) +{ + bl2_to_bl31_params_mem_t *bl31_params_mem; + + /* + * Allocate the memory for all the arguments that needs to + * be passed to BL31 + */ + bl31_params_mem = (bl2_to_bl31_params_mem_t *)PARAMS_BASE; + memset((void *)PARAMS_BASE, 0, sizeof(bl2_to_bl31_params_mem_t)); + + /* Assign memory for TF related information */ + bl2_to_bl31_params = &bl31_params_mem->bl31_params; + SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0); + + /* Fill BL31 related information */ + bl31_ep_info = &bl31_params_mem->bl31_ep_info; + bl2_to_bl31_params->bl31_image_info = &bl31_params_mem->bl31_image_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY, + VERSION_1, 0); + + /* Fill BL32 related information if it exists */ + if (BL32_BASE) { + bl2_to_bl31_params->bl32_ep_info = + &bl31_params_mem->bl32_ep_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, + PARAM_EP, VERSION_1, 0); + bl2_to_bl31_params->bl32_image_info = + &bl31_params_mem->bl32_image_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, + PARAM_IMAGE_BINARY, + VERSION_1, 0); + } + + /* Fill BL33 related information */ + bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem->bl33_ep_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl33_ep_info, + PARAM_EP, VERSION_1, 0); + bl2_to_bl31_params->bl33_image_info = &bl31_params_mem->bl33_image_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY, + VERSION_1, 0); + + return bl2_to_bl31_params; +} + + +/******************************************************************************* + * This function returns a pointer to the shared memory that the platform + * has kept to point to entry point information of BL31 to BL2 + ******************************************************************************/ +struct entry_point_info *bl2_plat_get_bl31_ep_info(void) +{ +#if DEBUG + bl31_ep_info->args.arg1 = FVP_BL31_PLAT_PARAM_VAL; +#endif + return bl31_ep_info; +} + + +/******************************************************************************* + * BL1 has passed the extents of the trusted SRAM that should be visible to BL2 + * in x0. This memory layout is sitting at the base of the free trusted SRAM. + * Copy it to a safe loaction before its reclaimed by later BL2 functionality. + ******************************************************************************/ +void bl2_early_platform_setup(meminfo_t *mem_layout) +{ + /* Initialize the console to provide early debug support */ + console_init(PL011_UART0_BASE, PL011_UART0_CLK_IN_HZ, PL011_BAUDRATE); + + /* Setup the BL2 memory layout */ + bl2_tzram_layout = *mem_layout; + + /* Initialize the platform config for future decision making */ + fvp_config_setup(); +} + +/******************************************************************************* + * Perform platform specific setup. For now just initialize the memory location + * to use for passing arguments to BL31. + ******************************************************************************/ +void bl2_platform_setup(void) +{ + /* + * Do initial security configuration to allow DRAM/device access. On + * Base FVP only DRAM security is programmable (via TrustZone), but + * other platforms might have more programmable security devices + * present. + */ + fvp_security_setup(); + + /* Initialise the IO layer and register platform IO devices */ + fvp_io_setup(); +} + +/* Flush the TF params and the TF plat params */ +void bl2_plat_flush_bl31_params(void) +{ + flush_dcache_range((unsigned long)PARAMS_BASE, \ + sizeof(bl2_to_bl31_params_mem_t)); +} + + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this is only intializes the mmu in a quick and dirty way. + ******************************************************************************/ +void bl2_plat_arch_setup(void) +{ + fvp_configure_mmu_el1(bl2_tzram_layout.total_base, + bl2_tzram_layout.total_size, + BL2_RO_BASE, + BL2_RO_LIMIT, + BL2_COHERENT_RAM_BASE, + BL2_COHERENT_RAM_LIMIT); +} + +/******************************************************************************* + * Before calling this function BL31 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL31 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl2_plat_set_bl31_ep_info(image_info_t *bl31_image_info, + entry_point_info_t *bl31_ep_info) +{ + SET_SECURITY_STATE(bl31_ep_info->h.attr, SECURE); + bl31_ep_info->spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); +} + + +/******************************************************************************* + * Before calling this function BL32 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL32 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl2_plat_set_bl32_ep_info(image_info_t *bl32_image_info, + entry_point_info_t *bl32_ep_info) +{ + SET_SECURITY_STATE(bl32_ep_info->h.attr, SECURE); + bl32_ep_info->spsr = fvp_get_spsr_for_bl32_entry(); +} + +/******************************************************************************* + * Before calling this function BL33 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL33 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl2_plat_set_bl33_ep_info(image_info_t *image, + entry_point_info_t *bl33_ep_info) +{ + SET_SECURITY_STATE(bl33_ep_info->h.attr, NON_SECURE); + bl33_ep_info->spsr = fvp_get_spsr_for_bl33_entry(); +} + + +/******************************************************************************* + * Populate the extents of memory available for loading BL32 + ******************************************************************************/ +void bl2_plat_get_bl32_meminfo(meminfo_t *bl32_meminfo) +{ + /* + * Populate the extents of memory available for loading BL32. + */ + bl32_meminfo->total_base = BL32_BASE; + bl32_meminfo->free_base = BL32_BASE; + bl32_meminfo->total_size = TSP_SEC_MEM_SIZE; + //(TSP_SEC_MEM_BASE + TSP_SEC_MEM_SIZE) - BL32_BASE; + bl32_meminfo->free_size =TSP_SEC_MEM_SIZE; + //(TSP_SEC_MEM_BASE + TSP_SEC_MEM_SIZE) - BL32_BASE; +} + + +/******************************************************************************* + * Populate the extents of memory available for loading BL33 + ******************************************************************************/ +void bl2_plat_get_bl33_meminfo(meminfo_t *bl33_meminfo) +{ + bl33_meminfo->total_base = DRAM_BASE; + bl33_meminfo->total_size = DRAM_SIZE - DRAM1_SEC_SIZE; + bl33_meminfo->free_base = DRAM_BASE; + bl33_meminfo->free_size = DRAM_SIZE - DRAM1_SEC_SIZE; +} diff --git a/plat/sun50iw1p1/bl31_sunxi_setup.c b/plat/sun50iw1p1/bl31_sunxi_setup.c new file mode 100644 index 0000000..4237a25 --- /dev/null +++ b/plat/sun50iw1p1/bl31_sunxi_setup.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <arm_gic.h> +#include <assert.h> +#include <bl_common.h> +#include <bl31.h> +#include <console.h> +#include <mmio.h> +#include <platform.h> +#include <stddef.h> +#include "sunxi_def.h" +#include "sunxi_private.h" + +/******************************************************************************* + * Declarations of linker defined symbols which will help us find the layout + * of trusted SRAM + ******************************************************************************/ +extern unsigned long __RO_START__; +extern unsigned long __RO_END__; + +extern unsigned long __COHERENT_RAM_START__; +extern unsigned long __COHERENT_RAM_END__; + +/* + * The next 2 constants identify the extents of the code & RO data region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses. + */ +#define BL31_RO_BASE (unsigned long)(&__RO_START__) +#define BL31_RO_LIMIT (unsigned long)(&__RO_END__) + +/* + * The next 2 constants identify the extents of the coherent memory region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols + * refer to page-aligned addresses. + */ +#define BL31_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__) +#define BL31_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__) + + +#if 0 +#if RESET_TO_BL31 +static entry_point_info_t bl32_image_ep_info; +static entry_point_info_t bl33_image_ep_info; +#else +/******************************************************************************* + * Reference to structure which holds the arguments that have been passed to + * BL31 from BL2. + ******************************************************************************/ +static bl31_params_t *bl2_to_bl31_params; +#endif +#else +static entry_point_info_t bl32_image_ep_info; +static entry_point_info_t bl33_image_ep_info; +#endif + + +/******************************************************************************* + * Return a pointer to the 'entry_point_info' structure of the next image for the + * security state specified. BL33 corresponds to the non-secure image type + * while BL32 corresponds to the secure image type. A NULL pointer is returned + * if the image does not exist. + ******************************************************************************/ +entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) +{ +//#if RESET_TO_BL31 +#if 1 + + assert(sec_state_is_valid(type)); + + if (type == NON_SECURE) + return &bl33_image_ep_info; + else + return &bl32_image_ep_info; +#else + entry_point_info_t *next_image_info; + + assert(sec_state_is_valid(type)); + + next_image_info = (type == NON_SECURE) ? + bl2_to_bl31_params->bl33_ep_info : + bl2_to_bl31_params->bl32_ep_info; + + /* None of the images on this platform can have 0x0 as the entrypoint */ + if (next_image_info->pc) + return next_image_info; + else + return NULL; +#endif +} + +/******************************************************************************* + * Perform any BL31 specific platform actions. Here is an opportunity to copy + * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they + * are lost (potentially). This needs to be done before the MMU is initialized + * so that the memory layout can be used while creating page tables. On the FVP + * we know that BL2 has populated the parameters in secure DRAM. So we just use + * the reference passed in 'from_bl2' instead of copying. The 'data' parameter + * is not used since all the information is contained in 'from_bl2'. Also, BL2 + * has flushed this information to memory, so we are guaranteed to pick up good + * data + ******************************************************************************/ +void bl31_early_platform_setup(bl31_params_t *from_bl2, + void *plat_params_from_bl2) +{ + + + /* Initialize the console to provide early debug support */ + console_init(SUNXI_UART0_BASE, UART0_CLK_IN_HZ, UART0_BAUDRATE); + + /* Initialize the platform config for future decision making */ + sunxi_config_setup(); + +#if 0 +#if RESET_TO_BL31 + /* There are no parameters from BL2 if BL31 is a reset vector */ + assert(from_bl2 == NULL); + assert(plat_params_from_bl2 == NULL); + + /* + * Do initial security configuration to allow DRAM/device access. On + * Base FVP only DRAM security is programmable (via TrustZone), but + * other platforms might have more programmable security devices + * present. + */ + sunxi_security_setup(); + + /* Populate entry point information for BL3-2 and BL3-3 */ + SET_PARAM_HEAD(&bl32_image_ep_info, + PARAM_EP, + VERSION_1, + 0); + SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); + bl32_image_ep_info.pc = BL32_BASE; + bl32_image_ep_info.spsr = sunxi_get_spsr_for_bl32_entry(); + + SET_PARAM_HEAD(&bl33_image_ep_info, + PARAM_EP, + VERSION_1, + 0); + /* + * Tell BL31 where the non-trusted software image + * is located and the entry state information + */ + bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); + bl33_image_ep_info.spsr = sunxi_get_spsr_for_bl33_entry(); + SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); + +#else + /* Check params passed from BL2 should not be NULL, + * We are not checking plat_params_from_bl2 as NULL as we are not + * using it on FVP + */ + assert(from_bl2 != NULL); + assert(from_bl2->h.type == PARAM_BL31); + assert(from_bl2->h.version >= VERSION_1); + sunxi_security_setup(); + bl2_to_bl31_params = from_bl2; + assert(((unsigned long)plat_params_from_bl2) == SUNXI_BL31_PLAT_PARAM_VAL); +#endif +#endif + /* + * Do initial security configuration to allow DRAM/device access. On + * Base FVP only DRAM security is programmable (via TrustZone), but + * other platforms might have more programmable security devices + * present. + */ + sunxi_security_setup(); + /* + * Tell BL31 where the non-trusted software image + * is located and the entry state information + */ + bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); + bl33_image_ep_info.spsr = sunxi_get_spsr_for_bl33_entry(); + SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); + + + +} + +/******************************************************************************* + * Initialize the gic, configure the CLCD and zero out variables needed by the + * secondaries to boot up correctly. + ******************************************************************************/ +void bl31_platform_setup(void) +{ + + //unsigned int reg_val; + + /* Initialize the gic cpu and distributor interfaces */ + sunxi_gic_init(); +#if 0 + + /* + * TODO: Configure the CLCD before handing control to + * linux. Need to see if a separate driver is needed + * instead. + */ + mmio_write_32(VE_SYSREGS_BASE + V2M_SYS_CFGDATA, 0); + mmio_write_32(VE_SYSREGS_BASE + V2M_SYS_CFGCTRL, + (1ull << 31) | (1 << 30) | (7 << 20) | (0 << 16)); + + /* Enable and initialize the System level generic timer */ + mmio_write_32(SYS_CNTCTL_BASE + CNTCR_OFF, CNTCR_FCREQ(0) | CNTCR_EN); + + /* Allow access to the System counter timer module */ + reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT); + reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT); + reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT); + mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(0), reg_val); + mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(1), reg_val); + + reg_val = (1 << CNTNSAR_NS_SHIFT(0)) | (1 << CNTNSAR_NS_SHIFT(1)); + mmio_write_32(SYS_TIMCTL_BASE + CNTNSAR, reg_val); +#endif + + /* Intialize the power controller */ + //sunxi_pwrc_setup(); + + /* Topologies are best known to the platform. */ + sunxi_setup_topology(); + +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this is only intializes the mmu in a quick and dirty way. + ******************************************************************************/ +void bl31_plat_arch_setup(void) +{ + //set smp bit before cache enable + platform_smp_init(); +#if 1 + sunxi_configure_mmu_el3(BL31_RO_BASE, + (BL31_COHERENT_RAM_LIMIT - BL31_RO_BASE), + BL31_RO_BASE, + BL31_RO_LIMIT, + BL31_COHERENT_RAM_BASE, + BL31_COHERENT_RAM_LIMIT); +#endif + +} diff --git a/plat/sun50iw1p1/drivers/gpio/gpio.c b/plat/sun50iw1p1/drivers/gpio/gpio.c new file mode 100644 index 0000000..f741041 --- /dev/null +++ b/plat/sun50iw1p1/drivers/gpio/gpio.c @@ -0,0 +1,228 @@ +/* +********************************************************************************************************************** +* +* the Embedded Secure Bootloader System +* +* +* Copyright(C), 2006-2014, Allwinnertech Co., Ltd. +* All Rights Reserved +* +* File : +* +* By : +* +* Version : V2.00 +* +* Date : +* +* Descript: +********************************************************************************************************************** +*/ + + +#include "../../sunxi_def.h" +#include <gpio.h> + +#define GPIO_REG_READ(reg) mmio_read_32((reg)) +#define GPIO_REG_WRITE(reg, value) mmio_write_32((reg),(value)) + +/* +************************************************************************************************************ +* +* normal_gpio_cfg +* +* 函数名称: +* +* 参数列表: +* +* +* +* 返回值 : +* +* 说明 : +* +* +************************************************************************************************************ +*/ +int32_t boot_set_gpio(void *user_gpio_list, uint32_t group_count_max, int32_t set_gpio) +{ + normal_gpio_set_t *tmp_user_gpio_data, *gpio_list; + uint32_t first_port; //保存真正有效的GPIO的个数 + uint32_t tmp_group_func_data; + uint32_t tmp_group_pull_data; + uint32_t tmp_group_dlevel_data; + uint32_t tmp_group_data_data; + uint32_t data_change = 0; + uint32_t tmp_group_func_addr, tmp_group_pull_addr; + uint32_t tmp_group_dlevel_addr, tmp_group_data_addr; + uint32_t port, port_num, port_num_func, port_num_pull; + uint32_t pre_port, pre_port_num_func; + uint32_t pre_port_num_pull; + int32_t i, tmp_val; + + + gpio_list = (normal_gpio_set_t *)user_gpio_list; + + for(first_port = 0; first_port < group_count_max; first_port++) + { + tmp_user_gpio_data = gpio_list + first_port; + port = tmp_user_gpio_data->port; //读出端口数值 + port_num = tmp_user_gpio_data->port_num; //读出端口中的某一个GPIO + if(!port) + { + continue; + } + port_num_func = (port_num >> 3); + port_num_pull = (port_num >> 4); + + tmp_group_func_addr = PIO_REG_CFG(port, port_num_func); //更新功能寄存器地址 + tmp_group_pull_addr = PIO_REG_PULL(port, port_num_pull); //更新pull寄存器 + tmp_group_dlevel_addr = PIO_REG_DLEVEL(port, port_num_pull);//更新level寄存器 + tmp_group_data_addr = PIO_REG_DATA(port); //更新data寄存器 + + tmp_group_func_data = GPIO_REG_READ(tmp_group_func_addr); + tmp_group_pull_data = GPIO_REG_READ(tmp_group_pull_addr); + tmp_group_dlevel_data = GPIO_REG_READ(tmp_group_dlevel_addr); + tmp_group_data_data = GPIO_REG_READ(tmp_group_data_addr); + + pre_port = port; + pre_port_num_func = port_num_func; + pre_port_num_pull = port_num_pull; + //更新功能寄存器 + tmp_val = (port_num - (port_num_func << 3)) << 2; + tmp_group_func_data &= ~(0x07 << tmp_val); + if(set_gpio) + { + tmp_group_func_data |= (tmp_user_gpio_data->mul_sel & 0x07) << tmp_val; + } + //根据pull的值决定是否更新pull寄存器 + tmp_val = (port_num - (port_num_pull << 4)) << 1; + if(tmp_user_gpio_data->pull >= 0) + { + tmp_group_pull_data &= ~( 0x03 << tmp_val); + tmp_group_pull_data |= (tmp_user_gpio_data->pull & 0x03) << tmp_val; + } + //根据driver level的值决定是否更新driver level寄存器 + if(tmp_user_gpio_data->drv_level >= 0) + { + tmp_group_dlevel_data &= ~( 0x03 << tmp_val); + tmp_group_dlevel_data |= (tmp_user_gpio_data->drv_level & 0x03) << tmp_val; + } + //根据用户输入,以及功能分配决定是否更新data寄存器 + if(tmp_user_gpio_data->mul_sel == 1) + { + if(tmp_user_gpio_data->data >= 0) + { + tmp_val = tmp_user_gpio_data->data & 1; + tmp_group_data_data &= ~(1 << port_num); + tmp_group_data_data |= tmp_val << port_num; + data_change = 1; + } + } + + break; + } + //检查是否有数据存在 + if(first_port >= group_count_max) + { + return -1; + } + //保存用户数据 + for(i = first_port + 1; i < group_count_max; i++) + { + tmp_user_gpio_data = gpio_list + i; //gpio_set依次指向用户的每个GPIO数组成员 + port = tmp_user_gpio_data->port; //读出端口数值 + port_num = tmp_user_gpio_data->port_num; //读出端口中的某一个GPIO + if(!port) + { + break; + } + port_num_func = (port_num >> 3); + port_num_pull = (port_num >> 4); + + if((port_num_pull != pre_port_num_pull) || (port != pre_port)) //如果发现当前引脚的端口不一致,或者所在的pull寄存器不一致 + { + GPIO_REG_WRITE(tmp_group_func_addr, tmp_group_func_data); //回写功能寄存器 + GPIO_REG_WRITE(tmp_group_pull_addr, tmp_group_pull_data); //回写pull寄存器 + GPIO_REG_WRITE(tmp_group_dlevel_addr, tmp_group_dlevel_data); //回写driver level寄存器 + if(data_change) + { + data_change = 0; + GPIO_REG_WRITE(tmp_group_data_addr, tmp_group_data_data); //回写data寄存器 + } + + tmp_group_func_addr = PIO_REG_CFG(port, port_num_func); //更新功能寄存器地址 + tmp_group_pull_addr = PIO_REG_PULL(port, port_num_pull); //更新pull寄存器 + tmp_group_dlevel_addr = PIO_REG_DLEVEL(port, port_num_pull);//更新level寄存器 + tmp_group_data_addr = PIO_REG_DATA(port); //更新data寄存器 + + tmp_group_func_data = GPIO_REG_READ(tmp_group_func_addr); + tmp_group_pull_data = GPIO_REG_READ(tmp_group_pull_addr); + tmp_group_dlevel_data = GPIO_REG_READ(tmp_group_dlevel_addr); + tmp_group_data_data = GPIO_REG_READ(tmp_group_data_addr); + } + else if(pre_port_num_func != port_num_func) //如果发现当前引脚的功能寄存器不一致 + { + GPIO_REG_WRITE(tmp_group_func_addr, tmp_group_func_data); //则只回写功能寄存器 + tmp_group_func_addr = PIO_REG_CFG(port, port_num_func); //更新功能寄存器地址 + + tmp_group_func_data = GPIO_REG_READ(tmp_group_func_addr); + } + //保存当前硬件寄存器数据 + pre_port_num_pull = port_num_pull; //设置当前GPIO成为前一个GPIO + pre_port_num_func = port_num_func; + pre_port = port; + + //更新功能寄存器 + tmp_val = (port_num - (port_num_func << 3)) << 2; + if(tmp_user_gpio_data->mul_sel >= 0) + { + tmp_group_func_data &= ~( 0x07 << tmp_val); + if(set_gpio) + { + tmp_group_func_data |= (tmp_user_gpio_data->mul_sel & 0x07) << tmp_val; + } + } + //根据pull的值决定是否更新pull寄存器 + tmp_val = (port_num - (port_num_pull << 4)) << 1; + if(tmp_user_gpio_data->pull >= 0) + { + tmp_group_pull_data &= ~( 0x03 << tmp_val); + tmp_group_pull_data |= (tmp_user_gpio_data->pull & 0x03) << tmp_val; + } + //根据driver level的值决定是否更新driver level寄存器 + if(tmp_user_gpio_data->drv_level >= 0) + { + tmp_group_dlevel_data &= ~( 0x03 << tmp_val); + tmp_group_dlevel_data |= (tmp_user_gpio_data->drv_level & 0x03) << tmp_val; + } + //根据用户输入,以及功能分配决定是否更新data寄存器 + if(tmp_user_gpio_data->mul_sel == 1) + { + if(tmp_user_gpio_data->data >= 0) + { + tmp_val = tmp_user_gpio_data->data & 1; + tmp_group_data_data &= ~(1 << port_num); + tmp_group_data_data |= tmp_val << port_num; + data_change = 1; + } + } + } + //for循环结束,如果存在还没有回写的寄存器,这里写回到硬件当中 + if(tmp_group_func_addr) //只要更新过寄存器地址,就可以对硬件赋值 + { //那么把所有的值全部回写到硬件寄存器 + GPIO_REG_WRITE(tmp_group_func_addr, tmp_group_func_data); //回写功能寄存器 + GPIO_REG_WRITE(tmp_group_pull_addr, tmp_group_pull_data); //回写pull寄存器 + GPIO_REG_WRITE(tmp_group_dlevel_addr, tmp_group_dlevel_data); //回写driver level寄存器 + if(data_change) + { + GPIO_REG_WRITE(tmp_group_data_addr, tmp_group_data_data); //回写data寄存器 + } + } + + return 0; +} + + + + diff --git a/plat/sun50iw1p1/drivers/uart/uart.c b/plat/sun50iw1p1/drivers/uart/uart.c new file mode 100644 index 0000000..710957c --- /dev/null +++ b/plat/sun50iw1p1/drivers/uart/uart.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <stdint.h> +#include <mmio.h> +#include <uart.h> +#include <gpio.h> +#include <ccmu.h> +#if DEBUG +#define thr rbr +#define dll rbr +#define dlh ier +#define iir fcr + +static serial_hw_t *serial_ctrl_base = NULL; +static uint32_t uart_lock = 1; +#if 0 +normal_gpio_set_t uart_ctrl[2] = +{ + { 2, 8, 4, 1, 1, 0, {0}},//PB8: 4--RX + { 2, 9, 4, 1, 1, 0, {0}},//PB9: 4--TX +}; +#endif + +void sunxi_serial_init(int uart_port, void *gpio_cfg, int gpio_max) +{ + uint32_t reg, i; + uint32_t uart_clk; + + if( (uart_port < 0) ||(uart_port > 0) ) + { + return ; + } + //reset + reg = mmio_read_32(CCMU_BUS_SOFT_RST_REG4); + reg &= ~(1<<(CCM_UART_PORT_OFFSET + uart_port)); + mmio_write_32(CCMU_BUS_SOFT_RST_REG4,reg); + for( i = 0; i < 100; i++ ); + reg |= (1<<(CCM_UART_PORT_OFFSET + uart_port)); + mmio_write_32(CCMU_BUS_SOFT_RST_REG4,reg); + //gate + reg = mmio_read_32(CCMU_BUS_CLK_GATING_REG3); + reg &= ~(1<<(CCM_UART_PORT_OFFSET + uart_port)); + mmio_write_32(CCMU_BUS_CLK_GATING_REG3,reg); + for( i = 0; i < 100; i++ ); + reg |= (1<<(CCM_UART_PORT_OFFSET + uart_port)); + mmio_write_32(CCMU_BUS_CLK_GATING_REG3,reg); + + //gpio + //boot_set_gpio(gpio_cfg, gpio_max, 1); //boot set,so not need to set again + //uart init + serial_ctrl_base = (serial_hw_t *)(SUNXI_UART0_BASE + uart_port * CCM_UART_ADDR_OFFSET); + serial_ctrl_base->mcr = 0x3; + uart_clk = (24000000 + 8 * UART_BAUD)/(16 * UART_BAUD); + serial_ctrl_base->lcr |= 0x80; + serial_ctrl_base->dlh = uart_clk>>8; + serial_ctrl_base->dll = uart_clk&0xff; + serial_ctrl_base->lcr &= ~0x80; + serial_ctrl_base->lcr = ((PARITY&0x03)<<3) | ((STOP&0x01)<<2) | (DLEN&0x03); + serial_ctrl_base->fcr = 0x7; + + uart_lock = 0; + + return; +} + + +void sunxi_serial_exit(void) +{ + uart_lock = 1; +} + +void sunxi_serial_putc (char c) +{ + if (uart_lock) + return; + + while((serial_ctrl_base->lsr & ( 1 << 6 )) == 0); + serial_ctrl_base->thr = c; +} + + +char sunxi_serial_getc (void) +{ + if (uart_lock) + return 0; + + while((serial_ctrl_base->lsr & 1) == 0); + return serial_ctrl_base->rbr; + +} + +int sunxi_serial_tstc (void) +{ + return serial_ctrl_base->lsr & 1; +} +#endif /* DEBUG */ + +int console_init(unsigned long base_addr, + unsigned int uart_clk, unsigned int baud_rate) +{ + sunxi_serial_init(0,NULL,0); + return 0; +} + +int console_exit() +{ + sunxi_serial_exit(); + return 0; +} + +int console_putc(int c) +{ + sunxi_serial_putc(c); + return 0; +} + +int console_getc(void) +{ + return sunxi_serial_getc(); +} + diff --git a/plat/sun50iw1p1/gic_sunxi.h b/plat/sun50iw1p1/gic_sunxi.h new file mode 100644 index 0000000..f52bde4 --- /dev/null +++ b/plat/sun50iw1p1/gic_sunxi.h @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#ifndef __GIC_SUNXI_H_ +#define __GIC_SUNXI_H_ + + +#include "sunxi_def.h" +/*irq num*/ +#define GIC_SRC_SPI(_n) (32 + (_n)) +#define AW_IRQ_UART0 GIC_SRC_SPI(0) /* 32 */ +#define AW_IRQ_UART1 GIC_SRC_SPI(1) /* 33 */ +#define AW_IRQ_UART2 GIC_SRC_SPI(2) /* 34 */ +#define AW_IRQ_UART3 GIC_SRC_SPI(3) /* 35 */ +#define AW_IRQ_UART4 GIC_SRC_SPI(4) /* 36 */ + +#define AW_IRQ_TWI0 GIC_SRC_SPI(6) /* 38 */ +#define AW_IRQ_TWI1 GIC_SRC_SPI(7) /* 39 */ +#define AW_IRQ_TWI2 GIC_SRC_SPI(8) /* 40 */ + +#define AW_IRQ_PBEINT GIC_SRC_SPI(11) /* 43 */ +#define AW_IRQ_OWA GIC_SRC_SPI(12) /* 44*/ +#define AW_IRQ_DAUDIO0 GIC_SRC_SPI(13) /* 45 */ +#define AW_IRQ_DAUDIO1 GIC_SRC_SPI(14) /* 46 */ +#define AW_IRQ_DAUDIO2 GIC_SRC_SPI(15) /* 47 */ + +#define AW_IRQ_PG_EINT GIC_SRC_SPI(17) /* 49 */ +#define AW_IRQ_TIMER0 GIC_SRC_SPI(18) /* 50 */ +#define AW_IRQ_TIMER1 GIC_SRC_SPI(19) /* 51 */ +#define AW_IRQ_PH_EINT GIC_SRC_SPI(21) /* 53 */ + +#define AW_IRQ_WATCHDOG GIC_SRC_SPI(25) /* 57*/ +#define AW_IRQ_NMI GIC_SRC_SPI(32) /* 64*/ + + +#define AW_IRQ_DMA GIC_SRC_SPI(50) /* 82 */ +#define AW_IRQ_HSTIMER GIC_SRC_SPI(51) /* 83 */ +#define AW_IRQ_SMC GIC_SRC_SPI(56) /* 88 */ +#define AW_IRQ_MMC0 GIC_SRC_SPI(60) /* 92 */ +#define AW_IRQ_MMC1 GIC_SRC_SPI(61) /* 93 */ +#define AW_IRQ_MMC2 GIC_SRC_SPI(62) /* 94 */ +#define AW_IRQ_SPI0 GIC_SRC_SPI(65) /* 97 */ +#define AW_IRQ_SPI1 GIC_SRC_SPI(66) /* 98 */ +#define AW_IRQ_NAND GIC_SRC_SPI(70) /* 102 */ +#define AW_IRQ_USB_OTG GIC_SRC_SPI(71) /* 103 */ +#define AW_IRQ_USB_EHCI0 GIC_SRC_SPI(72) /* 104*/ +#define AW_IRQ_USB_OHCI0 GIC_SRC_SPI(73) /* 105 */ +#define AW_IRQ_USB_EHCI1 GIC_SRC_SPI(74) /* 106 */ +#define AW_IRQ_USB_OHCI1 GIC_SRC_SPI(75) /* 107 */ + +#define AW_IRQ_CE0 GIC_SRC_SPI(80) /* 112 */ +#define AW_IRQ_TS GIC_SRC_SPI(81) /* 113 */ +#define AW_IRQ_EMC GIC_SRC_SPI(82) /* 114 */ +#define AW_IRQ_SCR GIC_SRC_SPI(83) /* 115 */ +#define AW_IRQ_CSI GIC_SRC_SPI(84) /* 116 */ +#define AW_IRQ_CSI_CCI GIC_SRC_SPI(85) /* 117 */ +#define AW_IRQ_TCON0 GIC_SRC_SPI(86) /* 118 */ +#define AW_IRQ_TCON1 GIC_SRC_SPI(87) /* 119 */ +#define AW_IRQ_HDMI GIC_SRC_SPI(88) /* 120 */ +#define AW_IRQ_MIPI_DSI GIC_SRC_SPI(89) /* 121 */ + +#define AW_IRQ_DIT GIC_SRC_SPI(93) /* 125 */ +#define AW_IRQ_CE1 GIC_SRC_SPI(94) /* 126 */ +#define AW_IRQ_DE GIC_SRC_SPI(95) /* 127 */ +#define AW_IRQ_ROT GIC_SRC_SPI(96) /* 128 */ +#define AW_IRQ_GPU_GP GIC_SRC_SPI(97) /* 129 */ +#define AW_IRQ_GPU_GPMMU GIC_SRC_SPI(98) /* 130 */ +#define AW_IRQ_GPU_PP0 GIC_SRC_SPI(99) /* 131 */ +#define AW_IRQ_GPU_PP0MMU GIC_SRC_SPI(100) /* 132 */ +#define AW_IRQ_GPU_PMU GIC_SRC_SPI(101) /* 133 */ +#define AW_IRQ_GPU_PP1 GIC_SRC_SPI(102) /* 134 */ +#define AW_IRQ_GPU_PPMMU1 GIC_SRC_SPI(103) /* 135 */ + +#define AW_IRQ_CTI0 GIC_SRC_SPI(108) /* 140 */ +#define AW_IRQ_CTI1 GIC_SRC_SPI(109) /* 141 */ +#define AW_IRQ_CTI2 GIC_SRC_SPI(110) /* 142 */ +#define AW_IRQ_CTI3 GIC_SRC_SPI(111) /* 143 */ +#define AW_IRQ_COMMTX0 GIC_SRC_SPI(112) /* 144 */ +#define AW_IRQ_COMMTX1 GIC_SRC_SPI(113) /* 145 */ +#define AW_IRQ_COMMTX2 GIC_SRC_SPI(114) /* 146 */ +#define AW_IRQ_COMMTX3 GIC_SRC_SPI(115) /* 147 */ +#define AW_IRQ_COMMRX0 GIC_SRC_SPI(116) /* 148 */ +#define AW_IRQ_COMMRX1 GIC_SRC_SPI(117) /* 149 */ +#define AW_IRQ_COMMRX2 GIC_SRC_SPI(118) /* 150 */ +#define AW_IRQ_COMMRX3 GIC_SRC_SPI(119) /* 151 */ +#define AW_IRQ_PMU0 GIC_SRC_SPI(120) /* 152 */ +#define AW_IRQ_PMU1 GIC_SRC_SPI(121) /* 153 */ +#define AW_IRQ_PMU2 GIC_SRC_SPI(122) /* 154 */ +#define AW_IRQ_PMU3 GIC_SRC_SPI(123) /* 155 */ +#define AW_IRQ_AXI_ERROR GIC_SRC_SPI(124) /*156*/ +#define GIC_IRQ_NUM (AW_IRQ_AXI_ERROR + 1) +/*irq num end*/ + + + +/* GIC registers */ +#define GIC_DIST_CON (ARMA9_GIC_BASE + 0x0000) +#define GIC_CON_TYPE (ARMA9_GIC_BASE + 0x0004) +#define GIC_CON_IIDR (ARMA9_GIC_BASE + 0x0008) + +#define GIC_CON_IGRP(n) (ARMA9_GIC_BASE + 0x0080 + (n)*4) + +#define GIC_SET_EN(_n) (ARMA9_GIC_BASE + 0x100 + 4 * (_n)) +#define GIC_SET_EN0 GIC_SET_EN(0) // 0x100 +#define GIC_SET_EN1 GIC_SET_EN(1) // 0x104 +#define GIC_SET_EN2 GIC_SET_EN(2) // 0x108 +#define GIC_SET_EN3 GIC_SET_EN(3) // 0x10c +#define GIC_SET_EN4 GIC_SET_EN(4) // 0x110 + +#define GIC_CLR_EN(_n) (ARMA9_GIC_BASE + 0x180 + 4 * (_n)) +#define GIC_CLR_EN0 GIC_CLR_EN(0) // 0x180 +#define GIC_CLR_EN1 GIC_CLR_EN(1) // 0x184 +#define GIC_CLR_EN2 GIC_CLR_EN(2) // 0x188 +#define GIC_CLR_EN3 GIC_CLR_EN(3) // 0x18c +#define GIC_CLR_EN4 GIC_CLR_EN(4) // 0x190 + +#define GIC_PEND_SET(_n) (ARMA9_GIC_BASE + 0x200 + 4 * (_n)) +#define GIC_PEND_SET0 GIC_PEND_SET(0) // 0x200 +#define GIC_PEND_SET1 GIC_PEND_SET(1) // 0x204 +#define GIC_PEND_SET2 GIC_PEND_SET(2) // 0x208 +#define GIC_PEND_SET3 GIC_PEND_SET(3) // 0x20c +#define GIC_PEND_SET4 GIC_PEND_SET(4) // 0x210 + +#define GIC_PEND_CLR(_n) (ARMA9_GIC_BASE + 0x280 + 4 * (_n)) +#define GIC_PEND_CLR0 GIC_PEND_CLR(0) // 0x280 +#define GIC_PEND_CLR1 GIC_PEND_CLR(1) // 0x284 +#define GIC_PEND_CLR2 GIC_PEND_CLR(2) // 0x288 +#define GIC_PEND_CLR3 GIC_PEND_CLR(3) // 0x28c +#define GIC_PEND_CLR4 GIC_PEND_CLR(4) // 0x290 + +#define GIC_ACT_SET(_n) (ARMA9_GIC_BASE + 0x300 + 4 * (_n)) +#define GIC_ACT_SET0 GIC_ACT_SET(0) // 0x300 +#define GIC_ACT_SET1 GIC_ACT_SET(1) // 0x304 +#define GIC_ACT_SET2 GIC_ACT_SET(2) // 0x308 +#define GIC_ACT_SET3 GIC_ACT_SET(3) // 0x30c +#define GIC_ACT_SET4 GIC_ACT_SET(4) // 0x310 + +#define GIC_ACT_CLR(_n) (ARMA9_GIC_BASE + 0x380 + 4 * (_n)) +#define GIC_ACT_CLR0 GIC_ACT_CLR(0) // 0x380 +#define GIC_ACT_CLR1 GIC_ACT_CLR(1) // 0x384 +#define GIC_ACT_CLR2 GIC_ACT_CLR(2) // 0x388 +#define GIC_ACT_CLR3 GIC_ACT_CLR(3) // 0x38c +#define GIC_ACT_CLR4 GIC_ACT_CLR(4) // 0x390 + +#define GIC_SGI_PRIO(_n) (ARMA9_GIC_BASE + 0x400 + 4 * (_n)) +#define GIC_SGI_PRIO0 GIC_SGI_PRIO(0) // 0x400 +#define GIC_SGI_PRIO1 GIC_SGI_PRIO(1) // 0x404 +#define GIC_SGI_PRIO2 GIC_SGI_PRIO(2) // 0x408 +#define GIC_SGI_PRIO3 GIC_SGI_PRIO(3) // 0x40C + +#define GIC_PPI_PRIO(_n) (ARMA9_GIC_BASE + 0x410 + 4 * (_n)) +#define GIC_PPI_PRIO0 GIC_PPI_PRIO(0) // 0x410 +#define GIC_PPI_PRIO1 GIC_PPI_PRIO(1) // 0x414 +#define GIC_PPI_PRIO2 GIC_PPI_PRIO(2) // 0x418 +#define GIC_PPI_PRIO3 GIC_PPI_PRIO(3) // 0x41C + +#define GIC_SPI_PRIO(_n) (ARMA9_GIC_BASE + 0x420 + 4 * (_n)) +#define GIC_SPI_PRIO0 GIC_SPI_PRIO(0 ) // 0x420 +#define GIC_SPI_PRIO1 GIC_SPI_PRIO(1 ) // 0x424 +#define GIC_SPI_PRIO2 GIC_SPI_PRIO(2 ) // 0x428 +#define GIC_SPI_PRIO3 GIC_SPI_PRIO(3 ) // 0x42C +#define GIC_SPI_PRIO4 GIC_SPI_PRIO(4 ) // 0x430 +#define GIC_SPI_PRIO5 GIC_SPI_PRIO(5 ) // 0x434 +#define GIC_SPI_PRIO6 GIC_SPI_PRIO(6 ) // 0x438 +#define GIC_SPI_PRIO7 GIC_SPI_PRIO(7 ) // 0x43C +#define GIC_SPI_PRIO8 GIC_SPI_PRIO(8 ) // 0x440 +#define GIC_SPI_PRIO9 GIC_SPI_PRIO(9 ) // 0x444 +#define GIC_SPI_PRIO10 GIC_SPI_PRIO(10) // 0x448 +#define GIC_SPI_PRIO11 GIC_SPI_PRIO(11) // 0x44C +#define GIC_SPI_PRIO12 GIC_SPI_PRIO(12) // 0x450 +#define GIC_SPI_PRIO13 GIC_SPI_PRIO(13) // 0x454 +#define GIC_SPI_PRIO14 GIC_SPI_PRIO(14) // 0x458 +#define GIC_SPI_PRIO15 GIC_SPI_PRIO(15) // 0x45C +#define GIC_SPI_PRIO16 GIC_SPI_PRIO(16) // 0x460 +#define GIC_SPI_PRIO17 GIC_SPI_PRIO(17) // 0x464 +#define GIC_SPI_PRIO18 GIC_SPI_PRIO(18) // 0x468 +#define GIC_SPI_PRIO19 GIC_SPI_PRIO(19) // 0x46C +#define GIC_SPI_PRIO20 GIC_SPI_PRIO(20) // 0x470 +#define GIC_SPI_PRIO21 GIC_SPI_PRIO(21) // 0x474 +#define GIC_SPI_PRIO22 GIC_SPI_PRIO(22) // 0x478 +#define GIC_SPI_PRIO23 GIC_SPI_PRIO(23) // 0x47C +#define GIC_SPI_PRIO24 GIC_SPI_PRIO(24) // 0x480 +#define GIC_SPI_PRIO25 GIC_SPI_PRIO(25) // 0x484 +#define GIC_SPI_PRIO26 GIC_SPI_PRIO(26) // 0x488 +#define GIC_SPI_PRIO27 GIC_SPI_PRIO(27) // 0x48C +#define GIC_SPI_PRIO28 GIC_SPI_PRIO(28) // 0x490 +#define GIC_SPI_PRIO29 GIC_SPI_PRIO(29) // 0x494 +#define GIC_SPI_PRIO30 GIC_SPI_PRIO(30) // 0x498 +#define GIC_SPI_PRIO31 GIC_SPI_PRIO(31) // 0x49C + +#define GIC_SGI_PROC_TARG(_n) (ARMA9_GIC_BASE + 0x800 + 4 * (_n)) +#define GIC_SGI_PROC_TARG0 GIC_SGI_PROC_TARG(0) // 0x800 +#define GIC_SGI_PROC_TARG1 GIC_SGI_PROC_TARG(1) // 0x804 +#define GIC_SGI_PROC_TARG2 GIC_SGI_PROC_TARG(2) // 0x808 +#define GIC_SGI_PROC_TARG3 GIC_SGI_PROC_TARG(3) // 0x80C + +#define GIC_PPI_PROC_TARG(_n) (ARMA9_GIC_BASE + 0x810 + 4 * (_n)) +#define GIC_PPI_PROC_TARG0 GIC_PPI_PROC_TARG(0) // 0x810 +#define GIC_PPI_PROC_TARG1 GIC_PPI_PROC_TARG(1) // 0x814 +#define GIC_PPI_PROC_TARG2 GIC_PPI_PROC_TARG(2) // 0x818 +#define GIC_PPI_PROC_TARG3 GIC_PPI_PROC_TARG(3) // 0x81C + +#define GIC_SPI_PROC_TARG(_n) (ARMA9_GIC_BASE + 0x820 + 4 * (_n)) +#define GIC_SPI_PROC_TARG0 GIC_SPI_PROC_TARG(0 ) // 0x820 +#define GIC_SPI_PROC_TARG1 GIC_SPI_PROC_TARG(1 ) // 0x824 +#define GIC_SPI_PROC_TARG2 GIC_SPI_PROC_TARG(2 ) // 0x828 +#define GIC_SPI_PROC_TARG3 GIC_SPI_PROC_TARG(3 ) // 0x82C +#define GIC_SPI_PROC_TARG4 GIC_SPI_PROC_TARG(4 ) // 0x830 +#define GIC_SPI_PROC_TARG5 GIC_SPI_PROC_TARG(5 ) // 0x834 +#define GIC_SPI_PROC_TARG6 GIC_SPI_PROC_TARG(6 ) // 0x838 +#define GIC_SPI_PROC_TARG7 GIC_SPI_PROC_TARG(7 ) // 0x83C +#define GIC_SPI_PROC_TARG8 GIC_SPI_PROC_TARG(8 ) // 0x840 +#define GIC_SPI_PROC_TARG9 GIC_SPI_PROC_TARG(9 ) // 0x844 +#define GIC_SPI_PROC_TARG10 GIC_SPI_PROC_TARG(10) // 0x848 +#define GIC_SPI_PROC_TARG11 GIC_SPI_PROC_TARG(11) // 0x84C +#define GIC_SPI_PROC_TARG12 GIC_SPI_PROC_TARG(12) // 0x850 +#define GIC_SPI_PROC_TARG13 GIC_SPI_PROC_TARG(13) // 0x854 +#define GIC_SPI_PROC_TARG14 GIC_SPI_PROC_TARG(14) // 0x858 +#define GIC_SPI_PROC_TARG15 GIC_SPI_PROC_TARG(15) // 0x85C +#define GIC_SPI_PROC_TARG16 GIC_SPI_PROC_TARG(16) // 0x860 +#define GIC_SPI_PROC_TARG17 GIC_SPI_PROC_TARG(17) // 0x864 +#define GIC_SPI_PROC_TARG18 GIC_SPI_PROC_TARG(18) // 0x868 +#define GIC_SPI_PROC_TARG19 GIC_SPI_PROC_TARG(19) // 0x86C +#define GIC_SPI_PROC_TARG20 GIC_SPI_PROC_TARG(20) // 0x870 +#define GIC_SPI_PROC_TARG21 GIC_SPI_PROC_TARG(21) // 0x874 +#define GIC_SPI_PROC_TARG22 GIC_SPI_PROC_TARG(22) // 0x878 +#define GIC_SPI_PROC_TARG23 GIC_SPI_PROC_TARG(23) // 0x87C +#define GIC_SPI_PROC_TARG24 GIC_SPI_PROC_TARG(24) // 0x880 +#define GIC_SPI_PROC_TARG25 GIC_SPI_PROC_TARG(25) // 0x884 +#define GIC_SPI_PROC_TARG26 GIC_SPI_PROC_TARG(26) // 0x888 +#define GIC_SPI_PROC_TARG27 GIC_SPI_PROC_TARG(27) // 0x88C +#define GIC_SPI_PROC_TARG28 GIC_SPI_PROC_TARG(28) // 0x890 +#define GIC_SPI_PROC_TARG29 GIC_SPI_PROC_TARG(29) // 0x894 +#define GIC_SPI_PROC_TARG30 GIC_SPI_PROC_TARG(30) // 0x898 +#define GIC_SPI_PROC_TARG31 GIC_SPI_PROC_TARG(31) // 0x89C + +#define GIC_IRQ_MOD_CFG(_n) (ARMA9_GIC_BASE + 0xc00 + 4 * (_n)) +#define GIC_IRQ_MOD_CFG0 GIC_IRQ_MOD_CFG(0) // 0xc00 - SGI +#define GIC_IRQ_MOD_CFG1 GIC_IRQ_MOD_CFG(1) // 0xc04 - PPI +#define GIC_IRQ_MOD_CFG2 GIC_IRQ_MOD_CFG(2) // 0xc08 - SPI0 ~ 15 +#define GIC_IRQ_MOD_CFG3 GIC_IRQ_MOD_CFG(3) // 0xc0C - SPI16 ~ 31 +#define GIC_IRQ_MOD_CFG4 GIC_IRQ_MOD_CFG(4) // 0xc10 - SPI32 ~ 47 +#define GIC_IRQ_MOD_CFG5 GIC_IRQ_MOD_CFG(5) // 0xc14 - SPI48 ~ 63 +#define GIC_IRQ_MOD_CFG6 GIC_IRQ_MOD_CFG(6) // 0xc18 - SPI64 ~ 79 +#define GIC_IRQ_MOD_CFG7 GIC_IRQ_MOD_CFG(7) // 0xc1C - SPI80 ~ 95 +#define GIC_IRQ_MOD_CFG8 GIC_IRQ_MOD_CFG(8) // 0xc20 - SPI96 ~ 111 +#define GIC_IRQ_MOD_CFG9 GIC_IRQ_MOD_CFG(9) // 0xc24 - SPI112 ~ 127 + +#define GIC_SOFT_IRQ_GEN (ARMA9_GIC_BASE + 0xf00) // 0xf00 +#define GIC_SGI_PEND_SET(_n) (ARMA9_GIC_BASE + 0xf10 + 4 * (_n)) +#define GIC_SGI_PEND_SET0 GIC_SGI_PEND_SET(0) // 0xf10 +#define GIC_SGI_PEND_SET1 GIC_SGI_PEND_SET(1) // 0xf14 +#define GIC_SGI_PEND_SET2 GIC_SGI_PEND_SET(2) // 0xf18 +#define GIC_SGI_PEND_SET3 GIC_SGI_PEND_SET(3) // 0xf1C +#define GIC_SGI_PEND_CLR(_n) (ARMA9_GIC_BASE + 0xf10 + 4 * (_n)) +#define GIC_SGI_PEND_CLR0 GIC_SGI_PEND_CLR(0) // 0xf20 +#define GIC_SGI_PEND_CLR1 GIC_SGI_PEND_CLR(1) // 0xf24 +#define GIC_SGI_PEND_CLR2 GIC_SGI_PEND_CLR(2) // 0xf28 +#define GIC_SGI_PEND_CLR3 GIC_SGI_PEND_CLR(3) // 0xf2C + + +#define GIC_CPU_IF_CTRL (ARMA9_CPUIF_BASE + 0x000) // 0x8000 +#define GIC_INT_PRIO_MASK (ARMA9_CPUIF_BASE + 0x004) // 0x8004 +#define GIC_BINARY_POINT (ARMA9_CPUIF_BASE + 0x008) // 0x8008 +#define GIC_INT_ACK_REG (ARMA9_CPUIF_BASE + 0x00c) // 0x800c +#define GIC_END_INT_REG (ARMA9_CPUIF_BASE + 0x010) // 0x8010 +#define GIC_RUNNING_PRIO (ARMA9_CPUIF_BASE + 0x014) // 0x8014 +#define GIC_HIGHEST_PENDINT (ARMA9_CPUIF_BASE + 0x018) // 0x8018 +#define GIC_DEACT_INT_REG (ARMA9_CPUIF_BASE + 0x1000)// 0x1000 +#define GIC_AIAR_REG (ARMA9_CPUIF_BASE + 0x020) // 0x8020 +#define GIC_AEOI_REG (ARMA9_CPUIF_BASE + 0x024) // 0x8024 +#define GIC_AHIGHEST_PENDINT (ARMA9_CPUIF_BASE + 0x028) // 0x8028 + + +/* gic source list */ +/* software generated interrupt */ +#define GIC_SRC_SGI(_n) (_n) +#define GIC_SRC_SGI0 GIC_SRC_SGI(0 ) // (0 ) +#define GIC_SRC_SGI1 GIC_SRC_SGI(1 ) // (1 ) +#define GIC_SRC_SGI2 GIC_SRC_SGI(2 ) // (2 ) +#define GIC_SRC_SGI3 GIC_SRC_SGI(3 ) // (3 ) +#define GIC_SRC_SGI4 GIC_SRC_SGI(4 ) // (4 ) +#define GIC_SRC_SGI5 GIC_SRC_SGI(5 ) // (5 ) +#define GIC_SRC_SGI6 GIC_SRC_SGI(6 ) // (6 ) +#define GIC_SRC_SGI7 GIC_SRC_SGI(7 ) // (7 ) +#define GIC_SRC_SGI8 GIC_SRC_SGI(8 ) // (8 ) +#define GIC_SRC_SGI9 GIC_SRC_SGI(9 ) // (9 ) +#define GIC_SRC_SGI10 GIC_SRC_SGI(10) // (10) +#define GIC_SRC_SGI11 GIC_SRC_SGI(11) // (11) +#define GIC_SRC_SGI12 GIC_SRC_SGI(12) // (12) +#define GIC_SRC_SGI13 GIC_SRC_SGI(13) // (13) +#define GIC_SRC_SGI14 GIC_SRC_SGI(14) // (14) +#define GIC_SRC_SGI15 GIC_SRC_SGI(15) // (15) +/* private peripheral interrupt */ +#define GIC_SRC_PPI(_n) (16 + (_n)) +#define GIC_SRC_PPI0 GIC_SRC_PPI(0 ) // (16) +#define GIC_SRC_PPI1 GIC_SRC_PPI(1 ) // (17) +#define GIC_SRC_PPI2 GIC_SRC_PPI(2 ) // (18) +#define GIC_SRC_PPI3 GIC_SRC_PPI(3 ) // (19) +#define GIC_SRC_PPI4 GIC_SRC_PPI(4 ) // (20) +#define GIC_SRC_PPI5 GIC_SRC_PPI(5 ) // (21) +#define GIC_SRC_PPI6 GIC_SRC_PPI(6 ) // (22) +#define GIC_SRC_PPI7 GIC_SRC_PPI(7 ) // (23) +#define GIC_SRC_PPI8 GIC_SRC_PPI(8 ) // (24) +#define GIC_SRC_PPI9 GIC_SRC_PPI(9 ) // (25) +#define GIC_SRC_PPI10 GIC_SRC_PPI(10) // (26) +#define GIC_SRC_PPI11 GIC_SRC_PPI(11) // (27) +#define GIC_SRC_PPI12 GIC_SRC_PPI(12) // (28) +#define GIC_SRC_PPI13 GIC_SRC_PPI(13) // (29) +#define GIC_SRC_PPI14 GIC_SRC_PPI(14) // (30) +#define GIC_SRC_PPI15 GIC_SRC_PPI(15) // (31) +/* external peripheral interrupt */ +#define GIC_SRC_SPI(_n) (32 + (_n)) + + +#endif + diff --git a/plat/sun50iw1p1/include/arisc.h b/plat/sun50iw1p1/include/arisc.h new file mode 100644 index 0000000..00384f5 --- /dev/null +++ b/plat/sun50iw1p1/include/arisc.h @@ -0,0 +1,789 @@ +/* + * include/linux/arisc/arisc.h + * + * Copyright 2012 (c) Allwinner. + * superm (superm@allwinnertech.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + */ + +#ifndef __ASM_ARCH_ARISC_H +#define __ASM_ARCH_ARISC_H + +/* the base of messages */ +#define ARISC_MESSAGE_BASE (0x10) + +/* standby commands */ +#define ARISC_SSTANDBY_ENTER_REQ (ARISC_MESSAGE_BASE + 0x00) /* request to enter (ac327 to arisc) */ +#define ARISC_SSTANDBY_RESTORE_NOTIFY (ARISC_MESSAGE_BASE + 0x01) /* restore finished (ac327 to arisc) */ +#define ARISC_NSTANDBY_ENTER_REQ (ARISC_MESSAGE_BASE + 0x02) /* request to enter (ac327 to arisc) */ +#define ARISC_NSTANDBY_WAKEUP_NOTIFY (ARISC_MESSAGE_BASE + 0x03) /* wakeup notify (arisc to ac327) */ +#define ARISC_NSTANDBY_RESTORE_REQ (ARISC_MESSAGE_BASE + 0x04) /* request to restore (ac327 to arisc) */ +#define ARISC_NSTANDBY_RESTORE_COMPLETE (ARISC_MESSAGE_BASE + 0x05) /* arisc restore complete (arisc to ac327) */ +#define ARISC_ESSTANDBY_ENTER_REQ (ARISC_MESSAGE_BASE + 0x06) /* request to enter (ac327 to arisc) */ +#define ARISC_TSTANDBY_ENTER_REQ (ARISC_MESSAGE_BASE + 0x07) /* request to enter (ac327 to arisc) */ +#define ARISC_TSTANDBY_RESTORE_NOTIFY (ARISC_MESSAGE_BASE + 0x08) /* restore finished (ac327 to arisc) */ +#define ARISC_FAKE_POWER_OFF_REQ (ARISC_MESSAGE_BASE + 0x09) /* request to enter (ac327 to arisc) */ +#define ARISC_CPUIDLE_ENTER_REQ (ARISC_MESSAGE_BASE + 0x0a) /* request to enter (ac327 to arisc) */ +#define ARISC_STANDBY_INFO_REQ (ARISC_MESSAGE_BASE + 0x10) /* request sst info (ac327 to arisc) */ +#define ARISC_CPUIDLE_CFG_REQ (ARISC_MESSAGE_BASE + 0x11) /* request to config (ac327 to arisc) */ +#define ARISC_CPU_OP_REQ (ARISC_MESSAGE_BASE + 0x12) /* cpu operations (ac327 to arisc) */ +#define ARISC_QUERY_WAKEUP_SRC_REQ (ARISC_MESSAGE_BASE + 0x13) /* query wakeup source (ac327 to arisc) */ +#define ARISC_SYS_OP_REQ (ARISC_MESSAGE_BASE + 0x14) /* system operations (ac327 to arisc) */ + +/* dvfs commands */ +#define ARISC_CPUX_DVFS_REQ (ARISC_MESSAGE_BASE + 0x20) /* request dvfs (ac327 to arisc) */ +#define ARISC_CPUX_DVFS_CFG_VF_REQ (ARISC_MESSAGE_BASE + 0x21) /* request config dvfs v-f table(ac327 to arisc) */ + +/* pmu commands */ +#define ARISC_AXP_INT_COMING_NOTIFY (ARISC_MESSAGE_BASE + 0x40) /* interrupt coming notify(arisc to ac327) */ +#define ARISC_AXP_DISABLE_IRQ (ARISC_MESSAGE_BASE + 0x41) /* disable axp irq of arisc */ +#define ARISC_AXP_ENABLE_IRQ (ARISC_MESSAGE_BASE + 0x42) /* enable axp irq of arisc */ +#define ARISC_AXP_GET_CHIP_ID (ARISC_MESSAGE_BASE + 0x43) /* axp get chip id */ +#define ARISC_AXP_SET_PARAS (ARISC_MESSAGE_BASE + 0x44) /* config axp parameters (ac327 to arisc) */ +#define ARISC_SET_PMU_VOLT (ARISC_MESSAGE_BASE + 0x45) /* set pmu volt (ac327 to arisc) */ +#define ARISC_GET_PMU_VOLT (ARISC_MESSAGE_BASE + 0x46) /* get pmu volt (ac327 to arisc) */ +#define ARISC_SET_LED_BLN (ARISC_MESSAGE_BASE + 0x47) /* set led bln (ac327 to arisc) */ +#define ARISC_AXP_REBOOT (ARISC_MESSAGE_BASE + 0x48) /* reboot system for no pmu protocols */ +#define ARISC_SET_PWR_TREE (ARISC_MESSAGE_BASE + 0x49) /* set power tree (ac327 to arisc) */ +#define ARISC_CLR_NMI_STATUS (ARISC_MESSAGE_BASE + 0x4a) /* clear nmi status (ac327 to arisc) */ +#define ARISC_SET_NMI_TRIGGER (ARISC_MESSAGE_BASE + 0x4b) /* set nmi tigger (ac327 to arisc) */ + +/* set arisc debug commands */ +#define ARISC_SET_DEBUG_LEVEL (ARISC_MESSAGE_BASE + 0x50) /* set arisc debug level (ac327 to arisc) */ +#define ARISC_MESSAGE_LOOPBACK (ARISC_MESSAGE_BASE + 0x51) /* loopback message (ac327 to arisc) */ +#define ARISC_SET_UART_BAUDRATE (ARISC_MESSAGE_BASE + 0x52) /* set uart baudrate (ac327 to arisc) */ +#define ARISC_SET_DRAM_PARAS (ARISC_MESSAGE_BASE + 0x53) /* config dram parameter (ac327 to arisc) */ +#define ARISC_SET_DEBUG_DRAM_CRC_PARAS (ARISC_MESSAGE_BASE + 0x54) /* config dram crc parameters (ac327 to arisc) */ +#define ARISC_SET_IR_PARAS (ARISC_MESSAGE_BASE + 0x55) /* config ir parameter (ac327 to arisc) */ +#define ARISC_REPORT_ERR_INFO (ARISC_MESSAGE_BASE + 0x56) /* report arisc error info (arisc to ac327) */ +#define ARISC_SET_PARAS (ARISC_MESSAGE_BASE + 0x57) /* set paras (arisc to ac327) */ + +/* audio commands */ +#define ARISC_AUDIO_START (ARISC_MESSAGE_BASE + 0x60) /* audio start play/capture(ac327 to arisc) */ +#define ARISC_AUDIO_STOP (ARISC_MESSAGE_BASE + 0x61) /* audio stop play/capture(ac327 to arisc) */ +#define ARISC_AUDIO_SET_BUF_PER_PARAS (ARISC_MESSAGE_BASE + 0x62) /* set audio buffer and peroid paras(ac327 to arisc) */ +#define ARISC_AUDIO_GET_POSITION (ARISC_MESSAGE_BASE + 0x63) /* get audio buffer position(ac327 to arisc) */ +#define ARISC_AUDIO_SET_TDM_PARAS (ARISC_MESSAGE_BASE + 0x64) /* set audio tdm parameters(ac327 to arisc) */ +#define ARISC_AUDIO_PERDONE_NOTIFY (ARISC_MESSAGE_BASE + 0x65) /* audio period done notify(arisc to ac327) */ +#define ARISC_AUDIO_ADD_PERIOD (ARISC_MESSAGE_BASE + 0x66) /* audio period done notify(arisc to ac327) */ + +/* rsb commands */ +#define ARISC_RSB_READ_BLOCK_DATA (ARISC_MESSAGE_BASE + 0x70) /* rsb read block data (ac327 to arisc) */ +#define ARISC_RSB_WRITE_BLOCK_DATA (ARISC_MESSAGE_BASE + 0x71) /* rsb write block data (ac327 to arisc) */ +#define ARISC_RSB_BITS_OPS_SYNC (ARISC_MESSAGE_BASE + 0x72) /* rsb clear bits sync (ac327 to arisc) */ +#define ARISC_RSB_SET_INTERFACE_MODE (ARISC_MESSAGE_BASE + 0x73) /* rsb set interface mode (ac327 to arisc) */ +#define ARISC_RSB_SET_RTSADDR (ARISC_MESSAGE_BASE + 0x74) /* rsb set runtime slave addr (ac327 to arisc) */ + +/* arisc initialize state notify commands */ +#define ARISC_STARTUP_NOTIFY (ARISC_MESSAGE_BASE + 0x80) /* arisc init state notify(arisc to ac327) */ + + +/* the base of ARM SVC ARISC */ +#define ARM_SVC_ARISC_BASE (0xc0000000) + +/* standby commands */ +#define ARM_SVC_ARISC_SSTANDBY_ENTER_REQ (ARM_SVC_ARISC_BASE + ARISC_SSTANDBY_ENTER_REQ) /* request to enter (ac327 to arisc) */ +#define ARM_SVC_ARISC_SSTANDBY_RESTORE_NOTIFY (ARM_SVC_ARISC_BASE + ARISC_SSTANDBY_RESTORE_NOTIFY) /* restore finished (ac327 to arisc) */ +#define ARM_SVC_ARISC_NSTANDBY_ENTER_REQ (ARM_SVC_ARISC_BASE + ARISC_NSTANDBY_ENTER_REQ) /* request to enter (ac327 to arisc) */ +#define ARM_SVC_ARISC_NSTANDBY_WAKEUP_NOTIFY (ARM_SVC_ARISC_BASE + ARISC_NSTANDBY_WAKEUP_NOTIFY) /* wakeup notify (arisc to ac327) */ +#define ARM_SVC_ARISC_NSTANDBY_RESTORE_REQ (ARM_SVC_ARISC_BASE + ARISC_NSTANDBY_RESTORE_REQ) /* request to restore (ac327 to arisc) */ +#define ARM_SVC_ARISC_NSTANDBY_RESTORE_COMPLETE (ARM_SVC_ARISC_BASE + ARISC_NSTANDBY_RESTORE_COMPLETE) /* arisc restore complete (arisc to ac327) */ +#define ARM_SVC_ARISC_ESSTANDBY_ENTER_REQ (ARM_SVC_ARISC_BASE + ARISC_ESSTANDBY_ENTER_REQ) /* request to enter (ac327 to arisc) */ +#define ARM_SVC_ARISC_TSTANDBY_ENTER_REQ (ARM_SVC_ARISC_BASE + ARISC_TSTANDBY_ENTER_REQ) /* request to enter (ac327 to arisc) */ +#define ARM_SVC_ARISC_TSTANDBY_RESTORE_NOTIFY (ARM_SVC_ARISC_BASE + ARISC_TSTANDBY_RESTORE_NOTIFY) /* restore finished (ac327 to arisc) */ +#define ARM_SVC_ARISC_FAKE_POWER_OFF_REQ (ARM_SVC_ARISC_BASE + ARISC_FAKE_POWER_OFF_REQ) /* request to enter (ac327 to arisc) */ +#define ARM_SVC_ARISC_CPUIDLE_ENTER_REQ (ARM_SVC_ARISC_BASE + ARISC_CPUIDLE_ENTER_REQ) /* request to enter (ac327 to arisc) */ +#define ARM_SVC_ARISC_STANDBY_INFO_REQ (ARM_SVC_ARISC_BASE + ARISC_STANDBY_INFO_REQ) /* request sst info (ac327 to arisc) */ +#define ARM_SVC_ARISC_CPUIDLE_CFG_REQ (ARM_SVC_ARISC_BASE + ARISC_CPUIDLE_CFG_REQ) /* request to config (ac327 to arisc) */ +#define ARM_SVC_ARISC_CPU_OP_REQ (ARM_SVC_ARISC_BASE + ARISC_CPU_OP_REQ) /* cpu operations (ac327 to arisc) */ +#define ARM_SVC_ARISC_QUERY_WAKEUP_SRC_REQ (ARM_SVC_ARISC_BASE + ARISC_QUERY_WAKEUP_SRC_REQ) /* query wakeup source (ac327 to arisc) */ +#define ARM_SVC_ARISC_SYS_OP_REQ (ARM_SVC_ARISC_BASE + ARISC_SYS_OP_REQ) /* system operations (ac327 to arisc) */ + +/* dvfs commands */ +#define ARM_SVC_ARISC_CPUX_DVFS_REQ (ARM_SVC_ARISC_BASE + ARISC_CPUX_DVFS_REQ) /* request dvfs (ac327 to arisc) */ +#define ARM_SVC_ARISC_CPUX_DVFS_CFG_VF_REQ (ARM_SVC_ARISC_BASE + ARISC_CPUX_DVFS_CFG_VF_REQ) /* request config dvfs v-f table(ac327 to arisc) */ + +/* pmu commands */ +#define ARM_SVC_ARISC_AXP_INT_COMING_NOTIFY (ARM_SVC_ARISC_BASE + ARISC_AXP_INT_COMING_NOTIFY) /* interrupt coming notify(arisc to ac327) */ +#define ARM_SVC_ARISC_AXP_DISABLE_IRQ (ARM_SVC_ARISC_BASE + ARISC_AXP_DISABLE_IRQ) /* disable axp irq of arisc */ +#define ARM_SVC_ARISC_AXP_ENABLE_IRQ (ARM_SVC_ARISC_BASE + ARISC_AXP_ENABLE_IRQ) /* enable axp irq of arisc */ +#define ARM_SVC_ARISC_AXP_GET_CHIP_ID (ARM_SVC_ARISC_BASE + ARISC_AXP_GET_CHIP_ID) /* axp get chip id */ +#define ARM_SVC_ARISC_AXP_SET_PARAS (ARM_SVC_ARISC_BASE + ARISC_AXP_SET_PARAS) /* config axp parameters (ac327 to arisc) */ +#define ARM_SVC_ARISC_SET_PMU_VOLT (ARM_SVC_ARISC_BASE + ARISC_SET_PMU_VOLT) /* set pmu volt (ac327 to arisc) */ +#define ARM_SVC_ARISC_GET_PMU_VOLT (ARM_SVC_ARISC_BASE + ARISC_GET_PMU_VOLT) /* get pmu volt (ac327 to arisc) */ +#define ARM_SVC_ARISC_SET_LED_BLN (ARM_SVC_ARISC_BASE + ARISC_SET_LED_BLN) /* set led bln (ac327 to arisc) */ +#define ARM_SVC_ARISC_AXP_REBOOT (ARM_SVC_ARISC_BASE + ARISC_AXP_REBOOT) /* reboot system for no pmu protocols */ +#define ARM_SVC_ARISC_SET_PWR_TREE (ARM_SVC_ARISC_BASE + ARISC_SET_PWR_TREE) /* set power tree (ac327 to arisc) */ +#define ARM_SVC_ARISC_CLR_NMI_STATUS (ARM_SVC_ARISC_BASE + ARISC_CLR_NMI_STATUS) /* clear nmi status (ac327 to arisc) */ +#define ARM_SVC_ARISC_SET_NMI_TRIGGER (ARM_SVC_ARISC_BASE + ARISC_SET_NMI_TRIGGER) /* set nmi tigger (ac327 to arisc) */ + +/* set arisc debug commands */ +#define ARM_SVC_ARISC_SET_DEBUG_LEVEL (ARM_SVC_ARISC_BASE + ARISC_SET_DEBUG_LEVEL) /* set arisc debug level (ac327 to arisc) */ +#define ARM_SVC_ARISC_MESSAGE_LOOPBACK (ARM_SVC_ARISC_BASE + ARISC_MESSAGE_LOOPBACK) /* loopback message (ac327 to arisc) */ +#define ARM_SVC_ARISC_SET_UART_BAUDRATE (ARM_SVC_ARISC_BASE + ARISC_SET_UART_BAUDRATE) /* set uart baudrate (ac327 to arisc) */ +#define ARM_SVC_ARISC_SET_DRAM_PARAS (ARM_SVC_ARISC_BASE + ARISC_SET_DRAM_PARAS) /* config dram parameter (ac327 to arisc) */ +#define ARM_SVC_ARISC_SET_DEBUG_DRAM_CRC_PARAS (ARM_SVC_ARISC_BASE + ARISC_SET_DEBUG_DRAM_CRC_PARAS) /* config dram crc parameters (ac327 to arisc) */ +#define ARM_SVC_ARISC_SET_IR_PARAS (ARM_SVC_ARISC_BASE + ARISC_SET_IR_PARAS) /* config ir parameter (ac327 to arisc) */ +#define ARM_SVC_ARISC_REPORT_ERR_INFO (ARM_SVC_ARISC_BASE + ARISC_REPORT_ERR_INFO) /* report arisc error info (arisc to ac327) */ +#define ARM_SVC_ARISC_SET_PARAS (ARM_SVC_ARISC_BASE + ARISC_SET_PARAS) /* set paras (arisc to ac327) */ + +/* audio commands */ +#define ARM_SVC_ARISC_AUDIO_START (ARM_SVC_ARISC_BASE + ARISC_AUDIO_START) /* audio start play/capture(ac327 to arisc) */ +#define ARM_SVC_ARISC_AUDIO_STOP (ARM_SVC_ARISC_BASE + ARISC_AUDIO_STOP) /* audio stop play/capture(ac327 to arisc) */ +#define ARM_SVC_ARISC_AUDIO_SET_BUF_PER_PARAS (ARM_SVC_ARISC_BASE + ARISC_AUDIO_SET_BUF_PER_PARAS) /* set audio buffer and peroid paras(ac327 to arisc) */ +#define ARM_SVC_ARISC_AUDIO_GET_POSITION (ARM_SVC_ARISC_BASE + ARISC_AUDIO_GET_POSITION) /* get audio buffer position(ac327 to arisc) */ +#define ARM_SVC_ARISC_AUDIO_SET_TDM_PARAS (ARM_SVC_ARISC_BASE + ARISC_AUDIO_SET_TDM_PARAS) /* set audio tdm parameters(ac327 to arisc) */ +#define ARM_SVC_ARISC_AUDIO_PERDONE_NOTIFY (ARM_SVC_ARISC_BASE + ARISC_AUDIO_PERDONE_NOTIFY) /* audio period done notify(arisc to ac327) */ +#define ARM_SVC_ARISC_AUDIO_ADD_PERIOD (ARM_SVC_ARISC_BASE + ARISC_AUDIO_ADD_PERIOD) /* audio period done notify(arisc to ac327) */ + +/* rsb commands */ +#define ARM_SVC_ARISC_RSB_READ_BLOCK_DATA (ARM_SVC_ARISC_BASE + ARISC_RSB_READ_BLOCK_DATA) /* rsb read block data (ac327 to arisc) */ +#define ARM_SVC_ARISC_RSB_WRITE_BLOCK_DATA (ARM_SVC_ARISC_BASE + ARISC_RSB_WRITE_BLOCK_DATA) /* rsb write block data (ac327 to arisc) */ +#define ARM_SVC_ARISC_RSB_BITS_OPS_SYNC (ARM_SVC_ARISC_BASE + ARISC_RSB_BITS_OPS_SYNC) /* rsb clear bits sync (ac327 to arisc) */ +#define ARM_SVC_ARISC_RSB_SET_INTERFACE_MODE (ARM_SVC_ARISC_BASE + ARISC_RSB_SET_INTERFACE_MODE) /* rsb set interface mode (ac327 to arisc) */ +#define ARM_SVC_ARISC_RSB_SET_RTSADDR (ARM_SVC_ARISC_BASE + ARISC_RSB_SET_RTSADDR) /* rsb set runtime slave addr (ac327 to arisc) */ + +/* arisc initialize state notify commands */ +#define ARM_SVC_ARISC_STARTUP_NOTIFY (ARM_SVC_ARISC_BASE + ARISC_STARTUP_NOTIFY) /* arisc init state notify(arisc to ac327) */ + +#define AW_MSG_HWSPINLOCK (0) +#define AW_AUDIO_HWSPINLOCK (1) +#define AW_RTC_REG_HWSPINLOCK (2) + +#define NMI_INT_TYPE_PMU (0) +#define NMI_INT_TYPE_RTC (1) +#define NMI_INT_TYPE_PMU_OFFSET (0x1 << NMI_INT_TYPE_PMU) +#define NMI_INT_TYPE_RTC_OFFSET (0x1 << NMI_INT_TYPE_RTC) + +/* the modes of arisc dvfs */ +#define ARISC_DVFS_SYN (1<<0) + +/* message attributes(only use 8bit) */ +#define ARISC_MESSAGE_ATTR_ASYN (0<<0) /* need asyn with another cpu */ +#define ARISC_MESSAGE_ATTR_SOFTSYN (1<<0) /* need soft syn with another cpu */ +#define ARISC_MESSAGE_ATTR_HARDSYN (1<<1) /* need hard syn with another cpu */ + +/* axp driver interfaces */ +#define AXP_TRANS_BYTE_MAX (4) +#define RSB_TRANS_BYTE_MAX (4) +#define P2WI_TRANS_BYTE_MAX (8) + +/* RSB devices' address */ +#define RSB_DEVICE_SADDR1 (0x3A3) /* (0x01d1)AXP22x(AW1669) */ +#define RSB_DEVICE_SADDR3 (0x745) /* (0x03a2)AXP15x(AW1657) */ +#define RSB_DEVICE_SADDR7 (0xE89) /* (0x0744)Audio codec, AC100 */ + +/* RSB run time address */ +#define RSB_RTSADDR_AXP809 (0x2d) +#define RSB_RTSADDR_AXP806 (0x3a) +#define RSB_RTSADDR_AC100 (0x4e) + +/* audio sram base address */ +#define AUDIO_SRAM_BASE_PALY (0x08117000) +#define AUDIO_SRAM_BASE_CAPTURE (0x0811f000) + +#define AUDIO_SRAM_BUF_SIZE_02K (2048) /* buffer size 2k = 0x800 = 2048 */ +#define AUDIO_SRAM_BUF_SIZE_04K (4096) /* buffer size 4k = 0x1000 = 4096 */ +#define AUDIO_SRAM_BUF_SIZE_08K (8192) /* buffer size 8k = 0x2000 = 8192 */ +#define AUDIO_SRAM_BUF_SIZE_16K (16384) /* buffer size 16k = 0x4000 = 16384 */ +#define AUDIO_SRAM_BUF_SIZE_32K (32768) /* buffer size 32k = 0x8000 = 32768 */ + +#define AUDIO_SRAM_PER_SIZE_02K (2048) /* period size 2k = 0x800 = 2048 */ +#define AUDIO_SRAM_PER_SIZE_04K (4096) /* period size 4k = 0x1000 = 4096 */ +#define AUDIO_SRAM_PER_SIZE_08K (8192) /* period size 8k = 0x2000 = 8192 */ +#define AUDIO_SRAM_PER_SIZE_16K (16384) /* period size 16k = 0x4000 = 16384 */ +#define AUDIO_SRAM_PER_SIZE_32K (32768) /* period size 32k = 0x8000 = 32768 */ + +typedef enum { + arisc_power_on = 0, + arisc_power_retention = 1, + arisc_power_off = 3, +} arisc_power_state_t; + +typedef enum { + arisc_system_shutdown = 0, + arisc_system_reboot = 1, + arisc_system_reset = 2 +} arisc_system_state_t; + +//pmu voltage types +typedef enum power_voltage_type +{ + AXP809_POWER_VOL_DCDC1 = 0x0, + AXP809_POWER_VOL_DCDC2, + AXP809_POWER_VOL_DCDC3, + AXP809_POWER_VOL_DCDC4, + AXP809_POWER_VOL_DCDC5, + AXP809_POWER_VOL_DC5LDO, + AXP809_POWER_VOL_ALDO1, + AXP809_POWER_VOL_ALDO2, + AXP809_POWER_VOL_ALDO3, + AXP809_POWER_VOL_DLDO1, + AXP809_POWER_VOL_DLDO2, + AXP809_POWER_VOL_ELDO1, + AXP809_POWER_VOL_ELDO2, + AXP809_POWER_VOL_ELDO3, + + AXP806_POWER_VOL_DCDCA, + AXP806_POWER_VOL_DCDCB, + AXP806_POWER_VOL_DCDCC, + AXP806_POWER_VOL_DCDCD, + AXP806_POWER_VOL_DCDCE, + AXP806_POWER_VOL_ALDO1, + AXP806_POWER_VOL_ALDO2, + AXP806_POWER_VOL_ALDO3, + AXP806_POWER_VOL_BLDO1, + AXP806_POWER_VOL_BLDO2, + AXP806_POWER_VOL_BLDO3, + AXP806_POWER_VOL_BLDO4, + AXP806_POWER_VOL_CLDO1, + AXP806_POWER_VOL_CLDO2, + AXP806_POWER_VOL_CLDO3, + + OZ80120_POWER_VOL_DCDC, + + POWER_VOL_MAX, +} power_voltage_type_e; + +/* the pll of arisc dvfs */ +typedef enum arisc_pll_no { + ARISC_DVFS_PLL1 = 1, + ARISC_DVFS_PLL2 = 2 +} arisc_pll_no_e; + +/* rsb transfer data type */ +typedef enum arisc_rsb_datatype { + RSB_DATA_TYPE_BYTE = 1, + RSB_DATA_TYPE_HWORD = 2, + RSB_DATA_TYPE_WORD = 4 +} arisc_rsb_datatype_e; + +#if defined CONFIG_ARCH_SUN8IW1P1 +typedef enum arisc_p2wi_bits_ops { + P2WI_CLR_BITS, + P2WI_SET_BITS +} arisc_p2wi_bits_ops_e; +#elif (defined CONFIG_ARCH_SUN8IW3P1) || (defined CONFIG_ARCH_SUN8IW5P1) || (defined CONFIG_ARCH_SUN8IW6P1) || \ + (defined CONFIG_ARCH_SUN8IW7P1) || (defined CONFIG_ARCH_SUN8IW9P1) || (defined CONFIG_ARCH_SUN9IW1P1) || \ + (defined CONFIG_ARCH_SUN50IW1P1) +/* rsb transfer data type */ +typedef enum arisc_rsb_bits_ops { + RSB_CLR_BITS, + RSB_SET_BITS +} arisc_rsb_bits_ops_e; +#endif + +typedef enum arisc_audio_mode { + AUDIO_PLAY, /* play mode */ + AUDIO_CAPTURE /* capture mode */ +} arisc_audio_mode_e; + +typedef struct arisc_audio_mem +{ + uint32_t mode; + uint32_t sram_base_addr; + uint32_t buffer_size; + uint32_t period_size; +}arisc_audio_mem_t; + +typedef struct arisc_audio_tdm +{ + uint32_t mode; + uint32_t samplerate; + uint32_t channum; +}arisc_audio_tdm_t; + +/* arisc call-back */ +typedef int (*arisc_cb_t)(void *arg); + +/* sunxi_perdone_cbfn + * + * period done callback routine type +*/ +/* audio callback struct */ +typedef struct audio_cb { + arisc_cb_t handler; /* dma callback fuction */ + void *arg; /* args of func */ +}audio_cb_t; + +/* + * @len : number of read registers, max len:4; + * @datatype: type of the data, 0:byte(8bits), 1:halfword(16bits), 2:word(32bits) + * @msgattr: message attribute, 0:async, 1:soft sync, 2:hard aync + * @devaddr: devices address; + * @regaddr: array of registers address; + * @data: array of registers data; + */ +typedef struct arisc_rsb_block_cfg +{ + uint32_t len; + uint32_t datatype; + uint32_t msgattr; + uint32_t devaddr; + unsigned char *regaddr; + uint32_t *data; +}arisc_rsb_block_cfg_t; + +/* + * @len : number of operate registers, max len:4; + * @datatype: type of the data, 0:byte(8bits), 1:halfword(16bits), 2:word(32bits) + * @msgattr: message attribute, 0:async, 1:soft sync, 2:hard aync + * @ops: bits operation, 0:clear bits, 1:set bits + * @devaddr : devices address; + * @regaddr : point of registers address; + * @mask : point of mask bits data; + * @delay: point of delay times; + */ +typedef struct arisc_rsb_bits_cfg +{ + uint32_t len; + uint32_t datatype; + uint32_t msgattr; + uint32_t ops; + uint32_t devaddr; + unsigned char *regaddr; + unsigned char *delay; + uint32_t *mask; +}arisc_rsb_bits_cfg_t; + +typedef enum arisc_rw_type +{ + ARISC_READ = 0x0, + ARISC_WRITE = 0x1, +} arisc_rw_type_e; + +typedef struct nmi_isr +{ + arisc_cb_t handler; + void *arg; +} nmi_isr_t; + +extern nmi_isr_t nmi_isr_node[2]; + +/* + * @flags: 0x01-clean pendings, 0x10-enter cupidle. + * @resume_addr: resume address for cpu0 out of idle. + */ +typedef struct sunxi_enter_idle_para{ + unsigned long flags; + void *resume_addr; +}sunxi_enter_idle_para_t; + +typedef struct sst_power_info_para +{ + /* + * define for sun9iw1p1 + * power_reg bit0 ~ 7 AXP_main REG10, bit 8~15 AXP_main REG12 + * power_reg bit16~23 AXP_slav REG10, bit24~31 AXP_slav REG11 + * + * AXP_main REG10: 0-off, 1-on + * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + * aldo2 aldo1 dcdc5 dcdc4 dcdc3 dcdc2 dcdc1 dc5ldo + * + * REG12: bit0~5:0-off, 1-on, bit6~7: 0-on, 1-off, dc1sw's power come from dcdc1 + * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + * dc1sw swout aldo3 dldo2 dldo1 eldo3 eldo2 eldo1 + * + * AXP_slave REG10: 0-off, 1-on. dcdc b&c is not used, ignore them. + * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + * aldo3 aldo2 aldo1 dcdce dcdcd dcdcc dcdcb dcdca + * + * AXP_slave REG11: 0-off, 1-on + * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + * swout cldo3 cldo2 cldo1 bldo4 bldo3 bldo2 bldo1 + */ + /* + * define for sun8iw5p1 + * power_reg0 ~ 7 AXP_main REG10, 8~15 AXP_main REG12 + * power_reg16~32 null + * + * AXP_main REG10: 0-off, 1-on + * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + * aldo2 aldo1 dcdc5 dcdc4 dcdc3 dcdc2 dcdc1 dc5ldo + * + * REG12: 0-off, 1-on + * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + * dc1sw dldo4 dldo3 dldo2 dldo1 eldo3 eldo2 eldo1 + * + * REG13: bit16 aldo3, 0-off, 1-on + * REG90: bit17 gpio0/ldo, 0-off, 1-on + * REG92: bit18 gpio1/ldo, 0-off, 1-on + */ + unsigned int enable; /* enable bit */ + unsigned int power_reg; /* registers of power state should be */ + signed int system_power; /* the max power of system, signed, power mabe negative when charge */ +} sst_power_info_para_t; + +typedef struct sst_dram_info +{ + unsigned int dram_crc_enable; + unsigned int dram_crc_src; + unsigned int dram_crc_len; + unsigned int dram_crc_error; + unsigned int dram_crc_total_count; + unsigned int dram_crc_error_count; +} sst_dram_info_t; + +typedef struct standby_info_para +{ + sst_power_info_para_t power_state; /* size 3W=12B */ + sst_dram_info_t dram_state; /*size 6W=24B */ +} standby_info_para_t; + +int sunxi_arisc_probe(void *cfg); +int sunxi_arisc_wait_ready(void); + + +/* ====================================dvfs interface==================================== */ +/* + * set specific pll target frequency. + * @freq: target frequency to be set, based on KHZ; + * @pll: which pll will be set + * @mode: the attribute of message, whether syn or asyn; + * @cb: callback handler; + * @cb_arg: callback handler arguments; + * + * return: result, 0 - set frequency successed, + * !0 - set frequency failed; + */ +int arisc_dvfs_set_cpufreq(uint32_t freq, uint32_t pll, uint32_t mode); + +/* + * enter cpu idle. + * @cb: callback function. + * @cb_arg: arg for callback function. + * @pars: arg for enter cpuidle. + * + * return: result, 0 - enter cpuidle successed, !0 - failed; + */ +int arisc_enter_cpuidle(arisc_cb_t cb, void *cb_arg, struct sunxi_enter_idle_para *para); + +/** + * cpu operations. + * @mpidr: cpu id; + * @entrypoint: cpu resume entrypoint; + * @cpu_state: cpu state; + * @cluster_state: cluster state; + * + * return: result, 0 - super standby successed, + * !0 - super standby failed; + */ +int arisc_cpu_op(uint32_t mpidr, uint32_t entrypoint, arisc_power_state_t cpu_state, + arisc_power_state_t cluster_state); + + /** + * system operations. + * @state: system state; + * + * return: result, 0 - system operations successed, + * !0 - system operations failed; + */ +int arisc_system_op(arisc_system_state_t state); + +/* ====================================standby interface==================================== */ +/** + * query super-standby wakeup source. + * @para: point of buffer to store wakeup event informations. + * + * return: result, 0 - query successed, !0 - query failed; + */ +int arisc_query_wakeup_source(uint32_t *event); + +int arisc_query_set_standby_info(struct standby_info_para *para, arisc_rw_type_e op); + +/* + * query config of standby power state and consumer. + * @para: point of buffer to store power informations. + * + * return: result, 0 - query successed, !0 - query failed; + */ +int arisc_query_standby_power_cfg(struct standby_info_para *para); + +/* + * set config of standby power state and consumer. + * @para: point of buffer to store power informations. + * + * return: result, 0 - set successed, !0 - set failed; + */ +#define arisc_set_standby_power_cfg(para) \ + arisc_query_set_standby_info(para, ARISC_WRITE) + +/* + * query standby power state and consumer. + * @para: point of buffer to store power informations. + * + * return: result, 0 - query successed, !0 - query failed; + */ +#define arisc_query_standby_power(para) \ + arisc_query_set_standby_info(para, ARISC_READ) + +/** + * query super-standby dram crc result. + * @perror: pointer of dram crc result. + * @ptotal_count: pointer of dram crc total count + * @perror_count: pointer of dram crc error count + * + * return: result, 0 - query successed, + * !0 - query failed; + */ +int arisc_query_dram_crc_result(unsigned long *perror, unsigned long *ptotal_count, + unsigned long *perror_count); + +int arisc_set_dram_crc_result(unsigned long error, unsigned long total_count, + unsigned long error_count); + +/** + * notify arisc cpux restored. + * @para: none. + * + * return: result, 0 - notify successed, !0 - notify failed; + */ +int arisc_cpux_ready_notify(void); + +#if defined CONFIG_ARCH_SUN8IW1P1 +void arisc_fake_power_off(void); +#endif + +/* ====================================axp interface==================================== */ +/** + * register call-back function, call-back function is for arisc notify some event to ac327, + * axp/rtc interrupt for external interrupt NMI. + * @type: nmi type, pmu/rtc; + * @func: call-back function; + * @para: parameter for call-back function; + * + * @return: result, 0 - register call-back function successed; + * !0 - register call-back function failed; + * NOTE: the function is like "int callback(void *para)"; + * this function will execute in system ISR. + */ +int arisc_nmi_cb_register(uint32_t type, arisc_cb_t func, void *para); + +/** + * unregister call-back function. + * @type: nmi type, pmu/rtc; + * @func: call-back function which need be unregister; + */ +void arisc_nmi_cb_unregister(uint32_t type, arisc_cb_t func); + +int arisc_disable_nmi_irq(void); +int arisc_enable_nmi_irq(void); +int arisc_clear_nmi_status(void); +int arisc_set_nmi_trigger(uint32_t type); + +int arisc_axp_get_chip_id(unsigned char *chip_id); +int arisc_adjust_pmu_chgcur(uint32_t max_chgcur, uint32_t chg_ic_temp, uint32_t flag); +int arisc_set_pwr_tree(uint32_t *pwr_tree); + +int arisc_set_led_bln(uint32_t *paras); + +/* ====================================audio interface==================================== */ +/** + * start audio play or capture. + * @mode: start audio in which mode ; 0:play, 1;capture. + * + * return: result, 0 - start audio play or capture successed, + * !0 - start audio play or capture failed. + */ +int arisc_audio_start(int mode); + +/** + * stop audio play or capture. + * @mode: stop audio in which mode ; 0:play, 1;capture. + * + * return: result, 0 - stop audio play or capture successed, + * !0 - stop audio play or capture failed. + */ +int arisc_audio_stop(int mode); + +/** + * set audio buffer and period parameters. + * @audio_mem: + * mode :which mode be set; 0:paly, 1:capture; + * sram_base_addr:sram base addr of buffer; + * buffer_size :the size of buffer; + * period_size :the size of period; + * + * |period|period|period|period|...|period|period|period|period|...| + * | paly buffer | capture buffer | + * | | + * 1 2 + * 1:paly sram_base_addr, 2:capture sram_base_addr; + * buffer size = capture sram_base_addr - paly sram_base_addr. + * + * return: result, 0 - set buffer and period parameters successed, + * !0 - set buffer and period parameters failed. + * + */ +int arisc_buffer_period_paras(struct arisc_audio_mem audio_mem); + +/** + * get audio play or capture real-time address. + * @mode: in which mode; 0:play, 1;capture; + * @addr: real-time address in which mode. + * + * return: result, 0 - get real-time address successed, + * !0 - get real-time address failed. + */ +int arisc_get_position(int mode, uint32_t *addr); + +/** + * register audio callback function. + * @mode: in which mode; 0:play, 1;capture; + * @handler: audio callback handler which need be register; + * @arg : the pointer of audio callback arguments. + * + * return: result, 0 - register audio callback function successed, + * !0 - register audio callback function failed. + */ +int arisc_audio_cb_register(int mode, arisc_cb_t handler, void *arg); + +/** + * unregister audio callback function. + * @mode: in which mode; 0:play, 1;capture; + * @handler: audio callback handler which need be register; + * @arg : the pointer of audio callback arguments. + * + * return: result, 0 - unregister audio callback function successed, + * !0 - unregister audio callback function failed. + */ +int arisc_audio_cb_unregister(int mode, arisc_cb_t handler); + +/** + * set audio tdm parameters. + * @tdm_cfg: audio tdm struct + * mode :in which mode; 0:play, 1;capture; + * samplerate:tdm samplerate depend on audio data; + * channel :audio channel number, 1 or 2. + + * return: result, 0 - set buffer and period parameters successed, + * !0 - set buffer and period parameters failed. + * + */ +int arisc_tdm_paras(struct arisc_audio_tdm tdm_cfg); + +/** + * add audio period. + * @mode: start audio in which mode ; 0:play, 1;capture. + * @addr: period address which will be add in buffer + * + * return: result, 0 - add audio period successed, + * !0 - add audio period failed. + * + */ +int arisc_add_period(uint32_t mode, uint32_t addr); + +/* ====================================rsb interface==================================== */ +/** + * rsb read block data. + * @cfg: point of arisc_rsb_block_cfg struct; + * + * return: result, 0 - read register successed, + * !0 - read register failed or the len more then max len; + */ +int arisc_rsb_read_block_data(uint32_t *paras); + +/** + * rsb write block data. + * @cfg: point of arisc_rsb_block_cfg struct; + * + * return: result, 0 - write register successed, + * !0 - write register failedor the len more then max len; + */ +int arisc_rsb_write_block_data(uint32_t *paras); + + +/** + * rsb read pmu reg. + * @addr: pmu reg addr; + * + * return: if read pmu reg successed, return data of pmu reg; + * if read pmu reg failed, return -1. + */ +uint8_t arisc_rsb_read_pmu_reg(uint32_t addr); + +/** + * rsb write pmu reg. + * @addr: pmu reg addr; + * @data: pmu reg data; + * + * return: result, 0 - write register successed, + * !0 - write register failedor the len more then max len; + */ +int arisc_rsb_write_pmu_reg(uint32_t addr, uint32_t data); + + +/** + * rsb bits operation sync. + * @cfg: point of arisc_rsb_bits_cfg struct; + * + * return: result, 0 - bits operation successed, + * !0 - bits operation failed, or the len more then max len; + * + * rsb clear bits internal: + * data = rsb_read(regaddr); + * data = data & (~mask); + * rsb_write(regaddr, data); + * + * rsb set bits internal: + * data = rsb_read(addr); + * data = data | mask; + * rsb_write(addr, data); + * + */ +int rsb_bits_ops_sync(uint32_t *paras); + +/** + * rsb set interface mode. + * @devaddr: rsb slave device address; + * @regaddr: register address of rsb slave device; + * @data: data which to init rsb slave device interface mode; + * + * return: result, 0 - set interface mode successed, + * !0 - set interface mode failed; + */ +int arisc_rsb_set_interface_mode(uint32_t devaddr, uint32_t regaddr, uint32_t data); + +/** + * rsb set runtime slave address. + * @devaddr: rsb slave device address; + * @rtsaddr: rsb slave device's runtime slave address; + * + * return: result, 0 - set rsb runtime address successed, + * !0 - set rsb runtime address failed; + */ +int arisc_rsb_set_rtsaddr(uint32_t devaddr, uint32_t rtsaddr); + +/** + * set pmu voltage. + * @type: pmu regulator type; + * @voltage: pmu regulator voltage; + * + * return: result, 0 - set pmu voltage successed, + * !0 - set pmu voltage failed; + */ +int arisc_pmu_set_voltage(uint32_t type, uint32_t voltage); + +/** + * get pmu voltage. + * @type: pmu regulator type; + * + * return: pmu regulator voltage; + */ +int arisc_pmu_get_voltage(uint32_t type, uint32_t *voltage); + +/* ====================================debug interface==================================== */ +int arisc_message_loopback(void); +int arisc_config_ir_paras(uint32_t ir_code, uint32_t ir_addr); +int arisc_set_debug_level(unsigned int level); +int arisc_set_uart_baudrate(uint32_t baudrate); +int arisc_set_dram_crc_paras(unsigned int dram_crc_en, unsigned int dram_crc_srcaddr, unsigned int dram_crc_len); +int arisc_set_paras(void); + +#endif /* __ASM_ARCH_A100_H */ + diff --git a/plat/sun50iw1p1/include/ccmu.h b/plat/sun50iw1p1/include/ccmu.h new file mode 100644 index 0000000..a1e817f --- /dev/null +++ b/plat/sun50iw1p1/include/ccmu.h @@ -0,0 +1,81 @@ +/* + * (C) Copyright 2007-2015 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Jerry Wang <wangflord@allwinnertech.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __CCMU_H +#define __CCMU_H + + +#include "../sunxi_def.h" + +/* pll list */ +#define CCMU_PLL_CPUX_CTRL_REG (SUNXI_CCM_BASE + 0x00) +#define CCMU_PLL_AUDIO_CTRL_REG (SUNXI_CCM_BASE + 0x08) +#define CCMU_PLL_VIDEO0_CTRL_REG (SUNXI_CCM_BASE + 0x10) +#define CCMU_PLL_VE_CTRL_REG (SUNXI_CCM_BASE + 0x18) +#define CCMU_PLL_DDR0_CTRL_REG (SUNXI_CCM_BASE + 0x20) +#define CCMU_PLL_PERIPH0_CTRL_REG (SUNXI_CCM_BASE + 0x28) +#define CCMU_PLL_PERIPH1_CTRL_REG (SUNXI_CCM_BASE + 0x2C) +#define CCMU_PLL_VIDEO1_CTRL_REG (SUNXI_CCM_BASE + 0x30) +#define CCMU_PLL_GPU_CTRL_REG (SUNXI_CCM_BASE + 0x38) +#define CCMU_PLL_MIPI_CTRL_REG (SUNXI_CCM_BASE + 0x40) +#define CCMU_PLL_HSIC_CTRL_REG (SUNXI_CCM_BASE + 0x44) +#define CCMU_PLL_DE_CTRL_REG (SUNXI_CCM_BASE + 0x48) +#define CCMU_PLL_DDR1_CTRL_REG (SUNXI_CCM_BASE + 0x4C) + +/* cfg list */ +#define CCMU_CPUX_AXI_CFG_REG (SUNXI_CCM_BASE + 0x50) +#define CCMU_AHB1_APB1_CFG_REG (SUNXI_CCM_BASE + 0x54) +#define CCMU_APB2_CFG_GREG (SUNXI_CCM_BASE + 0x58) +#define CCMU_AHB2_CFG_GREG (SUNXI_CCM_BASE + 0x5C) + +/* gate list */ +#define CCMU_BUS_CLK_GATING_REG0 (SUNXI_CCM_BASE + 0x60) +#define CCMU_BUS_CLK_GATING_REG1 (SUNXI_CCM_BASE + 0x64) +#define CCMU_BUS_CLK_GATING_REG2 (SUNXI_CCM_BASE + 0x68) +#define CCMU_BUS_CLK_GATING_REG3 (SUNXI_CCM_BASE + 0x6C) +#define CCMU_BUS_CLK_GATING_REG4 (SUNXI_CCM_BASE + 0x70) + +/* module list */ +#define CCMU_NAND0_CLK_REG (SUNXI_CCM_BASE + 0x80) +#define CCMU_SDMMC0_CLK_REG (SUNXI_CCM_BASE + 0x88) +#define CCMU_SDMMC1_CLK_REG (SUNXI_CCM_BASE + 0x8C) +#define CCMU_SDMMC2_CLK_REG (SUNXI_CCM_BASE + 0x90) + +#define CCMU_CE_CLK_REG (SUNXI_CCM_BASE + 0x9C) + +#define CCMU_USBPHY_CLK_REG (SUNXI_CCM_BASE + 0xCC) +#define CCMU_DRAM_CLK_REG (SUNXI_CCM_BASE + 0xF4) +#define CCMU_PLL_DDR_CFG_REG (SUNXI_CCM_BASE + 0xF8) +#define CCMU_MBUS_RST_REG (SUNXI_CCM_BASE + 0xFC) +#define CCMU_DRAM_CLK_GATING_REG (SUNXI_CCM_BASE + 0x100) + +#define CCMU_AVS_CLK_REG (SUNXI_CCM_BASE + 0x144) +#define CCMU_MBUS_CLK_REG (SUNXI_CCM_BASE + 0x15C) + +/*gate rst list*/ +#define CCMU_BUS_SOFT_RST_REG0 (SUNXI_CCM_BASE + 0x2C0) +#define CCMU_BUS_SOFT_RST_REG1 (SUNXI_CCM_BASE + 0x2C4) +#define CCMU_BUS_SOFT_RST_REG2 (SUNXI_CCM_BASE + 0x2C8) +#define CCMU_BUS_SOFT_RST_REG3 (SUNXI_CCM_BASE + 0x2D0) +#define CCMU_BUS_SOFT_RST_REG4 (SUNXI_CCM_BASE + 0x2D8) + +#endif + diff --git a/plat/sun50iw1p1/include/gpio.h b/plat/sun50iw1p1/include/gpio.h new file mode 100644 index 0000000..7cab9c9 --- /dev/null +++ b/plat/sun50iw1p1/include/gpio.h @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2007-2013 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Jerry Wang <wangflord@allwinnertech.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _SUNXI_GPIO_H +#define _SUNXI_GPIO_H + +#include <mmio.h> + + +#define PIOC_REG_o_CFG0 0x00 +#define PIOC_REG_o_CFG1 0x04 +#define PIOC_REG_o_CFG2 0x08 +#define PIOC_REG_o_CFG3 0x0C +#define PIOC_REG_o_DATA 0x10 +#define PIOC_REG_o_DRV0 0x14 +#define PIOC_REG_o_DRV1 0x18 +#define PIOC_REG_o_PUL0 0x1C +#define PIOC_REG_o_PUL1 0x20 + + + +/**############################################################################################################# + * + * GPIO(PIN) Operations + * +-##############################################################################################################*/ +#define PIO_REG_CFG(n, i) (( SUNXI_PIO_BASE + ((n)-1)*0x24 + ((i)<<2) + 0x00)) +#define PIO_REG_DLEVEL(n, i) (( SUNXI_PIO_BASE + ((n)-1)*0x24 + ((i)<<2) + 0x14)) +#define PIO_REG_PULL(n, i) (( SUNXI_PIO_BASE + ((n)-1)*0x24 + ((i)<<2) + 0x1C)) +#define PIO_REG_DATA(n) (( SUNXI_PIO_BASE + ((n)-1)*0x24 + 0x10)) + + +//struct for gpio +typedef struct +{ + unsigned char port; //端口号 + unsigned char port_num; //端口内编号 + char mul_sel; //功能编号 + char pull; //电阻状态 + char drv_level; //驱动驱动能力 + char data; //输出电平 + unsigned char reserved[2]; //保留位,保证对齐 +} +normal_gpio_set_t; + +int32_t boot_set_gpio(void *user_gpio_list, uint32_t group_count_max, int32_t set_gpio); + +#endif /* _SUNXI_GPIO_H */ diff --git a/plat/sun50iw1p1/include/plat_macros.S b/plat/sun50iw1p1/include/plat_macros.S new file mode 100644 index 0000000..4e35541 --- /dev/null +++ b/plat/sun50iw1p1/include/plat_macros.S @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ +#include <cci400.h> +#include <gic_v2.h> +#include <plat_config.h> +#include "../sunxi_def.h" + +.section .rodata.gic_reg_name, "aS" +gic_regs: + .asciz "gic_hppir", "gic_ahppir", "gic_ctlr", "" +gicd_pend_reg: + .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n" +newline: + .asciz "\n" +spacer: + .asciz ":\t\t0x" + + /* --------------------------------------------- + * The below macro prints out relevant GIC + * registers whenever an unhandled exception is + * taken in BL3-1. + * Clobbers: x0 - x10, x16, sp + * --------------------------------------------- + */ + .macro plat_print_gic_regs + adr x0, plat_config + ldr w16, [x0, #CONFIG_GICC_BASE_OFFSET] + cbz x16, exit_print_gic_regs + /* gic base address is now in x16 */ + adr x6, gic_regs /* Load the gic reg list to x6 */ + /* Load the gic regs to gp regs used by str_in_crash_buf_print */ + ldr w8, [x16, #GICC_HPPIR] + ldr w9, [x16, #GICC_AHPPIR] + ldr w10, [x16, #GICC_CTLR] + /* Store to the crash buf and print to console */ + bl str_in_crash_buf_print + + /* Print the GICD_ISPENDR regs */ + add x7, x16, #GICD_ISPENDR + adr x4, gicd_pend_reg + bl asm_print_str +gicd_ispendr_loop: + sub x4, x7, x16 + cmp x4, #0x280 + b.eq exit_print_gic_regs + bl asm_print_hex + adr x4, spacer + bl asm_print_str + ldr x4, [x7], #8 + bl asm_print_hex + adr x4, newline + bl asm_print_str + b gicd_ispendr_loop +exit_print_gic_regs: + .endm +#if 0 +.section .rodata.cci_reg_name, "aS" +cci_iface_regs: + .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , "" + + /* ------------------------------------------------ + * The below macro prints out relevant interconnect + * registers whenever an unhandled exception is + * taken in BL3-1. + * Clobbers: x0 - x9, sp + * ------------------------------------------------ + */ + .macro plat_print_interconnect_regs + adr x6, cci_iface_regs + /* Store in x7 the base address of the first interface */ + mov_imm x7, (CCI400_BASE + SLAVE_IFACE3_OFFSET) + ldr w8, [x7, #SNOOP_CTRL_REG] + /* Store in x7 the base address of the second interface */ + mov_imm x7, (CCI400_BASE + SLAVE_IFACE4_OFFSET) + ldr w9, [x7, #SNOOP_CTRL_REG] + /* Store to the crash buf and print to console */ + bl str_in_crash_buf_print + .endm +#endif diff --git a/plat/sun50iw1p1/include/platform_def.h b/plat/sun50iw1p1/include/platform_def.h new file mode 100644 index 0000000..70b8b79 --- /dev/null +++ b/plat/sun50iw1p1/include/platform_def.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#ifndef __PLATFORM_DEF_H__ +#define __PLATFORM_DEF_H__ + +#include <arch.h> +#include "../sunxi_def.h" + + +/******************************************************************************* + * Platform binary types for linking + ******************************************************************************/ +#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" +#define PLATFORM_LINKER_ARCH aarch64 + +/******************************************************************************* + * Generic platform constants + ******************************************************************************/ + +#define DEBUG_XLAT_TABLE 0 + +/* Size of cacheable stacks */ +#if DEBUG_XLAT_TABLE +#define PLATFORM_STACK_SIZE 0x800 +#elif IMAGE_BL1 +#define PLATFORM_STACK_SIZE 0x440 +#elif IMAGE_BL2 +#define PLATFORM_STACK_SIZE 0x400 +#elif IMAGE_BL31 +#define PLATFORM_STACK_SIZE 0x400 +#elif IMAGE_BL32 +#define PLATFORM_STACK_SIZE 0x440 +#endif + +#define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" + +/* Trusted Boot Firmware BL2 */ +#define BL2_IMAGE_NAME "bl2.bin" + +/* EL3 Runtime Firmware BL31 */ +#define BL31_IMAGE_NAME "bl31.bin" + +/* Secure Payload BL32 (Trusted OS) */ +#define BL32_IMAGE_NAME "bl32.bin" + +/* Non-Trusted Firmware BL33 */ +#define BL33_IMAGE_NAME "bl33.bin" /* e.g. UEFI */ + +#define PLATFORM_CACHE_LINE_SIZE 64 + +#define PLATFORM_CLUSTER_COUNT 1 +#define PLATFORM_CORE_COUNT 4 +#define PLATFORM_NUM_AFFS (PLATFORM_CLUSTER_COUNT + PLATFORM_CORE_COUNT) +#define PLATFORM_MAX_CPUS_PER_CLUSTER 4 + + +/******************************************************************************* + * BL31 specific defines. + ******************************************************************************/ +/* + * Put BL3-1 at the top of the Trusted SRAM (just below the shared memory, if + * present). BL31_BASE is calculated using the current BL3-1 debug size plus a + * little space for growth. + */ +#define BL31_BASE (SUNXI_TRUSTED_MONITOR_BASE) +#define BL31_PROGBITS_LIMIT (SUNXI_TRUSTED_MONITOR_LIMIT - 0x6000) +#define BL31_LIMIT SUNXI_TRUSTED_MONITOR_LIMIT + +/******************************************************************************* + * BL32 specific defines. + ******************************************************************************/ +/* + * On sun50iw1p1, the TSP can execute either from Trusted SRAM or Trusted DRAM. + */ + +#define TSP_SEC_MEM_BASE SUNXI_TRUSTED_DRAM_BASE +#define TSP_SEC_MEM_SIZE SUNXI_TRUSTED_DRAM_SIZE +#define BL32_BASE (SUNXI_TRUSTED_DRAM_BASE + SUNXI_SHARED_RAM_SIZE) +#define BL32_LIMIT (SUNXI_TRUSTED_DRAM_BASE + (1 << 21)) + + +/* + * ID of the secure physical generic timer interrupt used by the TSP. + */ +#define TSP_IRQ_SEC_PHY_TIMER IRQ_SEC_PHY_TIMER + +/******************************************************************************* + * Platform specific page table and MMU setup constants + ******************************************************************************/ +#define ADDR_SPACE_SIZE (1ull << 32) +#define MAX_XLAT_TABLES 2 +#define MAX_MMAP_REGIONS 16 + +/******************************************************************************* + * Declarations and constants to access the mailboxes safely. Each mailbox is + * aligned on the biggest cache line size in the platform. This is known only + * to the platform as it might have a combination of integrated and external + * caches. Such alignment ensures that two maiboxes do not sit on the same cache + * line at any cache level. They could belong to different cpus/clusters & + * get written while being protected by different locks causing corruption of + * a valid mailbox address. + ******************************************************************************/ +#define CACHE_WRITEBACK_SHIFT 6 +#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) + + +#endif /* __PLATFORM_DEF_H__ */ diff --git a/plat/sun50iw1p1/include/uart.h b/plat/sun50iw1p1/include/uart.h new file mode 100644 index 0000000..af26c0b --- /dev/null +++ b/plat/sun50iw1p1/include/uart.h @@ -0,0 +1,43 @@ +#ifndef _UART_H_ +#define _UART_H_ + +#define NULL ((void*)0) +#define CCM_UART_PORT_OFFSET 16 +#define CCM_UART_ADDR_OFFSET 0x400 + +typedef struct serial_hw +{ + volatile unsigned int rbr; /* 0 */ + volatile unsigned int ier; /* 1 */ + volatile unsigned int fcr; /* 2 */ + volatile unsigned int lcr; /* 3 */ + volatile unsigned int mcr; /* 4 */ + volatile unsigned int lsr; /* 5 */ + volatile unsigned int msr; /* 6 */ + volatile unsigned int sch; /* 7 */ +}serial_hw_t; + + +#define UART_BAUD 115200 // Baud rate for UART + // Compute the divisor factor +// UART Line Control Parameter +#define PARITY 0 // Parity: 0,2 - no parity; 1 - odd parity; 3 - even parity +#define STOP 0 // Number of Stop Bit: 0 - 1bit; 1 - 2(or 1.5)bits +#define DLEN 3 // Data Length: 0 - 5bits; 1 - 6bits; 2 - 7bits; 3 - 8bits + +#if DEBUG +void sunxi_serial_init(int uart_port, void *gpio_cfg, int gpio_max); +void sunxi_serial_exit(void); +void sunxi_serial_putc (char c); +char sunxi_serial_getc (void); +int sunxi_serial_tstc (void); +#else +static inline void sunxi_serial_init(int uart_port, void *gpio_cfg, int gpio_max) {} +static inline void sunxi_serial_exit(void) {} +static inline void sunxi_serial_putc(char c) {} +static inline char sunxi_serial_getc(void) { return 0;} +static inline int sunxi_serial_tstc(void) { return 0;} +#endif + + +#endif /* #ifndef _UART_H_ */ diff --git a/plat/sun50iw1p1/mhu.c b/plat/sun50iw1p1/mhu.c new file mode 100644 index 0000000..a817b4d --- /dev/null +++ b/plat/sun50iw1p1/mhu.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <arch_helpers.h> +#include <bakery_lock.h> +#include <mmio.h> +#include <debug.h> +#include "sunxi_def.h" +#include "mhu.h" +#include "scpi.h" + +#if 1 +void mhu_secure_message_start(void) +{ + +} + +void mhu_secure_message_send(uint32_t command) +{ + switch(command&0xf) + { + case SCPI_CMD_SCP_READY: + NOTICE("send cmd to scp: SCPI_CMD_SCP_READY\n"); + break; + case SCPI_CMD_SET_CSS_POWER_STATE: + NOTICE("send cmd to scp: SCPI_CMD_SET_CSS_POWER_STATE\n"); + break; + case SCPI_CMD_SYS_POWER_STATE: + NOTICE("send cmd to scp: SCPI_CMD_SYS_POWER_STATE\n"); + break; + } +} + +uint32_t mhu_secure_message_wait(void) +{ + /* Wait for response from SCP */ + + return 1; +} + +void mhu_secure_message_end(void) +{ + +} + +void mhu_secure_init(void) +{ + +} +#else +/* SCP MHU secure channel registers */ +#define SCP_INTR_S_STAT 0x200 +#define SCP_INTR_S_SET 0x208 +#define SCP_INTR_S_CLEAR 0x210 + +/* CPU MHU secure channel registers */ +#define CPU_INTR_S_STAT 0x300 +#define CPU_INTR_S_SET 0x308 +#define CPU_INTR_S_CLEAR 0x310 + + +static bakery_lock_t mhu_secure_lock __attribute__ ((section("tzfw_coherent_mem"))); + +void mhu_secure_message_start(void) +{ + bakery_lock_get(&mhu_secure_lock); + + /* Make sure any previous command has finished */ + while (mmio_read_32(MHU_BASE + CPU_INTR_S_STAT) != 0) + ; +} + +void mhu_secure_message_send(uint32_t command) +{ + /* Send command to SCP and wait for it to pick it up */ + mmio_write_32(MHU_BASE + CPU_INTR_S_SET, command); + while (mmio_read_32(MHU_BASE + CPU_INTR_S_STAT) != 0) + ; +} + +uint32_t mhu_secure_message_wait(void) +{ + /* Wait for response from SCP */ + uint32_t response; + while (!(response = mmio_read_32(MHU_BASE + SCP_INTR_S_STAT))) + ; + + return response; +} + +void mhu_secure_message_end(void) +{ + /* Clear any response we got by writing all ones to the CLEAR register */ + mmio_write_32(MHU_BASE + SCP_INTR_S_CLEAR, 0xffffffffu); + + bakery_lock_release(&mhu_secure_lock); +} + +void mhu_secure_init(void) +{ + bakery_lock_init(&mhu_secure_lock); + + /* + * Clear the CPU's INTR register to make sure we don't see a stale + * or garbage value and think it's a message we've already sent. + */ + mmio_write_32(MHU_BASE + CPU_INTR_S_CLEAR, 0xffffffffu); +} +#endif diff --git a/plat/sun50iw1p1/mhu.h b/plat/sun50iw1p1/mhu.h new file mode 100644 index 0000000..5149c82 --- /dev/null +++ b/plat/sun50iw1p1/mhu.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#ifndef __MHU_H__ +#define __MHU_H__ + +#include <stdint.h> + +extern void mhu_secure_message_start(void); +extern void mhu_secure_message_send(uint32_t command); +extern uint32_t mhu_secure_message_wait(void); +extern void mhu_secure_message_end(void); + +extern void mhu_secure_init(void); + +#endif /* __MHU_H__ */ diff --git a/plat/sun50iw1p1/plat_gic.c b/plat/sun50iw1p1/plat_gic.c new file mode 100644 index 0000000..78e1a81 --- /dev/null +++ b/plat/sun50iw1p1/plat_gic.c @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <gic_v2.h> +#include <interrupt_mgmt.h> +#include <platform.h> +#include <debug.h> +#include "sunxi_def.h" +#include "sunxi_private.h" +#include "gic_sunxi.h" + + +/* Value used to initialise Non-Secure irq priorities four at a time */ +#define DEFAULT_NS_PRIORITY_X4 \ + (GIC_HIGHEST_NS_PRIORITY | \ + (GIC_HIGHEST_NS_PRIORITY << 8) | \ + (GIC_HIGHEST_NS_PRIORITY << 16) | \ + (GIC_HIGHEST_NS_PRIORITY << 24)) + + +/******************************************************************************* + * Enable secure interrupts and use FIQs to route them. Disable legacy bypass + * and set the priority mask register to allow all interrupts to trickle in. + ******************************************************************************/ +void gic_cpuif_setup(unsigned int gicc_base) +{ + unsigned int val; + + gicc_write_pmr(gicc_base, GIC_PRI_MASK); + + val = ENABLE_GRP0 | FIQ_EN; + val |= FIQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP0; + val |= FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1; + gicc_write_ctlr(gicc_base, val); +} + +/******************************************************************************* + * Place the cpu interface in a state where it can never make a cpu exit wfi as + * as result of an asserted interrupt. This is critical for powering down a cpu + ******************************************************************************/ +void gic_cpuif_deactivate(unsigned int gicc_base) +{ + unsigned int val; + + /* Disable secure, non-secure interrupts and disable their bypass */ + val = gicc_read_ctlr(gicc_base); + val &= ~(ENABLE_GRP0 | ENABLE_GRP1); + val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0; + val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1; + gicc_write_ctlr(gicc_base, val); +} + +void gic_set_secure(unsigned int gicd_base, unsigned id) +{ + /* Set interrupt as Group 0 */ + gicd_clr_igroupr(gicd_base, id); + + /* Set priority to max */ + gicd_set_ipriorityr(gicd_base, id, GIC_HIGHEST_SEC_PRIORITY); +} + +#if 0 +/******************************************************************************* + * Per cpu gic distributor setup which will be done by all cpus after a cold + * boot/hotplug. This marks out the secure interrupts & enables them. + ******************************************************************************/ +void gic_pcpu_distif_setup(unsigned int gicd_base) +{ + unsigned i; + + /* Mark all 32 PPI interrupts as Group 1 (non-secure) */ + mmio_write_32(gicd_base + GICD_IGROUPR, 0xffffffffu); + + /* Setup PPI priorities doing four at a time */ + for (i = 0; i < 32; i += 4) + mmio_write_32(gicd_base + GICD_IPRIORITYR + i, DEFAULT_NS_PRIORITY_X4); + + /* Configure those PPIs we want as secure, and enable them. */ + static const char sec_irq[] = { + IRQ_SEC_PHY_TIMER, + IRQ_SEC_SGI_0, + IRQ_SEC_SGI_1, + IRQ_SEC_SGI_2, + IRQ_SEC_SGI_3, + IRQ_SEC_SGI_4, + IRQ_SEC_SGI_5, + IRQ_SEC_SGI_6, + IRQ_SEC_SGI_7 + }; + for (i = 0; i < sizeof(sec_irq) / sizeof(sec_irq[0]); i++) { + gic_set_secure(gicd_base, sec_irq[i]); + gicd_set_isenabler(gicd_base, sec_irq[i]); + } +} + +/******************************************************************************* + * Global gic distributor setup which will be done by the primary cpu after a + * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It + * then enables the secure GIC distributor interface. + ******************************************************************************/ +static void gic_distif_setup(unsigned int gicd_base) +{ + unsigned int i, ctlr; + const unsigned int ITLinesNumber = + gicd_read_typer(gicd_base) & IT_LINES_NO_MASK; + + /* Disable the distributor before going further */ + ctlr = gicd_read_ctlr(gicd_base); + ctlr &= ~(ENABLE_GRP0 | ENABLE_GRP1); + gicd_write_ctlr(gicd_base, ctlr); + + /* Mark all lines of SPIs as Group 1 (non-secure) */ + for (i = 0; i < ITLinesNumber; i++) + mmio_write_32(gicd_base + GICD_IGROUPR + 4 + i * 4, 0xffffffffu); + + /* Setup SPI priorities doing four at a time */ + for (i = 0; i < ITLinesNumber * 32; i += 4) + mmio_write_32(gicd_base + GICD_IPRIORITYR + 32 + i, DEFAULT_NS_PRIORITY_X4); + + /* Configure the SPIs we want as secure */ + static const char sec_irq[] = { + IRQ_MHU, + IRQ_GPU_SMMU_0, + IRQ_GPU_SMMU_1, + IRQ_ETR_SMMU, + IRQ_TZC400, + IRQ_TZ_WDOG + }; + for (i = 0; i < sizeof(sec_irq) / sizeof(sec_irq[0]); i++) + gic_set_secure(gicd_base, sec_irq[i]); + + /* Route watchdog interrupt to this CPU and enable it. */ + gicd_set_itargetsr(gicd_base, IRQ_TZ_WDOG, + platform_get_core_pos(read_mpidr())); + gicd_set_isenabler(gicd_base, IRQ_TZ_WDOG); + + /* Now setup the PPIs */ + gic_pcpu_distif_setup(gicd_base); + + /* Enable Group 0 (secure) interrupts */ + gicd_write_ctlr(gicd_base, ctlr | ENABLE_GRP0); +} +#endif + +#define writel(v,a) mmio_write_32((a),(v)) + +void gic_distributor_init(uint32_t addr) +{ + uint32_t cpumask = 0x01010101; + uint32_t gic_irqs; + uint32_t i; + + writel(0, GIC_DIST_CON); + /* check GIC hardware configutation */ + gic_irqs = ((mmio_read_32(GIC_CON_TYPE) & 0x1f) + 1) * 32; + if (gic_irqs > 1020) + { + gic_irqs = 1020; + } + if (gic_irqs < GIC_IRQ_NUM) + { + NOTICE("GIC parameter config error, only support %d" + " irqs < %d(spec define)!!\n", gic_irqs, GIC_IRQ_NUM); + return ; + } + + /* Set ALL interrupts as group1(non-secure) interrupts */ + for (i=1; i<GIC_IRQ_NUM; i+=16) + { + writel(0xffffffff, GIC_CON_IGRP(i>>4)); + } + + + /* set trigger type to be level-triggered, active low */ + for (i=0; i<GIC_IRQ_NUM; i+=16) + { + writel(0, GIC_IRQ_MOD_CFG(i>>4)); + } + /* set priority */ + for (i=GIC_SRC_SPI(0); i<GIC_IRQ_NUM; i+=4) + { + writel(0xa0a0a0a0, GIC_SPI_PRIO((i-32)>>2)); + } + /* set processor target */ + for (i=32; i<GIC_IRQ_NUM; i+=4) + { + writel(cpumask, GIC_SPI_PROC_TARG((i-32)>>2)); + } + /* disable all interrupts */ + for (i=32; i<GIC_IRQ_NUM; i+=32) + { + writel(0xffffffff, GIC_CLR_EN(i>>5)); + } + /* clear all interrupt active state */ + for (i=32; i<GIC_IRQ_NUM; i+=32) + { + writel(0xffffffff, GIC_ACT_CLR(i>>5)); + } + + writel(3, GIC_DIST_CON); + + + return ; +} +/* +************************************************************************************************************ +* +* function +* +* name : +* +* parmeters : +* +* return : +* +* note : +* +* +************************************************************************************************************ +*/ +void gic_cpuif_init(uint32_t addr) +{ + uint32_t i; + + writel(0, GIC_CPU_IF_CTRL); + /* + * Deal with the banked PPI and SGI interrupts - disable all + * PPI interrupts, ensure all SGI interrupts are enabled. + */ + writel(0xffff0000, GIC_CLR_EN(0)); + writel(0x0000ffff, GIC_SET_EN(0)); + /* Set priority on PPI and SGI interrupts */ + for (i=0; i<16; i+=4) + { + writel(0xa0a0a0a0, GIC_SGI_PRIO(i>>2)); + } + for (i=16; i<32; i+=4) + { + writel(0xa0a0a0a0, GIC_PPI_PRIO((i-16)>>2)); + } + + writel(0xf0, GIC_INT_PRIO_MASK); + + writel(0xb, GIC_CPU_IF_CTRL); + + return ; +} + +void gic_pcpu_distif_setup(unsigned int gicd_base) +{ + int i ; + /* Mark all 32 PPI interrupts as Group 1 (non-secure) */ + mmio_write_32(gicd_base + GICD_IGROUPR, 0xffffffffu); + + /* Setup PPI priorities doing four at a time */ + for (i = 0; i < 32; i += 4) + mmio_write_32(gicd_base + GICD_IPRIORITYR + i, 0xa0a0a0a0); +} + +void gic_setup(void) +{ + gic_cpuif_init(GICC_BASE); + gic_distributor_init(GICD_BASE); +} + +/******************************************************************************* + * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins. + * The interrupt controller knows which pin/line it uses to signal a type of + * interrupt. The platform knows which interrupt controller type is being used + * in a particular security state e.g. with an ARM GIC, normal world could use + * the GICv2 features while the secure world could use GICv3 features and vice + * versa. + * This function is exported by the platform to let the interrupt management + * framework determine for a type of interrupt and security state, which line + * should be used in the SCR_EL3 to control its routing to EL3. The interrupt + * line is represented as the bit position of the IRQ or FIQ bit in the SCR_EL3. + ******************************************************************************/ +uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state) +{ + assert(type == INTR_TYPE_S_EL1 || + type == INTR_TYPE_EL3 || + type == INTR_TYPE_NS); + + assert(sec_state_is_valid(security_state)); + + /* + * We ignore the security state parameter because Juno is GICv2 only + * so both normal and secure worlds are using ARM GICv2. + */ + return gicv2_interrupt_type_to_line(GICC_BASE, type); +} + +/******************************************************************************* + * This function returns the type of the highest priority pending interrupt at + * the GIC cpu interface. INTR_TYPE_INVAL is returned when there is no + * interrupt pending. + ******************************************************************************/ +uint32_t plat_ic_get_pending_interrupt_type(void) +{ + uint32_t id; + + id = gicc_read_hppir(GICC_BASE); + + /* Assume that all secure interrupts are S-EL1 interrupts */ + if (id < 1022) + return INTR_TYPE_S_EL1; + + if (id == GIC_SPURIOUS_INTERRUPT) + return INTR_TYPE_INVAL; + + return INTR_TYPE_NS; +} + +/******************************************************************************* + * This function returns the id of the highest priority pending interrupt at + * the GIC cpu interface. INTR_ID_UNAVAILABLE is returned when there is no + * interrupt pending. + ******************************************************************************/ +uint32_t plat_ic_get_pending_interrupt_id(void) +{ + uint32_t id; + + id = gicc_read_hppir(GICC_BASE); + + if (id < 1022) + return id; + + if (id == 1023) + return INTR_ID_UNAVAILABLE; + + /* + * Find out which non-secure interrupt it is under the assumption that + * the GICC_CTLR.AckCtl bit is 0. + */ + return gicc_read_ahppir(GICC_BASE); +} + +/******************************************************************************* + * This functions reads the GIC cpu interface Interrupt Acknowledge register + * to start handling the pending interrupt. It returns the contents of the IAR. + ******************************************************************************/ +uint32_t plat_ic_acknowledge_interrupt(void) +{ + return gicc_read_IAR(GICC_BASE); +} + +/******************************************************************************* + * This functions writes the GIC cpu interface End Of Interrupt register with + * the passed value to finish handling the active interrupt + ******************************************************************************/ +void plat_ic_end_of_interrupt(uint32_t id) +{ + gicc_write_EOIR(GICC_BASE, id); +} + +/******************************************************************************* + * This function returns the type of the interrupt id depending upon the group + * this interrupt has been configured under by the interrupt controller i.e. + * group0 or group1. + ******************************************************************************/ +uint32_t plat_ic_get_interrupt_type(uint32_t id) +{ + uint32_t group; + + group = gicd_get_igroupr(GICD_BASE, id); + + /* Assume that all secure interrupts are S-EL1 interrupts */ + if (group == GRP0) + return INTR_TYPE_S_EL1; + else + return INTR_TYPE_NS; +} diff --git a/plat/sun50iw1p1/plat_pm.c b/plat/sun50iw1p1/plat_pm.c new file mode 100644 index 0000000..f4f4e29 --- /dev/null +++ b/plat/sun50iw1p1/plat_pm.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2013, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <assert.h> +#include <arch_helpers.h> +#include <debug.h> +#include <errno.h> +#include <platform.h> +#include <platform_def.h> +#include <psci.h> +#include <mmio.h> +#include <bakery_lock.h> +#include "sunxi_def.h" +#include "sunxi_private.h" +#include "scpi.h" +#include "sunxi_cpu_ops.h" +#include <arisc.h> +#include <cci400.h> +#include <console.h> +#include <psci.h> + +bakery_lock_t plat_console_lock __attribute__ ((section("tzfw_coherent_mem"))); + +/******************************************************************************* + * Private Sunxi function to program the mailbox for a cpu before it is released + * from reset. + ******************************************************************************/ + +/******************************************************************************* + * Private Sunxi function which is used to determine if any platform actions + * should be performed for the specified affinity instance given its + * state. Nothing needs to be done if the 'state' is not off or if this is not + * the highest affinity level which will enter the 'state'. + ******************************************************************************/ +static int32_t sunxi_do_plat_actions(uint32_t afflvl, uint32_t state) +{ + uint32_t max_phys_off_afflvl; + + assert(afflvl <= MPIDR_MAX_AFFLVL); + + if (state != PSCI_STATE_OFF) + return -EAGAIN; + + /* + * Find the highest affinity level which will be suspended and postpone + * all the platform specific actions until that level is hit. + */ + max_phys_off_afflvl = psci_get_max_phys_off_afflvl(); + assert(max_phys_off_afflvl != PSCI_INVALID_DATA); + assert(psci_get_suspend_afflvl() >= max_phys_off_afflvl); + if (afflvl != max_phys_off_afflvl) + return -EAGAIN; + + return 0; +} + +/******************************************************************************* + * Sunxi handler called when an affinity instance is about to be turned on. The + * level and mpidr determine the affinity instance. + ******************************************************************************/ +int32_t sunxi_affinst_on(uint64_t mpidr, + uint64_t sec_entrypoint, + uint64_t ns_entrypoint, + uint32_t afflvl, + uint32_t state) +{ + /* + * SCP takes care of powering up higher affinity levels so we + * only need to care about level 0 + */ + if (afflvl != MPIDR_AFFLVL0) + return PSCI_E_SUCCESS; + + //INFO("mpidr:0x%llx, sec_entrypoint:0x%lx, ns_entrypoint:0x%lx, afflvl:0x%x, state:0x%x\n", + //mpidr, sec_entrypoint, ns_entrypoint, afflvl, state); + arisc_cpu_op(mpidr&0xff, sec_entrypoint, arisc_power_on, arisc_power_on); + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * Sunxi handler called when an affinity instance has just been powered on after + * being turned off earlier. The level and mpidr determine the affinity + * instance. The 'state' arg. allows the platform to decide whether the cluster + * was turned off prior to wakeup and do what's necessary to setup it up + * correctly. + ******************************************************************************/ +int32_t sunxi_affinst_on_finish(uint64_t mpidr, uint32_t afflvl, uint32_t state) +{ + /* Determine if any platform actions need to be executed. */ + if (sunxi_do_plat_actions(afflvl, state) == -EAGAIN) + return PSCI_E_SUCCESS; + + + /* + * Perform the common cluster specific operations i.e enable coherency + * if this cluster was off. + */ + if (afflvl != MPIDR_AFFLVL0) + { + //cci_enable_cluster_coherency(mpidr); + } + + // set smp bit before cache enable + platform_smp_init(); + + /* Enable the gic cpu interface */ + gic_cpuif_setup(GICC_BASE); + + /* Sunxi todo: Is this setup only needed after a cold boot? */ + gic_pcpu_distif_setup(GICD_BASE); + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * sunxi handler called when an affinity instance is about to enter standby. + ******************************************************************************/ +int sunxi_affinst_standby(unsigned int power_state) +{ + unsigned int target_afflvl; + uint64_t scr = 0; + + /* Sanity check the requested state */ + target_afflvl = psci_get_pstate_afflvl(power_state); + + /* + * * It's possible to enter standby only on affinity level 0 i.e. a cpu + * * on the FVP. Ignore any other affinity level. + * */ + if (target_afflvl != MPIDR_AFFLVL0) + return PSCI_E_INVALID_PARAMS; + + scr = read_scr_el3(); + /* enable physical IRQ bit for NS world to wakeup the CPU */ + write_scr_el3(scr | SCR_IRQ_BIT); + isb(); + + /* + * * Enter standby state + * * dsb is good practice before using wfi to enter low power states + * */ + dsb(); + wfi(); + + /* + * * Restore SCR to the original value, sync of scr_el3 is done + * * by eret while el3_exit to save some execution cycles. + * * */ + write_scr_el3(scr); + + return PSCI_E_SUCCESS; + +} + +/******************************************************************************* + * Common function called while turning a cpu off or suspending it. It is called + * from sunxi_off() or sunxi_suspend() when these functions in turn are called for + * the highest affinity level which will be powered down. It performs the + * actions common to the OFF and SUSPEND calls. + ******************************************************************************/ +static int32_t sunxi_power_down_common(uint32_t afflvl, uint64_t mpidr, uint64_t sec_entrypoint) +{ + uint32_t cluster_state = arisc_power_on; + + /* Prevent interrupts from spuriously waking up this cpu */ + gic_cpuif_deactivate(GICC_BASE); + + /* Cluster is to be turned off, so disable coherency */ + if (afflvl > MPIDR_AFFLVL0) { + //cci_disable_cluster_coherency(read_mpidr_el1()); + cluster_state = arisc_power_off; + } + + //INFO("afflvl:0x%x, mpidr:0x%lx, sec_entrypoint: %lx\n", + //afflvl, mpidr, sec_entrypoint); + arisc_cpu_op(mpidr&0xff, sec_entrypoint, scpi_power_off, cluster_state); + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * Handler called when an affinity instance is about to be turned off. The + * level and mpidr determine the affinity instance. The 'state' arg. allows the + * platform to decide whether the cluster is being turned off and take + * appropriate actions. + * + * CAUTION: There is no guarantee that caches will remain turned on across calls + * to this function as each affinity level is dealt with. So do not write & read + * global variables across calls. It will be wise to do flush a write to the + * global to prevent unpredictable results. + ******************************************************************************/ +static int32_t sunxi_affinst_off(uint64_t mpidr, uint32_t afflvl, uint32_t state) +{ + /* Determine if any platform actions need to be executed */ + if (sunxi_do_plat_actions(afflvl, state) == -EAGAIN) + return PSCI_E_SUCCESS; + + return sunxi_power_down_common(afflvl, mpidr, 0); +} + +/******************************************************************************* + * Handler called when an affinity instance is about to be suspended. The + * level and mpidr determine the affinity instance. The 'state' arg. allows the + * platform to decide whether the cluster is being turned off and take apt + * actions. The 'sec_entrypoint' determines the address in BL3-1 from where + * execution should resume. + * + * CAUTION: There is no guarantee that caches will remain turned on across calls + * to this function as each affinity level is dealt with. So do not write & read + * global variables across calls. It will be wise to do flush a write to the + * global to prevent unpredictable results. + ******************************************************************************/ +static int32_t sunxi_affinst_suspend(uint64_t mpidr, + uint64_t sec_entrypoint, + uint64_t ns_entrypoint, + uint32_t afflvl, + uint32_t state) +{ + /* Determine if any platform actions need to be executed */ + if (sunxi_do_plat_actions(afflvl, state) == -EAGAIN) + return PSCI_E_SUCCESS; + + if (afflvl == psci_get_suspend_afflvl()) + console_exit(); + + return sunxi_power_down_common(afflvl, mpidr, sec_entrypoint); +} + +/******************************************************************************* + * Sunxi handler called when an affinity instance has just been powered on after + * having been suspended earlier. The level and mpidr determine the affinity + * instance. + * TODO: At the moment we reuse the on finisher and reinitialize the secure + * context. Need to implement a separate suspend finisher. + ******************************************************************************/ +static int32_t sunxi_affinst_suspend_finish(uint64_t mpidr, + uint32_t afflvl, + uint32_t state) +{ + if ((afflvl == psci_get_suspend_afflvl()) && ((mpidr & 0xff) == 0x0)) { + gic_setup(); + console_init(SUNXI_UART0_BASE, UART0_CLK_IN_HZ, UART0_BAUDRATE); + arisc_cpux_ready_notify(); + + } + + return sunxi_affinst_on_finish(mpidr, afflvl, state); +} + +/******************************************************************************* + * Sunxi handlers to shutdown/reboot the system + ******************************************************************************/ +static void __dead2 sunxi_system_off(void) +{ + uint32_t response; + + /* Send the power down request to the SCP */ + response = arisc_system_op(arisc_system_shutdown); + + if (response != SCP_OK) { + ERROR("Sunxi System Off: SCP error %u.\n", response); + panic(); + } + wfi(); + ERROR("Sunxi System Off: operation not handled.\n"); + panic(); +} + +static void __dead2 sunxi_system_reset(void) +{ + uint32_t response; + + /* Send the system reset request to the SCP */ + response = arisc_system_op(scpi_system_reboot); + + if (response != SCP_OK) { + ERROR("Sunxi System Reset: SCP error %u.\n", response); + panic(); + } + wfi(); + ERROR("Sunxi System Reset: operation not handled.\n"); + panic(); +} + +/******************************************************************************* + * Export the platform handlers to enable psci to invoke them + ******************************************************************************/ +static const plat_pm_ops_t sunxi_ops = { + .affinst_standby = sunxi_affinst_standby, + .affinst_on = sunxi_affinst_on, + .affinst_on_finish = sunxi_affinst_on_finish, + .affinst_off = sunxi_affinst_off, + .affinst_suspend = sunxi_affinst_suspend, + .affinst_suspend_finish = sunxi_affinst_suspend_finish, + .system_off = sunxi_system_off, + .system_reset = sunxi_system_reset +}; + +/******************************************************************************* + * Export the platform specific power ops. + ******************************************************************************/ +int32_t platform_setup_pm(const plat_pm_ops_t **plat_ops) +{ + *plat_ops = &sunxi_ops; + bakery_lock_init(&plat_console_lock); + return 0; +} diff --git a/plat/sun50iw1p1/plat_topology.c b/plat/sun50iw1p1/plat_topology.c new file mode 100644 index 0000000..7b2426a --- /dev/null +++ b/plat/sun50iw1p1/plat_topology.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <assert.h> +#include <platform_def.h> +/* TODO: Reusing psci error codes & state information. Get our own! */ +#include <psci.h> + +/* We treat '255' as an invalid affinity instance */ +#define AFFINST_INVAL 0xff + +/******************************************************************************* + * We support 3 flavours of the FVP: Foundation, Base AEM & Base Cortex. Each + * flavour has a different topology. The common bit is that there can be a max. + * of 2 clusters (affinity 1) and 4 cpus (affinity 0) per cluster. So we define + * a tree like data structure which caters to these maximum bounds. It simply + * marks the absent affinity level instances as PSCI_AFF_ABSENT e.g. there is no + * cluster 1 on the Foundation FVP. The 'data' field is currently unused. + ******************************************************************************/ +typedef struct affinity_info { + unsigned char sibling; + unsigned char child; + unsigned char state; + unsigned int data; +} affinity_info_t; + +/******************************************************************************* + * The following two data structures store the topology tree for the fvp. There + * is a separate array for each affinity level i.e. cpus and clusters. The child + * and sibling references allow traversal inside and in between the two arrays. + ******************************************************************************/ +static affinity_info_t sunxi_aff2_topology_map[1]; +static affinity_info_t sunxi_aff1_topology_map[PLATFORM_CLUSTER_COUNT]; +static affinity_info_t sunxi_aff0_topology_map[PLATFORM_CORE_COUNT]; + +/* Simple global variable to safeguard us from stupidity */ +static unsigned int topology_setup_done; + +/******************************************************************************* + * This function implements a part of the critical interface between the psci + * generic layer and the platform to allow the former to detect the platform + * topology. psci queries the platform to determine how many affinity instances + * are present at a particular level for a given mpidr e.g. consider a dual + * cluster platform where each cluster has 4 cpus. A call to this function with + * (0, 0x100) will return the number of cpus implemented under cluster 1 i.e. 4. + * Similarly a call with (1, 0x100) will return 2 i.e. the number of clusters. + * This is 'cause we are effectively asking how many affinity level 1 instances + * are implemented under affinity level 2 instance 0. + ******************************************************************************/ +unsigned int plat_get_aff_count(unsigned int aff_lvl, + unsigned long mpidr) +{ + unsigned int aff_count = 1, ctr; + unsigned char parent_aff_id; + + assert(topology_setup_done == 1); + + switch (aff_lvl) { + case 3: + case 2: + /* + * Assert if the parent affinity instance is not 0. + * This also takes care of level 3 in an obfuscated way + */ + parent_aff_id = (mpidr >> MPIDR_AFF3_SHIFT) & MPIDR_AFFLVL_MASK; + assert(parent_aff_id == 0); + + /* Fetch the starting index in the aff1 array */ + for (ctr = 0; + sunxi_aff2_topology_map[ctr].sibling != AFFINST_INVAL; + ctr = sunxi_aff2_topology_map[ctr].sibling) { + aff_count++; + } + + /* + * Report that we implement a single instance of + * affinity levels 2 & 3 which are AFF_ABSENT + */ + break; + case 1: + /* Assert if the parent affinity instance is not 0. */ + parent_aff_id = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK; + assert(parent_aff_id == 0); + + /* Fetch the starting index in the aff1 array */ + for (ctr = 0; + sunxi_aff1_topology_map[ctr].sibling != AFFINST_INVAL; + ctr = sunxi_aff1_topology_map[ctr].sibling) { + aff_count++; + } + + break; + case 0: + /* Assert if the cluster id is anything apart from 0 or 1 */ + parent_aff_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + assert(parent_aff_id < PLATFORM_CLUSTER_COUNT); + + /* Fetch the starting index in the aff0 array */ + for (ctr = sunxi_aff1_topology_map[parent_aff_id].child; + sunxi_aff0_topology_map[ctr].sibling != AFFINST_INVAL; + ctr = sunxi_aff0_topology_map[ctr].sibling) { + aff_count++; + } + + break; + default: + assert(0); + } + + return aff_count; +} + +/******************************************************************************* + * This function implements a part of the critical interface between the psci + * generic layer and the platform to allow the former to detect the state of a + * affinity instance in the platform topology. psci queries the platform to + * determine whether an affinity instance is present or absent. This caters for + * topologies where an intermediate affinity level instance is missing e.g. + * consider a platform which implements a single cluster with 4 cpus and there + * is another cpu sitting directly on the interconnect along with the cluster. + * The mpidrs of the cluster would range from 0x0-0x3. The mpidr of the single + * cpu would be 0x100 to highlight that it does not belong to cluster 0. Cluster + * 1 is however missing but needs to be accounted to reach this single cpu in + * the topology tree. Hence it will be marked as PSCI_AFF_ABSENT. This is not + * applicable to the FVP but depicted as an example. + ******************************************************************************/ +unsigned int plat_get_aff_state(unsigned int aff_lvl, + unsigned long mpidr) +{ + unsigned int aff_state = PSCI_AFF_ABSENT, idx; + idx = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + + assert(topology_setup_done == 1); + + switch (aff_lvl) { + case 3: + case 2: + aff_state = sunxi_aff2_topology_map[0].state; + /* Report affinity levels 2 & 3 as absent */ + break; + case 1: + aff_state = sunxi_aff1_topology_map[idx].state; + break; + case 0: + /* + * First get start index of the aff0 in its array & then add + * to it the affinity id that we want the state of + */ + idx = sunxi_aff1_topology_map[idx].child; + idx += (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; + aff_state = sunxi_aff0_topology_map[idx].state; + break; + default: + assert(0); + } + + return aff_state; +} + +/******************************************************************************* + * Handy optimization to prevent the psci implementation from traversing through + * affinity levels which are not present while detecting the platform topology. + ******************************************************************************/ +int plat_get_max_afflvl(void) +{ + return MPIDR_MAX_AFFLVL; +} + +/******************************************************************************* + * This function populates the FVP specific topology information depending upon + * the FVP flavour its running on. We construct all the mpidrs we can handle + * and rely on the PWRC.PSYSR to flag absent cpus when their status is queried. + ******************************************************************************/ +int sunxi_setup_topology(void) +{ + unsigned char aff0, aff1, aff_state, aff0_offset = 0; + unsigned long mpidr; + + topology_setup_done = 0; + + sunxi_aff2_topology_map[0].child = 0; + sunxi_aff2_topology_map[0].sibling = AFFINST_INVAL; + sunxi_aff2_topology_map[0].state = PSCI_AFF_PRESENT; + + + for (aff1 = 0; aff1 < PLATFORM_CLUSTER_COUNT; aff1++) { + + sunxi_aff1_topology_map[aff1].child = aff0_offset; + sunxi_aff1_topology_map[aff1].sibling = aff1 + 1; + + for (aff0 = 0; aff0 < PLATFORM_MAX_CPUS_PER_CLUSTER; aff0++) { + + mpidr = aff1 << MPIDR_AFF1_SHIFT; + mpidr |= aff0 << MPIDR_AFF0_SHIFT; + + if (1) { + /* + * Presence of even a single aff0 indicates + * presence of parent aff1 on the FVP. + */ + aff_state = PSCI_AFF_PRESENT; + sunxi_aff1_topology_map[aff1].state = + PSCI_AFF_PRESENT; + } else { + aff_state = PSCI_AFF_ABSENT; + } + + sunxi_aff0_topology_map[aff0_offset].child = AFFINST_INVAL; + sunxi_aff0_topology_map[aff0_offset].state = aff_state; + sunxi_aff0_topology_map[aff0_offset].sibling = + aff0_offset + 1; + + /* Increment the absolute number of aff0s traversed */ + aff0_offset++; + } + + /* Tie-off the last aff0 sibling to -1 to avoid overflow */ + sunxi_aff0_topology_map[aff0_offset - 1].sibling = AFFINST_INVAL; + } + + /* Tie-off the last aff1 sibling to AFFINST_INVAL to avoid overflow */ + sunxi_aff1_topology_map[aff1 - 1].sibling = AFFINST_INVAL; + + topology_setup_done = 1; + return 0; +} diff --git a/plat/sun50iw1p1/platform.mk b/plat/sun50iw1p1/platform.mk new file mode 100644 index 0000000..b250d20 --- /dev/null +++ b/plat/sun50iw1p1/platform.mk @@ -0,0 +1,91 @@ +# +# Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. +# + +# Shared memory may be allocated at the top of Trusted SRAM (tsram) or at the +# base of Trusted SRAM (tdram) +SUNXI_SHARED_DATA_LOCATION := tdram +ifeq (${SUNXI_SHARED_DATA_LOCATION}, tsram) + SUNXI_SHARED_DATA_LOCATION_ID := SUNXI_IN_TRUSTED_SRAM +else ifeq (${SUNXI_SHARED_DATA_LOCATION}, tdram) + SUNXI_SHARED_DATA_LOCATION_ID := SUNXI_IN_TRUSTED_DRAM +else + $(error "Unsupported SUNXI_SHARED_DATA_LOCATION value") +endif + +# On FVP, the TSP can execute either from Trusted SRAM or Trusted DRAM. +# Trusted SRAM is the default. +SUNXI_TSP_RAM_LOCATION := tdram +ifeq (${SUNXI_TSP_RAM_LOCATION}, tsram) + SUNXI_TSP_RAM_LOCATION_ID := SUNXI_IN_TRUSTED_SRAM +else ifeq (${SUNXI_TSP_RAM_LOCATION}, tdram) + SUNXI_TSP_RAM_LOCATION_ID := SUNXI_IN_TRUSTED_DRAM +else + $(error "Unsupported SUNXI_TSP_RAM_LOCATION value") +endif + +ifeq (${SUNXI_SHARED_DATA_LOCATION}, tsram) + ifeq (${SUNXI_TSP_RAM_LOCATION}, tdram) + $(error Shared data in Trusted SRAM and TSP in Trusted DRAM is not supported) + endif +endif + +# Process flags +$(eval $(call add_define,SUNXI_SHARED_DATA_LOCATION_ID)) +$(eval $(call add_define,SUNXI_TSP_RAM_LOCATION_ID)) + +PLAT_INCLUDES := -Iplat/sun50iw1p1/include/ + + +PLAT_BL_COMMON_SOURCES := lib/aarch64/xlat_tables.c \ + plat/common/aarch64/plat_common.c \ + plat/sun50iw1p1/drivers/uart/uart.c \ + plat/sun50iw1p1/drivers/gpio/gpio.c + + + +BL31_SOURCES += drivers/arm/cci400/cci400.c \ + drivers/arm/gic/gic_v2.c \ + lib/cpus/aarch64/aem_generic.S \ + lib/cpus/aarch64/cortex_a53.S \ + lib/cpus/aarch64/cortex_a57.S \ + plat/common/aarch64/platform_mp_stack.S \ + plat/sun50iw1p1/bl31_sunxi_setup.c \ + plat/sun50iw1p1/plat_pm.c \ + plat/sun50iw1p1/plat_gic.c \ + plat/sun50iw1p1/mhu.c \ + plat/sun50iw1p1/scpi.c \ + plat/sun50iw1p1/sunxi_security.c \ + plat/sun50iw1p1/sunxi_cpu_ops.c \ + plat/sun50iw1p1/plat_topology.c \ + plat/sun50iw1p1/aarch64/plat_helpers.S \ + plat/sun50iw1p1/aarch64/sunxi_common.c \ + services/arm/arm_svc_setup.c + +include plat/${PLAT}/scp/arisc.mk diff --git a/plat/sun50iw1p1/scp/arisc.c b/plat/sun50iw1p1/scp/arisc.c new file mode 100644 index 0000000..1430b7e --- /dev/null +++ b/plat/sun50iw1p1/scp/arisc.c @@ -0,0 +1,248 @@ +/* + * drivers/arisc/arisc.c + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "arisc_i.h" + +/* local functions */ +static int arisc_wait_ready(unsigned int timeout); + +struct dts_cfg dts_cfg; +unsigned int arisc_debug_dram_crc_en = 0; +unsigned int arisc_debug_dram_crc_srcaddr = 0x40000000; +unsigned int arisc_debug_dram_crc_len = (1024 * 1024); +unsigned int arisc_debug_dram_crc_error = 0; +unsigned int arisc_debug_dram_crc_total_count = 0; +unsigned int arisc_debug_dram_crc_error_count = 0; +volatile const unsigned int arisc_debug_level = 2; +static unsigned char arisc_version[40] = "arisc defualt version"; + +static int arisc_wait_ready(unsigned int timeout) +{ + /* wait arisc startup ready */ + while (1) { + /* + * linux cpu interrupt is disable now, + * we should query message by hand. + */ + struct arisc_message *pmessage = arisc_hwmsgbox_query_message(); + if (pmessage == NULL) { + /* try to query again */ + continue; + } + /* query valid message */ + if (pmessage->type == ARISC_STARTUP_NOTIFY) { + /* check arisc software and driver version match or not */ + if (pmessage->paras[0] != ARISC_VERSIONS) { + ARISC_ERR("arisc firmware:%d and driver version:%u not matched\n", pmessage->paras[0], ARISC_VERSIONS); + return -EINVAL; + } else { + /* printf the main and sub version string */ + memcpy((void *)arisc_version, (const void*)(&(pmessage->paras[1])), 40); + ARISC_LOG("arisc version: [%s]\n", arisc_version); + } + + /* received arisc startup ready message */ + ARISC_INF("arisc startup ready\n"); + if ((pmessage->attr & ARISC_MESSAGE_ATTR_SOFTSYN) || + (pmessage->attr & ARISC_MESSAGE_ATTR_HARDSYN)) { + /* synchronous message, just feedback it */ + ARISC_INF("arisc startup notify message feedback\n"); + pmessage->paras[0] = (uint32_t)dts_cfg.image.base; + arisc_hwmsgbox_feedback_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + } else { + /* asyn message, free message directly */ + ARISC_INF("arisc startup notify message free directly\n"); + arisc_message_free(pmessage); + } + break; + } + /* + * invalid message detected, ignore it. + * by superm at 2012-7-6 18:34:38. + */ + ARISC_WRN("arisc startup waiting ignore message\n"); + if ((pmessage->attr & ARISC_MESSAGE_ATTR_SOFTSYN) || + (pmessage->attr & ARISC_MESSAGE_ATTR_HARDSYN)) { + /* synchronous message, just feedback it */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + } else { + /* asyn message, free message directly */ + arisc_message_free(pmessage); + } + /* we need waiting continue */ + } + + return 0; +} + +int sunxi_deassert_arisc(void) +{ + ARISC_INF("set arisc reset to de-assert state\n"); + { + volatile unsigned long value; + value = readl(dts_cfg.cpuscfg.base + 0x0); + value &= ~1; + writel(value, dts_cfg.cpuscfg.base + 0x0); + value = readl(dts_cfg.cpuscfg.base + 0x0); + value |= 1; + writel(value, dts_cfg.cpuscfg.base + 0x0); + } + + return 0; +} + +static int sunxi_arisc_para_init(struct arisc_para *para) +{ + /* init para */ + memset(para, 0, sizeof(struct arisc_para)); + para->message_pool_phys = (uint32_t)dts_cfg.space.msgpool_dst; + para->message_pool_size = (uint32_t)dts_cfg.space.msgpool_size; + para->standby_base = (uint32_t)dts_cfg.space.standby_dst; + para->standby_size = (uint32_t)dts_cfg.space.standby_size; + memcpy((void *)¶->vf, (void *)dts_cfg.vf, sizeof(para->vf)); + memcpy((void *)¶->dram_para, (void *)&dts_cfg.dram_para, sizeof(para->dram_para)); + para->power_key_code = dts_cfg.s_cir.power_key_code; + para->addr_code = dts_cfg.s_cir.addr_code; + para->suart_status = dts_cfg.s_uart.status; + para->pmu_bat_shutdown_ltf = dts_cfg.pmu.pmu_bat_shutdown_ltf; + para->pmu_bat_shutdown_htf = dts_cfg.pmu.pmu_bat_shutdown_htf; + para->pmu_pwroff_vol = dts_cfg.pmu.pmu_pwroff_vol; + para->power_start = dts_cfg.pmu.power_start; + para->powchk_used = dts_cfg.power.powchk_used; + para->power_reg = dts_cfg.power.power_reg; + para->system_power = dts_cfg.power.system_power; + + ARISC_LOG("arisc_para size:%llx\n", sizeof(struct arisc_para)); + ARISC_INF("msgpool base:%x, size:%u\n", para->message_pool_phys, + para->message_pool_size); + + return 0; +} + +uint32_t sunxi_load_arisc(uintptr_t image_addr, size_t image_size, void *para, size_t para_size) +{ + void *dst; + void *src; + size_t size; + +#if 0 + /* + * phys addr to virt addr + * io space: ioremap + * kernel space: phys_to_virt + */ + /* sram code space */ + dst = (void *)dts_cfg.space.sram_dst; + src = (void *)((ptrdiff_t)image_addr + (ptrdiff_t)dts_cfg.space.sram_offset); + size = dts_cfg.space.sram_size; + memset(dst, 0, size); + memcpy(dst, src, size); + flush_dcache_range((uint64_t)dst, (uint64_t)size); + + /* dram code space */ + dst = (void *)dts_cfg.space.dram_dst; + src = (void *)((ptrdiff_t)image_addr + (ptrdiff_t)dts_cfg.space.dram_offset); + size = dts_cfg.space.dram_size; + memset(dst, 0, size); + memcpy(dst, src, size); + flush_dcache_range((uint64_t)dst, (uint64_t)size); + + ARISC_INF("load arisc image finish\n"); +#endif + /* para space */ + dst = (void *)dts_cfg.space.para_dst; + src = para; + size = dts_cfg.space.para_size; + memset(dst, 0, size); + memcpy(dst, src, size); + ARISC_INF("setup arisc para finish\n"); + //dcsw_op_all(DCCISW); + flush_dcache_range((uint64_t)dst, (uint64_t)size); + isb(); + +#if 0 + /* relese arisc reset */ + sunxi_deassert_arisc(); + ARISC_INF("release arisc reset finish\n"); + + ARISC_INF("load arisc finish\n"); +#endif + + return 0; +} + +int sunxi_arisc_probe(void *cfg) +{ + struct arisc_para para; + + ARISC_LOG("sunxi-arisc driver begin startup %d\n", arisc_debug_level); + memcpy((void *)&dts_cfg, (const void *)cfg, sizeof(struct dts_cfg)); + + /* init arisc parameter */ + sunxi_arisc_para_init(¶); + + /* load arisc */ + sunxi_load_arisc(dts_cfg.image.base, dts_cfg.image.size, + (void *)(¶), sizeof(struct arisc_para)); + + /* initialize hwspinlock */ + ARISC_INF("hwspinlock initialize\n"); + arisc_hwspinlock_init(); + + /* initialize hwmsgbox */ + ARISC_INF("hwmsgbox initialize\n"); + arisc_hwmsgbox_init(); + + /* initialize message manager */ + ARISC_INF("message manager initialize start:0x%llx, size:0x%llx\n", dts_cfg.space.msgpool_dst, dts_cfg.space.msgpool_size); + arisc_message_manager_init((void *)dts_cfg.space.msgpool_dst, dts_cfg.space.msgpool_size); + + /* wait arisc ready */ + ARISC_INF("wait arisc ready....\n"); + if (arisc_wait_ready(10000)) { + ARISC_LOG("arisc startup failed\n"); + } + + arisc_set_paras(); + + /* enable arisc asyn tx interrupt */ + //arisc_hwmsgbox_enable_receiver_int(ARISC_HWMSGBOX_ARISC_ASYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); + + /* enable arisc syn tx interrupt */ + //arisc_hwmsgbox_enable_receiver_int(ARISC_HWMSGBOX_ARISC_SYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); + + /* arisc initialize succeeded */ + ARISC_LOG("sunxi-arisc driver v%s is starting\n", DRV_VERSION); + + return 0; +} + +int sunxi_arisc_wait_ready(void) +{ + ARISC_INF("wait arisc ready....\n"); + if (arisc_wait_ready(10000)) { + ARISC_LOG("arisc startup failed\n"); + } + arisc_set_paras(); + ARISC_LOG("sunxi-arisc driver v%s startup ok\n", DRV_VERSION); + return 0; +} + diff --git a/plat/sun50iw1p1/scp/arisc.mk b/plat/sun50iw1p1/scp/arisc.mk new file mode 100644 index 0000000..f75311c --- /dev/null +++ b/plat/sun50iw1p1/scp/arisc.mk @@ -0,0 +1,35 @@ +# +# Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. +# +BL31_SOURCES += plat/sun50iw1p1/scp/arisc.c + +include plat/sun50iw1p1/scp/hwmsgbox/hwmsgbox.mk +include plat/sun50iw1p1/scp/hwspinlock/hwspinlock.mk +include plat/sun50iw1p1/scp/message_manager/message_manager.mk +include plat/sun50iw1p1/scp/interfaces/interfaces.mk diff --git a/plat/sun50iw1p1/scp/arisc_i.h b/plat/sun50iw1p1/scp/arisc_i.h new file mode 100644 index 0000000..f44ffc1 --- /dev/null +++ b/plat/sun50iw1p1/scp/arisc_i.h @@ -0,0 +1,84 @@ +/* + * arch/arm/mach-sun6i/arisc/arisc_i.h + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ARISC_I_H__ +#define __ARISC_I_H__ + +//#include <asm/atomic.h> +//#include <asm/barrier.h> +//#include <asm/memory.h> +//#include <linux/arisc/arisc.h> +//#include <linux/sysfs.h> +//#include <linux/device.h> +//#include <linux/gpio.h> +//#include <linux/pinctrl/consumer.h> +//#include <linux/module.h> +//#include <linux/platform_device.h> +//#include <linux/delay.h> +//#include <linux/clk.h> +//#include <linux/arisc/arisc-notifier.h> +//#include <linux/of_address.h> +//#include <linux/of_irq.h> +//#include <linux/of_platform.h> + +#include "./include/arisc_includes.h" + +#define DRV_NAME "sunxi-arisc" +#define DEV_NAME "sunxi-arisc" + +#if defined CONFIG_ARCH_SUN8IW1P1 +#define DRV_VERSION "1.00" +#elif defined CONFIG_ARCH_SUN8IW3P1 +#define DRV_VERSION "1.01" +#elif defined CONFIG_ARCH_SUN8IW5P1 +#define DRV_VERSION "1.02" +#elif defined CONFIG_ARCH_SUN8IW6P1 +#define DRV_VERSION "1.03" +#elif defined CONFIG_ARCH_SUN8IW7P1 +#define DRV_VERSION "1.04" +#elif defined CONFIG_ARCH_SUN8IW9P1 +#define DRV_VERSION "1.05" +#elif defined CONFIG_ARCH_SUN50IW1P1 +#define DRV_VERSION "1.10" +#elif defined CONFIG_ARCH_SUN9IW1P1 +#define DRV_VERSION "2.00" +#else +#error "please select a platform\n" +#endif + +extern unsigned int arisc_debug_dram_crc_en; +extern unsigned int arisc_debug_dram_crc_srcaddr; +extern unsigned int arisc_debug_dram_crc_len; +extern unsigned int arisc_debug_dram_crc_error; +extern unsigned int arisc_debug_dram_crc_total_count; +extern unsigned int arisc_debug_dram_crc_error_count; +extern volatile const unsigned int arisc_debug_level; +extern struct standby_info_para arisc_powchk_back; + +//local functions +extern int arisc_config_dram_paras(void); +extern int arisc_sysconfig_ir_paras(void); +extern int arisc_config_pmu_paras(void); +extern int arisc_suspend_flag_query(void); +#if (defined CONFIG_ARCH_SUN8IW7P1) +extern void arisc_power_off(void); +#endif +#endif //__ARISC_I_H__ diff --git a/plat/sun50iw1p1/scp/hwmsgbox/hwmsgbox.c b/plat/sun50iw1p1/scp/hwmsgbox/hwmsgbox.c new file mode 100644 index 0000000..f1bc032 --- /dev/null +++ b/plat/sun50iw1p1/scp/hwmsgbox/hwmsgbox.c @@ -0,0 +1,291 @@ +/* + * arch/arm/mach-sunxi/arisc/hwmsgbox/hwmsgbox.c + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "hwmsgbox_i.h" + +/* spinlock for syn and asyn channel */ +static spinlock_t syn_channel_lock; +static spinlock_t asyn_channel_lock; +static uintptr_t base; + +/** + * initialize hwmsgbox. + * @para: none. + * + * returns: 0 if initialize hwmsgbox succeeded, others if failed. + */ +int arisc_hwmsgbox_init(void) +{ + base = dts_cfg.msgbox.base; + + /* initialize syn and asyn spinlock */ + //writel(0xffffffff, base + AW_MSGBOX_IRQ_STATUS_REG(AW_HWMSG_QUEUE_USER_AC327)); + //writel(0x0, base + AW_MSGBOX_IRQ_EN_REG(AW_HWMSG_QUEUE_USER_AC327)); + + return 0; +} + +/** + * exit hwmsgbox. + * @para: none. + * + * returns: 0 if exit hwmsgbox succeeded, others if failed. + */ +int arisc_hwmsgbox_exit(void) +{ + return 0; +} + +/** + * send one message to another processor by hwmsgbox. + * @pmessage: the pointer of sended message frame. + * @timeout: the wait time limit when message fifo is full, it is valid only when parameter mode = HWMSG_SEND_WAIT_TIMEOUT. + * + * returns: 0 if send message succeeded, other if failed. + */ +int arisc_hwmsgbox_send_message(struct arisc_message *pmessage, unsigned int timeout) +{ + volatile uint32_t value; + + if (pmessage == NULL) { + return -EINVAL; + } + if (pmessage->attr & ARISC_MESSAGE_ATTR_HARDSYN) { + /* use ac327 hwsyn transmit channel */ + spin_lock(&syn_channel_lock); + while (readl(base + AW_MSGBOX_FIFO_STATUS_REG(ARISC_HWMSGBOX_AC327_SYN_TX_CH)) == 1); + + value = arisc_message_map_to_cpus(pmessage); + ARISC_INF("ac327 send hard syn message : %x\n", (unsigned int)value); + writel(value, base + AW_MSGBOX_MSG_REG(ARISC_HWMSGBOX_AC327_SYN_TX_CH)); + + /* hwsyn messsage must feedback use syn rx channel */ + while (readl(base + AW_MSGBOX_MSG_STATUS_REG(ARISC_HWMSGBOX_AC327_SYN_RX_CH)) == 0); + + /* check message valid */ + if (value != (readl(base + AW_MSGBOX_MSG_REG(ARISC_HWMSGBOX_AC327_SYN_RX_CH)))) { + ARISC_ERR("hard syn message error [%x, %x]\n", (uint32_t)value, (uint32_t)(readl(base + AW_MSGBOX_MSG_REG(ARISC_HWMSGBOX_AC327_SYN_RX_CH)))); + spin_unlock(&syn_channel_lock); + return -EINVAL; + } + ARISC_INF("ac327 hard syn message [%x, %x] feedback\n", (unsigned int)value, (unsigned int)pmessage->type); + /* if error call the callback function. by superm */ + if(pmessage->result != 0) { + ARISC_ERR("message process error\n"); + ARISC_ERR("message addr : %llx\n", pmessage); + ARISC_ERR("message state : %x\n", pmessage->state); + ARISC_ERR("message attr : %x\n", pmessage->attr); + ARISC_ERR("message type : %x\n", pmessage->type); + ARISC_ERR("message result : %x\n", pmessage->result); + if (pmessage->cb.handler == NULL) { + ARISC_WRN("callback not install\n"); + } else { + /* call callback function */ + ARISC_WRN("call the callback function\n"); + (*(pmessage->cb.handler))(pmessage->cb.arg); + } + } + spin_unlock(&syn_channel_lock); + return 0; + } + + /* use ac327 asyn transmit channel */ + spin_lock(&asyn_channel_lock); + while (readl(base + AW_MSGBOX_FIFO_STATUS_REG(ARISC_HWMSGBOX_ARISC_ASYN_RX_CH)) == 1); + + /* write message to message-queue fifo */ + value = arisc_message_map_to_cpus(pmessage); + ARISC_INF("ac327 send message : %x\n", (unsigned int)value); + writel(value, base + AW_MSGBOX_MSG_REG(ARISC_HWMSGBOX_ARISC_ASYN_RX_CH)); + spin_unlock(&asyn_channel_lock); + + return 0; +} + +int arisc_hwmsgbox_feedback_message(struct arisc_message *pmessage, unsigned int timeout) +{ + volatile unsigned long value; + + if (pmessage->attr & ARISC_MESSAGE_ATTR_HARDSYN) { + /* use ac327 hard syn receiver channel */ + spin_lock(&syn_channel_lock); + while (readl(base + AW_MSGBOX_FIFO_STATUS_REG(ARISC_HWMSGBOX_ARISC_SYN_RX_CH)) == 1); + + value = arisc_message_map_to_cpus(pmessage); + ARISC_INF("arisc feedback hard syn message : %x\n", (unsigned int)value); + writel(value, base + AW_MSGBOX_MSG_REG(ARISC_HWMSGBOX_ARISC_SYN_RX_CH)); + spin_unlock(&syn_channel_lock); + + return 0; + } + + /* invalid syn message */ + return -EINVAL; +} + +/** + * enbale the receiver interrupt of message-queue. + * @queue: the number of message-queue which we want to enable interrupt. + * @user: the user which we want to enable interrupt. + * + * returns: 0 if enable interrupt succeeded, others if failed. + */ +int arisc_hwmsgbox_enable_receiver_int(int queue, int user) +{ + volatile unsigned int value; + + value = readl(base + AW_MSGBOX_IRQ_EN_REG(user)); + value &= ~(0x1 << (queue * 2)); + value |= (0x1 << (queue * 2)); + writel(value, base + AW_MSGBOX_IRQ_EN_REG(user)); + + return 0; +} + +/** + * disbale the receiver interrupt of message-queue. + * @queue: the number of message-queue which we want to enable interrupt. + * @user: the user which we want to enable interrupt. + * + * returns: 0 if disable interrupt succeeded, others if failed. + */ +int arisc_hwmsgbox_disable_receiver_int(int queue, int user) +{ + volatile unsigned int value; + + value = readl(base + AW_MSGBOX_IRQ_EN_REG(user)); + value &= ~(0x1 << (queue * 2)); + writel(value, base + AW_MSGBOX_IRQ_EN_REG(user)); + + return 0; +} + +/** + * query the receiver interrupt pending of message-queue. + * @queue: the number of message-queue which we want to query. + * @user: the user which we want to query. + * + * returns: 0 if query pending succeeded, others if failed. + */ +int arisc_hwmsgbox_query_receiver_pending(int queue, int user) +{ + volatile unsigned long value; + + value = readl(base + (AW_MSGBOX_IRQ_STATUS_REG(user))); + + return value & (0x1 << (queue * 2)); +} + +/** + * clear the receiver interrupt pending of message-queue. + * @queue: the number of message-queue which we want to clear. + * @user: the user which we want to clear. + * + * returns: 0 if clear pending succeeded, others if failed. + */ +int arisc_hwmsgbox_clear_receiver_pending(int queue, int user) +{ + writel((0x1 << (queue * 2)), base + AW_MSGBOX_IRQ_STATUS_REG(user)); + + return 0; +} + +/** + * query message of hwmsgbox by hand, mainly for. + * @para: none. + * + * returns: the point of message, NULL if timeout. + */ +struct arisc_message *arisc_hwmsgbox_query_message(void) +{ + struct arisc_message *pmessage = NULL; + + /* query ac327 asyn received channel */ + if (readl(base + AW_MSGBOX_MSG_STATUS_REG(ARISC_HWMSGBOX_ARISC_ASYN_TX_CH))) { + volatile unsigned long value; + value = readl(base + AW_MSGBOX_MSG_REG(ARISC_HWMSGBOX_ARISC_ASYN_TX_CH)); + pmessage = arisc_message_map_to_cpux(value); + + if (arisc_message_valid(pmessage)) { + /* message state switch */ + if (pmessage->state == ARISC_MESSAGE_PROCESSED) { + /* ARISC_MESSAGE_PROCESSED->ARISC_MESSAGE_FEEDBACKED */ + pmessage->state = ARISC_MESSAGE_FEEDBACKED; + } else { + /* ARISC_MESSAGE_INITIALIZED->ARISC_MESSAGE_RECEIVED */ + pmessage->state = ARISC_MESSAGE_RECEIVED; + } + } else { + ARISC_ERR("invalid asyn message received: pmessage = 0x%llx. \n", pmessage); + return NULL; + } + /* clear pending */ + arisc_hwmsgbox_clear_receiver_pending(ARISC_HWMSGBOX_ARISC_ASYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); + return pmessage; + } + /* query ac327 syn received channel */ + if (readl(base + AW_MSGBOX_MSG_STATUS_REG(ARISC_HWMSGBOX_ARISC_SYN_TX_CH))) { + volatile unsigned long value; + value = readl(base + AW_MSGBOX_MSG_REG(ARISC_HWMSGBOX_ARISC_SYN_TX_CH)); + pmessage = arisc_message_map_to_cpux(value); + if (arisc_message_valid(pmessage)) { + /* message state switch */ + if (pmessage->state == ARISC_MESSAGE_PROCESSED) { + /* ARISC_MESSAGE_PROCESSED->ARISC_MESSAGE_FEEDBACKED */ + pmessage->state = ARISC_MESSAGE_FEEDBACKED; + } else { + /* ARISC_MESSAGE_INITIALIZED->ARISC_MESSAGE_RECEIVED */ + pmessage->state = ARISC_MESSAGE_RECEIVED; + } + } else { + ARISC_ERR("invalid syn message received: pmessage = 0x%llx. \n", pmessage); + arisc_hwmsgbox_clear_receiver_pending(ARISC_HWMSGBOX_ARISC_SYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); + return NULL; + } + arisc_hwmsgbox_clear_receiver_pending(ARISC_HWMSGBOX_ARISC_SYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); + return pmessage; + } + + /* no valid message now */ + return NULL; +} + +int arisc_hwmsgbox_standby_suspend(void) +{ + /* enable arisc asyn tx interrupt */ + //arisc_hwmsgbox_disable_receiver_int(ARISC_HWMSGBOX_ARISC_ASYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); + + /* enable arisc syn tx interrupt */ + //arisc_hwmsgbox_disable_receiver_int(ARISC_HWMSGBOX_ARISC_SYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); + + return 0; +} + +int arisc_hwmsgbox_standby_resume(void) +{ + /* enable arisc asyn tx interrupt */ + //arisc_hwmsgbox_enable_receiver_int(ARISC_HWMSGBOX_ARISC_ASYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); + + /* enable arisc syn tx interrupt */ + //arisc_hwmsgbox_enable_receiver_int(ARISC_HWMSGBOX_ARISC_SYN_TX_CH, AW_HWMSG_QUEUE_USER_AC327); + + return 0; +} diff --git a/plat/sun50iw1p1/scp/hwmsgbox/hwmsgbox.mk b/plat/sun50iw1p1/scp/hwmsgbox/hwmsgbox.mk new file mode 100644 index 0000000..aebb5ec --- /dev/null +++ b/plat/sun50iw1p1/scp/hwmsgbox/hwmsgbox.mk @@ -0,0 +1,31 @@ +# +# Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. +# + +BL31_SOURCES += plat/sun50iw1p1/scp/hwmsgbox/hwmsgbox.c diff --git a/plat/sun50iw1p1/scp/hwmsgbox/hwmsgbox_i.h b/plat/sun50iw1p1/scp/hwmsgbox/hwmsgbox_i.h new file mode 100644 index 0000000..ffee2a9 --- /dev/null +++ b/plat/sun50iw1p1/scp/hwmsgbox/hwmsgbox_i.h @@ -0,0 +1,46 @@ +/* + * arch/arm/mach-sunxi/arisc/hwmsgbox/hwmsgbox_i.h + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ARISC_HWMSGBOX_I_H +#define __ARISC_HWMSGBOX_I_H + +#include "../include/arisc_includes.h" + +//hardware message-box register list +#define AW_MSGBOX_CTRL_REG(m) (0x0000 + (0x4 * (m>>2))) +#define AW_MSGBOX_IRQ_EN_REG(u) (0x0040 + (0x20* u)) +#define AW_MSGBOX_IRQ_STATUS_REG(u) (0x0050 + (0x20* u)) +#define AW_MSGBOX_FIFO_STATUS_REG(m) (0x0100 + (0x4 * m)) +#define AW_MSGBOX_MSG_STATUS_REG(m) (0x0140 + (0x4 * m)) +#define AW_MSGBOX_MSG_REG(m) (0x0180 + (0x4 * m)) +#define AW_MSGBOX_DEBUG_REG (0x01c0) + +/* local functions */ +int arisc_hwmsgbox_clear_receiver_pending(int queue, int user); +int arisc_hwmsgbox_query_receiver_pending(int queue, int user); +int arisc_hwmsgbox_enable_receiver_int(int queue, int user); +int arisc_hwmsgbox_set_receiver(int queue, int user); +int arisc_hwmsgbox_set_transmitter(int queue, int user); +int arisc_hwmsgbox_wait_message_feedback(struct arisc_message *pmessage); +int arisc_hwmsgbox_message_feedback(struct arisc_message *pmessage); +int arisc_message_valid(struct arisc_message *pmessage); + +#endif /* __ARISC_HWMSGBOX_I_H */ diff --git a/plat/sun50iw1p1/scp/hwspinlock/hwspinlock.c b/plat/sun50iw1p1/scp/hwspinlock/hwspinlock.c new file mode 100644 index 0000000..863d457 --- /dev/null +++ b/plat/sun50iw1p1/scp/hwspinlock/hwspinlock.c @@ -0,0 +1,109 @@ +/* + * arch/arm/mach-sunxi/arisc/hwspinlock/hwspinlock.c + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "hwspinlock_i.h" + +static struct arisc_hwspinlock arisc_hwspinlocks[ARISC_HW_SPINLOCK_NUM]; +static uintptr_t base; + +/** + * initialize hwspinlock. + * @para: none. + * + * returns: 0 if initialize hwspinlock succeeded, others if failed. + */ +int arisc_hwspinlock_init(void) +{ + base = dts_cfg.hwspinlock.base; + + return 0; +} + +/** + * exit hwspinlock. + * @para:none. + * + * returns: 0 if exit hwspinlock succeeded, others if failed. + */ +int arisc_hwspinlock_exit(void) +{ + return 0; +} + +/** + * lock an hwspinlock with timeout limit, + * and hwspinlock will be unlocked in arisc_hwspin_unlock(). + * @hwid: an hwspinlock id which we want to lock. + * + * returns: 0 if lock hwspinlock succeeded, other if failed. + */ +int arisc_hwspin_lock(int hwid) +{ + arisc_hwspinlock_t *spinlock; + + if (hwid >= ARISC_HW_SPINLOCK_NUM) { + ARISC_ERR("invalid hwspinlock id [%d] for trylock\n", hwid); + return -EINVAL; + } + spinlock = &(arisc_hwspinlocks[hwid]); + + /* is lock already taken by another context on the local cpu ? */ + spin_lock(&(spinlock->lock)); + + /* try to take spinlock */ + while (readl(base + AW_SPINLOCK_LOCK_REG(hwid)) == AW_SPINLOCK_TAKEN); + + return 0; +} + +/** + * unlock a specific hwspinlock. + * hwid: an hwspinlock id which we want to unlock. + * + * returns: 0 if unlock hwspinlock succeeded, other if failed. + */ +int arisc_hwspin_unlock(int hwid) +{ + arisc_hwspinlock_t *spinlock; + + if (hwid >= ARISC_HW_SPINLOCK_NUM) { + ARISC_ERR("invalid hwspinlock id [%d] for unlock\n", hwid); + return -EINVAL; + } + spinlock = &(arisc_hwspinlocks[hwid]); + + /* untaken the spinlock */ + writel(0x0, base + AW_SPINLOCK_LOCK_REG(hwid)); + + spin_unlock(&(spinlock->lock)); + + return 0; +} + +int arisc_hwspinlock_standby_suspend(void) +{ + return 0; +} + +int arisc_hwspinlock_standby_resume(void) +{ + return 0; +} diff --git a/plat/sun50iw1p1/scp/hwspinlock/hwspinlock.mk b/plat/sun50iw1p1/scp/hwspinlock/hwspinlock.mk new file mode 100644 index 0000000..2c5ee59 --- /dev/null +++ b/plat/sun50iw1p1/scp/hwspinlock/hwspinlock.mk @@ -0,0 +1,31 @@ +# +# Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. +# + +BL31_SOURCES += plat/sun50iw1p1/scp/hwspinlock/hwspinlock.c diff --git a/plat/sun50iw1p1/scp/hwspinlock/hwspinlock_i.h b/plat/sun50iw1p1/scp/hwspinlock/hwspinlock_i.h new file mode 100644 index 0000000..231d7ee --- /dev/null +++ b/plat/sun50iw1p1/scp/hwspinlock/hwspinlock_i.h @@ -0,0 +1,48 @@ +/* + * arch/arm/mach-sunxi/arisc/hwspinlock/hwspinlock-i.h + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __HW_SPINLOCK_I_H +#define __HW_SPINLOCK_I_H + +#include "../include/arisc_includes.h" + +/* the used state of spinlock */ +#define SPINLOCK_FREE (0) +#define SPINLOCK_USED (1) + +//the taken ot not state of spinlock +#define AW_SPINLOCK_NOTTAKEN (0) +#define AW_SPINLOCK_TAKEN (1) + +//hardware spinlock register list +#define AW_SPINLOCK_SYS_STATUS_REG (0x0000) +#define AW_SPINLOCK_STATUS_REG (0x0010) +#define AW_SPINLOCK_IRQ_EN_REG (0x0020) +#define AW_SPINLOCK_IRQ_PEND_REG (0x0040) +#define AW_SPINLOCK_LOCK_REG(id) (0x0100 + id * 4) + +typedef struct arisc_hwspinlock +{ + unsigned long flags; + spinlock_t lock; +} arisc_hwspinlock_t; + +#endif /* __HW_SPINLOCK_I_H */ diff --git a/plat/sun50iw1p1/scp/include/arisc_cfgs.h b/plat/sun50iw1p1/scp/include/arisc_cfgs.h new file mode 100644 index 0000000..32234ba --- /dev/null +++ b/plat/sun50iw1p1/scp/include/arisc_cfgs.h @@ -0,0 +1,74 @@ +/* + * arch/arm/mach-sunxi/arisc/include/arisc_cfgs.h + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ARISC_CFGS_H +#define __ARISC_CFGS_H + +/* arisc software version number */ +#if defined CONFIG_ARCH_SUN8IW1P1 +#define ARISC_VERSIONS (100) +#elif defined CONFIG_ARCH_SUN8IW3P1 +#define ARISC_VERSIONS (101) +#elif defined CONFIG_ARCH_SUN8IW5P1 +#define ARISC_VERSIONS (102) +#elif defined CONFIG_ARCH_SUN8IW6P1 +#define ARISC_VERSIONS (103) +#elif defined CONFIG_ARCH_SUN8IW7P1 +#define ARISC_VERSIONS (104) +#elif defined CONFIG_ARCH_SUN8IW9P1 +#define ARISC_VERSIONS (105) +#elif defined CONFIG_ARCH_SUN50IW1P1 +#define ARISC_VERSIONS (110) +#elif defined CONFIG_ARCH_SUN9IW1P1 +#define ARISC_VERSIONS (200) +#else +#error "please select a platform\n" +#endif + +/* debugger system */ +#define ARISC_DEBUG_ON +#define ARISC_DEBUG_LEVEL (3) /* debug level */ + +/* the max number of cached message frame */ +#define ARISC_MESSAGE_CACHED_MAX (4) + +/* spinlock max timeout, base on ms */ +#define ARISC_SPINLOCK_TIMEOUT (100) + +/* send message max timeout, base on ms */ +#define ARISC_SEND_MSG_TIMEOUT (4000) + +/* hwmsgbox channels configure */ +#define ARISC_HWMSGBOX_ARISC_ASYN_TX_CH (0) +#define ARISC_HWMSGBOX_ARISC_ASYN_RX_CH (1) +#define ARISC_HWMSGBOX_ARISC_SYN_TX_CH (2) +#define ARISC_HWMSGBOX_ARISC_SYN_RX_CH (3) +#define ARISC_HWMSGBOX_AC327_SYN_TX_CH (4) +#define ARISC_HWMSGBOX_AC327_SYN_RX_CH (5) + +/* dvfs config */ +#define ARISC_DVFS_VF_TABLE_MAX (16) +/* ir config */ +#define ARISC_IR_KEY_SUP_NUM (8) /* the number of IR remote support */ + +#define ARISC_DEV_CLKSRC_NUM (4) /* the number of dev clocksource support */ + +#endif /* __ARISC_CFGS_H */ diff --git a/plat/sun50iw1p1/scp/include/arisc_dbgs.h b/plat/sun50iw1p1/scp/include/arisc_dbgs.h new file mode 100644 index 0000000..aef8f5e --- /dev/null +++ b/plat/sun50iw1p1/scp/include/arisc_dbgs.h @@ -0,0 +1,66 @@ +/* + * arch/arm/mach-sunxi/arisc/include/arisc_dbgs.h + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ARISC_DBGS_H +#define __ARISC_DBGS_H + +/* + * debug level define, + * level 0 : dump debug information--none; + * level 1 : dump debug information--error; + * level 2 : dump debug information--error+warning; + * level 3 : dump debug information--error+warning+information; + * extern void printk(const char *, ...); + */ +#ifdef ARISC_DEBUG_ON +/* debug levels */ +#define DEBUG_LEVEL_INF ((uint32_t)1 << 0) +#define DEBUG_LEVEL_LOG ((uint32_t)1 << 1) +#define DEBUG_LEVEL_WRN ((uint32_t)1 << 2) +#define DEBUG_LEVEL_ERR ((uint32_t)1 << 3) + +#define ARISC_INF(format, args...) \ + if(DEBUG_LEVEL_INF & (0xf0 >> (arisc_debug_level +1))) \ + tf_printf("[SCP] :"format, ##args); + +#define ARISC_LOG(format, args...) \ + if(DEBUG_LEVEL_LOG & (0xf0 >> (arisc_debug_level +1))) \ + tf_printf("[SCP] :"format, ##args); + +#define ARISC_WRN(format, args...) \ + if(DEBUG_LEVEL_WRN & (0xf0 >> (arisc_debug_level +1))) \ + tf_printf("[SCP WARING] :"format, ##args); + +#define ARISC_ERR(format, args...) \ + if(DEBUG_LEVEL_ERR & (0xf0 >> (arisc_debug_level +1))) \ + tf_printf("[SCP ERROR] :"format, ##args); + +#else /* ARISC_DEBUG_ON */ +#define ARISC_INF(...) +#define ARISC_WRN(...) +#define ARISC_ERR(...) +#define ARISC_LOG(...) +#endif /* ARISC_DEBUG_ON */ + +/* report error information id */ +#define ERR_NMI_INT_TIMEOUT (0x1) + +#endif /* __ARISC_DBGS_H */ diff --git a/plat/sun50iw1p1/scp/include/arisc_hwmsgbox.h b/plat/sun50iw1p1/scp/include/arisc_hwmsgbox.h new file mode 100644 index 0000000..4bab7bc --- /dev/null +++ b/plat/sun50iw1p1/scp/include/arisc_hwmsgbox.h @@ -0,0 +1,77 @@ +/* + * arch/arm/mach-sunxi/arisc/include/arisc_hwmsgbox.h + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ARISC_HWMSGBOX_H +#define __ARISC_HWMSGBOX_H + +//the number of hardware message queue. +#define AW_HWMSG_QUEUE_NUMBER (8) + +//the user of hardware message queue. +typedef enum aw_hwmsg_queue_user +{ + AW_HWMSG_QUEUE_USER_ARISC, //arisc + AW_HWMSG_QUEUE_USER_AC327, //cpu0 +} aw_hwmsg_queue_user_e; + +/** + * initialize hwmsgbox. + * @para: none. + * + * returns: OK if initialize hwmsgbox succeeded, others if failed. + */ +int arisc_hwmsgbox_init(void); + +/** + * exit hwmsgbox. + * @para: none. + * + * returns: OK if exit hwmsgbox succeeded, others if failed. + */ +int arisc_hwmsgbox_exit(void); + +/** + * send one message to another processor by hwmsgbox. + * @pmessage: the pointer of sended message frame. + * @timeout: the wait time limit when message fifo is full, + * it is valid only when parameter mode = SEND_MESSAGE_WAIT_TIMEOUT. + * + * returns: OK if send message succeeded, other if failed. + */ +int arisc_hwmsgbox_send_message(struct arisc_message *pmessage, unsigned int timeout); + +/** + * Description: query message of hwmsgbox by hand, mainly for. + * @para: none. + * + * returns: the point of message, NULL if timeout. + */ +struct arisc_message *arisc_hwmsgbox_query_message(void); + +int arisc_hwmsgbox_enable_receiver_int(int queue, int user); +int arisc_hwmsgbox_disable_receiver_int(int queue, int user); + +int arisc_hwmsgbox_feedback_message(struct arisc_message *pmessage, unsigned int timeout); + +int arisc_hwmsgbox_standby_resume(void); +int arisc_hwmsgbox_standby_suspend(void); + +#endif /* __ARISC_HWMSGBOX_H */ diff --git a/plat/sun50iw1p1/scp/include/arisc_hwspinlock.h b/plat/sun50iw1p1/scp/include/arisc_hwspinlock.h new file mode 100644 index 0000000..2b34276 --- /dev/null +++ b/plat/sun50iw1p1/scp/include/arisc_hwspinlock.h @@ -0,0 +1,63 @@ +/* + * arch/arm/mach-sunxi/arisc/include/arisc_hwspinlock.h + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ARISC_HW_SPINLOCK_H +#define __ARISC_HW_SPINLOCK_H + +/* the max number of hardware spinlock */ +#define ARISC_HW_SPINLOCK_NUM (32) + +/** + * initialize hwspinlock. + * @para: none. + * + * returns: OK if initialize hwspinlock succeeded, others if failed. + */ +int arisc_hwspinlock_init(void); + +/** + * exit hwspinlock. + * @para: none. + * + * returns: OK if exit hwspinlock succeeded, others if failed. + */ +int arisc_hwspinlock_exit(void); + +/** + * lock an hwspinlock with timeout limit. + * @hwid : an hwspinlock id which we want to lock. + * + * returns: OK if lock hwspinlock succeeded, other if failed. + */ +int arisc_hwspin_lock(int hwid); + +/** + * unlock a specific hwspinlock. + * @hwid : an hwspinlock id which we want to unlock. + * + * returns: OK if unlock hwspinlock succeeded, other if failed. + */ +int arisc_hwspin_unlock(int hwid); + +int arisc_hwspinlock_standby_suspend(void); +int arisc_hwspinlock_standby_resume(void); + +#endif /* __ARISC_HW_SPINLOCK_H */ diff --git a/plat/sun50iw1p1/scp/include/arisc_includes.h b/plat/sun50iw1p1/scp/include/arisc_includes.h new file mode 100644 index 0000000..571c90c --- /dev/null +++ b/plat/sun50iw1p1/scp/include/arisc_includes.h @@ -0,0 +1,92 @@ +/* + * arch/arm/mach-sunxi/arisc/include/arisc_includes.h + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ARISC_INCLUDES_H +#define __ARISC_INCLUDES_H + +//#include <linux/kernel.h> +//#include <linux/module.h> +//#include <linux/string.h> +//#include <linux/spinlock.h> +//#include <linux/err.h> +//#include <linux/io.h> +//#include <linux/slab.h> +//#include <linux/semaphore.h> +//#include <linux/interrupt.h> +//#include <linux/jiffies.h> +//#include <linux/delay.h> +//#include <linux/arisc/hwmsgbox.h> +//#include <linux/arisc/hwspinlock.h> +#define CONFIG_ARCH_SUN50IW1P1 + +#include <arch_helpers.h> +#include <platform.h> +#include <platform_def.h> +#include <bakery_lock.h> +#include <mmio.h> +#include <debug.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <psci.h> +#include <bakery_lock.h> +#include <spinlock.h> +#include <arisc.h> + +#include "../../sunxi_private.h" +#include "../../sunxi_cpu_ops.h" +#include "../../sunxi_def.h" +#include "../../mhu.h" +#include "../../scpi.h" +#include "../../sun50iw1p1.h" + +/* configure and debugger */ +#include "../arisc_i.h" +#include "./arisc_cfgs.h" +#include "./arisc_dbgs.h" +#include "./arisc_para.h" + +/* messages define */ +#include "./arisc_messages.h" +#include "./arisc_message_manager.h" + +/* driver headers */ +#include "./arisc_hwmsgbox.h" +#include "./arisc_hwspinlock.h" + +#define readl(x) mmio_read_32((x)) +#define writel(v, a) mmio_write_32((a), (v)) + +/* global functions */ +extern int arisc_axp_int_notify(struct arisc_message *pmessage); +extern int arisc_audio_perdone_notify(struct arisc_message *pmessage); +extern int arisc_dvfs_cfg_vf_table(void); +extern int arisc_query_set_standby_info(struct standby_info_para *para, arisc_rw_type_e op); +extern int arisc_sysconfig_sstpower_paras(void); +extern int arisc_report_error_info(struct arisc_message *pmessage); + +/* global vars */ +extern unsigned long arisc_sram_a2_base; +extern struct dts_cfg dts_cfg; + +#endif /* __ARISC_INCLUDES_H */ diff --git a/plat/sun50iw1p1/scp/include/arisc_message_manager.h b/plat/sun50iw1p1/scp/include/arisc_message_manager.h new file mode 100644 index 0000000..5b80596 --- /dev/null +++ b/plat/sun50iw1p1/scp/include/arisc_message_manager.h @@ -0,0 +1,73 @@ +/* + * arch/arm/mach-sunxi/arisc/include/arisc_message_manager.h + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ARISC_MESSAGE_MANAGER_H +#define __ARISC_MESSAGE_MANAGER_H + +/** + * initialize message manager. + * @para: none. + * + * returns: OK if initialize succeeded, others if failed. + */ +int arisc_message_manager_init(void *addr, uint32_t size); + +/** + * exit message manager. + * para: none. + * + * returns: OK if exit succeeded, others if failed. + */ +int arisc_message_manager_exit(void); + +/** + * allocate one message frame. mainly use for send message by message-box, + * the message frame allocate form messages pool shared memory area. + * @para: none. + * + * returns: the pointer of allocated message frame, NULL if failed; + */ +struct arisc_message *arisc_message_allocate(unsigned int msg_attr); + +/** + * free one message frame. mainly use for process message finished, + * free it to messages pool or add to free message queue. + * @pmessage: the pointer of free message frame. + * + * returns: none. + */ +void arisc_message_free(struct arisc_message *pmessage); + +/** + * notify system that one message coming. + * @pmessage : the pointer of coming message frame. + * + * returns: OK if notify succeeded, other if failed. + */ +int arisc_message_coming_notify(struct arisc_message *pmessage); + +int arisc_semaphore_used_num_query(void); + +struct arisc_message *arisc_message_map_to_cpux(uint32_t addr); +uint32_t arisc_message_map_to_cpus(struct arisc_message *message); +int arisc_message_valid(struct arisc_message *pmessage); + +#endif /* __MESSAGE_MANAGER_H */ diff --git a/plat/sun50iw1p1/scp/include/arisc_messages.h b/plat/sun50iw1p1/scp/include/arisc_messages.h new file mode 100644 index 0000000..98c47b1 --- /dev/null +++ b/plat/sun50iw1p1/scp/include/arisc_messages.h @@ -0,0 +1,81 @@ +/* + * arch/arm/mach-sunxi/arisc/include/arisc_messages.h + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __ARISC_MESSAGES_H__ +#define __ARISC_MESSAGES_H__ + +#include <arisc.h> + +/* message states */ +#define ARISC_MESSAGE_FREED (0x0) /* freed state */ +#define ARISC_MESSAGE_ALLOCATED (0x1) /* allocated state */ +#define ARISC_MESSAGE_INITIALIZED (0x2) /* initialized state */ +#define ARISC_MESSAGE_RECEIVED (0x3) /* received state */ +#define ARISC_MESSAGE_PROCESSING (0x4) /* processing state */ +#define ARISC_MESSAGE_PROCESSED (0x5) /* processed state */ +#define ARISC_MESSAGE_FEEDBACKED (0x6) /* feedback state */ + +/* call back struct */ +typedef struct arisc_msg_cb +{ + arisc_cb_t handler; + void *arg; +} arisc_msg_cb_t; + +#ifdef CONFIG_ARCH_SUN50IW1P1 +/* + * the structure of message frame, + * this structure will transfer between arisc and ac327. + * sizeof(struct message) : 128Byte. + */ +typedef struct arisc_message +{ + volatile unsigned char state; /* identify the used status of message frame */ + volatile unsigned char attr; /* message attribute : SYN OR ASYN */ + volatile unsigned char type; /* message type : DVFS_REQ */ + volatile unsigned char result; /* message process result */ + volatile unsigned char reserved[4]; /* reserved for 8byte align */ + volatile struct arisc_message *next; /* pointer of next message frame */ + volatile struct arisc_msg_cb cb; /* the callback function and arg of message */ + volatile void *private; /* message private data */ + volatile unsigned int paras[22]; /* the parameters of message */ +} arisc_message_t; +#else +/* + * the structure of message frame, + * this structure will transfer between arisc and ac327. + * sizeof(struct message) : 64Byte. + */ +typedef struct arisc_message +{ + volatile unsigned char state; /* identify the used status of message frame */ + volatile unsigned char attr; /* message attribute : SYN OR ASYN */ + volatile unsigned char type; /* message type : DVFS_REQ */ + volatile unsigned char result; /* message process result */ + volatile struct arisc_message *next; /* pointer of next message frame */ + volatile struct arisc_msg_cb cb; /* the callback function and arg of message */ + volatile void *private; /* message private data */ + volatile unsigned int paras[11]; /* the parameters of message */ +} arisc_message_t; +#endif + +#endif /* __ARISC_MESSAGES_H */ diff --git a/plat/sun50iw1p1/scp/include/arisc_para.h b/plat/sun50iw1p1/scp/include/arisc_para.h new file mode 100644 index 0000000..1943759 --- /dev/null +++ b/plat/sun50iw1p1/scp/include/arisc_para.h @@ -0,0 +1,192 @@ +#ifndef __ARISC_PARA_H__ +#define __ARISC_PARA_H__ + +#define ARISC_MACHINE_PAD 0 +#define ARISC_MACHINE_HOMLET 1 + +/* arisc parameter size: 128byte */ +/* + * machine: machine id, pad = 0, homlet = 1; + * message_pool_phys: message pool physical address; + * message_pool_size: message pool size; + */ +#define SERVICES_DVFS_USED (1<<0) + +/* FIXME: if you modify this struct, you should + * sync this change with linux source, + * by superm at 2015-05-15. + */ +typedef enum power_dm +{ + DM_CPUA = 0, /* 0 */ + DM_CPUB, /* 1 */ + DM_DRAM, /* 2 */ + DM_GPU, /* 3 */ + DM_SYS, /* 4 */ + DM_VPU, /* 5 */ + DM_CPUS, /* 6 */ + DM_DRAMPLL, /* 7 */ + DM_ADC, /* 8 */ + DM_PL, /* 9 */ + DM_PM, /* 10 */ + DM_IO, /* 11 */ + DM_CPVDD, /* 12 */ + DM_LDOIN, /* 13 */ + DM_PLL, /* 14 */ + DM_LPDDR, /* 15 */ + DM_TEST, /* 16 */ + DM_RES1, /* 17 */ + DM_RES2, /* 18 */ + DM_RES3, /* 19 */ + DM_MAX, /* 20 */ +} power_dm_e; + +typedef struct mem_cfg +{ + uintptr_t base; + size_t size; +} mem_cfg_t; + +typedef struct dev_cfg +{ + uintptr_t base; + size_t size; + uint32_t irq; + int status; +} dev_cfg_t; + +typedef struct cir_cfg +{ + uintptr_t base; + size_t size; + uint32_t irq; + uint32_t power_key_code; + uint32_t addr_code; + int status; +} cir_cfg_t; + +typedef struct pmu_cfg +{ + uint32_t pmu_bat_shutdown_ltf; + uint32_t pmu_bat_shutdown_htf; + uint32_t pmu_pwroff_vol; + uint32_t power_start; +} pmu_cfg_t; + +typedef struct power_cfg +{ + uint32_t powchk_used; + uint32_t power_reg; + uint32_t system_power; +} power_cfg_t; + +typedef struct image_cfg +{ + uintptr_t base; + size_t size; +} image_cfg_t; + +typedef struct space_cfg +{ + uintptr_t sram_dst; + uintptr_t sram_offset; + size_t sram_size; + uintptr_t dram_dst; + uintptr_t dram_offset; + size_t dram_size; + uintptr_t para_dst; + uintptr_t para_offset; + size_t para_size; + uintptr_t msgpool_dst; + uintptr_t msgpool_offset; + size_t msgpool_size; + uintptr_t standby_dst; + uintptr_t standby_offset; + size_t standby_size; +} space_cfg_t; + +typedef struct dram_para +{ + //normal configuration + uint32_t dram_clk; + uint32_t dram_type; //dram_type DDR2: 2 DDR3: 3 LPDDR2: 6 DDR3L: 31 + uint32_t dram_zq; + uint32_t dram_odt_en; + + //control configuration + uint32_t dram_para1; + uint32_t dram_para2; + + //timing configuration + uint32_t dram_mr0; + uint32_t dram_mr1; + uint32_t dram_mr2; + uint32_t dram_mr3; + uint32_t dram_tpr0; + uint32_t dram_tpr1; + uint32_t dram_tpr2; + uint32_t dram_tpr3; + uint32_t dram_tpr4; + uint32_t dram_tpr5; + uint32_t dram_tpr6; + + //reserved for future use + uint32_t dram_tpr7; + uint32_t dram_tpr8; + uint32_t dram_tpr9; + uint32_t dram_tpr10; + uint32_t dram_tpr11; + uint32_t dram_tpr12; + uint32_t dram_tpr13; + +}dram_para_t; + +typedef struct arisc_freq_voltage +{ + uint32_t freq; //cpu frequency + uint32_t voltage; //voltage for the frequency + uint32_t axi_div; //the divide ratio of axi bus +} arisc_freq_voltage_t; + +typedef struct dts_cfg +{ + struct dram_para dram_para; + struct arisc_freq_voltage vf[ARISC_DVFS_VF_TABLE_MAX]; + struct space_cfg space; + struct image_cfg image; + struct mem_cfg prcm; + struct mem_cfg cpuscfg; + struct dev_cfg msgbox; + struct dev_cfg hwspinlock; + struct dev_cfg s_uart; + struct dev_cfg s_rsb; + struct dev_cfg s_jtag; + struct cir_cfg s_cir; + struct pmu_cfg pmu; + struct power_cfg power; +} dts_cfg_t; + +typedef struct arisc_para +{ + uint32_t message_pool_phys; + uint32_t message_pool_size; + uint32_t standby_base; + uint32_t standby_size; + uint32_t power_key_code; + uint32_t addr_code; + uint32_t suart_status; + uint32_t pmu_bat_shutdown_ltf; + uint32_t pmu_bat_shutdown_htf; + uint32_t pmu_pwroff_vol; + uint32_t power_start; + uint32_t powchk_used; + uint32_t power_reg; + uint32_t system_power; + struct dram_para dram_para; + struct arisc_freq_voltage vf[ARISC_DVFS_VF_TABLE_MAX]; + uint32_t power_regu_tree[DM_MAX]; +} arisc_para_t; + +#define ARISC_PARA_SIZE (sizeof(struct arisc_para)) + +#endif /* __ARISC_PARA_H__ */ diff --git a/plat/sun50iw1p1/scp/interfaces/arisc_axp.c b/plat/sun50iw1p1/scp/interfaces/arisc_axp.c new file mode 100644 index 0000000..a33cfe2 --- /dev/null +++ b/plat/sun50iw1p1/scp/interfaces/arisc_axp.c @@ -0,0 +1,402 @@ +/* + * drivers/arisc/interfaces/arisc_axp.c + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../arisc_i.h" + +/* nmi isr node, record current nmi interrupt handler and argument */ +nmi_isr_t nmi_isr_node[2]; + +/** + * register call-back function, call-back function is for arisc notify some event to ac327, + * axp/rtc interrupt for external interrupt NMI. + * @type: nmi type, pmu/rtc; + * @func: call-back function; + * @para: parameter for call-back function; + * + * @return: result, 0 - register call-back function successed; + * !0 - register call-back function failed; + * NOTE: the function is like "int callback(void *para)"; + * this function will execute in system ISR. + */ +int arisc_nmi_cb_register(uint32_t type, arisc_cb_t func, void *para) +{ + if (nmi_isr_node[type].handler) { + if(func == nmi_isr_node[type].handler) { + ARISC_WRN("nmi interrupt handler register already\n"); + return 0; + } + /* just output warning message, overlay handler */ + ARISC_WRN("nmi interrupt handler register already\n"); + return -EINVAL; + } + nmi_isr_node[type].handler = func; + nmi_isr_node[type].arg = para; + + return 0; +} + + +/** + * unregister call-back function. + * @type: nmi type, pmu/rtc; + * @func: call-back function which need be unregister; + */ +void arisc_nmi_cb_unregister(uint32_t type, arisc_cb_t func) +{ + if ((nmi_isr_node[type].handler) != (func)) { + /* invalid handler */ + ARISC_WRN("invalid handler for unreg\n\n"); + return ; + } + nmi_isr_node[type].handler = NULL; + nmi_isr_node[type].arg = NULL; +} + +int arisc_disable_nmi_irq(void) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_AXP_DISABLE_IRQ; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + +int arisc_enable_nmi_irq(void) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_AXP_ENABLE_IRQ; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + +int arisc_clear_nmi_status(void) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_CLR_NMI_STATUS; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + +int arisc_set_nmi_trigger(uint32_t type) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_SET_NMI_TRIGGER; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + pmessage->paras[0] = type; + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + +int arisc_axp_get_chip_id(unsigned char *chip_id) +{ + int i; + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_AXP_GET_CHIP_ID; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + memset((void *)pmessage->paras, 0, 16); + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* |paras[0] |paras[1] |paras[2] |paras[3] | + * |chip_id[0~3]|chip_id[4~7]|chip_id[8~11]|chip_id[12~15]| + */ + /* copy message readout data to user data buffer */ + for (i = 0; i < 4; i++) { + chip_id[i] = (pmessage->paras[0] >> (i * 8)) & 0xff; + chip_id[4 + i] = (pmessage->paras[1] >> (i * 8)) & 0xff; + chip_id[8 + i] = (pmessage->paras[2] >> (i * 8)) & 0xff; + chip_id[12 + i] = (pmessage->paras[3] >> (i * 8)) & 0xff; + } + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + +int arisc_set_led_bln(uint32_t *paras) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_SET_LED_BLN; + pmessage->paras[0] = paras[0]; + pmessage->paras[1] = paras[1]; + pmessage->paras[2] = paras[2]; + pmessage->paras[3] = paras[3]; + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; + +} + +#if (defined CONFIG_ARCH_SUN8IW5P1) || (defined CONFIG_ARCH_SUN50IW1P1) +int arisc_adjust_pmu_chgcur(uint32_t max_chgcur, uint32_t chg_ic_temp, uint32_t flag) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_AXP_SET_PARAS; + pmessage->paras[0] = chg_ic_temp; + pmessage->paras[1] = max_chgcur; + pmessage->paras[2] = flag; + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} +#endif + +int arisc_set_pwr_tree(uint32_t *pwr_tree) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_SET_PWR_TREE; + memcpy((void *)pmessage->paras, (void *)pwr_tree, sizeof(int)*DM_MAX); + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + +int arisc_axp_int_notify(struct arisc_message *pmessage) +{ + uint32_t type = pmessage->paras[0]; + uint32_t ret = 0; + + if (type & NMI_INT_TYPE_PMU_OFFSET) { + /* call pmu interrupt handler */ + if (nmi_isr_node[NMI_INT_TYPE_PMU].handler == NULL) { + ARISC_WRN("pmu irq handler not install\n"); + return 1; + } + + ARISC_INF("call pmu interrupt handler\n"); + ret |= (*(nmi_isr_node[NMI_INT_TYPE_PMU].handler))(nmi_isr_node[NMI_INT_TYPE_PMU].arg); + } + if (type & NMI_INT_TYPE_RTC_OFFSET) + { + /* call rtc interrupt handler */ + if (nmi_isr_node[NMI_INT_TYPE_RTC].handler == NULL) { + ARISC_WRN("rtc irq handler not install\n"); + return 1; + } + + ARISC_INF("call rtc interrupt handler\n"); + ret |= (*(nmi_isr_node[NMI_INT_TYPE_RTC].handler))(nmi_isr_node[NMI_INT_TYPE_RTC].arg); + } + + return ret; +} + +int arisc_pmu_set_voltage(uint32_t type, uint32_t voltage) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_SET_PMU_VOLT; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + pmessage->paras[0] = type; + pmessage->paras[1] = voltage; + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + +int arisc_pmu_get_voltage(uint32_t type, uint32_t *voltage) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_GET_PMU_VOLT; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + pmessage->paras[0] = type; + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + *voltage = pmessage->paras[1]; + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} diff --git a/plat/sun50iw1p1/scp/interfaces/arisc_debug_level.c b/plat/sun50iw1p1/scp/interfaces/arisc_debug_level.c new file mode 100644 index 0000000..e1e5346 --- /dev/null +++ b/plat/sun50iw1p1/scp/interfaces/arisc_debug_level.c @@ -0,0 +1,137 @@ +/* + * drivers/arisc/interfaces/arisc_debug_level.c + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../arisc_i.h" + +/** + * set arisc debug level. + * @level: arisc debug level; + * + * return: 0 - set arisc debug level successed, !0 - set arisc debug level failed; + */ +int arisc_set_debug_level(unsigned int level) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_ERR("allocate message for debug level request failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_SET_DEBUG_LEVEL; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->paras[0] = level; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + /* send set debug level request to arisc */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + +int arisc_set_uart_baudrate(uint32_t baudrate) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_ERR("allocate message for set baudrate request failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_SET_UART_BAUDRATE; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->paras[0] = baudrate; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + +int arisc_report_error_info(struct arisc_message *pmessage) +{ + uint32_t id = pmessage->paras[0]; + + switch(id) { + case ERR_NMI_INT_TIMEOUT: { + ARISC_ERR("arisc report error info: nmi int response timeout\n"); + break; + } + default: { + ARISC_ERR("invaid arisc report error infomation id:%u\n", id); + return -EINVAL; + } + } + + return 0; +} + +/** + * set paras. + * + * return: 0 - set paras successed, !0 - set paras failed; + */ +int arisc_set_paras(void) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_ERR("allocate message for set paras request failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_SET_PARAS; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + /* send set debug level request to arisc */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +}
\ No newline at end of file diff --git a/plat/sun50iw1p1/scp/interfaces/arisc_dram_crc.c b/plat/sun50iw1p1/scp/interfaces/arisc_dram_crc.c new file mode 100644 index 0000000..fd82232 --- /dev/null +++ b/plat/sun50iw1p1/scp/interfaces/arisc_dram_crc.c @@ -0,0 +1,57 @@ +/* + * drivers/arisc/interfaces/arisc_dram_crc.c + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../arisc_i.h" + +/** + * set arisc debug dram crc paras. + * @dram_crc_en: arisc debug dram crc enable or disable; + * @dram_crc_srcaddr: source address of dram crc area + * @dram_crc_len: lenght of dram crc area + * + * return: 0 - set arisc debug dram crc paras successed, !0 - set arisc debug dram crc paras failed; + */ +int arisc_set_dram_crc_paras(unsigned int dram_crc_en, unsigned int dram_crc_srcaddr, unsigned int dram_crc_len) +{ + struct arisc_message *pmessage; + + ARISC_INF("en:%x, src:%x len:%x\n", dram_crc_en, dram_crc_srcaddr, dram_crc_len); + + /* allocate a message frame */ + pmessage = arisc_message_allocate(0); + if (pmessage == NULL) { + ARISC_ERR("allocate message for seting dram crc paras request failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_SET_DEBUG_DRAM_CRC_PARAS; + pmessage->paras[0] = dram_crc_en; + pmessage->paras[1] = dram_crc_srcaddr; + pmessage->paras[2] = dram_crc_len; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + + /* send set debug level request to arisc */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + return 0; +} + diff --git a/plat/sun50iw1p1/scp/interfaces/arisc_dvfs.c b/plat/sun50iw1p1/scp/interfaces/arisc_dvfs.c new file mode 100644 index 0000000..c7c50cc --- /dev/null +++ b/plat/sun50iw1p1/scp/interfaces/arisc_dvfs.c @@ -0,0 +1,81 @@ +/* + * drivers/arisc/interfaces/arisc_dvfs.c + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../arisc_i.h" + +static int dvfs_err_cb(void *arg) +{ + ARISC_ERR("dvfs error\n"); + + return 0; +} + +/* + * set specific pll target frequency. + * @freq: target frequency to be set, based on KHZ; + * @pll: which pll will be set + * @mode: the attribute of message, whether syn or asyn; + * @cb: callback handler; + * @cb_arg: callback handler arguments; + * + * return: result, 0 - set frequency successed, + * !0 - set frequency failed; + */ +int arisc_dvfs_set_cpufreq(uint32_t freq, uint32_t pll, uint32_t mode) +{ + unsigned int msg_attr = 0; + struct arisc_message *pmessage; + int result = 0; + + if (mode & ARISC_DVFS_SYN) { + msg_attr |= ARISC_MESSAGE_ATTR_HARDSYN; + } + + /* allocate a message frame */ + pmessage = arisc_message_allocate(msg_attr); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message + * + * |paras[0]|paras[1]| + * |freq |pll | + */ + pmessage->type = ARISC_CPUX_DVFS_REQ; + pmessage->paras[0] = freq; + pmessage->paras[1] = pll; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = dvfs_err_cb; + pmessage->cb.arg = NULL; + + ARISC_INF("arisc dvfs request : %d\n", freq); + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* dvfs mode : syn or not */ + if (mode & ARISC_DVFS_SYN) { + result = pmessage->result; + arisc_message_free(pmessage); + } + + return result; +} diff --git a/plat/sun50iw1p1/scp/interfaces/arisc_loopback.c b/plat/sun50iw1p1/scp/interfaces/arisc_loopback.c new file mode 100644 index 0000000..029d4dc --- /dev/null +++ b/plat/sun50iw1p1/scp/interfaces/arisc_loopback.c @@ -0,0 +1,51 @@ +/* + * drivers/arisc/interfaces/arisc_loopback.c + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../arisc_i.h" + +int arisc_message_loopback(void) +{ + int result; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_MESSAGE_LOOPBACK; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->paras[0] = 11; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} diff --git a/plat/sun50iw1p1/scp/interfaces/arisc_rsb.c b/plat/sun50iw1p1/scp/interfaces/arisc_rsb.c new file mode 100644 index 0000000..f3b685b --- /dev/null +++ b/plat/sun50iw1p1/scp/interfaces/arisc_rsb.c @@ -0,0 +1,329 @@ +/* + * drivers/arisc/interfaces/arisc_rsb.c + * + * Copyright (c) 2013 Allwinner. + * 2013-07-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../arisc_i.h" + +#if (defined CONFIG_ARCH_SUN8IW3P1) || (defined CONFIG_ARCH_SUN8IW5P1) || (defined CONFIG_ARCH_SUN8IW6P1) || \ + (defined CONFIG_ARCH_SUN8IW7P1) || (defined CONFIG_ARCH_SUN8IW9P1) || (defined CONFIG_ARCH_SUN9IW1P1) || \ + (defined CONFIG_ARCH_SUN50IW1P1) + +/* + * used for indicate aduio codec been initialized, + * modules like audio & trc mabye initialize, + * but audio codec only can be initialize once + */ +static int audio_codec_init = 0; + +/** + * rsb read block data. + * @cfg: point of arisc_rsb_block_cfg struct; + * + * return: result, 0 - read register successed, + * !0 - read register failed or the len more then max len; + */ +int arisc_rsb_read_block_data(uint32_t *paras) +{ + int result; + struct arisc_message *pmessage; + + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_RSB_READ_BLOCK_DATA; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + memcpy((void *)pmessage->paras, (const void *)paras, sizeof(pmessage->paras)); + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + memcpy((void *)paras, (const void *)pmessage->paras, sizeof(pmessage->paras)); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + + +/** + * rsb write block data. + * @cfg: point of arisc_rsb_block_cfg struct; + * + * return: result, 0 - write register successed, + * !0 - write register failedor the len more then max len; + */ +int arisc_rsb_write_block_data(uint32_t *paras) +{ + int result; + struct arisc_message *pmessage; + + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + /* initialize message */ + pmessage->type = ARISC_RSB_WRITE_BLOCK_DATA; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + memcpy((void *)pmessage->paras, (const void *)paras, sizeof(pmessage->paras)); + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + + +/** + * rsb read pmu reg. + * @addr: pmu reg addr; + * + * return: if read pmu reg successed, return data of pmu reg; + * if read pmu reg failed, return -1. + */ +uint8_t arisc_rsb_read_pmu_reg(uint32_t addr) +{ + int result; + uint32_t paras[22]; + uint32_t data = 0; + + /* + * package address and data to message->paras, + * message->paras data layout: + * |para[0] |para[1]|para[2] |para[3]|para[4]|para[5]|para[6]| + * |(len|datatype)|devaddr|regaddr0~3|data0 |data1 |data2 |data3 | + */ + memset((void *)paras, 0, sizeof(uint32_t) * 6); + paras[0] = ((1 & 0xffff) | ((RSB_DATA_TYPE_BYTE << 16) & 0xffff0000)); + paras[1] = 0x2d; + paras[2] = addr&0xff; + + result = arisc_rsb_read_block_data(paras); + if (!result) { + data = paras[3]; + } else { + ARISC_ERR("arisc rsb read pmu reg 0x%x err\n", addr); + return -1; + } + + ARISC_INF("read pmu reg 0x%x:0x%x\n", addr, data); + + return data; +} + + +/** + * rsb write pmu reg. + * @addr: pmu reg addr; + * @data: pmu reg data; + * + * return: result, 0 - write register successed, + * !0 - write register failedor the len more then max len; + */ +int arisc_rsb_write_pmu_reg(uint32_t addr, uint32_t data) +{ + int result; + uint32_t paras[22]; + + /* + * package address and data to message->paras, + * message->paras data layout: + * |para[0] |para[1]|para[2] |para[3]|para[4]|para[5]|para[6]| + * |(len|datatype)|devaddr|regaddr0~3|data0 |data1 |data2 |data3 | + */ + memset((void *)paras, 0, sizeof(uint32_t) * 6); + paras[0] = ((1 & 0xffff) | ((RSB_DATA_TYPE_BYTE << 16) & 0xffff0000)); + paras[1] = 0x2d; + paras[2] = addr&0xff; + paras[3] = data&0xff; + + result = arisc_rsb_write_block_data(paras); + if (result) { + ARISC_ERR("arisc rsb write pmu reg 0x%x:0x%x err\n", addr, data); + } + ARISC_INF("write pmu reg 0x%x:0x%x\n", addr, data); + + return result; +} + + +/** + * rsb bits operation sync. + * @cfg: point of arisc_rsb_bits_cfg struct; + * + * return: result, 0 - bits operation successed, + * !0 - bits operation failed, or the len more then max len; + * + * rsb clear bits internal: + * data = rsb_read(regaddr); + * data = data & (~mask); + * rsb_write(regaddr, data); + * + * rsb set bits internal: + * data = rsb_read(addr); + * data = data | mask; + * rsb_write(addr, data); + * + */ +int rsb_bits_ops_sync(uint32_t *paras) +{ + int result; + struct arisc_message *pmessage; + + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + /* initialize message */ + pmessage->type = ARISC_RSB_BITS_OPS_SYNC; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + memcpy((void *)pmessage->paras, (const void *)paras, sizeof(pmessage->paras)); + + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + +/** + * rsb set interface mode. + * @devaddr: rsb slave device address; + * @regaddr: register address of rsb slave device; + * @data: data which to init rsb slave device interface mode; + * + * return: result, 0 - set interface mode successed, + * !0 - set interface mode failed; + */ +int arisc_rsb_set_interface_mode(uint32_t devaddr, uint32_t regaddr, uint32_t data) +{ + int result; + struct arisc_message *pmessage; + + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_RSB_SET_INTERFACE_MODE; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + /* + * package address and data to message->paras, + * message->paras data layout: + * |para[0]|para[1]|para[2]| + * |devaddr|regaddr|data | + */ + pmessage->paras[0] = devaddr; + pmessage->paras[1] = regaddr; + pmessage->paras[2] = data; + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} + +/** + * rsb set runtime slave address. + * @devaddr: rsb slave device address; + * @rtsaddr: rsb slave device's runtime slave address; + * + * return: result, 0 - set rsb runtime address successed, + * !0 - set rsb runtime address failed; + */ +int arisc_rsb_set_rtsaddr(uint32_t devaddr, uint32_t rtsaddr) +{ + int result; + struct arisc_message *pmessage; + + /* check audio codec has been initialized */ + if (devaddr == RSB_DEVICE_SADDR7) { + if (audio_codec_init) + return 0; + else + audio_codec_init = 1; + } + + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_RSB_SET_RTSADDR; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + /* + * package address and data to message->paras, + * message->paras data layout: + * |para[0]|para[1]| + * |devaddr|rtsaddr| + */ + pmessage->paras[0] = devaddr; + pmessage->paras[1] = rtsaddr; + /* send message use hwmsgbox */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* free message */ + result = pmessage->result; + arisc_message_free(pmessage); + + return result; +} +#endif diff --git a/plat/sun50iw1p1/scp/interfaces/arisc_standby.c b/plat/sun50iw1p1/scp/interfaces/arisc_standby.c new file mode 100644 index 0000000..d570ddf --- /dev/null +++ b/plat/sun50iw1p1/scp/interfaces/arisc_standby.c @@ -0,0 +1,286 @@ +/* + * drivers/arisc/interfaces/arisc_standby.c + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../arisc_i.h" + +/* record super-standby wakeup event */ +static unsigned long wakeup_event = 0; +static unsigned long dram_crc_error = 0; +static unsigned long dram_crc_total_count = 0; +static unsigned long dram_crc_error_count = 0; + +/** + * cpu operations. + * @mpidr: cpu id; + * @entrypoint: cpu resume entrypoint; + * @cpu_state: cpu state; + * @cluster_state: cluster state; + * + * return: result, 0 - cpu operations successed, + * !0 - cpu operations failed; + */ +int arisc_cpu_op(uint32_t mpidr, uint32_t entrypoint, arisc_power_state_t cpu_state, + arisc_power_state_t cluster_state) +{ + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(0); + if (pmessage == NULL) { + ARISC_ERR("allocate message for cpu op request failed\n"); + return -ENOMEM; + } + + pmessage->type = ARISC_CPU_OP_REQ; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + pmessage->paras[0] = mpidr; + pmessage->paras[1] = entrypoint; + pmessage->paras[2] = cpu_state; + pmessage->paras[3] = cluster_state; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + + /* send enter cpu operations request to arisc */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + return 0; +} + + /** + * system operations. + * @state: system state; + * + * return: result, 0 - system operations successed, + * !0 - system operations failed; + */ +int arisc_system_op(arisc_system_state_t state) +{ + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(0); + if (pmessage == NULL) { + ARISC_ERR("allocate message for sys op request failed\n"); + return -ENOMEM; + } + + pmessage->type = ARISC_SYS_OP_REQ; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + pmessage->paras[0] = state; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + + /* send enter sys operations request to arisc */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + return 0; +} + +/* + * enter cpu idle. + * @para: parameter for enter cpu idle. + * para->flag: 0x01-clear pending, 0x10-enter cpuidle + * para->resume_addr: the address cpu0 will run when exit idle + * + * return: result, 0 - super standby successed, + * !0 - super standby failed; + */ +int arisc_enter_cpuidle(arisc_cb_t cb, void *cb_arg, struct sunxi_enter_idle_para *para) +{ + struct arisc_message *pmessage; /* allocate a message frame */ + pmessage = arisc_message_allocate(0); + if (pmessage == NULL) { + ARISC_ERR("allocate message for super-standby request failed\n"); + return -ENOMEM; + } + pmessage->type = ARISC_CPUIDLE_ENTER_REQ; + pmessage->cb.handler = cb; + pmessage->cb.arg = cb_arg; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->paras[0] = para->flags; + pmessage->paras[1] = (unsigned long)para->resume_addr; + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + return 0; +} + +/** + * query super-standby wakeup source. + * @para: point of buffer to store wakeup event informations. + * + * return: result, 0 - query successed, + * !0 - query failed; + */ +int arisc_query_wakeup_source(uint32_t *event) +{ + *event = wakeup_event; + + return 0; +} + +/* + * query super-standby infoation. + * @para: point of array to store power states informations during sst. + * @op: 0:read, 1:set + * + * return: result, 0 - query successed, + * !0 - query failed; + */ +int arisc_query_set_standby_info(struct standby_info_para *para, arisc_rw_type_e op) +{ + struct arisc_message *pmsg; + int result; + + /* allocate a message frame */ + pmsg = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmsg == NULL) { + ARISC_ERR("allocate message for query standby info failed\n"); + return -ENOMEM; + } + + /* check standby_info_para size valid or not */ + if (sizeof(struct standby_info_para) > sizeof(pmsg->paras)) { + ARISC_ERR("standby info parameters number too long\n"); + return -EINVAL; + } + + /* initialize message */ + pmsg->type = ARISC_STANDBY_INFO_REQ; + pmsg->cb.handler = NULL; + pmsg->cb.arg = NULL; + pmsg->private = (void *)op; + if (ARISC_WRITE == op) { + memcpy((void *)pmsg->paras, (const void *)para, sizeof(struct standby_info_para)); + } + pmsg->state = ARISC_MESSAGE_INITIALIZED; + + /* send query sst info request to arisc */ + arisc_hwmsgbox_send_message(pmsg, ARISC_SEND_MSG_TIMEOUT); + if (ARISC_READ == op) + memcpy((void *)para, (void *)pmsg->paras, sizeof(struct standby_info_para)); + + /* free message */ + result = pmsg->result; + arisc_message_free(pmsg); + + return result; +} + +/* + * query super-standby dram crc result. + * @para: point of buffer to store dram crc result informations. + * + * return: result, 0 - query successed, + * !0 - query failed; + */ +int arisc_query_dram_crc_result(unsigned long *perror, unsigned long *ptotal_count, + unsigned long *perror_count) +{ + *perror = dram_crc_error; + *ptotal_count = dram_crc_total_count; + *perror_count = dram_crc_error_count; + + return 0; +} + +int arisc_set_dram_crc_result(unsigned long error, unsigned long total_count, + unsigned long error_count) +{ + dram_crc_error = error; + dram_crc_total_count = total_count; + dram_crc_error_count = error_count; + + return 0; +} + +/** + * notify arisc cpux restored. + * @para: none. + * + * return: result, 0 - notify successed, !0 - notify failed; + */ +int arisc_cpux_ready_notify(void) +{ + struct arisc_message *pmessage; + + /* notify hwspinlock and hwmsgbox resume first */ + arisc_hwmsgbox_standby_resume(); + arisc_hwspinlock_standby_resume(); + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + + /* initialize message */ + pmessage->type = ARISC_SSTANDBY_RESTORE_NOTIFY; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + + /* record wakeup event */ + wakeup_event = pmessage->paras[0]; + if (arisc_debug_dram_crc_en) { + dram_crc_error = pmessage->paras[1]; + dram_crc_total_count++; + dram_crc_error_count += (dram_crc_error ? 1 : 0); + } + + /* free message */ + arisc_message_free(pmessage); + + return 0; +} + +int arisc_config_ir_paras(uint32_t ir_code, uint32_t ir_addr) +{ + int result = 0; + struct arisc_message *pmessage; + + /* allocate a message frame */ + pmessage = arisc_message_allocate(ARISC_MESSAGE_ATTR_HARDSYN); + if (pmessage == NULL) { + ARISC_WRN("allocate message failed\n"); + return -ENOMEM; + } + /* initialize message */ + pmessage->type = ARISC_SET_IR_PARAS; + pmessage->paras[0] = ir_code; + pmessage->paras[1] = ir_addr; + pmessage->state = ARISC_MESSAGE_INITIALIZED; + pmessage->cb.handler = NULL; + pmessage->cb.arg = NULL; + + ARISC_INF("ir power key:0x%x, addr:0x%x\n", ir_code, ir_addr); + + /* send request message */ + arisc_hwmsgbox_send_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + if (pmessage->result) { + ARISC_WRN("config ir power key code [%d] fail\n", pmessage->paras[0]); + result = -EINVAL; + } + + /* free allocated message */ + arisc_message_free(pmessage); + + return result; +} diff --git a/plat/sun50iw1p1/scp/interfaces/interfaces.mk b/plat/sun50iw1p1/scp/interfaces/interfaces.mk new file mode 100644 index 0000000..1571046 --- /dev/null +++ b/plat/sun50iw1p1/scp/interfaces/interfaces.mk @@ -0,0 +1,37 @@ +# +# Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. +# + +BL31_SOURCES += plat/sun50iw1p1/scp/interfaces/arisc_loopback.c \ + plat/sun50iw1p1/scp/interfaces/arisc_dvfs.c \ + plat/sun50iw1p1/scp/interfaces/arisc_rsb.c\ + plat/sun50iw1p1/scp/interfaces/arisc_axp.c \ + plat/sun50iw1p1/scp/interfaces/arisc_standby.c \ + plat/sun50iw1p1/scp/interfaces/arisc_dram_crc.c \ + plat/sun50iw1p1/scp/interfaces/arisc_debug_level.c diff --git a/plat/sun50iw1p1/scp/message_manager/message_manager.c b/plat/sun50iw1p1/scp/message_manager/message_manager.c new file mode 100644 index 0000000..46b8969 --- /dev/null +++ b/plat/sun50iw1p1/scp/message_manager/message_manager.c @@ -0,0 +1,282 @@ +/* + * arch/arm/mach-sunxi/arisc/message_manager/message_manager.c + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "message_manager_i.h" + +/* the start and end of message pool */ +static struct arisc_message *message_start; +static struct arisc_message *message_end; + +/* spinlock for this module */ +static spinlock_t msg_mgr_lock; + +/* message cache manager */ +static struct arisc_message_cache message_cache; + +static void *arisc_message_pool_base; +static uint32_t arisc_message_pool_size; + +/** + * initialize message manager. + * @para: none. + * + * returns: 0 if initialize succeeded, others if failed. + */ +int arisc_message_manager_init(void *addr, uint32_t size) +{ + int i; + + arisc_message_pool_base = addr; + arisc_message_pool_size = size; + + /* initialize message pool start and end */ + message_start = (struct arisc_message *)(arisc_message_pool_base); + message_end = (struct arisc_message *)((ptrdiff_t)arisc_message_pool_base + arisc_message_pool_size); + + //memset((void *)message_start, 0, arisc_message_pool_size); + + /* initialize message_cache */ + for (i = 0; i < ARISC_MESSAGE_CACHED_MAX; i++) { + message_cache.cache[i] = NULL; + } + message_cache.number = 0; + + return 0; +} + +/** + * exit message manager. + * @para: none. + * + * returns: 0 if exit succeeded, others if failed. + */ +int arisc_message_manager_exit(void) +{ + return 0; +} + +static int arisc_message_invalid(struct arisc_message *pmessage) +{ + if ((pmessage >= message_start) && + (pmessage < message_end)) { + /* valid arisc message */ + return 0; + } + /* invalid arisc message */ + return 1; +} + +/** + * allocate one message frame. mainly use for send message by message-box, + * the message frame allocate form messages pool shared memory area. + * @para: none. + * + * returns: the pointer of allocated message frame, NULL if failed; + */ +struct arisc_message *arisc_message_allocate(unsigned int msg_attr) +{ + struct arisc_message *pmessage = NULL; + struct arisc_message *palloc = NULL; + + /* first find in message_cache */ + spin_lock(&msg_mgr_lock); + if (message_cache.number) { + ARISC_INF("arisc message_cache.number = 0x%x.\n", message_cache.number); + message_cache.number--; + palloc = message_cache.cache[message_cache.number]; + ARISC_INF("message [%llx] allocate from message_cache\n", palloc); + if (arisc_message_invalid(palloc)) { + ARISC_ERR("allocate cache message [%llx] invalid\n", palloc); + } + } + spin_unlock(&msg_mgr_lock); + if (arisc_message_invalid(palloc)) { + /* + * cached message_cache finded fail, + * use spinlock 0 to exclusive with arisc. + */ + arisc_hwspin_lock(AW_MSG_HWSPINLOCK); + + /* search from the start of message pool every time. */ + pmessage = message_start; + while (pmessage < message_end) { + if (pmessage->state == ARISC_MESSAGE_FREED) { + /* find free message in message pool, allocate it */ + palloc = pmessage; + palloc->state = ARISC_MESSAGE_ALLOCATED; + ARISC_INF("message [%llx] allocate from message pool\n", palloc); + break; + } + /* next message frame */ + pmessage++; + } + /* unlock hwspinlock 0 */ + arisc_hwspin_unlock(AW_MSG_HWSPINLOCK); + } + if (arisc_message_invalid(palloc)) { + ARISC_ERR("allocate message [%llx] frame is invalid\n", palloc); + return NULL; + } + /* initialize messgae frame */ + palloc->next = NULL; + palloc->attr = msg_attr; + palloc->private = NULL; + + return palloc; +} + +/** + * free one message frame. mainly use for process message finished, + * free it to messages pool or add to free message queue. + * @pmessage: the pointer of free message frame. + * + * returns: none. + */ +void arisc_message_free(struct arisc_message *pmessage) +{ + struct arisc_message *free_message = pmessage; + + /* check this message valid or not */ + if (arisc_message_invalid(free_message)) { + ARISC_ERR("free invalid arisc message [%llx]\n", free_message); + return; + } + + /* try to free to free_list first */ + spin_lock(&msg_mgr_lock); + if (message_cache.number < ARISC_MESSAGE_CACHED_MAX) { + ARISC_INF("insert message [%llx] to message_cache\n", free_message); + ARISC_INF("message_cache number : %d\n", message_cache.number); + /* cached this message, message state: ALLOCATED */ + message_cache.cache[message_cache.number] = free_message; + message_cache.number++; + free_message->next = NULL; + free_message->state = ARISC_MESSAGE_ALLOCATED; + free_message = NULL; + } + spin_unlock(&msg_mgr_lock); + + /* try to free message to pool if free to cache fail */ + if (free_message) { + /* free to message pool,set message state as FREED. */ + arisc_hwspin_lock(AW_MSG_HWSPINLOCK); + ARISC_INF("insert message [%llx] to message pool\n", free_message); + free_message->state = ARISC_MESSAGE_FREED; + free_message->next = NULL; + arisc_hwspin_unlock(AW_MSG_HWSPINLOCK); + } +} + +/** + * notify system that one message coming. + * @pmessage: the pointer of coming message frame. + * + * returns: 0 if notify succeeded, other if failed. + */ +int arisc_message_coming_notify(struct arisc_message *pmessage) +{ + int ret; + + /* ac327 receive message to arisc */ + ARISC_INF("-------------------------------------------------------------\n"); + ARISC_INF(" MESSAGE FROM ARISC \n"); + ARISC_INF("message addr : %llx\n", pmessage); + ARISC_INF("message type : %x\n", pmessage->type); + ARISC_INF("message attr : %x\n", pmessage->attr); + ARISC_INF("-------------------------------------------------------------\n"); + + /* message per-process */ + pmessage->state = ARISC_MESSAGE_PROCESSING; + + /* process message */ + switch (pmessage->type) { + case ARISC_AXP_INT_COMING_NOTIFY: { + ARISC_INF("pmu interrupt coming notify\n"); + ret = arisc_axp_int_notify(pmessage); + pmessage->result = ret; + break; + } + case ARISC_AUDIO_PERDONE_NOTIFY: { + ARISC_INF("audio perdone notify\n"); + ret = arisc_audio_perdone_notify(pmessage); + pmessage->result = ret; + break; + } + case ARISC_REPORT_ERR_INFO: { + ARISC_INF("arisc report error info\n"); + ret = arisc_report_error_info(pmessage); + pmessage->result = ret; + break; + } + + default : { + ARISC_ERR("invalid message type for ac327 process\n"); + ARISC_ERR("message addr : %llx\n", pmessage); + ARISC_ERR("message state : %x\n", pmessage->state); + ARISC_ERR("message attr : %x\n", pmessage->attr); + ARISC_ERR("message type : %x\n", pmessage->type); + ARISC_ERR("message result : %x\n", pmessage->result); + ret = -EINVAL; + break; + } + } + /* message post process */ + pmessage->state = ARISC_MESSAGE_PROCESSED; + if (pmessage->attr & ARISC_MESSAGE_ATTR_HARDSYN) { + /* synchronous message, should feedback process result */ + arisc_hwmsgbox_feedback_message(pmessage, ARISC_SEND_MSG_TIMEOUT); + } else { + /* + * asyn message, no need feedback message result, + * free message directly. + */ + arisc_message_free(pmessage); + } + + return ret; +} + +struct arisc_message *arisc_message_map_to_cpux(uint32_t addr) +{ + struct arisc_message *message; + message = (struct arisc_message *)((ptrdiff_t)addr + (ptrdiff_t)arisc_message_pool_base); + + return message; +} + +uint32_t arisc_message_map_to_cpus(struct arisc_message *message) +{ + uint32_t value = (uint32_t)((ptrdiff_t)message - (ptrdiff_t)arisc_message_pool_base); + + return value; +} + +int arisc_message_valid(struct arisc_message *pmessage) +{ + if ((pmessage >= message_start) && (pmessage < message_end)) { + /* valid message */ + return 1; + } + + return 0; +} + diff --git a/plat/sun50iw1p1/scp/message_manager/message_manager.mk b/plat/sun50iw1p1/scp/message_manager/message_manager.mk new file mode 100644 index 0000000..806f3ef --- /dev/null +++ b/plat/sun50iw1p1/scp/message_manager/message_manager.mk @@ -0,0 +1,31 @@ +# +# Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. +# + +BL31_SOURCES += plat/sun50iw1p1/scp/message_manager/message_manager.c diff --git a/plat/sun50iw1p1/scp/message_manager/message_manager_i.h b/plat/sun50iw1p1/scp/message_manager/message_manager_i.h new file mode 100644 index 0000000..54c5383 --- /dev/null +++ b/plat/sun50iw1p1/scp/message_manager/message_manager_i.h @@ -0,0 +1,40 @@ +/* + * arch/arm/mach-sunxi/arisc/message_manager/message_manager_i.h + * + * Copyright (c) 2012 Allwinner. + * 2012-10-01 Written by superm (superm@allwinnertech.com). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ARISC_MESSAGE_MANAGER_I_H +#define __ARISC_MESSAGE_MANAGER_I_H + +#include "../include/arisc_includes.h" +#include "../arisc_i.h" + +#define ARISC_SEM_CACHE_MAX (8) + +/* + *the strcuture of message cache, + *main for messages cache management. + */ +typedef struct arisc_message_cache +{ + uint32_t number; /* valid message number */ + struct arisc_message *cache[ARISC_MESSAGE_CACHED_MAX]; /* message cache table */ +} arisc_message_cache_t; + +#endif /* __ARISC_MESSAGE_MANAGER_I_H */ diff --git a/plat/sun50iw1p1/scpi.c b/plat/sun50iw1p1/scpi.c new file mode 100644 index 0000000..e09ed90 --- /dev/null +++ b/plat/sun50iw1p1/scpi.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <arch_helpers.h> +#include <platform.h> +#include "sunxi_def.h" +#include "mhu.h" +#include "scpi.h" + +#define MHU_SECURE_SCP_TO_AP_PAYLOAD (MHU_SECURE_BASE+0x0080) +#define MHU_SECURE_AP_TO_SCP_PAYLOAD (MHU_SECURE_BASE+0x0280) + +#define SIZE_SHIFT 20 /* Bit position for size value in MHU header */ +#define SIZE_MASK 0x1ff /* Mask to extract size value in MHU header*/ + + +void *scpi_secure_message_start(void) +{ + mhu_secure_message_start(); + + /* Return address of payload area. */ + return (void *)MHU_SECURE_AP_TO_SCP_PAYLOAD; +} + +void scpi_secure_message_send(unsigned command, size_t size) +{ + /* Make sure payload can be seen by SCP */ + if (MHU_PAYLOAD_CACHED) + flush_dcache_range(MHU_SECURE_AP_TO_SCP_PAYLOAD, size); + + mhu_secure_message_send(command | (size << SIZE_SHIFT)); +} + +unsigned scpi_secure_message_receive(void **message_out, size_t *size_out) +{ + uint32_t response = mhu_secure_message_wait(); + + /* Get size of payload */ + size_t size = (response >> SIZE_SHIFT) & SIZE_MASK; + + /* Clear size from response */ + response &= ~(SIZE_MASK << SIZE_SHIFT); + + /* Make sure we don't read stale data */ + if (MHU_PAYLOAD_CACHED) + inv_dcache_range(MHU_SECURE_SCP_TO_AP_PAYLOAD, size); + + if (size_out) + *size_out = size; + + if (message_out) + *message_out = (void *)MHU_SECURE_SCP_TO_AP_PAYLOAD; + + return response; +} + +void scpi_secure_message_end(void) +{ + mhu_secure_message_end(); +} + +static void scpi_secure_send32(unsigned command, uint32_t message) +{ + *(__typeof__(message) *)scpi_secure_message_start() = message; + scpi_secure_message_send(command, sizeof(message)); + scpi_secure_message_end(); +} + +int scpi_wait_ready(void) +{ + /* Get a message from the SCP */ + scpi_secure_message_start(); + size_t size; + unsigned command = scpi_secure_message_receive(NULL, &size); + scpi_secure_message_end(); + + /* We are expecting 'SCP Ready', produce correct error if it's not */ + scpi_status_t response = SCP_OK; + if (command != SCPI_CMD_SCP_READY) + response = SCP_E_SUPPORT; + else if (size != 0) + response = SCP_E_SIZE; + + /* Send our response back to SCP */ + scpi_secure_send32(command, response); + + return response == SCP_OK ? 0 : -1; +} + +void scpi_set_css_power_state(unsigned mpidr, scpi_power_state_t cpu_state, + scpi_power_state_t cluster_state, scpi_power_state_t css_state) +{ + uint32_t state = mpidr & 0x0f; /* CPU ID */ + state |= (mpidr & 0xf00) >> 4; /* Cluster ID */ + state |= cpu_state << 8; + state |= cluster_state << 12; + state |= css_state << 16; + scpi_secure_send32(SCPI_CMD_SET_CSS_POWER_STATE, state); +} + +uint32_t scpi_sys_power_state(scpi_system_state_t system_state) +{ + uint32_t *response; + size_t size; + uint8_t state = system_state & 0xff; + + /* Send the command */ + *(__typeof__(state) *)scpi_secure_message_start() = state; + scpi_secure_message_send(SCPI_CMD_SYS_POWER_STATE, sizeof(state)); + scpi_secure_message_receive((void *)&response, &size); + scpi_secure_message_end(); + return *response; +} diff --git a/plat/sun50iw1p1/scpi.h b/plat/sun50iw1p1/scpi.h new file mode 100644 index 0000000..8a5ef65 --- /dev/null +++ b/plat/sun50iw1p1/scpi.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#ifndef __SCPI_H__ +#define __SCPI_H__ + +#include <stddef.h> +#include <stdint.h> + +extern void *scpi_secure_message_start(void); +extern void scpi_secure_message_send(unsigned command, size_t size); +extern unsigned scpi_secure_message_receive(void **message_out, size_t *size_out); +extern void scpi_secure_message_end(void); + + +enum { + SCP_OK = 0, /* Success */ + SCP_E_PARAM, /* Invalid parameter(s) */ + SCP_E_ALIGN, /* Invalid alignment */ + SCP_E_SIZE, /* Invalid size */ + SCP_E_HANDLER, /* Invalid handler or callback */ + SCP_E_ACCESS, /* Invalid access or permission denied */ + SCP_E_RANGE, /* Value out of range */ + SCP_E_TIMEOUT, /* Time out has ocurred */ + SCP_E_NOMEM, /* Invalid memory area or pointer */ + SCP_E_PWRSTATE, /* Invalid power state */ + SCP_E_SUPPORT, /* Feature not supported or disabled */ +}; + +typedef uint32_t scpi_status_t; + +typedef enum { + SCPI_CMD_SCP_READY = 0x01, + SCPI_CMD_SET_CSS_POWER_STATE = 0x04, + SCPI_CMD_SYS_POWER_STATE = 0x08 +} scpi_command_t; + +typedef enum { + scpi_power_on = 0, + scpi_power_retention = 1, + scpi_power_off = 3, +} scpi_power_state_t; + +typedef enum { + scpi_system_shutdown = 0, + scpi_system_reboot = 1, + scpi_system_reset = 2 +} scpi_system_state_t; + +extern int scpi_wait_ready(void); +extern void scpi_set_css_power_state(unsigned mpidr, scpi_power_state_t cpu_state, + scpi_power_state_t cluster_state, scpi_power_state_t css_state); +uint32_t scpi_sys_power_state(scpi_system_state_t system_state); + +#endif /* __SCPI_H__ */ diff --git a/plat/sun50iw1p1/sun50iw1p1.h b/plat/sun50iw1p1/sun50iw1p1.h new file mode 100644 index 0000000..2013b38 --- /dev/null +++ b/plat/sun50iw1p1/sun50iw1p1.h @@ -0,0 +1,127 @@ +/* + * (C) Copyright 2007-2015 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Jerry Wang <wangflord@allwinnertech.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __PLATFORM_H +#define __PLATFORM_H + +#define SUNXI_SRAM_D_BASE (0x00010000L) +/* base address of modules */ +#define SUNXI_DE_BASE (0x01000000L) +#define SUNXI_CORESIGHT_DEBUG_BASE (0x01400000L) +#define SUNXI_CPU_MBIST_BASE (0x01502000L) +#define SUNXI_CPUX_CFG_BASE (0x01700000L) + + +#define SUNXI_SYSCRL_BASE (0x01c00000L) + +#define SUNXI_DMA_BASE (0x01c02000L) +#define SUNXI_NFC_BASE (0x01c03000L) +#define SUNXI_TSC_BASE (0x01c06000L) + +#define SUNXI_TCON0_BASE (0x01c0c000L) +#define SUNXI_TCON1_BASE (0x01c0d000L) +#define SUNXI_VE_BASE (0x01c0e000L) + +#define SUNXI_SMHC0_BASE (0x01c0f000L) +#define SUNXI_SMHC1_BASE (0x01c10000L) +#define SUNXI_SMHC2_BASE (0x01c11000L) + +#define SUNXI_SID_BASE (0x01c14000L) +#define SUNXI_SS_BASE (0x01c15000L) + +#define SUNXI_MSGBOX_BASE (0x01c17000L) +#define SUNXI_SPINLOCK_BASE (0x01c18000L) + +#define SUNXI_USBOTG_BASE (0x01c19000L) +#define SUNXI_EHCI0_BASE (0x01c1a000L) +#define SUNXI_EHCI1_BASE (0x01c1b000L) + +#define SUNXI_SMC_BASE (0x01c1e000L) + +#define SUNXI_CCM_BASE (0x01c20000L) +#define SUNXI_PIO_BASE (0x01c20800L) +#define SUNXI_TIMER_BASE (0x01c20c00L) +#define SUNXI_SPDIF_BASE (0x01c21000L) +#define SUNXI_PWM03_BASE (0x01c21400L) + +#define SUNXI_KEYADC_BASE (0x01c21800L) +#define SUNXI_DAUDIO0_BASE (0x01c22000L) +#define SUNXI_DAUDIO1_BASE (0x01c24000L) +#define SUNXI_DAUDIO2_BASE (0x01c28000L) + +#define SUNXI_AC_BASE (0x01c22c00L) +#define SUNXI_SPC_BASE (0x01c23400L) +#define SUNXI_THC_BASE (0x01c25000L) + +#define SUNXI_UART0_BASE (0x01c28000L) +#define SUNXI_UART1_BASE (0x01c28400L) +#define SUNXI_UART2_BASE (0x01c28800L) +#define SUNXI_UART3_BASE (0x01c28c00L) +#define SUNXI_UART4_BASE (0x01c29000L) + +#define SUNXI_TWI0_BASE (0x01c2ac00L) +#define SUNXI_TWI1_BASE (0x01c2b000L) +#define SUNXI_TWI2_BASE (0x01c2b400L) +#define SUNXI_SCR_BASE (0x01c2c400L) + +#define SUNXI_EMAC_BASE (0x01c30000L) +#define SUNXI_GPU_BASE (0x01c40000L) +#define SUNXI_HSTMR_BASE (0x01c60000L) + +#define SUNXI_DRAMCOM_BASE (0x01c62000L) +#define SUNXI_DRAMCTL0_BASE (0x01c63000L) +#define SUNXI_DRAMPHY0_BASE (0x01c65000L) + +#define SUNXI_SPI0_BASE (0x01c68000L) +#define SUNXI_SPI1_BASE (0x01c69000L) + +#define ARMA9_SCU_BASE (0x01c80000L) +#define ARMA9_GIC_BASE (0x01c81000L) +#define ARMA9_CPUIF_BASE (0x01c82000L) + +/* Base sunxi compatible GIC memory map */ +#define GICD_BASE ARMA9_GIC_BASE +#define GICC_BASE ARMA9_CPUIF_BASE + + +#define SUNXI_MIPI_DSI0_BASE (0x01ca0000L) +#define SUNXI_MIPI_DSIPHY_BASE (0x01ca1000L) + +#define SUNXI_CSI0_BASE (0x01cb0000L) +#define SUNXI_DE_INTERLACED_BASE (0x01e00000L) +#define SUNXI_HDMI_BASE (0x01ee0000L) +#define HDMI_BASE SUNXI_HDMI_BASE + +#define SUNXI_RTC_BASE (0x01f00000L) +#define SUNXI_RTMR01_BASE (0x01f00800L) +#define SUNXI_RINTC_BASE (0x01f00C00L) +#define SUNXI_RWDOG_BASE (0x01f01000L) +#define SUNXI_RPRCM_BASE (0x01f01400L) +#define SUNXI_RTWD_BASE (0x01f01800L) +#define SUNXI_RCPUCFG_BASE (0x01f01C00L) +#define SUNXI_RCIR_BASE (0x01f02000L) +#define SUNXI_RTWI_BASE (0x01f02400L) +#define SUNXI_RUART_BASE (0x01f02800L) +#define SUNXI_RPIO_BASE (0x01f02c00L) +#define SUNXI_RRSB_BASE (0x01f03400L) +#define SUNXI_RPWM_BASE (0x01f03800L) + +#endif diff --git a/plat/sun50iw1p1/sunxi_cpu_ops.c b/plat/sun50iw1p1/sunxi_cpu_ops.c new file mode 100644 index 0000000..04978b1 --- /dev/null +++ b/plat/sun50iw1p1/sunxi_cpu_ops.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ +#include <arch.h> +#include <arch_helpers.h> +#include <platform.h> +#include <platform_def.h> +#include <mmio.h> +#include <debug.h> +#include <bakery_lock.h> +#include "sunxi_def.h" +#include "sunxi_private.h" + +#define SUN50I_PRCM_PBASE (0x01F01400) +#define SUN50I_CPUCFG_PBASE (0x01700000) +#define SUN50I_RCPUCFG_PBASE (0x01F01C00) + +#define SUNXI_CPU_PWR_CLAMP(cluster, cpu) (0x140 + (cluster*4 + cpu)*0x04) +#define SUNXI_CLUSTER_PWROFF_GATING(cluster) (0x100 + (cluster)*0x04) +#define SUNXI_CLUSTER_PWRON_RESET(cluster) (0x30 + (cluster)*0x04) + +#define SUNXI_DBG_REG0 (0x20) +#define SUNXI_CLUSTER_CPU_STATUS(cluster) (0x30 + (cluster)*0x4) +#define SUNXI_CPU_RST_CTRL(cluster) (0x80 + (cluster)*0x4) +#define SUNXI_CLUSTER_CTRL0(cluster) (0x00 + (cluster)*0x10) + +#define SUNXI_CPU_RVBA_L(cpu) (0xA0 + (cpu)*0x8) +#define SUNXI_CPU_RVBA_H(cpu) (0xA4 + (cpu)*0x8) + +#define readl(x) mmio_read_32((x)) +#define writel(v, a) mmio_write_32((a), (v)) + typedef unsigned int bool; + + static unsigned int sun50i_cpucfg_base = SUN50I_CPUCFG_PBASE; + static unsigned int sun50i_prcm_base = SUN50I_PRCM_PBASE; + static unsigned int sun50i_r_cpucfg_base = SUN50I_RCPUCFG_PBASE; + extern bakery_lock_t plat_console_lock; + void udelay(unsigned int delay) + { + unsigned int i, j; + + for (i=0; i<1000*delay; i++) + { + j+=i; + } + } + + void sun50i_set_secondary_entry(unsigned long entry, unsigned int cpu) + { + mmio_write_32(sun50i_cpucfg_base + SUNXI_CPU_RVBA_L(cpu) ,entry); + mmio_write_32(sun50i_cpucfg_base + SUNXI_CPU_RVBA_H(cpu), 0); + } + + void sun50i_set_AA32nAA64(unsigned int cluster, unsigned int cpu, bool is_aa64) + { + volatile unsigned int value; + + value = readl(sun50i_cpucfg_base + SUNXI_CLUSTER_CTRL0(cluster)); + value &= ~(1<<(cpu + 24)); + value |= (is_aa64 <<(cpu + 24)); + writel(value, sun50i_cpucfg_base + SUNXI_CLUSTER_CTRL0(cluster)); + value = readl(sun50i_cpucfg_base + SUNXI_CLUSTER_CTRL0(cluster)); + } + + int sun50i_power_switch_set(unsigned int cluster, unsigned int cpu, bool enable) + { + if (enable) { + if (0x00 == readl(sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu))) { + NOTICE("%s: power switch enable already\n", __func__); + return 0; + } + + /* de-active cpu power clamp */ + writel(0xFE, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); + udelay(20); + + writel(0xF8, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); + udelay(10); + + writel(0xE0, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); + udelay(10); + + writel(0x80, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); + udelay(10); + + writel(0x00, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); + udelay(20); + + while (0x00 != readl(sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu))); + } else { + if (0xFF == readl(sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu))) { + NOTICE("%s: power switch disable already\n", __func__); + return 0; + } + + writel(0xFF, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); + udelay(30); + + while (0xFF != readl(sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu))); + } + return 0; + } + + void sun50i_cpu_power_up(unsigned int cluster, unsigned int cpu) + { + unsigned int value; + + /* Assert nCPUPORESET LOW */ + value = readl(sun50i_cpucfg_base + SUNXI_CPU_RST_CTRL(cluster)); + value &= (~(1<<cpu)); + writel(value, sun50i_cpucfg_base + SUNXI_CPU_RST_CTRL(cluster)); + udelay(10); + + /* Assert cpu power-on reset */ + value = readl(sun50i_r_cpucfg_base + SUNXI_CLUSTER_PWRON_RESET(cluster)); + value &= (~(1<<cpu)); + writel(value, sun50i_r_cpucfg_base + SUNXI_CLUSTER_PWRON_RESET(cluster)); + udelay(10); + + /* set AA32nAA64 to AA64 */ + sun50i_set_AA32nAA64(cluster, cpu, 1); + + /* Apply power to the PDCPU power domain. */ + sun50i_power_switch_set(cluster, cpu, 1); + + /* Release the core output clamps */ + value = readl(sun50i_prcm_base + SUNXI_CLUSTER_PWROFF_GATING(cluster)); + value &= (~(0x1<<cpu)); + writel(value, sun50i_prcm_base + SUNXI_CLUSTER_PWROFF_GATING(cluster)); + udelay(20); + + /* Deassert cpu power-on reset */ + value = readl(sun50i_r_cpucfg_base + SUNXI_CLUSTER_PWRON_RESET(cluster)); + value |= ((1<<cpu)); + writel(value, sun50i_r_cpucfg_base + SUNXI_CLUSTER_PWRON_RESET(cluster)); + udelay(10); + + /* Deassert core reset */ + value = readl(sun50i_cpucfg_base + SUNXI_CPU_RST_CTRL(cluster)); + value |= (1<<cpu); + writel(value, sun50i_cpucfg_base + SUNXI_CPU_RST_CTRL(cluster)); + udelay(10); + + /* Assert DBGPWRDUP HIGH */ + value = readl(sun50i_cpucfg_base + SUNXI_DBG_REG0); + value |= (1<<cpu); + writel(value, sun50i_cpucfg_base + SUNXI_DBG_REG0); + udelay(10); + bakery_lock_get(&plat_console_lock); + INFO("sun50i power-up cluster-%d cpu-%d ok\n", cluster, cpu); + bakery_lock_release(&plat_console_lock); + } + +void sun50i_cpu_power_down(unsigned int cluster, unsigned int cpu) +{ + unsigned int value; + + /* step7: Deassert DBGPWRDUP LOW */ + value = readl(sun50i_cpucfg_base + SUNXI_DBG_REG0); + value &= (~(1<<cpu)); + writel(value, sun50i_cpucfg_base + SUNXI_DBG_REG0); + udelay(10); + + /* step8: Activate the core output clamps */ + value = readl(sun50i_prcm_base + SUNXI_CLUSTER_PWROFF_GATING(cluster)); + value |= (1 << cpu); + writel(value, sun50i_prcm_base + SUNXI_CLUSTER_PWROFF_GATING(cluster)); + udelay(20); + + /* step9: Assert nCPUPORESET LOW */ + value = readl(sun50i_cpucfg_base + SUNXI_CPU_RST_CTRL(cluster)); + value &= (~(1<<cpu)); + writel(value, sun50i_cpucfg_base + SUNXI_CPU_RST_CTRL(cluster)); + udelay(10); + + /* step10: Remove power from th e PDCPU power domain */ + sun50i_power_switch_set(cluster, cpu, 0); + bakery_lock_get(&plat_console_lock); + INFO("sun50i power-down cluster-%d cpu-%d ok.\n", cluster, cpu); + bakery_lock_release(&plat_console_lock); + +} + +void sunxi_cpu_die(unsigned int cpu) +{ + #if 0 + unsigned long sctlr, cpuectlr; + + /* step1: Disable the data cache */ + __asm("mrs %0, SCTLR_EL1\n" : "=r" (sctlr)); + sctlr &= ~(0x1<<2); + __asm volatile("msr SCTLR_EL1, %0\n" : : "r" (sctlr)); + + /* step2: Clean and invalidate all data from the L1 Data cache */ + //flush_cache_all(); + dcsw_op_louis(DCCSW); + + /* step3: Disable data coherency with other cores in the cluster */ + __asm("mrs %0, S3_1_c15_c2_1\n" : "=r" (cpuectlr)); + cpuectlr &= ~(0x1<<6); + __asm volatile("msr S3_1_c15_c2_1, %0\n" : : "r" (cpuectlr)); + + /* + * step4: Execute an ISB instruction to ensure that + * all of the register changes from the previous steps + * have been committed + */ + isb(); + + /* + * step5: Execute a DSB SY instruction to ensure that all cache, + * TLB and branch predictor maintenance operations issued + * by any core in the cluster device before the SMPEN bit + * was cleared have completed + */ + dsb(); + #endif +} + diff --git a/plat/sun50iw1p1/sunxi_cpu_ops.h b/plat/sun50iw1p1/sunxi_cpu_ops.h new file mode 100644 index 0000000..ce49903 --- /dev/null +++ b/plat/sun50iw1p1/sunxi_cpu_ops.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#ifndef __SUNXI_CPU_OPS_H__ +#define __SUNXI_CPU_OPS_H__ + +void sun50i_set_secondary_entry(unsigned long entry, unsigned int cpu); +void sun50i_cpu_power_up(unsigned int cluster, unsigned int cpu); +void sun50i_cpu_power_down(unsigned int cluster, unsigned int cpu); +void sunxi_cpu_die(unsigned int cpu); + +#endif diff --git a/plat/sun50iw1p1/sunxi_def.h b/plat/sun50iw1p1/sunxi_def.h new file mode 100644 index 0000000..f4db727 --- /dev/null +++ b/plat/sun50iw1p1/sunxi_def.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + + /*------------------------------------------------------------------------------- +| | | | | +| ATF | (atf&scp)share | Trusted OS | Linux | +| | | | | + ---------------------------------------------------------------------------------- +| | | | | +| 1M | 1M | 14M | other | +| | | | | +----------------------------------------------------------------------------------*/ + +#ifndef __SUNXI_DEF_H__ +#define __SUNXI_DEF_H__ + +#include "sun50iw1p1.h" +/* Firmware Image Package */ +#define FIP_IMAGE_NAME "fip.bin" +#define SUNXI_PRIMARY_CPU 0x0 + +/* Memory location options for Shared data and TSP in sunxi */ +#define SUNXI_IN_TRUSTED_SRAM 0 +#define SUNXI_IN_TRUSTED_DRAM 1 + +/******************************************************************************* + * sunxi memory map related constants + ******************************************************************************/ + +#define SUNXI_MAX_DRAM_SIZE (2ull<<30) /*2G*/ + +//monitor area(atf+scp) +#define SUNXI_TRUSTED_MONITOR_BASE 0x40000000 +#define SUNXI_TRUSTED_MONITOR_SIZE (2<<20) //2MB + +//sec os area +#define SUNXI_TRUSTED_DRAM_BASE 0x40200000 +#define SUNXI_TRUSTED_DRAM_SIZE (14<<20) //14 MB + +//monitor area + sec os area +#define SUNXI_TRUSTED_RAM_SIZE 0x01000000 //total 16M + +//atf code limit +#define SUNXI_TRUSTED_MONITOR_LIMIT (SUNXI_TRUSTED_MONITOR_BASE + (1<<20)) //1M + + +/* 4KB shared memory */ +#define SUNXI_SHARED_RAM_SIZE 0x1000 + +/* Shared memory at the base of Trusted DRAM */ +#define SUNXI_SHARED_RAM_BASE SUNXI_TRUSTED_DRAM_BASE + + +#define DRAM1_BASE 0x40000000ull +#define DRAM1_SIZE 0x40000000ull //1G +#define DRAM1_END (DRAM1_BASE + DRAM1_SIZE - 1) +#define DRAM1_SEC_SIZE 0x01000000ull + +#define DRAM_BASE DRAM1_BASE +#define DRAM_SIZE DRAM1_SIZE + +#define MEMRES_BASE SUNXI_TRUSTED_MONITOR_LIMIT //0x40100000 +#define MEMRES_SIZE 0x100000 //1M + +/* Load address of BL33 in the sunxi */ +#define NS_IMAGE_OFFSET (DRAM1_BASE + 0xA000000) /* DRAM + 128MB */ + +/* Special value used to verify platform parameters from BL2 to BL3-1 */ +#define SUNXI_BL31_PLAT_PARAM_VAL 0x12345678 //0x0f1e2d3c4b5a6978ULL + + +/******************************************************************************* + * PL011 related constants + ******************************************************************************/ +#define UART0_BAUDRATE 115200 + +#define UART0_CLK_IN_HZ 24000000 + +/******************************************************************************* + * Shared Data + ******************************************************************************/ + +/* Entrypoint mailboxes */ +#define TRUSTED_MAILBOXES_BASE SUNXI_SHARED_RAM_BASE +#define TRUSTED_MAILBOXES_SIZE 0x200 +#define TRUSTED_MAILBOX_SHIFT 4 + + +/* Base address where parameters to BL31 are stored */ +#define PARAMS_BASE (TRUSTED_MAILBOXES_BASE + TRUSTED_MAILBOXES_SIZE) + +#define MHU_SECURE_BASE 0x10000 +#define MHU_SECURE_SIZE 0x1000 + +#define MHU_PAYLOAD_CACHED 0 + +#endif /* __SUNXI_DEF_H__ */ diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h new file mode 100644 index 0000000..e2c548f --- /dev/null +++ b/plat/sun50iw1p1/sunxi_private.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#ifndef __SUNXI_PRIVATE_H__ +#define __SUNXI_PRIVATE_H__ + +#include <bl_common.h> +#include <platform_def.h> + + +void gic_cpuif_deactivate(unsigned int gicc_base); +void gic_cpuif_setup(unsigned int gicc_base); +void gic_pcpu_distif_setup(unsigned int gicd_base); +void gic_setup(void); + + +typedef volatile struct mailbox { + unsigned long value + __attribute__((__aligned__(CACHE_WRITEBACK_GRANULE))); +} mailbox_t; + +/******************************************************************************* + * This structure represents the superset of information that is passed to + * BL31 e.g. while passing control to it from BL2 which is bl31_params + * and bl31_plat_params and its elements + ******************************************************************************/ +typedef struct bl2_to_bl31_params_mem { + bl31_params_t bl31_params; + image_info_t bl31_image_info; + image_info_t bl32_image_info; + image_info_t bl33_image_info; + entry_point_info_t bl33_ep_info; + entry_point_info_t bl32_ep_info; + entry_point_info_t bl31_ep_info; +} bl2_to_bl31_params_mem_t; + +/******************************************************************************* + * Forward declarations + ******************************************************************************/ +struct meminfo; + +/******************************************************************************* + * Function and variable prototypes + ******************************************************************************/ +void sunxi_configure_mmu_el1(unsigned long total_base, + unsigned long total_size, + unsigned long, + unsigned long, + unsigned long, + unsigned long); +void sunxi_configure_mmu_el3(unsigned long total_base, + unsigned long total_size, + unsigned long, + unsigned long, + unsigned long, + unsigned long); +int sunxi_config_setup(void); + +void sunxi_cci_init(void); +void sunxi_cci_enable(void); + +void sunxi_gic_init(void); + +/* Declarations for sunxi_topology.c */ +int sunxi_setup_topology(void); + +/* Declarations for sunxi_io_storage.c */ +void sunxi_io_setup(void); + +/* Declarations for sunxi_security.c */ +void sunxi_security_setup(void); + +/* Gets the SPR for BL32 entry */ +uint32_t sunxi_get_spsr_for_bl32_entry(void); + +/* Gets the SPSR for BL33 entry */ +uint32_t sunxi_get_spsr_for_bl33_entry(void); + + +#endif /* __FVP_PRIVATE_H__ */ diff --git a/plat/sun50iw1p1/sunxi_security.c b/plat/sun50iw1p1/sunxi_security.c new file mode 100644 index 0000000..c0ccac0 --- /dev/null +++ b/plat/sun50iw1p1/sunxi_security.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <assert.h> +#include <debug.h> +#include <plat_config.h> +#include <tzc400.h> +#include <mmio.h> +#include "sunxi_def.h" +#include "sunxi_private.h" + +#define SPC_BASE (0x1c23400ull) + +#define SPC_DECPORT0_STA_REG (SPC_BASE+0x4) +#define SPC_DECPORT0_SET_REG (SPC_BASE+0x8) +#define SPC_DECPORT0_CLR_REG (SPC_BASE+0xc) + +#define SPC_DECPORT1_STA_REG (SPC_BASE+0x10) +#define SPC_DECPORT1_SET_REG (SPC_BASE+0x14) +#define SPC_DECPORT1_CLR_REG (SPC_BASE+0x18) + +#define SPC_DECPORT2_STA_REG (SPC_BASE+0x1c) +#define SPC_DECPORT2_SET_REG (SPC_BASE+0x20) +#define SPC_DECPORT2_CLR_REG (SPC_BASE+0x24) + +#define SPC_DECPORT3_STA_REG (SPC_BASE+0x28) +#define SPC_DECPORT3_SET_REG (SPC_BASE+0x2c) +#define SPC_DECPORT3_CLR_REG (SPC_BASE+0x30) + +#define SPC_DECPORT4_STA_REG (SPC_BASE+0x34) +#define SPC_DECPORT4_SET_REG (SPC_BASE+0x38) +#define SPC_DECPORT4_CLR_REG (SPC_BASE+0x3c) + +#define SPC_DECPORT5_STA_REG (SPC_BASE+0x40) +#define SPC_DECPORT5_SET_REG (SPC_BASE+0x44) +#define SPC_DECPORT5_CLR_REG (SPC_BASE+0x48) + + + + + + + + +/* Used to improve readability for configuring regions. */ +#define FILTER_SHIFT(filter) (1 << filter) + +/* + * For the moment we assume that all security programming is done by the + * primary core. + * TODO: + * Might want to enable interrupt on violations when supported? + */ +void sunxi_security_setup(void) +{ + /* + * + * If the platform had additional peripheral specific security + * configurations, those would be configured here. + */ + + //if (!(get_plat_config()->flags & CONFIG_HAS_TZC)) + // return; + + INFO("Configuring SPC Controller\n"); + //set all peripherals to non-sec + mmio_write_32(SPC_DECPORT0_SET_REG,0xff); + mmio_write_32(SPC_DECPORT1_SET_REG,0xff); + mmio_write_32(SPC_DECPORT2_SET_REG,0xff); + mmio_write_32(SPC_DECPORT3_SET_REG,0xff); + mmio_write_32(SPC_DECPORT4_SET_REG,0xff); + mmio_write_32(SPC_DECPORT5_SET_REG,0xff); + + //set ccmu security switch: set mbus_sec bus_sec pll_sec to non-sec + mmio_write_32(0x01c20000+0x2f0, 0x7); + + //set R_PRCM security switch: set power_sec pll_sec cpus_clk to non-sec + mmio_write_32(0x01f01400+0x1d0, 0x7); + + //set dma security switch: set DMA channel0-7 to non-sec + mmio_write_32(0x01c02000+0x20, 0xff); + +} diff --git a/plat/sun50iw1p1/tsp/tsp-wine.mk b/plat/sun50iw1p1/tsp/tsp-wine.mk new file mode 100644 index 0000000..3cbc6ec --- /dev/null +++ b/plat/sun50iw1p1/tsp/tsp-wine.mk @@ -0,0 +1,38 @@ +# +# Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. +# + +# TSP source files specific to FVP platform +BL32_SOURCES += drivers/arm/gic/arm_gic.c \ + drivers/arm/gic/gic_v2.c \ + plat/common/aarch64/platform_mp_stack.S \ + plat/common/plat_gic.c \ + plat/sun50iw1p1/aarch64/sunxi_common.c \ + plat/sun50iw1p1/aarch64/sunxi_helpers.S \ + plat/sun50iw1p1/tsp/tsp_sunxi_setup.c diff --git a/plat/sun50iw1p1/tsp/tsp_sunxi_setup.c b/plat/sun50iw1p1/tsp/tsp_sunxi_setup.c new file mode 100644 index 0000000..82c74af --- /dev/null +++ b/plat/sun50iw1p1/tsp/tsp_sunxi_setup.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <bl_common.h> +#include <console.h> +#include <platform_tsp.h> +#include "../sunxi_def.h" +#include "../sunxi_private.h" + +/******************************************************************************* + * Declarations of linker defined symbols which will help us find the layout + * of trusted SRAM + ******************************************************************************/ +extern unsigned long __RO_START__; +extern unsigned long __RO_END__; + +extern unsigned long __COHERENT_RAM_START__; +extern unsigned long __COHERENT_RAM_END__; + +/* + * The next 2 constants identify the extents of the code & RO data region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses. + */ +#define BL32_RO_BASE (unsigned long)(&__RO_START__) +#define BL32_RO_LIMIT (unsigned long)(&__RO_END__) + +/* + * The next 2 constants identify the extents of the coherent memory region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to + * page-aligned addresses. + */ +#define BL32_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__) +#define BL32_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__) + +/******************************************************************************* + * Initialize the UART + ******************************************************************************/ +void tsp_early_platform_setup(void) +{ + /* + * Initialize a different console than already in use to display + * messages from TSP + */ + console_init(SUNXI_UART0_BASE, UART0_CLK_IN_HZ, UART0_BAUDRATE); + + /* Initialize the platform config for future decision making */ + sunxi_config_setup(); +} + +/******************************************************************************* + * Perform platform specific setup placeholder + ******************************************************************************/ +void tsp_platform_setup(void) +{ + sunxi_gic_init(); +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this is only intializes the MMU + ******************************************************************************/ +void tsp_plat_arch_setup(void) +{ + sunxi_configure_mmu_el1(BL32_RO_BASE, + (BL32_COHERENT_RAM_LIMIT - BL32_RO_BASE), + BL32_RO_BASE, + BL32_RO_LIMIT, + BL32_COHERENT_RAM_BASE, + BL32_COHERENT_RAM_LIMIT); +} diff --git a/services/arm/arm_svc_setup.c b/services/arm/arm_svc_setup.c new file mode 100644 index 0000000..7e2a396 --- /dev/null +++ b/services/arm/arm_svc_setup.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. 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 ARM 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 HOLDER 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. + */ + +#include <debug.h> +#include <psci.h> +#include <runtime_svc.h> +#include <std_svc.h> +#include <stdint.h> +#include <uuid.h> +#include <assert.h> +#include <string.h> +#include <bl_common.h> +#include <context_mgmt.h> +#include <arisc.h> +#include <mmio.h> + +#define ARM_NUM_CALLS 6 + +#define ARM_SVC_CALL_COUNT 0x8000ff00 +#define ARM_SVC_UID 0x8000ff01 +//0x8000ff02 reserved +#define ARM_SVC_VERSION 0x8000ff03 +#define ARM_SVC_RUNNSOS 0x8000ff04 +#define ARM_SVC_READ_SEC_REG 0x8000ff05 +#define ARM_SVC_WRITE_SEC_REG 0x8000ff06 + +#define ARM_SVC_ARISC_STARTUP 0x8000ff10 +#define ARM_SVC_ARISC_WAIT_READY 0x8000ff11 +#define ARM_SVC_ARISC_READ_PMU 0x8000ff12 +#define ARM_SVC_ARISC_WRITE_PMU 0x8000ff13 + + +/* ARM Standard Service Calls version numbers */ +#define ARM_SVC_VERSION_MAJOR 0x0 +#define ARM_SVC_VERSION_MINOR 0x1 + +/* Arm arch Service UUID */ + +DEFINE_SVC_UUID(arm_svc_uid, + 0x83B53A5B, 0xC594, 0x40B9, 0x53, 0x91, + 0xF2, 0xFC, 0x54, 0x29, 0x86, 0x48); +/******************************************************************************* + * This function programs EL3 registers and performs other setup to enable entry + * into the next image after BL31 at the next ERET. + ******************************************************************************/ +void prepare_nonsec_os_entry(uint64_t kernel_addr, uint64_t dtb_addr) +{ + entry_point_info_t next_image_info; + uint32_t image_type; + + /* Determine which image to execute next */ + image_type = NON_SECURE; + + /* Program EL3 registers to enable entry into the next EL */ + memset(&next_image_info, 0, sizeof(next_image_info)); + SET_SECURITY_STATE(next_image_info.h.attr, NON_SECURE); + next_image_info.spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); + next_image_info.pc = kernel_addr; + next_image_info.args.arg0 = dtb_addr; + + + + INFO("BL3-1: Next image address = 0x%llx\n",(unsigned long long) next_image_info.pc); + INFO("BL3-1: Next image spsr = 0x%x\n", next_image_info.spsr); + + cm_init_context(read_mpidr_el1(), &next_image_info); + cm_prepare_el3_exit(image_type); +} + + +/* + * Top-level Standard Service SMC handler. This handler will in turn dispatch + * calls to PSCI SMC handler + */ +uint64_t arm_svc_smc_handler(uint32_t smc_fid, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + //INFO(" Arm Architechture Service Call: 0x%x \n", smc_fid); + + switch (smc_fid) { + case ARM_SVC_CALL_COUNT: + SMC_RET1(handle, ARM_NUM_CALLS); + case ARM_SVC_UID: + /* Return UID to the caller */ + SMC_UUID_RET(handle, arm_svc_uid); + case ARM_SVC_VERSION: + /* Return the version of current implementation */ + SMC_RET2(handle, ARM_SVC_VERSION_MAJOR, ARM_SVC_VERSION_MINOR); + case ARM_SVC_RUNNSOS: + prepare_nonsec_os_entry((uint32_t)x1,(uint32_t)x2); + SMC_RET0(handle); + case ARM_SVC_READ_SEC_REG: + SMC_RET1(handle, mmio_read_32((uintptr_t)x1)); + case ARM_SVC_WRITE_SEC_REG: + mmio_write_32((uintptr_t)x1,(uint32_t)x2); + SMC_RET0(handle); + + //arise cmd begin + //arise aa32 cmd + case ARM_SVC_ARISC_STARTUP: + SMC_RET1(handle, sunxi_arisc_probe((void *)x1)); + case ARM_SVC_ARISC_WAIT_READY: + SMC_RET1(handle, sunxi_arisc_wait_ready()); + case ARM_SVC_ARISC_READ_PMU: + SMC_RET1(handle, arisc_rsb_read_pmu_reg((uint32_t)x1)); + case ARM_SVC_ARISC_WRITE_PMU: + SMC_RET1(handle,arisc_rsb_write_pmu_reg((uint32_t)x1,(uint32_t)x2)); + + //arise aa64 cmd + case ARM_SVC_ARISC_CPUX_DVFS_REQ: + SMC_RET1(handle, arisc_dvfs_set_cpufreq((uint32_t)x1, (uint32_t)x2, (uint32_t)x3)); + case ARM_SVC_ARISC_RSB_READ_BLOCK_DATA: + SMC_RET1(handle, arisc_rsb_read_block_data((uint32_t *)x1)); + case ARM_SVC_ARISC_RSB_WRITE_BLOCK_DATA: + SMC_RET1(handle, arisc_rsb_write_block_data((uint32_t *)x1)); + case ARM_SVC_ARISC_RSB_BITS_OPS_SYNC: + SMC_RET1(handle, rsb_bits_ops_sync((uint32_t *)x1)); + case ARM_SVC_ARISC_RSB_SET_INTERFACE_MODE: + SMC_RET1(handle, arisc_rsb_set_interface_mode((uint32_t)x1, (uint32_t)x2, (uint32_t)x3)); + case ARM_SVC_ARISC_RSB_SET_RTSADDR: + SMC_RET1(handle, arisc_rsb_set_rtsaddr((uint32_t)x1, (uint32_t)x2)); + case ARM_SVC_ARISC_SET_DEBUG_LEVEL: + SMC_RET1(handle, arisc_set_debug_level((uint32_t)x1)); + case ARM_SVC_ARISC_SET_UART_BAUDRATE: + SMC_RET1(handle, arisc_set_uart_baudrate((uint32_t)x1)); + case ARM_SVC_ARISC_MESSAGE_LOOPBACK: + SMC_RET1(handle, arisc_message_loopback()); + case ARM_SVC_ARISC_SET_DEBUG_DRAM_CRC_PARAS: + SMC_RET1(handle, arisc_set_dram_crc_paras((uint32_t)x1, (uint32_t)x2, (uint32_t)x3)); + case ARM_SVC_ARISC_AXP_DISABLE_IRQ: + SMC_RET1(handle, arisc_disable_nmi_irq()); + case ARM_SVC_ARISC_AXP_ENABLE_IRQ: + SMC_RET1(handle, arisc_enable_nmi_irq()); + case ARM_SVC_ARISC_CLR_NMI_STATUS: + SMC_RET1(handle, arisc_clear_nmi_status()); + case ARM_SVC_ARISC_SET_NMI_TRIGGER: + SMC_RET1(handle, arisc_set_nmi_trigger((uint32_t)x1)); + case ARM_SVC_ARISC_AXP_GET_CHIP_ID: + SMC_RET1(handle, arisc_axp_get_chip_id((unsigned char *)x1)); + case ARM_SVC_ARISC_AXP_SET_PARAS: + SMC_RET1(handle, arisc_adjust_pmu_chgcur((uint32_t)x1, (uint32_t)x2, (uint32_t)x3)); + case ARM_SVC_ARISC_SET_PWR_TREE: + SMC_RET1(handle, arisc_set_pwr_tree((uint32_t *)x1)); + case ARM_SVC_ARISC_SET_PMU_VOLT: + SMC_RET1(handle, arisc_pmu_set_voltage((uint32_t)x1, (uint32_t)x2)); + case ARM_SVC_ARISC_GET_PMU_VOLT: + SMC_RET1(handle, arisc_pmu_get_voltage((uint32_t)x1, (uint32_t *)x2)); + case ARM_SVC_ARISC_SET_LED_BLN: + SMC_RET1(handle, arisc_set_led_bln((uint32_t *)x1)); + case ARM_SVC_ARISC_QUERY_WAKEUP_SRC_REQ: + SMC_RET1(handle, arisc_query_wakeup_source((uint32_t *)x1)); + case ARM_SVC_ARISC_STANDBY_INFO_REQ: + SMC_RET1(handle, arisc_query_set_standby_info((standby_info_para_t *)x1, (arisc_rw_type_e)x2)); + default: + WARN("Unimplemented Standard Service Call: 0x%x \n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } +} + +/* Register Standard Service Calls as runtime service */ +DECLARE_RT_SVC( + arm_svc, + + OEN_ARM_START, + OEN_ARM_END, + SMC_TYPE_FAST, + NULL, + arm_svc_smc_handler +); diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c index b8d4569..1d5d5c5 100644 --- a/services/spd/tspd/tspd_main.c +++ b/services/spd/tspd/tspd_main.c @@ -255,7 +255,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, #if TSP_INIT_ASYNC entry_point_info_t *next_image_info; #endif - + WARN("tspd_smc_handler call\n"); /* Determine which security state this SMC originated from */ ns = is_caller_non_secure(flags); @@ -358,6 +358,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, * finished initialising itself after a cold boot */ case TSP_ENTRY_DONE: + WARN("tspd_smc_handler call:TSP_ENTRY_DONE\n"); if (ns) SMC_RET1(handle, SMC_UNK); diff --git a/services/std_svc/psci/psci_afflvl_off.c b/services/std_svc/psci/psci_afflvl_off.c index 7e05789..f0f4234 100644 --- a/services/std_svc/psci/psci_afflvl_off.c +++ b/services/std_svc/psci/psci_afflvl_off.c @@ -62,12 +62,6 @@ static int psci_afflvl0_off(aff_map_node_t *cpu_node) return rc; } - /* - * Arch. management. Perform the necessary steps to flush all - * cpu caches. - */ - psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0); - if (!psci_plat_pm_ops->affinst_off) return PSCI_E_SUCCESS; @@ -75,22 +69,25 @@ static int psci_afflvl0_off(aff_map_node_t *cpu_node) * Plat. management: Perform platform specific actions to turn this * cpu off e.g. exit cpu coherency, program the power controller etc. */ - return psci_plat_pm_ops->affinst_off(read_mpidr_el1(), + rc = psci_plat_pm_ops->affinst_off(read_mpidr_el1(), cpu_node->level, psci_get_phys_state(cpu_node)); + /* + * Arch. management. Perform the necessary steps to flush all + * cpu caches. + */ + psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0); + + return rc; } static int psci_afflvl1_off(aff_map_node_t *cluster_node) { + int rc; + /* Sanity check the cluster level */ assert(cluster_node->level == MPIDR_AFFLVL1); - /* - * Arch. Management. Flush all levels of caches to PoC if - * the cluster is to be shutdown. - */ - psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1); - if (!psci_plat_pm_ops->affinst_off) return PSCI_E_SUCCESS; @@ -99,13 +96,23 @@ static int psci_afflvl1_off(aff_map_node_t *cluster_node) * specific bookeeping e.g. turn off interconnect coherency, * program the power controller etc. */ - return psci_plat_pm_ops->affinst_off(read_mpidr_el1(), + rc = psci_plat_pm_ops->affinst_off(read_mpidr_el1(), cluster_node->level, psci_get_phys_state(cluster_node)); + + /* + * Arch. Management. Flush all levels of caches to PoC if + * the cluster is to be shutdown. + */ + psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1); + + return rc; } static int psci_afflvl2_off(aff_map_node_t *system_node) { + int rc; + /* Cannot go beyond this level */ assert(system_node->level == MPIDR_AFFLVL2); @@ -114,12 +121,6 @@ static int psci_afflvl2_off(aff_map_node_t *system_node) * action needs to be taken */ - /* - * Arch. Management. Flush all levels of caches to PoC if - * the system is to be shutdown. - */ - psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL2); - if (!psci_plat_pm_ops->affinst_off) return PSCI_E_SUCCESS; @@ -127,9 +128,17 @@ static int psci_afflvl2_off(aff_map_node_t *system_node) * Plat. Management : Allow the platform to do its bookeeping * at this affinity level */ - return psci_plat_pm_ops->affinst_off(read_mpidr_el1(), + rc = psci_plat_pm_ops->affinst_off(read_mpidr_el1(), system_node->level, psci_get_phys_state(system_node)); + + /* + * Arch. Management. Flush all levels of caches to PoC if + * the system is to be shutdown. + */ + psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL2); + + return rc; } static const afflvl_off_handler_t psci_afflvl_off_handlers[] = { diff --git a/services/std_svc/psci/psci_afflvl_on.c b/services/std_svc/psci/psci_afflvl_on.c index f1d30c9..de08251 100644 --- a/services/std_svc/psci/psci_afflvl_on.c +++ b/services/std_svc/psci/psci_afflvl_on.c @@ -38,6 +38,7 @@ #include <runtime_svc.h> #include <stddef.h> #include "psci_private.h" +#include <debug.h> typedef int (*afflvl_on_handler_t)(unsigned long, aff_map_node_t *, diff --git a/services/std_svc/psci/psci_afflvl_suspend.c b/services/std_svc/psci/psci_afflvl_suspend.c index 4fcabfc..8472821 100644 --- a/services/std_svc/psci/psci_afflvl_suspend.c +++ b/services/std_svc/psci/psci_afflvl_suspend.c @@ -38,6 +38,7 @@ #include <platform.h> #include <runtime_svc.h> #include <stddef.h> +#include <debug.h> #include "psci_private.h" typedef int (*afflvl_suspend_handler_t)(aff_map_node_t *, @@ -146,12 +147,6 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node, /* Set the secure world (EL3) re-entry point after BL1 */ psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry; - /* - * Arch. management. Perform the necessary steps to flush all - * cpu caches. - */ - psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0); - if (!psci_plat_pm_ops->affinst_suspend) return PSCI_E_SUCCESS; @@ -161,11 +156,19 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node, * platform defined mailbox with the psci entrypoint, * program the power controller etc. */ - return psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(), + rc = psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(), psci_entrypoint, ns_entrypoint, cpu_node->level, psci_get_phys_state(cpu_node)); + + /* + * Arch. management. Perform the necessary steps to flush all + * cpu caches. + */ + psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0); + + return rc; } static int psci_afflvl1_suspend(aff_map_node_t *cluster_node, @@ -175,16 +178,11 @@ static int psci_afflvl1_suspend(aff_map_node_t *cluster_node, { unsigned int plat_state; unsigned long psci_entrypoint; + int rc; /* Sanity check the cluster level */ assert(cluster_node->level == MPIDR_AFFLVL1); - /* - * Arch. management: Flush all levels of caches to PoC if the - * cluster is to be shutdown. - */ - psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1); - if (!psci_plat_pm_ops->affinst_suspend) return PSCI_E_SUCCESS; @@ -198,11 +196,18 @@ static int psci_afflvl1_suspend(aff_map_node_t *cluster_node, */ plat_state = psci_get_phys_state(cluster_node); psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry; - return psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(), + rc = psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(), psci_entrypoint, ns_entrypoint, cluster_node->level, plat_state); + /* + * Arch. management: Flush all levels of caches to PoC if the + * cluster is to be shutdown. + */ + psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1); + + return rc; } @@ -213,6 +218,7 @@ static int psci_afflvl2_suspend(aff_map_node_t *system_node, { unsigned int plat_state; unsigned long psci_entrypoint; + int rc; /* Cannot go beyond this */ assert(system_node->level == MPIDR_AFFLVL2); @@ -224,12 +230,6 @@ static int psci_afflvl2_suspend(aff_map_node_t *system_node, plat_state = psci_get_phys_state(system_node); /* - * Arch. management: Flush all levels of caches to PoC if the - * system is to be shutdown. - */ - psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL2); - - /* * Plat. Management : Allow the platform to do its bookeeping * at this affinity level */ @@ -244,11 +244,18 @@ static int psci_afflvl2_suspend(aff_map_node_t *system_node, */ plat_state = psci_get_phys_state(system_node); psci_entrypoint = (unsigned long) psci_aff_suspend_finish_entry; - return psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(), + rc = psci_plat_pm_ops->affinst_suspend(read_mpidr_el1(), psci_entrypoint, ns_entrypoint, system_node->level, plat_state); + /* + * Arch. management: Flush all levels of caches to PoC if the + * system is to be shutdown. + */ + psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL2); + + return rc; } static const afflvl_suspend_handler_t psci_afflvl_suspend_handlers[] = { diff --git a/services/std_svc/psci/psci_common.c b/services/std_svc/psci/psci_common.c index 2267ad0..75f52f5 100644 --- a/services/std_svc/psci/psci_common.c +++ b/services/std_svc/psci/psci_common.c @@ -140,7 +140,11 @@ int get_power_on_target_afflvl() * Sanity check the state of the cpu. It should be either suspend or "on * pending" */ - state = psci_get_state(node); + do + { + state = psci_get_state(node); //wait cpu0 set this state --by wangwei + }while(state != PSCI_STATE_SUSPEND && state != PSCI_STATE_ON_PENDING); + assert(state == PSCI_STATE_SUSPEND || state == PSCI_STATE_ON_PENDING); #endif @@ -480,7 +484,6 @@ void psci_afflvl_power_on_finish(int start_afflvl, int rc; unsigned int max_phys_off_afflvl; - /* * Collect the pointers to the nodes in the topology tree for * each affinity instance in the mpidr. If this function does diff --git a/services/std_svc/psci/psci_entry.S b/services/std_svc/psci/psci_entry.S index 8145012..b2ad074 100644 --- a/services/std_svc/psci/psci_entry.S +++ b/services/std_svc/psci/psci_entry.S @@ -70,7 +70,6 @@ psci_aff_common_finish_entry: msr sctlr_el3, x0 isb #endif - /* --------------------------------------------- * Initialise the pcpu cache pointer for the CPU * --------------------------------------------- @@ -78,12 +77,6 @@ psci_aff_common_finish_entry: bl init_cpu_data_ptr /* --------------------------------------------- - * Initialize the cpu_ops pointer. - * --------------------------------------------- - */ - bl init_cpu_ops - - /* --------------------------------------------- * Set the exception vectors * --------------------------------------------- */ @@ -157,7 +150,7 @@ psci_aff_common_finish_entry: */ func psci_power_down_wfi dsb sy // ensure write buffer empty - wfi wfi_spill: + wfi b wfi_spill diff --git a/services/std_svc/psci/psci_main.c b/services/std_svc/psci/psci_main.c index 0ffa5d7..900c5e1 100644 --- a/services/std_svc/psci/psci_main.c +++ b/services/std_svc/psci/psci_main.c @@ -115,8 +115,11 @@ int psci_cpu_suspend(unsigned int power_state, power_state, MPIDR_AFFLVL0, target_afflvl); - if (rc == PSCI_E_SUCCESS) + if (rc == PSCI_E_SUCCESS) { + dcsw_op_all(DCCISW); psci_power_down_wfi(); + } + assert(rc == PSCI_E_INVALID_PARAMS); return rc; } @@ -139,8 +142,11 @@ int psci_cpu_off(void) * successfully completed. Enter a wfi loop which will allow the * power controller to physically power down this cpu. */ - if (rc == PSCI_E_SUCCESS) + if (rc == PSCI_E_SUCCESS) { + dcsw_op_all(DCCISW); psci_power_down_wfi(); + } + /* * The only error cpu_off can return is E_DENIED. So check if that's diff --git a/services/std_svc/psci/psci_private.h b/services/std_svc/psci/psci_private.h index 924a24f..24a5604 100644 --- a/services/std_svc/psci/psci_private.h +++ b/services/std_svc/psci/psci_private.h @@ -60,7 +60,7 @@ typedef struct aff_limits_node { int max; } aff_limits_node_t; -typedef aff_map_node_t (*mpidr_aff_map_nodes_t[MPIDR_MAX_AFFLVL]); +typedef aff_map_node_t (*mpidr_aff_map_nodes_t[MPIDR_MAX_AFFLVL + 1]); typedef unsigned int (*afflvl_power_on_finisher_t)(aff_map_node_t *); /******************************************************************************* diff --git a/services/std_svc/psci/psci_setup.c b/services/std_svc/psci/psci_setup.c index a5ae4ef..6abf151 100644 --- a/services/std_svc/psci/psci_setup.c +++ b/services/std_svc/psci/psci_setup.c @@ -36,6 +36,7 @@ #include <context_mgmt.h> #include <platform.h> #include <stddef.h> +#include <debug.h> #include "psci_private.h" /******************************************************************************* @@ -194,6 +195,7 @@ static void psci_init_aff_map_node(unsigned long mpidr, * instance through the context management library. */ linear_id = platform_get_core_pos(mpidr); + //NOTICE("linear_id %d, mpidr %d max %d\n",linear_id,mpidr,PLATFORM_CORE_COUNT ); assert(linear_id < PLATFORM_CORE_COUNT); /* Invalidate the suspend context for the node */ @@ -210,10 +212,11 @@ static void psci_init_aff_map_node(unsigned long mpidr, psci_svc_cpu_data.max_phys_off_afflvl, PSCI_INVALID_DATA); + flush_cpu_data_by_index(linear_id, psci_svc_cpu_data); + cm_set_context_by_mpidr(mpidr, (void *) &psci_ns_context[linear_id], NON_SECURE); - } return; diff --git a/services/std_svc/std_svc_setup.c b/services/std_svc/std_svc_setup.c index 6cb0319..79c94b0 100644 --- a/services/std_svc/std_svc_setup.c +++ b/services/std_svc/std_svc_setup.c @@ -35,8 +35,9 @@ #include <stdint.h> #include <uuid.h> + /* Standard Service UUID */ -DEFINE_SVC_UUID(arm_svc_uid, +DEFINE_SVC_UUID(std_svc_uid, 0x108d905b, 0xf863, 0x47e8, 0xae, 0x2d, 0xc0, 0xfb, 0x56, 0x41, 0xf6, 0xe2); @@ -71,7 +72,7 @@ uint64_t std_svc_smc_handler(uint32_t smc_fid, return psci_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } - + switch (smc_fid) { case ARM_STD_SVC_CALL_COUNT: /* @@ -82,12 +83,11 @@ uint64_t std_svc_smc_handler(uint32_t smc_fid, case ARM_STD_SVC_UID: /* Return UID to the caller */ - SMC_UUID_RET(handle, arm_svc_uid); + SMC_UUID_RET(handle, std_svc_uid); case ARM_STD_SVC_VERSION: /* Return the version of current implementation */ SMC_RET2(handle, STD_SVC_VERSION_MAJOR, STD_SVC_VERSION_MINOR); - default: WARN("Unimplemented Standard Service Call: 0x%x \n", smc_fid); SMC_RET1(handle, SMC_UNK); diff --git a/tools/add_hash_bl31.sh b/tools/add_hash_bl31.sh new file mode 100755 index 0000000..1814460 --- /dev/null +++ b/tools/add_hash_bl31.sh @@ -0,0 +1,51 @@ +#!/bin/bash +set -e + +BUILD_FILE=bl31.bin +BUILD_MODE=bl31 + +show_help() +{ + printf "\n add_hash.sh - add git log hash value into uboot,boot0,sboot,fes \n" + echo " eg :" + echo " ./add_hash.sh -f input_file -m file_flag " + echo " file_flag = uboot or boot0 or sboot" + printf "\n\n" +} + + +build_bl31() +{ + dd if=./${BUILD_FILE} of=./bl31_back bs=48 count=1 status=noxfer 2> /dev/null + dd if=./cur.log of=./bl31_back ibs=64 conv=notrunc,sync oflag=append obs=64 count=1 status=noxfer 2> /dev/null + dd if=./${BUILD_FILE} of=./bl31_back ibs=112 obs=112 conv=notrunc oflag=append skip=1 status=noxfer 2> /dev/null + mv bl31_back ${BUILD_FILE} +} + + +do_common() +{ + if [ "x${BUILD_MODE}" = "xbl31" ] ; then + echo " add commit info for bl31 " + build_bl31 + else + echo "build none" + fi +} +while getopts f:m: OPTION +do + case $OPTION in + f) + BUILD_FILE=$OPTARG + ;; + m) + BUILD_MODE=$OPTARG + ;; + *) + show_help + exit + ;; + esac +done + +do_common diff --git a/tools/fip_create/Makefile b/tools/fip_create/Makefile index 69569a1..1ffb62f 100644 --- a/tools/fip_create/Makefile +++ b/tools/fip_create/Makefile @@ -31,6 +31,8 @@ PROJECT = fip_create OBJECTS = fip_create.o + + CFLAGS = -Wall -Werror -pedantic -std=c99 ifeq (${DEBUG},1) CFLAGS += -g -O0 -DDEBUG @@ -51,7 +53,7 @@ all: ${PROJECT} ${PROJECT}: ${OBJECTS} Makefile @echo " LD $@" - ${Q}${CC} ${OBJECTS} -o $@ + ${Q}${CC} ${OBJECTS} -o $@ -static %.o: %.c %.h Makefile @echo " CC $<" |