132e9fc1aSHaojian Zhuang /* 232e9fc1aSHaojian Zhuang * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 332e9fc1aSHaojian Zhuang * 432e9fc1aSHaojian Zhuang * SPDX-License-Identifier: BSD-3-Clause 532e9fc1aSHaojian Zhuang */ 632e9fc1aSHaojian Zhuang 732e9fc1aSHaojian Zhuang #include <assert.h> 832e9fc1aSHaojian Zhuang #include <string.h> 932e9fc1aSHaojian Zhuang 10*09d40e0eSAntonio Nino Diaz #include <platform_def.h> 11*09d40e0eSAntonio Nino Diaz 12*09d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 13*09d40e0eSAntonio Nino Diaz #include <common/bl_common.h> 14*09d40e0eSAntonio Nino Diaz #include <common/debug.h> 15*09d40e0eSAntonio Nino Diaz #include <drivers/console.h> 16*09d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 17*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 18*09d40e0eSAntonio Nino Diaz 19*09d40e0eSAntonio Nino Diaz #include <hi6220.h> 20*09d40e0eSAntonio Nino Diaz 2132e9fc1aSHaojian Zhuang #define MCU_SECTION_MAX 30 2232e9fc1aSHaojian Zhuang 2332e9fc1aSHaojian Zhuang enum MCU_IMAGE_SEC_TYPE_ENUM { 2432e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_TYPE_TEXT = 0, /* text section */ 2532e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_TYPE_DATA, /* data section */ 2632e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_TYPE_BUTT 2732e9fc1aSHaojian Zhuang }; 2832e9fc1aSHaojian Zhuang 2932e9fc1aSHaojian Zhuang enum MCU_IMAGE_SEC_LOAD_ENUM { 3032e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_LOAD_STATIC = 0, 3132e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_LOAD_DYNAMIC, 3232e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_LOAD_BUFFER, 3332e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_LOAD_MODEM_ENTRY, 3432e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_LOAD_BUTT 3532e9fc1aSHaojian Zhuang }; 3632e9fc1aSHaojian Zhuang 3732e9fc1aSHaojian Zhuang struct mcu_image_sec { 3832e9fc1aSHaojian Zhuang unsigned short serial; 3932e9fc1aSHaojian Zhuang char type; 4032e9fc1aSHaojian Zhuang char load_attr; 4132e9fc1aSHaojian Zhuang uint32_t src_offset; /* offset in image */ 4232e9fc1aSHaojian Zhuang uint32_t dst_offset; /* offset in memory */ 4332e9fc1aSHaojian Zhuang uint32_t size; 4432e9fc1aSHaojian Zhuang }; 4532e9fc1aSHaojian Zhuang 4632e9fc1aSHaojian Zhuang struct mcu_image_head { 4732e9fc1aSHaojian Zhuang char time_stamp[24]; 4832e9fc1aSHaojian Zhuang uint32_t image_size; 4932e9fc1aSHaojian Zhuang uint32_t secs_num; 5032e9fc1aSHaojian Zhuang struct mcu_image_sec secs[MCU_SECTION_MAX]; 5132e9fc1aSHaojian Zhuang }; 5232e9fc1aSHaojian Zhuang 5332e9fc1aSHaojian Zhuang #define SOC_SRAM_M3_BASE_ADDR (0xF6000000) 5432e9fc1aSHaojian Zhuang 5532e9fc1aSHaojian Zhuang #define MCU_SRAM_SIZE (0x0000C000) 5632e9fc1aSHaojian Zhuang #define MCU_CACHE_SIZE (0x00004000) 5732e9fc1aSHaojian Zhuang #define MCU_CODE_SIZE (MCU_SRAM_SIZE - MCU_CACHE_SIZE) 5832e9fc1aSHaojian Zhuang 5932e9fc1aSHaojian Zhuang #define MCU_SYS_MEM_ADDR (0x05E00000) 6032e9fc1aSHaojian Zhuang #define MCU_SYS_MEM_SIZE (0x00100000) 6132e9fc1aSHaojian Zhuang 6232e9fc1aSHaojian Zhuang static uint32_t mcu2ap_addr(uint32_t mcu_addr) 6332e9fc1aSHaojian Zhuang { 6432e9fc1aSHaojian Zhuang if (mcu_addr < MCU_CODE_SIZE) 6532e9fc1aSHaojian Zhuang return (mcu_addr + SOC_SRAM_M3_BASE_ADDR); 6632e9fc1aSHaojian Zhuang else if ((mcu_addr >= MCU_SRAM_SIZE) && 6732e9fc1aSHaojian Zhuang (mcu_addr < MCU_SRAM_SIZE + MCU_SYS_MEM_SIZE)) 6832e9fc1aSHaojian Zhuang return mcu_addr - MCU_SRAM_SIZE + MCU_SYS_MEM_ADDR; 6932e9fc1aSHaojian Zhuang else 7032e9fc1aSHaojian Zhuang return mcu_addr; 7132e9fc1aSHaojian Zhuang } 7232e9fc1aSHaojian Zhuang 7332e9fc1aSHaojian Zhuang static int is_binary_header_invalid(struct mcu_image_head *head, 7432e9fc1aSHaojian Zhuang unsigned int length) 7532e9fc1aSHaojian Zhuang { 7632e9fc1aSHaojian Zhuang /* invalid cases */ 7732e9fc1aSHaojian Zhuang if ((head->image_size == 0) || 7832e9fc1aSHaojian Zhuang (head->image_size > length) || 7932e9fc1aSHaojian Zhuang (head->secs_num > MCU_SECTION_MAX) || 8032e9fc1aSHaojian Zhuang (head->secs_num == 0)) 8132e9fc1aSHaojian Zhuang return 1; 8232e9fc1aSHaojian Zhuang 8332e9fc1aSHaojian Zhuang return 0; 8432e9fc1aSHaojian Zhuang } 8532e9fc1aSHaojian Zhuang 8632e9fc1aSHaojian Zhuang static int is_binary_section_invalid(struct mcu_image_sec *sec, 8732e9fc1aSHaojian Zhuang struct mcu_image_head *head) 8832e9fc1aSHaojian Zhuang { 8932e9fc1aSHaojian Zhuang unsigned long ap_dst_offset = 0; 9032e9fc1aSHaojian Zhuang 9132e9fc1aSHaojian Zhuang if ((sec->serial >= head->secs_num) || 9232e9fc1aSHaojian Zhuang (sec->src_offset + sec->size > head->image_size)) 9332e9fc1aSHaojian Zhuang return 1; 9432e9fc1aSHaojian Zhuang 9532e9fc1aSHaojian Zhuang if ((sec->type >= MCU_IMAGE_SEC_TYPE_BUTT) || 9632e9fc1aSHaojian Zhuang (sec->load_attr >= MCU_IMAGE_SEC_LOAD_BUTT)) 9732e9fc1aSHaojian Zhuang return 1; 9832e9fc1aSHaojian Zhuang 9932e9fc1aSHaojian Zhuang ap_dst_offset = mcu2ap_addr(sec->dst_offset); 10032e9fc1aSHaojian Zhuang if ((ap_dst_offset >= SOC_SRAM_M3_BASE_ADDR) && 10132e9fc1aSHaojian Zhuang (ap_dst_offset < SOC_SRAM_M3_BASE_ADDR + 0x20000 - sec->size)) 10232e9fc1aSHaojian Zhuang return 0; 10332e9fc1aSHaojian Zhuang else if ((ap_dst_offset >= MCU_SYS_MEM_ADDR) && 10432e9fc1aSHaojian Zhuang (ap_dst_offset < MCU_SYS_MEM_ADDR + MCU_SYS_MEM_SIZE - sec->size)) 10532e9fc1aSHaojian Zhuang return 0; 10632e9fc1aSHaojian Zhuang else if ((ap_dst_offset >= 0xfff8e000) && 10732e9fc1aSHaojian Zhuang (ap_dst_offset < 0xfff91c00 - sec->size)) 10832e9fc1aSHaojian Zhuang return 0; 10932e9fc1aSHaojian Zhuang 11032e9fc1aSHaojian Zhuang ERROR("%s: mcu destination address invalid.\n", __func__); 11132e9fc1aSHaojian Zhuang ERROR("%s: number=%d, dst offset=%d size=%d\n", 11232e9fc1aSHaojian Zhuang __func__, sec->serial, sec->dst_offset, sec->size); 11332e9fc1aSHaojian Zhuang return 1; 11432e9fc1aSHaojian Zhuang } 11532e9fc1aSHaojian Zhuang 11632e9fc1aSHaojian Zhuang void hisi_mcu_enable_sram(void) 11732e9fc1aSHaojian Zhuang { 11832e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_PERIPH_CLKEN4, 11932e9fc1aSHaojian Zhuang AO_SC_PERIPH_CLKEN4_HCLK_IPC_S | 12032e9fc1aSHaojian Zhuang AO_SC_PERIPH_CLKEN4_HCLK_IPC_NS); 12132e9fc1aSHaojian Zhuang 12232e9fc1aSHaojian Zhuang /* set register to enable dvfs which is used by mcu */ 12332e9fc1aSHaojian Zhuang mmio_write_32(PERI_SC_RESERVED8_ADDR, 0x0A001022); 12432e9fc1aSHaojian Zhuang 12532e9fc1aSHaojian Zhuang /* mcu mem is powered on, need de-assert reset */ 12632e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_PERIPH_RSTDIS4, 12732e9fc1aSHaojian Zhuang AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N); 12832e9fc1aSHaojian Zhuang 12932e9fc1aSHaojian Zhuang /* enable mcu hclk */ 13032e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_PERIPH_CLKEN4, 13132e9fc1aSHaojian Zhuang AO_SC_PERIPH_CLKEN4_HCLK_MCU | 13232e9fc1aSHaojian Zhuang AO_SC_PERIPH_CLKEN4_CLK_MCU_DAP); 13332e9fc1aSHaojian Zhuang } 13432e9fc1aSHaojian Zhuang 13532e9fc1aSHaojian Zhuang void hisi_mcu_start_run(void) 13632e9fc1aSHaojian Zhuang { 13732e9fc1aSHaojian Zhuang unsigned int val; 13832e9fc1aSHaojian Zhuang 13932e9fc1aSHaojian Zhuang /* set mcu ddr remap configuration */ 14032e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_MCU_SUBSYS_CTRL2, MCU_SYS_MEM_ADDR); 14132e9fc1aSHaojian Zhuang 14232e9fc1aSHaojian Zhuang /* de-assert reset for mcu and to run */ 14332e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_PERIPH_RSTDIS4, 14432e9fc1aSHaojian Zhuang AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N | 14532e9fc1aSHaojian Zhuang AO_SC_PERIPH_RSTDIS4_RESET_MCU_SYS_N | 14632e9fc1aSHaojian Zhuang AO_SC_PERIPH_RSTDIS4_RESET_MCU_POR_N | 14732e9fc1aSHaojian Zhuang AO_SC_PERIPH_RSTDIS4_RESET_MCU_DAP_N); 14832e9fc1aSHaojian Zhuang 14932e9fc1aSHaojian Zhuang val = mmio_read_32(AO_SC_SYS_CTRL2); 15032e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_SYS_CTRL2, 15132e9fc1aSHaojian Zhuang val | AO_SC_SYS_CTRL2_GLB_SRST_STAT_CLEAR); 15232e9fc1aSHaojian Zhuang 15332e9fc1aSHaojian Zhuang INFO("%s: AO_SC_SYS_CTRL2=%x\n", __func__, 15432e9fc1aSHaojian Zhuang mmio_read_32(AO_SC_SYS_CTRL2)); 15532e9fc1aSHaojian Zhuang } 15632e9fc1aSHaojian Zhuang 15732e9fc1aSHaojian Zhuang int hisi_mcu_load_image(uintptr_t image_base, uint32_t image_size) 15832e9fc1aSHaojian Zhuang { 15932e9fc1aSHaojian Zhuang unsigned int i; 16032e9fc1aSHaojian Zhuang struct mcu_image_head *head; 16132e9fc1aSHaojian Zhuang char *buf; 16232e9fc1aSHaojian Zhuang 16332e9fc1aSHaojian Zhuang head = (struct mcu_image_head *)image_base; 16432e9fc1aSHaojian Zhuang if (is_binary_header_invalid(head, image_size)) { 16532e9fc1aSHaojian Zhuang ERROR("Invalid %s image header.\n", head->time_stamp); 16632e9fc1aSHaojian Zhuang return -1; 16732e9fc1aSHaojian Zhuang } 16832e9fc1aSHaojian Zhuang 16932e9fc1aSHaojian Zhuang buf = (char *)head; 17032e9fc1aSHaojian Zhuang for (i = 0; i < head->secs_num; i++) { 17132e9fc1aSHaojian Zhuang 17232e9fc1aSHaojian Zhuang int *src, *dst; 17332e9fc1aSHaojian Zhuang 17432e9fc1aSHaojian Zhuang /* check the sections */ 17532e9fc1aSHaojian Zhuang if (is_binary_section_invalid(&head->secs[i], head)) { 17632e9fc1aSHaojian Zhuang ERROR("Invalid mcu section.\n"); 17732e9fc1aSHaojian Zhuang return -1; 17832e9fc1aSHaojian Zhuang } 17932e9fc1aSHaojian Zhuang 18032e9fc1aSHaojian Zhuang /* check if the section is static-loaded */ 18132e9fc1aSHaojian Zhuang if (head->secs[i].load_attr != MCU_IMAGE_SEC_LOAD_STATIC) 18232e9fc1aSHaojian Zhuang continue; 18332e9fc1aSHaojian Zhuang 18432e9fc1aSHaojian Zhuang /* copy the sections */ 18532e9fc1aSHaojian Zhuang src = (int *)(intptr_t)(buf + head->secs[i].src_offset); 18632e9fc1aSHaojian Zhuang dst = (int *)(intptr_t)mcu2ap_addr(head->secs[i].dst_offset); 18732e9fc1aSHaojian Zhuang 18832e9fc1aSHaojian Zhuang memcpy((void *)dst, (void *)src, head->secs[i].size); 18932e9fc1aSHaojian Zhuang 19032e9fc1aSHaojian Zhuang INFO("%s: mcu sections %d:\n", __func__, i); 19132e9fc1aSHaojian Zhuang INFO("%s: src = 0x%x\n", 19232e9fc1aSHaojian Zhuang __func__, (unsigned int)(uintptr_t)src); 19332e9fc1aSHaojian Zhuang INFO("%s: dst = 0x%x\n", 19432e9fc1aSHaojian Zhuang __func__, (unsigned int)(uintptr_t)dst); 19532e9fc1aSHaojian Zhuang INFO("%s: size = %d\n", __func__, head->secs[i].size); 19632e9fc1aSHaojian Zhuang 19732e9fc1aSHaojian Zhuang INFO("%s: [SRC 0x%x] 0x%x 0x%x 0x%x 0x%x\n", 19832e9fc1aSHaojian Zhuang __func__, (unsigned int)(uintptr_t)src, 19932e9fc1aSHaojian Zhuang src[0], src[1], src[2], src[3]); 20032e9fc1aSHaojian Zhuang INFO("%s: [DST 0x%x] 0x%x 0x%x 0x%x 0x%x\n", 20132e9fc1aSHaojian Zhuang __func__, (unsigned int)(uintptr_t)dst, 20232e9fc1aSHaojian Zhuang dst[0], dst[1], dst[2], dst[3]); 20332e9fc1aSHaojian Zhuang } 20432e9fc1aSHaojian Zhuang 20532e9fc1aSHaojian Zhuang return 0; 20632e9fc1aSHaojian Zhuang } 207