From f3ff9f77d3a5d2d619a8bb8d2ec33d8abc113308 Mon Sep 17 00:00:00 2001 From: Antonio Nino Diaz Date: Tue, 18 Sep 2018 01:36:00 +0100 Subject: [PATCH] gxbb: Initial port of Amlogic Meson S905 (GXBB) The Amlogic Meson S905 is a SoC with a quad core Arm Cortex-A53 running at 1.5Ghz. It also contains a Cortex-M3 used as SCP. This port is a minimal implementation of BL31 capable of booting mainline U-Boot and Linux: - Partial SCPI support. - Basic PSCI support (CPU_ON, SYSTEM_RESET, SYSTEM_OFF). - GICv2 driver set up. - Basic SIP services (read efuse data, enable/disable JTAG). This port has been tested in an ODROID-C2. Change-Id: Ia4bc82d7aca42a69d6b118b947279f82b3f6c6da Tested-by: Amit Singh Tomar Signed-off-by: Antonio Nino Diaz --- plat/meson/gxbb/aarch64/gxbb_helpers.S | 97 +++++++++++++++++ plat/meson/gxbb/gxbb_bl31_setup.c | 144 +++++++++++++++++++++++++ plat/meson/gxbb/gxbb_common.c | 143 ++++++++++++++++++++++++ plat/meson/gxbb/gxbb_def.h | 118 ++++++++++++++++++++ plat/meson/gxbb/gxbb_efuse.c | 25 +++++ plat/meson/gxbb/gxbb_mhu.c | 52 +++++++++ plat/meson/gxbb/gxbb_pm.c | 120 +++++++++++++++++++++ plat/meson/gxbb/gxbb_private.h | 38 +++++++ plat/meson/gxbb/gxbb_scpi.c | 137 +++++++++++++++++++++++ plat/meson/gxbb/gxbb_sip_svc.c | 66 ++++++++++++ plat/meson/gxbb/gxbb_thermal.c | 27 +++++ plat/meson/gxbb/gxbb_topology.c | 53 +++++++++ plat/meson/gxbb/include/plat_macros.S | 71 ++++++++++++ plat/meson/gxbb/include/platform_def.h | 66 ++++++++++++ plat/meson/gxbb/platform.mk | 78 ++++++++++++++ 15 files changed, 1235 insertions(+) create mode 100644 plat/meson/gxbb/aarch64/gxbb_helpers.S create mode 100644 plat/meson/gxbb/gxbb_bl31_setup.c create mode 100644 plat/meson/gxbb/gxbb_common.c create mode 100644 plat/meson/gxbb/gxbb_def.h create mode 100644 plat/meson/gxbb/gxbb_efuse.c create mode 100644 plat/meson/gxbb/gxbb_mhu.c create mode 100644 plat/meson/gxbb/gxbb_pm.c create mode 100644 plat/meson/gxbb/gxbb_private.h create mode 100644 plat/meson/gxbb/gxbb_scpi.c create mode 100644 plat/meson/gxbb/gxbb_sip_svc.c create mode 100644 plat/meson/gxbb/gxbb_thermal.c create mode 100644 plat/meson/gxbb/gxbb_topology.c create mode 100644 plat/meson/gxbb/include/plat_macros.S create mode 100644 plat/meson/gxbb/include/platform_def.h create mode 100644 plat/meson/gxbb/platform.mk diff --git a/plat/meson/gxbb/aarch64/gxbb_helpers.S b/plat/meson/gxbb/aarch64/gxbb_helpers.S new file mode 100644 index 00000000..760d6c46 --- /dev/null +++ b/plat/meson/gxbb/aarch64/gxbb_helpers.S @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + + .globl plat_crash_console_flush + .globl plat_crash_console_init + .globl plat_crash_console_putc + .globl platform_mem_init + .globl plat_is_my_cpu_primary + .globl plat_my_core_pos + .globl plat_reset_handler + .globl plat_gxbb_calc_core_pos + + /* ----------------------------------------------------- + * unsigned int plat_my_core_pos(void); + * ----------------------------------------------------- + */ +func plat_my_core_pos + mrs x0, mpidr_el1 + b plat_gxbb_calc_core_pos +endfunc plat_my_core_pos + + /* ----------------------------------------------------- + * unsigned int plat_gxbb_calc_core_pos(u_register_t mpidr); + * ----------------------------------------------------- + */ +func plat_gxbb_calc_core_pos + and x0, x0, #MPIDR_CPU_MASK + ret +endfunc plat_gxbb_calc_core_pos + + /* ----------------------------------------------------- + * unsigned int plat_is_my_cpu_primary(void); + * ----------------------------------------------------- + */ +func plat_is_my_cpu_primary + mrs x0, mpidr_el1 + and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) + cmp x0, #GXBB_PRIMARY_CPU + cset w0, eq + ret +endfunc plat_is_my_cpu_primary + + /* --------------------------------------------- + * void platform_mem_init(void); + * --------------------------------------------- + */ +func platform_mem_init + ret +endfunc platform_mem_init + + /* --------------------------------------------- + * int plat_crash_console_init(void) + * --------------------------------------------- + */ +func plat_crash_console_init + mov_imm x0, GXBB_UART0_AO_BASE + mov_imm x1, GXBB_UART0_AO_CLK_IN_HZ + mov_imm x2, GXBB_UART_BAUDRATE + b console_meson_init +endfunc plat_crash_console_init + + /* --------------------------------------------- + * int plat_crash_console_putc(int c) + * Clobber list : x1, x2 + * --------------------------------------------- + */ +func plat_crash_console_putc + mov_imm x1, GXBB_UART0_AO_BASE + b console_meson_core_putc +endfunc plat_crash_console_putc + + /* --------------------------------------------- + * int plat_crash_console_flush() + * Out : return -1 on error else return 0. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func plat_crash_console_flush + mov_imm x0, GXBB_UART0_AO_BASE + b console_meson_core_flush +endfunc plat_crash_console_flush + + /* --------------------------------------------- + * void plat_reset_handler(void); + * --------------------------------------------- + */ +func plat_reset_handler + ret +endfunc plat_reset_handler diff --git a/plat/meson/gxbb/gxbb_bl31_setup.c b/plat/meson/gxbb/gxbb_bl31_setup.c new file mode 100644 index 00000000..3e176f9a --- /dev/null +++ b/plat/meson/gxbb/gxbb_bl31_setup.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gxbb_private.h" + +/* + * Placeholder variables for copying the arguments that have been passed to + * BL31 from BL2. + */ +static entry_point_info_t bl33_image_ep_info; + +/******************************************************************************* + * 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) +{ + entry_point_info_t *next_image_info; + + assert(type == NON_SECURE); + + next_image_info = &bl33_image_ep_info; + + /* None of the images can have 0x0 as the entrypoint. */ + if (next_image_info->pc != 0U) { + return next_image_info; + } else { + return NULL; + } +} + +/******************************************************************************* + * Perform any BL31 early platform setup. 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. BL2 has flushed this information to memory, so we are guaranteed + * to pick up good data. + ******************************************************************************/ +struct gxbb_bl31_param { + param_header_t h; + image_info_t *bl31_image_info; + entry_point_info_t *bl32_ep_info; + image_info_t *bl32_image_info; + entry_point_info_t *bl33_ep_info; + image_info_t *bl33_image_info; +}; + +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + struct gxbb_bl31_param *from_bl2; + + /* Initialize the console to provide early debug support */ + gxbb_console_init(); + + /* + * In debug builds, we pass a special value in 'arg1' to verify platform + * parameters from BL2 to BL31. In release builds it's not used. + */ + assert(arg1 == GXBB_BL31_PLAT_PARAM_VAL); + + /* Check that params passed from BL2 are not NULL. */ + from_bl2 = (struct gxbb_bl31_param *) arg0; + + /* Check params passed from BL2 are not NULL. */ + assert(from_bl2 != NULL); + assert(from_bl2->h.type == PARAM_BL31); + assert(from_bl2->h.version >= VERSION_1); + + /* + * Copy BL33 entry point information. It is stored in Secure RAM, in + * BL2's address space. + */ + bl33_image_ep_info = *from_bl2->bl33_ep_info; + + if (bl33_image_ep_info.pc == 0U) { + ERROR("BL31: BL33 entrypoint not obtained from BL2\n"); + panic(); + } +} + +void bl31_plat_arch_setup(void) +{ + gxbb_setup_page_tables(); + + enable_mmu_el3(0); +} + +/******************************************************************************* + * GICv2 driver setup information + ******************************************************************************/ +static const interrupt_prop_t gxbb_interrupt_props[] = { + INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), +}; + +static const gicv2_driver_data_t gxbb_gic_data = { + .gicd_base = GXBB_GICD_BASE, + .gicc_base = GXBB_GICC_BASE, + .interrupt_props = gxbb_interrupt_props, + .interrupt_props_num = ARRAY_SIZE(gxbb_interrupt_props), +}; + +void bl31_platform_setup(void) +{ + mhu_secure_init(); + + gicv2_driver_init(&gxbb_gic_data); + gicv2_distif_init(); + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); + + gxbb_thermal_unknown(); +} diff --git a/plat/meson/gxbb/gxbb_common.c b/plat/meson/gxbb/gxbb_common.c new file mode 100644 index 00000000..349d02f9 --- /dev/null +++ b/plat/meson/gxbb/gxbb_common.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/******************************************************************************* + * Platform memory map regions + ******************************************************************************/ +#define MAP_NSDRAM0 MAP_REGION_FLAT(GXBB_NSDRAM0_BASE, \ + GXBB_NSDRAM0_SIZE, \ + MT_MEMORY | MT_RW | MT_NS) + +#define MAP_NSDRAM1 MAP_REGION_FLAT(GXBB_NSDRAM1_BASE, \ + GXBB_NSDRAM1_SIZE, \ + MT_MEMORY | MT_RW | MT_NS) + +#define MAP_SEC_DEVICE0 MAP_REGION_FLAT(GXBB_SEC_DEVICE0_BASE, \ + GXBB_SEC_DEVICE0_SIZE, \ + MT_DEVICE | MT_RW | MT_SECURE) + +#define MAP_SEC_DEVICE1 MAP_REGION_FLAT(GXBB_SEC_DEVICE1_BASE, \ + GXBB_SEC_DEVICE1_SIZE, \ + MT_DEVICE | MT_RW | MT_SECURE) + +#define MAP_TZRAM MAP_REGION_FLAT(GXBB_TZRAM_BASE, \ + GXBB_TZRAM_SIZE, \ + MT_DEVICE | MT_RW | MT_SECURE) + +#define MAP_SEC_DEVICE2 MAP_REGION_FLAT(GXBB_SEC_DEVICE2_BASE, \ + GXBB_SEC_DEVICE2_SIZE, \ + MT_DEVICE | MT_RW | MT_SECURE) + +#define MAP_SEC_DEVICE3 MAP_REGION_FLAT(GXBB_SEC_DEVICE3_BASE, \ + GXBB_SEC_DEVICE3_SIZE, \ + MT_DEVICE | MT_RW | MT_SECURE) + +static const mmap_region_t gxbb_mmap[] = { + MAP_NSDRAM0, + MAP_NSDRAM1, + MAP_SEC_DEVICE0, + MAP_SEC_DEVICE1, + MAP_TZRAM, + MAP_SEC_DEVICE2, + MAP_SEC_DEVICE3, + {0} +}; + +/******************************************************************************* + * Per-image regions + ******************************************************************************/ +#define MAP_BL31 MAP_REGION_FLAT(BL31_BASE, \ + BL31_END - BL31_BASE, \ + MT_MEMORY | MT_RW | MT_SECURE) + +#define MAP_BL_CODE MAP_REGION_FLAT(BL_CODE_BASE, \ + BL_CODE_END - BL_CODE_BASE, \ + MT_CODE | MT_SECURE) + +#define MAP_BL_RO_DATA MAP_REGION_FLAT(BL_RO_DATA_BASE, \ + BL_RO_DATA_END - BL_RO_DATA_BASE, \ + MT_RO_DATA | MT_SECURE) + +#define MAP_BL_COHERENT MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, \ + BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, \ + MT_DEVICE | MT_RW | MT_SECURE) + +/******************************************************************************* + * Function that sets up the translation tables. + ******************************************************************************/ +void gxbb_setup_page_tables(void) +{ +#if IMAGE_BL31 + const mmap_region_t gxbb_bl_mmap[] = { + MAP_BL31, + MAP_BL_CODE, + MAP_BL_RO_DATA, +#if USE_COHERENT_MEM + MAP_BL_COHERENT, +#endif + {0} + }; +#endif + + mmap_add(gxbb_bl_mmap); + + mmap_add(gxbb_mmap); + + init_xlat_tables(); +} + +/******************************************************************************* + * Function that sets up the console + ******************************************************************************/ +static console_meson_t gxbb_console; + +void gxbb_console_init(void) +{ + int rc = console_meson_register(GXBB_UART0_AO_BASE, + GXBB_UART0_AO_CLK_IN_HZ, + GXBB_UART_BAUDRATE, + &gxbb_console); + if (rc == 0) { + /* + * The crash console doesn't use the multi console API, it uses + * the core console functions directly. It is safe to call panic + * and let it print debug information. + */ + panic(); + } + + console_set_scope(&gxbb_console.console, + CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME); +} + +/******************************************************************************* + * Function that returns the system counter frequency + ******************************************************************************/ +unsigned int plat_get_syscnt_freq2(void) +{ + uint32_t val; + + val = mmio_read_32(GXBB_SYS_CPU_CFG7); + val &= 0xFDFFFFFF; + mmio_write_32(GXBB_SYS_CPU_CFG7, val); + + val = mmio_read_32(GXBB_AO_TIMESTAMP_CNTL); + val &= 0xFFFFFE00; + mmio_write_32(GXBB_AO_TIMESTAMP_CNTL, val); + + return GXBB_OSC24M_CLK_IN_HZ; +} diff --git a/plat/meson/gxbb/gxbb_def.h b/plat/meson/gxbb/gxbb_def.h new file mode 100644 index 00000000..0c73ac08 --- /dev/null +++ b/plat/meson/gxbb/gxbb_def.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef GXBB_DEF_H +#define GXBB_DEF_H + +#include + +/******************************************************************************* + * System oscillator + ******************************************************************************/ +#define GXBB_OSC24M_CLK_IN_HZ ULL(24000000) /* 24 MHz */ + +/******************************************************************************* + * Memory regions + ******************************************************************************/ +#define GXBB_NSDRAM0_BASE UL(0x01000000) +#define GXBB_NSDRAM0_SIZE UL(0x0F000000) + +#define GXBB_NSDRAM1_BASE UL(0x10000000) +#define GXBB_NSDRAM1_SIZE UL(0x00100000) + +#define BL31_BASE UL(0x10100000) +#define BL31_SIZE UL(0x000C0000) +#define BL31_LIMIT (BL31_BASE + BL31_SIZE) + +/* Shared memory used for SMC services */ +#define GXBB_SHARE_MEM_INPUT_BASE UL(0x100FE000) +#define GXBB_SHARE_MEM_OUTPUT_BASE UL(0x100FF000) + +#define GXBB_SEC_DEVICE0_BASE UL(0xC0000000) +#define GXBB_SEC_DEVICE0_SIZE UL(0x09000000) + +#define GXBB_SEC_DEVICE1_BASE UL(0xD0040000) +#define GXBB_SEC_DEVICE1_SIZE UL(0x00008000) + +#define GXBB_TZRAM_BASE UL(0xD9000000) +#define GXBB_TZRAM_SIZE UL(0x00014000) +/* Top 0xC000 bytes (up to 0xD9020000) used by BL2 */ + +/* Mailboxes */ +#define GXBB_MHU_SECURE_SCP_TO_AP_PAYLOAD UL(0xD9013800) +#define GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD UL(0xD9013A00) +#define GXBB_PSCI_MAILBOX_BASE UL(0xD9013F00) + +#define GXBB_TZROM_BASE UL(0xD9040000) +#define GXBB_TZROM_SIZE UL(0x00010000) + +#define GXBB_SEC_DEVICE2_BASE UL(0xDA000000) +#define GXBB_SEC_DEVICE2_SIZE UL(0x00200000) + +#define GXBB_SEC_DEVICE3_BASE UL(0xDA800000) +#define GXBB_SEC_DEVICE3_SIZE UL(0x00200000) + +/******************************************************************************* + * GIC-400 and interrupt handling related constants + ******************************************************************************/ +#define GXBB_GICD_BASE UL(0xC4301000) +#define GXBB_GICC_BASE UL(0xC4302000) + +#define IRQ_SEC_PHY_TIMER 29 + +#define IRQ_SEC_SGI_0 8 +#define IRQ_SEC_SGI_1 9 +#define IRQ_SEC_SGI_2 10 +#define IRQ_SEC_SGI_3 11 +#define IRQ_SEC_SGI_4 12 +#define IRQ_SEC_SGI_5 13 +#define IRQ_SEC_SGI_6 14 +#define IRQ_SEC_SGI_7 15 + +/******************************************************************************* + * UART definitions + ******************************************************************************/ +#define GXBB_UART0_AO_BASE UL(0xC81004C0) +#define GXBB_UART0_AO_CLK_IN_HZ GXBB_OSC24M_CLK_IN_HZ +#define GXBB_UART_BAUDRATE U(115200) + +/******************************************************************************* + * Memory-mapped I/O Registers + ******************************************************************************/ +#define GXBB_AO_TIMESTAMP_CNTL UL(0xC81000B4) + +#define GXBB_SYS_CPU_CFG7 UL(0xC8834664) + +#define GXBB_AO_RTI_STATUS_REG3 UL(0xDA10001C) + +#define GXBB_HIU_MAILBOX_SET_0 UL(0xDA83C404) +#define GXBB_HIU_MAILBOX_STAT_0 UL(0xDA83C408) +#define GXBB_HIU_MAILBOX_CLR_0 UL(0xDA83C40C) +#define GXBB_HIU_MAILBOX_SET_3 UL(0xDA83C428) +#define GXBB_HIU_MAILBOX_STAT_3 UL(0xDA83C42C) +#define GXBB_HIU_MAILBOX_CLR_3 UL(0xDA83C430) + +/******************************************************************************* + * System Monitor Call IDs and arguments + ******************************************************************************/ +#define GXBB_SM_GET_SHARE_MEM_INPUT_BASE U(0x82000020) +#define GXBB_SM_GET_SHARE_MEM_OUTPUT_BASE U(0x82000021) + +#define GXBB_SM_EFUSE_READ U(0x82000030) +#define GXBB_SM_EFUSE_USER_MAX U(0x82000033) + +#define GXBB_SM_JTAG_ON U(0x82000040) +#define GXBB_SM_JTAG_OFF U(0x82000041) + +#define GXBB_JTAG_STATE_ON U(0) +#define GXBB_JTAG_STATE_OFF U(1) + +#define GXBB_JTAG_M3_AO U(0) +#define GXBB_JTAG_M3_EE U(1) +#define GXBB_JTAG_A53_AO U(2) +#define GXBB_JTAG_A53_EE U(3) + +#endif /* GXBB_DEF_H */ diff --git a/plat/meson/gxbb/gxbb_efuse.c b/plat/meson/gxbb/gxbb_efuse.c new file mode 100644 index 00000000..edea5426 --- /dev/null +++ b/plat/meson/gxbb/gxbb_efuse.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include "gxbb_private.h" + +#define EFUSE_BASE 0x140 +#define EFUSE_SIZE 0xC0 + +uint64_t gxbb_efuse_read(void *dst, uint32_t offset, uint32_t size) +{ + if ((uint64_t)(offset + size) > (uint64_t)EFUSE_SIZE) + return 0; + + return scpi_efuse_read(dst, offset + EFUSE_BASE, size); +} + +uint64_t gxbb_efuse_user_max(void) +{ + return EFUSE_SIZE; +} diff --git a/plat/meson/gxbb/gxbb_mhu.c b/plat/meson/gxbb/gxbb_mhu.c new file mode 100644 index 00000000..78b895c5 --- /dev/null +++ b/plat/meson/gxbb/gxbb_mhu.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +static DEFINE_BAKERY_LOCK(mhu_lock); + +void mhu_secure_message_start(void) +{ + bakery_lock_get(&mhu_lock); + + while (mmio_read_32(GXBB_HIU_MAILBOX_STAT_3) != 0) + ; +} + +void mhu_secure_message_send(uint32_t msg) +{ + mmio_write_32(GXBB_HIU_MAILBOX_SET_3, msg); + + while (mmio_read_32(GXBB_HIU_MAILBOX_STAT_3) != 0) + ; +} + +uint32_t mhu_secure_message_wait(void) +{ + uint32_t val; + + do { + val = mmio_read_32(GXBB_HIU_MAILBOX_STAT_0); + } while (val == 0); + + return val; +} + +void mhu_secure_message_end(void) +{ + mmio_write_32(GXBB_HIU_MAILBOX_CLR_0, 0xFFFFFFFF); + + bakery_lock_release(&mhu_lock); +} + +void mhu_secure_init(void) +{ + bakery_lock_init(&mhu_lock); + + mmio_write_32(GXBB_HIU_MAILBOX_CLR_3, 0xFFFFFFFF); +} diff --git a/plat/meson/gxbb/gxbb_pm.c b/plat/meson/gxbb/gxbb_pm.c new file mode 100644 index 00000000..6a13159a --- /dev/null +++ b/plat/meson/gxbb/gxbb_pm.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gxbb_private.h" + +#define SCPI_POWER_ON 0 +#define SCPI_POWER_RETENTION 1 +#define SCPI_POWER_OFF 3 + +#define SCPI_SYSTEM_SHUTDOWN 0 +#define SCPI_SYSTEM_REBOOT 1 + +static uintptr_t gxbb_sec_entrypoint; + +static void gxbb_program_mailbox(u_register_t mpidr, uint64_t value) +{ + unsigned int core = plat_gxbb_calc_core_pos(mpidr); + uintptr_t cpu_mailbox_addr = GXBB_PSCI_MAILBOX_BASE + (core << 4); + + mmio_write_64(cpu_mailbox_addr, value); + flush_dcache_range(cpu_mailbox_addr, sizeof(uint64_t)); +} + +static void __dead2 gxbb_system_reset(void) +{ + INFO("BL31: PSCI_SYSTEM_RESET\n"); + + uint32_t status = mmio_read_32(GXBB_AO_RTI_STATUS_REG3); + + NOTICE("BL31: Reboot reason: 0x%x\n", status); + + status &= 0xFFFF0FF0; + + console_flush(); + + mmio_write_32(GXBB_AO_RTI_STATUS_REG3, status); + + int ret = scpi_sys_power_state(SCPI_SYSTEM_REBOOT); + + if (ret != 0) { + ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %u\n", ret); + panic(); + } + + wfi(); + + ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n"); + panic(); +} + +static void __dead2 gxbb_system_off(void) +{ + INFO("BL31: PSCI_SYSTEM_OFF\n"); + + unsigned int ret = scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN); + + if (ret != 0) { + ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %u\n", ret); + panic(); + } + + gxbb_program_mailbox(read_mpidr_el1(), 0); + + wfi(); + + ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n"); + panic(); +} + +static int32_t gxbb_pwr_domain_on(u_register_t mpidr) +{ + gxbb_program_mailbox(mpidr, gxbb_sec_entrypoint); + scpi_set_css_power_state(mpidr, + SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON); + dmbsy(); + sev(); + + return PSCI_E_SUCCESS; +} + +static void gxbb_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == + PLAT_LOCAL_STATE_OFF); + + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); +} + +/******************************************************************************* + * Platform handlers and setup function. + ******************************************************************************/ +static const plat_psci_ops_t gxbb_ops = { + .pwr_domain_on = gxbb_pwr_domain_on, + .pwr_domain_on_finish = gxbb_pwr_domain_on_finish, + .system_off = gxbb_system_off, + .system_reset = gxbb_system_reset, +}; + +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) +{ + gxbb_sec_entrypoint = sec_entrypoint; + *psci_ops = &gxbb_ops; + return 0; +} diff --git a/plat/meson/gxbb/gxbb_private.h b/plat/meson/gxbb/gxbb_private.h new file mode 100644 index 00000000..910a42c1 --- /dev/null +++ b/plat/meson/gxbb/gxbb_private.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef GXBB_PRIVATE_H +#define GXBB_PRIVATE_H + +#include + +/* Utility functions */ +unsigned int plat_gxbb_calc_core_pos(u_register_t mpidr); +void gxbb_console_init(void); +void gxbb_setup_page_tables(void); + +/* MHU functions */ +void mhu_secure_message_start(void); +void mhu_secure_message_send(uint32_t msg); +uint32_t mhu_secure_message_wait(void); +void mhu_secure_message_end(void); +void mhu_secure_init(void); + +/* SCPI functions */ +void scpi_set_css_power_state(u_register_t mpidr, uint32_t cpu_state, + uint32_t cluster_state, uint32_t css_state); +uint32_t scpi_sys_power_state(uint64_t system_state); +void scpi_jtag_set_state(uint32_t state, uint8_t select); +uint32_t scpi_efuse_read(void *dst, uint32_t base, uint32_t size); +void scpi_unknown_thermal(uint32_t arg0, uint32_t arg1, + uint32_t arg2, uint32_t arg3); + +/* Peripherals */ +void gxbb_thermal_unknown(void); +uint64_t gxbb_efuse_read(void *dst, uint32_t offset, uint32_t size); +uint64_t gxbb_efuse_user_max(void); + +#endif /* GXBB_PRIVATE_H */ diff --git a/plat/meson/gxbb/gxbb_scpi.c b/plat/meson/gxbb/gxbb_scpi.c new file mode 100644 index 00000000..2390bcad --- /dev/null +++ b/plat/meson/gxbb/gxbb_scpi.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#include "gxbb_private.h" + +#define SIZE_SHIFT 20 +#define SIZE_MASK 0x1FF + +/* + * Note: The Amlogic SCP firmware uses the legacy SCPI protocol. + */ +#define SCPI_CMD_SET_CSS_POWER_STATE 0x04 +#define SCPI_CMD_SET_SYS_POWER_STATE 0x08 + +#define SCPI_CMD_JTAG_SET_STATE 0xC0 +#define SCPI_CMD_EFUSE_READ 0xC2 + +static inline uint32_t scpi_cmd(uint32_t command, uint32_t size) +{ + return command | (size << SIZE_SHIFT); +} + +void scpi_secure_message_send(uint32_t command, uint32_t size) +{ + mhu_secure_message_send(scpi_cmd(command, size)); +} + +uint32_t scpi_secure_message_receive(void **message_out, size_t *size_out) +{ + uint32_t response = mhu_secure_message_wait(); + + size_t size = (response >> SIZE_SHIFT) & SIZE_MASK; + + response &= ~(SIZE_MASK << SIZE_SHIFT); + + if (size_out != NULL) + *size_out = size; + + if (message_out != NULL) + *message_out = (void *)GXBB_MHU_SECURE_SCP_TO_AP_PAYLOAD; + + return response; +} + +void scpi_set_css_power_state(u_register_t mpidr, uint32_t cpu_state, + uint32_t cluster_state, uint32_t css_state) +{ + uint32_t state = (mpidr & 0x0F) | /* CPU ID */ + ((mpidr & 0xF00) >> 4) | /* Cluster ID */ + (cpu_state << 8) | + (cluster_state << 12) | + (css_state << 16); + + mhu_secure_message_start(); + mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, state); + mhu_secure_message_send(scpi_cmd(SCPI_CMD_SET_CSS_POWER_STATE, 4)); + mhu_secure_message_wait(); + mhu_secure_message_end(); +} + +uint32_t scpi_sys_power_state(uint64_t system_state) +{ + uint32_t *response; + size_t size; + + mhu_secure_message_start(); + mmio_write_8(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, system_state); + mhu_secure_message_send(scpi_cmd(SCPI_CMD_SET_SYS_POWER_STATE, 1)); + scpi_secure_message_receive((void *)&response, &size); + mhu_secure_message_end(); + + return *response; +} + +void scpi_jtag_set_state(uint32_t state, uint8_t select) +{ + assert(state <= GXBB_JTAG_STATE_OFF); + + if (select > GXBB_JTAG_A53_EE) { + WARN("BL31: Invalid JTAG select (0x%x).\n", select); + return; + } + + mhu_secure_message_start(); + mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, + (state << 8) | (uint32_t)select); + mhu_secure_message_send(scpi_cmd(SCPI_CMD_JTAG_SET_STATE, 4)); + mhu_secure_message_wait(); + mhu_secure_message_end(); +} + +uint32_t scpi_efuse_read(void *dst, uint32_t base, uint32_t size) +{ + uint32_t *response; + size_t resp_size; + + if (size > 0x1FC) + return 0; + + mhu_secure_message_start(); + mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, base); + mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 4, size); + mhu_secure_message_send(scpi_cmd(SCPI_CMD_EFUSE_READ, 8)); + scpi_secure_message_receive((void *)&response, &resp_size); + mhu_secure_message_end(); + + /* + * response[0] is the size of the response message. + * response[1 ... N] are the contents. + */ + if (*response != 0) + memcpy(dst, response + 1, *response); + + return *response; +} + +void scpi_unknown_thermal(uint32_t arg0, uint32_t arg1, + uint32_t arg2, uint32_t arg3) +{ + mhu_secure_message_start(); + mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x0, arg0); + mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x4, arg1); + mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x8, arg2); + mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0xC, arg3); + mhu_secure_message_send(scpi_cmd(0xC3, 16)); + mhu_secure_message_wait(); + mhu_secure_message_end(); +} diff --git a/plat/meson/gxbb/gxbb_sip_svc.c b/plat/meson/gxbb/gxbb_sip_svc.c new file mode 100644 index 00000000..82ed4493 --- /dev/null +++ b/plat/meson/gxbb/gxbb_sip_svc.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#include "gxbb_private.h" + +/******************************************************************************* + * This function is responsible for handling all SiP calls + ******************************************************************************/ +static uintptr_t gxbb_sip_handler(uint32_t smc_fid, + u_register_t x1, u_register_t x2, + u_register_t x3, u_register_t x4, + void *cookie, void *handle, + u_register_t flags) +{ + switch (smc_fid) { + + case GXBB_SM_GET_SHARE_MEM_INPUT_BASE: + SMC_RET1(handle, GXBB_SHARE_MEM_INPUT_BASE); + + case GXBB_SM_GET_SHARE_MEM_OUTPUT_BASE: + SMC_RET1(handle, GXBB_SHARE_MEM_OUTPUT_BASE); + + case GXBB_SM_EFUSE_READ: + { + void *dst = (void *)GXBB_SHARE_MEM_OUTPUT_BASE; + uint64_t ret = gxbb_efuse_read(dst, (uint32_t)x1, x2); + + SMC_RET1(handle, ret); + } + case GXBB_SM_EFUSE_USER_MAX: + SMC_RET1(handle, gxbb_efuse_user_max()); + + case GXBB_SM_JTAG_ON: + scpi_jtag_set_state(GXBB_JTAG_STATE_ON, x1); + SMC_RET1(handle, 0); + + case GXBB_SM_JTAG_OFF: + scpi_jtag_set_state(GXBB_JTAG_STATE_OFF, x1); + SMC_RET1(handle, 0); + + default: + ERROR("BL31: Unhandled SIP SMC: 0x%08x\n", smc_fid); + break; + } + + SMC_RET1(handle, SMC_UNK); +} + +DECLARE_RT_SVC( + gxbb_sip_handler, + + OEN_SIP_START, + OEN_SIP_END, + SMC_TYPE_FAST, + NULL, + gxbb_sip_handler +); diff --git a/plat/meson/gxbb/gxbb_thermal.c b/plat/meson/gxbb/gxbb_thermal.c new file mode 100644 index 00000000..b6048eee --- /dev/null +++ b/plat/meson/gxbb/gxbb_thermal.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include "gxbb_private.h" + +static int32_t modules_initialized = -1; + +/******************************************************************************* + * Unknown commands related to something thermal-related + ******************************************************************************/ +void gxbb_thermal_unknown(void) +{ + uint16_t ret; + + if (modules_initialized == -1) { + scpi_efuse_read(&ret, 0, 2); + modules_initialized = ret; + } + + scpi_unknown_thermal(10, 2, /* thermal */ + 13, 1); /* thermalver */ +} diff --git a/plat/meson/gxbb/gxbb_topology.c b/plat/meson/gxbb/gxbb_topology.c new file mode 100644 index 00000000..49bb2dca --- /dev/null +++ b/plat/meson/gxbb/gxbb_topology.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include "gxbb_private.h" + +/* The power domain tree descriptor */ +static unsigned char power_domain_tree_desc[] = { + /* Number of root nodes */ + PLATFORM_CLUSTER_COUNT, + /* Number of children for the first node */ + PLATFORM_CLUSTER0_CORE_COUNT +}; + +/******************************************************************************* + * This function returns the ARM default topology tree information. + ******************************************************************************/ +const unsigned char *plat_get_power_domain_tree_desc(void) +{ + return power_domain_tree_desc; +} + +/******************************************************************************* + * This function implements a part of the critical interface between the psci + * generic layer and the platform that allows the former to query the platform + * to convert an MPIDR to a unique linear index. An error code (-1) is returned + * in case the MPIDR is invalid. + ******************************************************************************/ +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ + unsigned int cluster_id, cpu_id; + + mpidr &= MPIDR_AFFINITY_MASK; + if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) + return -1; + + cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; + + if (cluster_id >= PLATFORM_CLUSTER_COUNT) + return -1; + + if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) + return -1; + + return plat_gxbb_calc_core_pos(mpidr); +} diff --git a/plat/meson/gxbb/include/plat_macros.S b/plat/meson/gxbb/include/plat_macros.S new file mode 100644 index 00000000..948b5f98 --- /dev/null +++ b/plat/meson/gxbb/include/plat_macros.S @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_MACROS_S +#define PLAT_MACROS_S + +#include +#include + +.section .rodata.gic_reg_name, "aS" + +gicc_regs: + .asciz "gicc_hppir", "gicc_ahppir", "gicc_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 required platform porting macro + * prints out relevant GIC and CCI registers + * whenever an unhandled exception is taken in + * BL31. + * Clobbers: x0 - x10, x16, x17, sp + * --------------------------------------------- + */ + .macro plat_crash_print_regs + + /* GICC registers */ + + mov_imm x17, GXBB_GICC_BASE + + adr x6, gicc_regs + ldr w8, [x17, #GICC_HPPIR] + ldr w9, [x17, #GICC_AHPPIR] + ldr w10, [x17, #GICC_CTLR] + bl str_in_crash_buf_print + + /* GICD registers */ + + mov_imm x16, GXBB_GICD_BASE + + 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 + +#endif /* PLAT_MACROS_S */ diff --git a/plat/meson/gxbb/include/platform_def.h b/plat/meson/gxbb/include/platform_def.h new file mode 100644 index 00000000..a85637fe --- /dev/null +++ b/plat/meson/gxbb/include/platform_def.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +#include +#include + +#include "../gxbb_def.h" + +#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" +#define PLATFORM_LINKER_ARCH aarch64 + +/* Special value used to verify platform parameters from BL2 to BL31 */ +#define GXBB_BL31_PLAT_PARAM_VAL ULL(0x0F1E2D3C4B5A6978) + +#define PLATFORM_STACK_SIZE UL(0x1000) + +#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4) +#define PLATFORM_CLUSTER_COUNT U(1) +#define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER +#define PLATFORM_CORE_COUNT PLATFORM_CLUSTER0_CORE_COUNT + +#define GXBB_PRIMARY_CPU U(0) + +#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 +#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ + PLATFORM_CORE_COUNT) + +#define PLAT_MAX_RET_STATE U(1) +#define PLAT_MAX_OFF_STATE U(2) + +/* Local power state for power domains in Run state. */ +#define PLAT_LOCAL_STATE_RUN U(0) +/* Local power state for retention. Valid only for CPU power domains */ +#define PLAT_LOCAL_STATE_RET U(1) +/* Local power state for power-down. Valid for CPU and cluster power domains. */ +#define PLAT_LOCAL_STATE_OFF U(2) + +/* + * Macros used to parse state information from State-ID if it is using the + * recommended encoding for State-ID. + */ +#define PLAT_LOCAL_PSTATE_WIDTH U(4) +#define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1) + +/* + * Some data must be 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. + */ +#define CACHE_WRITEBACK_SHIFT U(6) +#define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) + +/* Memory-related defines */ +#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) +#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) + +#define MAX_MMAP_REGIONS 12 +#define MAX_XLAT_TABLES 5 + +#endif /* PLATFORM_DEF_H */ diff --git a/plat/meson/gxbb/platform.mk b/plat/meson/gxbb/platform.mk new file mode 100644 index 00000000..e6f5ae48 --- /dev/null +++ b/plat/meson/gxbb/platform.mk @@ -0,0 +1,78 @@ +# +# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include lib/xlat_tables_v2/xlat_tables.mk + +PLAT_INCLUDES := -Iinclude/drivers/meson/ \ + -Iplat/meson/gxbb/include + +GXBB_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ + drivers/arm/gic/v2/gicv2_main.c \ + drivers/arm/gic/v2/gicv2_helpers.c \ + plat/common/plat_gicv2.c + +PLAT_BL_COMMON_SOURCES := drivers/console/aarch64/multi_console.S \ + drivers/meson/console/aarch64/meson_console.S \ + plat/meson/gxbb/gxbb_common.c \ + plat/meson/gxbb/gxbb_topology.c \ + ${XLAT_TABLES_LIB_SRCS} + +BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ + plat/common/plat_psci_common.c \ + plat/meson/gxbb/aarch64/gxbb_helpers.S \ + plat/meson/gxbb/gxbb_bl31_setup.c \ + plat/meson/gxbb/gxbb_efuse.c \ + plat/meson/gxbb/gxbb_mhu.c \ + plat/meson/gxbb/gxbb_pm.c \ + plat/meson/gxbb/gxbb_scpi.c \ + plat/meson/gxbb/gxbb_sip_svc.c \ + plat/meson/gxbb/gxbb_thermal.c \ + ${GXBB_GIC_SOURCES} + +# Tune compiler for Cortex-A53 +ifeq ($(notdir $(CC)),armclang) + TF_CFLAGS_aarch64 += -mcpu=cortex-a53 +else ifneq ($(findstring clang,$(notdir $(CC))),) + TF_CFLAGS_aarch64 += -mcpu=cortex-a53 +else + TF_CFLAGS_aarch64 += -mtune=cortex-a53 +endif + +# Build config flags +# ------------------ + +# Enable all errata workarounds for Cortex-A53 +ERRATA_A53_826319 := 1 +ERRATA_A53_835769 := 1 +ERRATA_A53_836870 := 1 +ERRATA_A53_843419 := 1 +ERRATA_A53_855873 := 1 + +WORKAROUND_CVE_2017_5715 := 0 + +# Have different sections for code and rodata +SEPARATE_CODE_AND_RODATA := 1 + +# Use Coherent memory +USE_COHERENT_MEM := 1 + +# Use multi console API +MULTI_CONSOLE_API := 1 + +# Verify build config +# ------------------- + +ifneq (${MULTI_CONSOLE_API}, 1) + $(error Error: gxbb needs MULTI_CONSOLE_API=1) +endif + +ifneq (${RESET_TO_BL31}, 0) + $(error Error: gxbb needs RESET_TO_BL31=0) +endif + +ifeq (${ARCH},aarch32) + $(error Error: AArch32 not supported on gxbb) +endif -- 2.30.2