diff --git a/plat/meson/gxl/gxl_bl31_setup.c b/plat/meson/gxl/gxl_bl31_setup.c index 0e52f6c..7fe0529 100644 --- a/plat/meson/gxl/gxl_bl31_setup.c +++ b/plat/meson/gxl/gxl_bl31_setup.c @@ -19,6 +19,8 @@ * 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 @@ -50,19 +52,20 @@ * tables. BL2 has flushed this information to memory, so we are guaranteed * to pick up good data. ******************************************************************************/ -struct gxbb_bl31_param { +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 gxbb_bl31_param *from_bl2; + struct gxl_bl31_param *from_bl2; /* Initialize the console to provide early debug support */ gxbb_console_init(); @@ -74,7 +77,7 @@ assert(arg1 == GXBB_BL31_PLAT_PARAM_VAL); /* Check that params passed from BL2 are not NULL. */ - from_bl2 = (struct gxbb_bl31_param *) arg0; + from_bl2 = (struct gxl_bl31_param *) arg0; /* Check params passed from BL2 are not NULL. */ assert(from_bl2 != NULL); @@ -91,6 +94,9 @@ 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) @@ -100,6 +106,14 @@ 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 ******************************************************************************/ @@ -140,5 +154,7 @@ gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); -// gxbb_thermal_unknown(); + gxl_scp_boot(); + + gxbb_thermal_unknown(); } diff --git a/plat/meson/gxl/gxl_private.h b/plat/meson/gxl/gxl_private.h index 910a42c..913cbf6 100644 --- a/plat/meson/gxl/gxl_private.h +++ b/plat/meson/gxl/gxl_private.h @@ -8,6 +8,7 @@ #define GXBB_PRIVATE_H #include +#include /* Utility functions */ unsigned int plat_gxbb_calc_core_pos(u_register_t mpidr); @@ -29,6 +30,7 @@ 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); diff --git a/plat/meson/gxl/gxl_scpi.c b/plat/meson/gxl/gxl_scpi.c index daa495e..13d6524 100644 --- a/plat/meson/gxl/gxl_scpi.c +++ b/plat/meson/gxl/gxl_scpi.c @@ -9,11 +9,13 @@ #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. @@ -24,12 +26,16 @@ #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); } -void scpi_secure_message_send(uint32_t command, uint32_t size) +static void scpi_secure_message_send(uint32_t command, uint32_t size) { mhu_secure_message_send(scpi_cmd(command, size)); } @@ -135,3 +141,71 @@ 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)); +}