diff --git a/.gitignore b/.gitignore index 341308ca94833896d1f5cf60418ef9a06a7721a4..6b1e05774880281fd69a8eb0a655c91d08cec368 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ tools/cert_create/src/**/*.o tools/cert_create/cert_create tools/cert_create/cert_create.exe tools/marvell/doimage/doimage +tools/meson/doimage tools/stm32image/*.o tools/stm32image/stm32image tools/stm32image/stm32image.exe diff --git a/docs/plat/meson-gxl.rst b/docs/plat/meson-gxl.rst new file mode 100644 index 0000000000000000000000000000000000000000..feac2dd07cfc5fc90cbd3722939454291079c2fc --- /dev/null +++ b/docs/plat/meson-gxl.rst @@ -0,0 +1,27 @@ +Trusted Firmware-A for Amlogic Meson S905x (GXL) +================================================ + +The Amlogic Meson S905x 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: + +- SCPI support. +- Basic PSCI support (CPU_ON, CPU_OFF, SYSTEM_RESET, SYSTEM_OFF). Note that CPU0 + can't be turned off, so there is a workaround to hide this from the caller. +- GICv2 driver set up. +- Basic SIP services (read efuse data, enable/disable JTAG). + +In order to build it: + +:: + + CROSS_COMPILE=aarch64-linux-gnu- make DEBUG=1 PLAT=gxl + +This port has been tested on a Lepotato. After building it, follow the +instructions in the `gxlimg repository` or `U-Boot repository`_, replacing the +mentioned **bl31.img** by the one built from this port. + +.. _gxlimg repository: https://github.com/repk/gxlimg/blob/master/README +.. _U-Boot repository: https://github.com/u-boot/u-boot/blob/master/board/amlogic/p212/README.libretech-cc diff --git a/drivers/meson/gxl/crypto/sha_dma.c b/drivers/meson/gxl/crypto/sha_dma.c new file mode 100644 index 0000000000000000000000000000000000000000..565099c4a76b35826ca60da088ec9bac1e9366c1 --- /dev/null +++ b/drivers/meson/gxl/crypto/sha_dma.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2019, Remi Pommarel + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +#define AML_SHA_DMA_BASE 0xc883e000 + +#define AML_SHA_DMA_DESC (AML_SHA_DMA_BASE + 0x08) +#define AML_SHA_DMA_STATUS (AML_SHA_DMA_BASE + 0x18) + +#define ASD_MODE_SHA224 0x7 +#define ASD_MODE_SHA256 0x6 + +/* SHA DMA descriptor */ +struct asd_desc { + uint32_t cfg; + uint32_t src; + uint32_t dst; +}; +#define ASD_DESC_GET(x, msk, off) (((x) >> (off)) & (msk)) +#define ASD_DESC_SET(x, v, msk, off) \ + ((x) = ((x) & ~((msk) << (off))) | (((v) & (msk)) << (off))) + +#define ASD_DESC_LEN_OFF 0 +#define ASD_DESC_LEN_MASK 0x1ffff +#define ASD_DESC_LEN(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_LEN_MASK, ASD_DESC_LEN_OFF)) +#define ASD_DESC_LEN_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_LEN_MASK, ASD_DESC_LEN_OFF)) + +#define ASD_DESC_IRQ_OFF 17 +#define ASD_DESC_IRQ_MASK 0x1 +#define ASD_DESC_IRQ(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_IRQ_MASK, ASD_DESC_IRQ_OFF)) +#define ASD_DESC_IRQ_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_IRQ_MASK, ASD_DESC_IRQ_OFF)) + +#define ASD_DESC_EOD_OFF 18 +#define ASD_DESC_EOD_MASK 0x1 +#define ASD_DESC_EOD(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_EOD_MASK, ASD_DESC_EOD_OFF)) +#define ASD_DESC_EOD_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_EOD_MASK, ASD_DESC_EOD_OFF)) + +#define ASD_DESC_LOOP_OFF 19 +#define ASD_DESC_LOOP_MASK 0x1 +#define ASD_DESC_LOOP(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_LOOP_MASK, ASD_DESC_LOOP_OFF)) +#define ASD_DESC_LOOP_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_LOOP_MASK, ASD_DESC_LOOP_OFF)) + +#define ASD_DESC_MODE_OFF 20 +#define ASD_DESC_MODE_MASK 0xf +#define ASD_DESC_MODE(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_MODE_MASK, ASD_DESC_MODE_OFF)) +#define ASD_DESC_MODE_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_MODE_MASK, ASD_DESC_MODE_OFF)) + +#define ASD_DESC_BEGIN_OFF 24 +#define ASD_DESC_BEGIN_MASK 0x1 +#define ASD_DESC_BEGIN(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_BEGIN_MASK, ASD_DESC_BEGIN_OFF)) +#define ASD_DESC_BEGIN_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_BEGIN_MASK, ASD_DESC_BEGIN_OFF)) + +#define ASD_DESC_END_OFF 25 +#define ASD_DESC_END_MASK 0x1 +#define ASD_DESC_END(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_END_MASK, ASD_DESC_END_OFF)) +#define ASD_DESC_END_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_END_MASK, ASD_DESC_END_OFF)) + +#define ASD_DESC_OP_OFF 26 +#define ASD_DESC_OP_MASK 0x2 +#define ASD_DESC_OP(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_OP_MASK, ASD_DESC_OP_OFF)) +#define ASD_DESC_OP_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_OP_MASK, ASD_DESC_OP_OFF)) + +#define ASD_DESC_ENCONLY_OFF 28 +#define ASD_DESC_ENCONLY_MASK 0x1 +#define ASD_DESC_ENCONLY(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_ENCONLY_MASK, ASD_DESC_ENCONLY_OFF)) +#define ASD_DESC_ENCONLY_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_ENCONLY_MASK, ASD_DESC_ENCONLY_OFF)) + +#define ASD_DESC_BLOCK_OFF 29 +#define ASD_DESC_BLOCK_MASK 0x1 +#define ASD_DESC_BLOCK(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_BLOCK_MASK, ASD_DESC_BLOCK_OFF)) +#define ASD_DESC_BLOCK_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_BLOCK_MASK, ASD_DESC_BLOCK_OFF)) + +#define ASD_DESC_ERR_OFF 30 +#define ASD_DESC_ERR_MASK 0x1 +#define ASD_DESC_ERR(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_ERR_MASK, ASD_DESC_ERR_OFF)) +#define ASD_DESC_ERR_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_ERR_MASK, ASD_DESC_ERR_OFF)) + +#define ASD_DESC_OWNER_OFF 31 +#define ASD_DESC_OWNER_MASK 0x1 +#define ASD_DESC_OWNER(d) \ + (ASD_DESC_GET((d)->cfg, ASD_DESC_OWNER_MASK, ASD_DESC_OWNER_OFF)) +#define ASD_DESC_OWNER_SET(d, v) \ + (ASD_DESC_SET((d)->cfg, v, ASD_DESC_OWNER_MASK, ASD_DESC_OWNER_OFF)) + +static void asd_compute_sha(struct asd_ctx *ctx, void *data, size_t len, + int finalize) +{ + /* Make it cache line size aligned ? */ + struct asd_desc desc = { + .src = (uint32_t)(uintptr_t)data, + .dst = (uint32_t)(uintptr_t)ctx->digest, + }; + + /* Check data address is 32bit compatible */ + assert((uintptr_t)data == (uintptr_t)desc.src); + assert((uintptr_t)ctx->digest == (uintptr_t)desc.dst); + assert((uintptr_t)&desc == (uintptr_t)&desc); + + ASD_DESC_LEN_SET(&desc, len); + ASD_DESC_OWNER_SET(&desc, 1); + ASD_DESC_ENCONLY_SET(&desc, 1); + ASD_DESC_EOD_SET(&desc, 1); + if (ctx->started == 0) { + ASD_DESC_BEGIN_SET(&desc, 1); + ctx->started = 1; + } + if (finalize) { + ASD_DESC_END_SET(&desc, 1); + ctx->started = 0; + } + if (ctx->mode == ASM_SHA224) + ASD_DESC_MODE_SET(&desc, ASD_MODE_SHA224); + else + ASD_DESC_MODE_SET(&desc, ASD_MODE_SHA256); + + flush_dcache_range((uintptr_t)&desc, sizeof(desc)); + flush_dcache_range((uintptr_t)data, len); + + mmio_write_32(AML_SHA_DMA_STATUS, 0xf); + mmio_write_32(AML_SHA_DMA_DESC, ((uintptr_t)&desc) | 2); + while (mmio_read_32(AML_SHA_DMA_STATUS) == 0) + continue; + flush_dcache_range((uintptr_t)ctx->digest, SHA256_HASHSZ); +} + +void asd_sha_update(struct asd_ctx *ctx, void *data, size_t len) +{ + size_t nr; + + if (ctx->blocksz) { + nr = MIN(len, SHA256_BLOCKSZ - ctx->blocksz); + memcpy(ctx->block + ctx->blocksz, data, nr); + ctx->blocksz += nr; + len -= nr; + data += nr; + } + + if (ctx->blocksz == SHA256_BLOCKSZ) { + asd_compute_sha(ctx, ctx->block, SHA256_BLOCKSZ, 0); + ctx->blocksz = 0; + } + + asd_compute_sha(ctx, data, len & ~(SHA256_BLOCKSZ - 1), 0); + data += len & ~(SHA256_BLOCKSZ - 1); + + if (len & (SHA256_BLOCKSZ - 1)) { + nr = len & (SHA256_BLOCKSZ - 1); + memcpy(ctx->block + ctx->blocksz, data, nr); + ctx->blocksz += nr; + } +} + +void asd_sha_finalize(struct asd_ctx *ctx) +{ + asd_compute_sha(ctx, ctx->block, ctx->blocksz, 1); +} diff --git a/include/drivers/meson/gxl/crypto/sha_dma.h b/include/drivers/meson/gxl/crypto/sha_dma.h new file mode 100644 index 0000000000000000000000000000000000000000..52129a61f744094848d8976a19f8a55e09095a14 --- /dev/null +++ b/include/drivers/meson/gxl/crypto/sha_dma.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, Remi Pommarel + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef SHA_DMA_H +#define SHA_DMA_H + +#define SHA256_HASHSZ 32 +#define SHA256_BLOCKSZ 0x40 + +enum ASD_MODE { + ASM_INVAL, + ASM_SHA256, + ASM_SHA224, +}; + +struct asd_ctx { + uint8_t digest[SHA256_HASHSZ]; + uint8_t block[SHA256_BLOCKSZ]; + size_t blocksz; + enum ASD_MODE mode; + uint8_t started; +}; + +static inline void asd_sha_init(struct asd_ctx *ctx, enum ASD_MODE mode) +{ + ctx->started = 0; + ctx->mode = mode; + ctx->blocksz = 0; +} + +void asd_sha_update(struct asd_ctx *ctx, void *data, size_t len); +void asd_sha_finalize(struct asd_ctx *ctx); + +#endif diff --git a/maintainers.rst b/maintainers.rst index a1ad137fe49f5e11b8846da7f1bd9ae1febed6f4..52c3daca1d0b213b1e104346dd2314a612bb2d04 100644 --- a/maintainers.rst +++ b/maintainers.rst @@ -34,6 +34,14 @@ Amlogic Meson S905 (GXBB) platform port :F: drivers/meson/ :F: plat/meson/gxbb/ +Amlogic Meson S905x (GXL) platform port +--------------------------------------- +:M: Remi Pommarel +:G: `remi-triplefault`_ +:F: docs/plat/meson-gxl.rst +:F: drivers/meson/gxl +:F: plat/meson/gxl/ + Armv7-A architecture port ------------------------- :M: Etienne Carriere @@ -272,6 +280,7 @@ Xilinx platform port .. _mtk09422: https://github.com/mtk09422 .. _npoushin: https://github.com/npoushin .. _qoriq-open-source: https://github.com/qoriq-open-source +.. _remi-triplefault: https://github.com/repk .. _rockchip-linux: https://github.com/rockchip-linux .. _shawnguo2: https://github.com/shawnguo2 .. _sivadur: https://github.com/sivadur diff --git a/plat/meson/gxl/aarch64/gxl_helpers.S b/plat/meson/gxl/aarch64/gxl_helpers.S new file mode 100644 index 0000000000000000000000000000000000000000..760d6c46d9f36823464c3a3af70229ae92f53d52 --- /dev/null +++ b/plat/meson/gxl/aarch64/gxl_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/gxl/gxl_bl31_setup.c b/plat/meson/gxl/gxl_bl31_setup.c new file mode 100644 index 0000000000000000000000000000000000000000..7fe05292ddf0f9cf3ec51624fbfc66f65f520f1c --- /dev/null +++ b/plat/meson/gxl/gxl_bl31_setup.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gxl_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; +static image_info_t bl30_image_info; +static image_info_t bl301_image_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 gxl_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; + image_info_t *scp_image_info[]; +}; + +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + struct gxl_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 gxl_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(); + } + + bl30_image_info = *from_bl2->scp_image_info[0]; + bl301_image_info = *from_bl2->scp_image_info[1]; +} + +void bl31_plat_arch_setup(void) +{ + gxbb_setup_page_tables(); + + enable_mmu_el3(0); +} + +static inline void gxl_scp_boot(void) +{ + scpi_upload_scp_fw(bl30_image_info.image_base, + bl30_image_info.image_size, 0); + scpi_upload_scp_fw(bl301_image_info.image_base, + bl301_image_info.image_size, 1); +} + +/******************************************************************************* + * 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(); + + gxl_scp_boot(); + + gxbb_thermal_unknown(); +} diff --git a/plat/meson/gxl/gxl_common.c b/plat/meson/gxl/gxl_common.c new file mode 100644 index 0000000000000000000000000000000000000000..e3bd6048af8d9007e16c9eb865908891ee1b2a78 --- /dev/null +++ b/plat/meson/gxl/gxl_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/gxl/gxl_def.h b/plat/meson/gxl/gxl_def.h new file mode 100644 index 0000000000000000000000000000000000000000..ada26560c45a6ff9909b62095fe6980e1a18149b --- /dev/null +++ b/plat/meson/gxl/gxl_def.h @@ -0,0 +1,122 @@ +/* + * 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(0x05100000) +#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(0x050FE000) +#define GXBB_SHARE_MEM_OUTPUT_BASE UL(0x050FF000) + +#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) + +// * [ 1K] 0xD901_3800 - 0xD901_3BFF Secure Mailbox (3) +// * [ 1K] 0xD901_3400 - 0xD901_37FF High Mailbox (2) * +// * [ 1K] 0xD901_3000 - 0xD901_33FF High Mailbox (1) * + +#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/gxl/gxl_efuse.c b/plat/meson/gxl/gxl_efuse.c new file mode 100644 index 0000000000000000000000000000000000000000..b17d1b8e36b54bc00112398d477d3f4f4e963326 --- /dev/null +++ b/plat/meson/gxl/gxl_efuse.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include "gxl_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/gxl/gxl_mhu.c b/plat/meson/gxl/gxl_mhu.c new file mode 100644 index 0000000000000000000000000000000000000000..4c1d5b600d8c5ec81c4099d6cd428b0ac4cf22d0 --- /dev/null +++ b/plat/meson/gxl/gxl_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/gxl/gxl_pm.c b/plat/meson/gxl/gxl_pm.c new file mode 100644 index 0000000000000000000000000000000000000000..d9b69ef8235b03e16a0d235efb35fea52afa2831 --- /dev/null +++ b/plat/meson/gxl/gxl_pm.c @@ -0,0 +1,193 @@ +/* + * 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 "gxl_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 volatile uint32_t gxbb_cpu0_go; + +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) +{ + unsigned int core = plat_gxbb_calc_core_pos(mpidr); + + /* CPU0 can't be turned OFF, emulate it with a WFE loop */ + if (core == GXBB_PRIMARY_CPU) { + VERBOSE("BL31: Releasing CPU0 from wait loop...\n"); + + gxbb_cpu0_go = 1; + flush_dcache_range((uintptr_t)&gxbb_cpu0_go, + sizeof(gxbb_cpu0_go)); + dsb(); + isb(); + + sev(); + + return PSCI_E_SUCCESS; + } + + 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) +{ + unsigned int core = plat_gxbb_calc_core_pos(read_mpidr_el1()); + + assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == + PLAT_LOCAL_STATE_OFF); + + if (core == GXBB_PRIMARY_CPU) { + gxbb_cpu0_go = 0; + flush_dcache_range((uintptr_t)&gxbb_cpu0_go, + sizeof(gxbb_cpu0_go)); + dsb(); + isb(); + } + + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); +} + +static void gxbb_pwr_domain_off(const psci_power_state_t *target_state) +{ + u_register_t mpidr = read_mpidr_el1(); + unsigned int core = plat_gxbb_calc_core_pos(mpidr); + uintptr_t addr = GXBB_PSCI_MAILBOX_BASE + 8 + (core << 4); + + mmio_write_32(addr, 0xFFFFFFFF); + flush_dcache_range(addr, sizeof(uint32_t)); + + gicv2_cpuif_disable(); + + /* CPU0 can't be turned OFF, emulate it with a WFE loop */ + if (core == GXBB_PRIMARY_CPU) + return; + + scpi_set_css_power_state(mpidr, + SCPI_POWER_OFF, SCPI_POWER_ON, SCPI_POWER_ON); +} + +static void __dead2 gxbb_pwr_domain_pwr_down_wfi(const psci_power_state_t + *target_state) +{ + unsigned int core = plat_gxbb_calc_core_pos(read_mpidr_el1()); + + /* CPU0 can't be turned OFF, emulate it with a WFE loop */ + if (core == GXBB_PRIMARY_CPU) { + VERBOSE("BL31: CPU0 entering wait loop...\n"); + + while (gxbb_cpu0_go == 0) + wfe(); + + VERBOSE("BL31: CPU0 resumed.\n"); + + write_rmr_el3(RMR_EL3_RR_BIT | RMR_EL3_AA64_BIT); + } + + dsbsy(); + + for (;;) + wfi(); +} + +/******************************************************************************* + * 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, + .pwr_domain_off = gxbb_pwr_domain_off, + .pwr_domain_pwr_down_wfi = gxbb_pwr_domain_pwr_down_wfi, + .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; + gxbb_cpu0_go = 0; + return 0; +} diff --git a/plat/meson/gxl/gxl_private.h b/plat/meson/gxl/gxl_private.h new file mode 100644 index 0000000000000000000000000000000000000000..913cbf6530bc9a7a335ba22ed10c7ee0fbcc71f0 --- /dev/null +++ b/plat/meson/gxl/gxl_private.h @@ -0,0 +1,40 @@ +/* + * 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 +#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); +void scpi_upload_scp_fw(uintptr_t addr, size_t size, int send); + +/* 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/gxl/gxl_scpi.c b/plat/meson/gxl/gxl_scpi.c new file mode 100644 index 0000000000000000000000000000000000000000..13d6524365bb65a97daea9303e8dc1ad43930822 --- /dev/null +++ b/plat/meson/gxl/gxl_scpi.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include "gxl_private.h" + +#define SIZE_SHIFT 20 +#define SIZE_MASK 0x1FF +#define SIZE_FWBLK 0x200UL + +/* + * 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 + +#define SCPI_CMD_COPY_FW 0xd4 +#define SCPI_CMD_SET_FW_ADDR 0xd3 +#define SCPI_CMD_FW_SIZE 0xd2 + +static inline uint32_t scpi_cmd(uint32_t command, uint32_t size) +{ + return command | (size << SIZE_SHIFT); +} + +static 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(); +} + +static inline void scpi_copy_scp_data(uint8_t *data, size_t len) +{ + void *dst = (void *)GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD; + size_t sz; + + mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, len); + scpi_secure_message_send(SCPI_CMD_FW_SIZE, len); + mhu_secure_message_wait(); + + for (sz = 0; sz < len; sz += SIZE_FWBLK) { + memcpy(dst, data + sz, MIN(SIZE_FWBLK, len - sz)); + mhu_secure_message_send(SCPI_CMD_COPY_FW); + } +} + +static inline void scpi_set_scp_addr(uint64_t addr, size_t len) +{ + volatile uint64_t *dst = (uint64_t *)GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD; + + /* + * It is ok as GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD is mapped as + * non cachable + */ + *dst = addr; + scpi_secure_message_send(SCPI_CMD_SET_FW_ADDR, sizeof(addr)); + mhu_secure_message_wait(); + + mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, len); + scpi_secure_message_send(SCPI_CMD_FW_SIZE, len); + mhu_secure_message_wait(); +} + +static inline void scpi_send_fw_hash(uint8_t hash[], size_t len) +{ + void *dst = (void *)GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD; + + memcpy(dst, hash, len); + mhu_secure_message_send(0xd0); + mhu_secure_message_send(0xd1); + mhu_secure_message_send(0xd5); + mhu_secure_message_end(); +} + +/** + * Upload a FW to SCP. + * + * @param addr: firmware data address + * @param size: size of firmware + * @param send: If set, actually copy the firmware in SCP memory otherwise only + * send the firmware address. + */ +void scpi_upload_scp_fw(uintptr_t addr, size_t size, int send) +{ + struct asd_ctx ctx; + + asd_sha_init(&ctx, ASM_SHA256); + asd_sha_update(&ctx, (void *)addr, size); + asd_sha_finalize(&ctx); + + mhu_secure_message_start(); + if (send == 0) + scpi_set_scp_addr(addr, size); + else + scpi_copy_scp_data((void *)addr, size); + + scpi_send_fw_hash(ctx.digest, sizeof(ctx.digest)); +} diff --git a/plat/meson/gxl/gxl_sip_svc.c b/plat/meson/gxl/gxl_sip_svc.c new file mode 100644 index 0000000000000000000000000000000000000000..74fbc80e42c6a47046c219ae818a83964b977b67 --- /dev/null +++ b/plat/meson/gxl/gxl_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 "gxl_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/gxl/gxl_thermal.c b/plat/meson/gxl/gxl_thermal.c new file mode 100644 index 0000000000000000000000000000000000000000..3af1c6dc660a84341e198fb58700ab9446c28199 --- /dev/null +++ b/plat/meson/gxl/gxl_thermal.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include "gxl_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/gxl/gxl_topology.c b/plat/meson/gxl/gxl_topology.c new file mode 100644 index 0000000000000000000000000000000000000000..cca3ead50cc7a24dad90f98b04a59d6aca6770b6 --- /dev/null +++ b/plat/meson/gxl/gxl_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 "gxl_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/gxl/include/plat_macros.S b/plat/meson/gxl/include/plat_macros.S new file mode 100644 index 0000000000000000000000000000000000000000..c721c21b68455d0626822fb4f1dbedc8d417f50a --- /dev/null +++ b/plat/meson/gxl/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/gxl/include/platform_def.h b/plat/meson/gxl/include/platform_def.h new file mode 100644 index 0000000000000000000000000000000000000000..b32ec56dab4b7995d2685a676952156974ad5777 --- /dev/null +++ b/plat/meson/gxl/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 "../gxl_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 6 + +#endif /* PLATFORM_DEF_H */ diff --git a/plat/meson/gxl/platform.mk b/plat/meson/gxl/platform.mk new file mode 100644 index 0000000000000000000000000000000000000000..ea4aead72e6fc9ea590977da9badc3f5ad04616c --- /dev/null +++ b/plat/meson/gxl/platform.mk @@ -0,0 +1,94 @@ +# +# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include lib/xlat_tables_v2/xlat_tables.mk + +DOIMAGEPATH ?= tools/meson +DOIMAGETOOL ?= ${DOIMAGEPATH}/doimage + +PLAT_INCLUDES := -Iinclude/drivers/meson/ \ + -Iinclude/drivers/meson/gxl \ + -Iplat/meson/gxl/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/meson/console/aarch64/meson_console.S \ + plat/meson/gxl/gxl_common.c \ + plat/meson/gxl/gxl_topology.c \ + ${XLAT_TABLES_LIB_SRCS} + +BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ + plat/common/plat_psci_common.c \ + plat/meson/gxl/aarch64/gxl_helpers.S \ + plat/meson/gxl/gxl_bl31_setup.c \ + plat/meson/gxl/gxl_efuse.c \ + plat/meson/gxl/gxl_mhu.c \ + plat/meson/gxl/gxl_pm.c \ + plat/meson/gxl/gxl_scpi.c \ + plat/meson/gxl/gxl_sip_svc.c \ + plat/meson/gxl/gxl_thermal.c \ + drivers/meson/gxl/crypto/sha_dma.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_855873 := 1 +ERRATA_A53_819472 := 1 +ERRATA_A53_824069 := 1 +ERRATA_A53_827319 := 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: gxl needs MULTI_CONSOLE_API=1) +endif + +ifneq (${RESET_TO_BL31}, 0) + $(error Error: gxl needs RESET_TO_BL31=0) +endif + +ifeq (${ARCH},aarch32) + $(error Error: AArch32 not supported on gxl) +endif + +all: ${BUILD_PLAT}/bl31.img +distclean realclean clean: cleanimage + +cleanimage: + ${Q}${MAKE} -C ${DOIMAGEPATH} clean + +${DOIMAGETOOL}: + ${Q}${MAKE} -C ${DOIMAGEPATH} + +${BUILD_PLAT}/bl31.img: ${BUILD_PLAT}/bl31.bin ${DOIMAGETOOL} + ${DOIMAGETOOL} ${BUILD_PLAT}/bl31.bin ${BUILD_PLAT}/bl31.img + diff --git a/readme.rst b/readme.rst index 41ffc0fd60e671dd4f354e0cf67c36b053f01ad8..6f47812d5a059ebc2f36ae3b748ec89e094ac819 100644 --- a/readme.rst +++ b/readme.rst @@ -211,6 +211,7 @@ This release also contains the following platform support: - Allwinner sun50i_a64 and sun50i_h6 - Amlogic Meson S905 (GXBB) +- Amlogic Meson S905x (GXL) - Arm Juno Software Development Platform - Arm Neoverse N1 System Development Platform (N1SDP) - Arm Neoverse Reference Design N1 Edge (RD-N1-Edge) FVP diff --git a/tools/meson/Makefile b/tools/meson/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1a1d1f8124d1e5793ae54f7217fe2722cfb356c1 --- /dev/null +++ b/tools/meson/Makefile @@ -0,0 +1,49 @@ +# +# Copyright (C) 2019 Remi Pommarel +# +# SPDX-License-Identifier: BSD-3-Clause +# https://spdx.org/licenses +# +MAKE_HELPERS_DIRECTORY := ../../make_helpers/ +include ${MAKE_HELPERS_DIRECTORY}build_macros.mk +include ${MAKE_HELPERS_DIRECTORY}build_env.mk + +PROJECT := doimage${BIN_EXT} +OBJECTS := doimage.o +V := 0 + +HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 -D_GNU_SOURCE + +ifeq (${DEBUG},1) + HOSTCCFLAGS += -g -O0 -DDEBUG +else + HOSTCCFLAGS += -O2 +endif + +ifeq (${V},0) + Q := @ +else + Q := +endif + +HOSTCC := gcc + +.PHONY: all clean distclean + +all: ${PROJECT} + +${PROJECT}: ${OBJECTS} Makefile + @echo " HOSTLD $@" + ${Q}${HOSTCC} ${OBJECTS} -o $@ + @${ECHO_BLANK_LINE} + @echo "Built $@ successfully" + @${ECHO_BLANK_LINE} + +%.o: %.c Makefile + @echo " HOSTCC $<" + ${Q}${HOSTCC} -c ${HOSTCCFLAGS} $< -o $@ + +clean: + $(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS}) + +distclean: clean diff --git a/tools/meson/doimage.c b/tools/meson/doimage.c new file mode 100644 index 0000000000000000000000000000000000000000..b304038d18bc87f975afb9b598fcd58ba5f78717 --- /dev/null +++ b/tools/meson/doimage.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2019, Remi Pommarel + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include + +#define DEFAULT_PROGNAME "doimage" +#define PROGNAME(argc, argv) (((argc) >= 1) ? ((argv)[0]) : DEFAULT_PROGNAME) + +#define BL31_MAGIC 0x12348765 +#define BL31_LOADADDR 0x05100000 +#define BUFLEN 512 + +static inline void usage(char const *prog) +{ + fprintf(stderr, "Usage: %s \n", prog); +} + +static inline int fdwrite(int fd, uint8_t *data, size_t len) +{ + ssize_t nr; + size_t l; + int ret = -1; + + for (l = 0; l < len; l += nr) { + nr = write(fd, data + l, len - l); + if (nr < 0) { + perror("Cannot write to bl31.img"); + goto out; + } + } + + ret = 0; +out: + return ret; +} + +int main(int argc, char **argv) +{ + int fin, fout, ret = -1; + ssize_t len; + uint32_t data; + uint8_t buf[BUFLEN]; + + if (argc != 3) { + usage(PROGNAME(argc, argv)); + goto out; + } + + fin = open(argv[1], O_RDONLY); + if (fin < 0) { + perror("Cannot open bl31.bin"); + goto out; + } + + fout = open(argv[2], O_WRONLY | O_CREAT, 0660); + if (fout < 0) { + perror("Cannot open bl31.img"); + goto closefin; + } + + data = htole32(BL31_MAGIC); + if (fdwrite(fout, (uint8_t *)&data, sizeof(data)) < 0) + goto closefout; + + lseek(fout, 8, SEEK_SET); + data = htole32(BL31_LOADADDR); + if (fdwrite(fout, (uint8_t *)&data, sizeof(data)) < 0) + goto closefout; + + lseek(fout, 0x200, SEEK_SET); + while ((len = read(fin, buf, sizeof(buf))) > 0) + if (fdwrite(fout, buf, len) < 0) + goto closefout; + if (len < 0) { + perror("Cannot read bl31.bin"); + goto closefout; + } + + ret = 0; + +closefout: + close(fout); +closefin: + close(fin); +out: + return ret; +}