1*32e9fc1aSHaojian Zhuang /* 2*32e9fc1aSHaojian Zhuang * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3*32e9fc1aSHaojian Zhuang * 4*32e9fc1aSHaojian Zhuang * SPDX-License-Identifier: BSD-3-Clause 5*32e9fc1aSHaojian Zhuang */ 6*32e9fc1aSHaojian Zhuang 7*32e9fc1aSHaojian Zhuang #include <arch_helpers.h> 8*32e9fc1aSHaojian Zhuang #include <assert.h> 9*32e9fc1aSHaojian Zhuang #include <bl_common.h> 10*32e9fc1aSHaojian Zhuang #include <console.h> 11*32e9fc1aSHaojian Zhuang #include <debug.h> 12*32e9fc1aSHaojian Zhuang #include <hi6220.h> 13*32e9fc1aSHaojian Zhuang #include <mmio.h> 14*32e9fc1aSHaojian Zhuang #include <platform.h> 15*32e9fc1aSHaojian Zhuang #include <platform_def.h> 16*32e9fc1aSHaojian Zhuang #include <string.h> 17*32e9fc1aSHaojian Zhuang 18*32e9fc1aSHaojian Zhuang #define MCU_SECTION_MAX 30 19*32e9fc1aSHaojian Zhuang 20*32e9fc1aSHaojian Zhuang enum MCU_IMAGE_SEC_TYPE_ENUM { 21*32e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_TYPE_TEXT = 0, /* text section */ 22*32e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_TYPE_DATA, /* data section */ 23*32e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_TYPE_BUTT 24*32e9fc1aSHaojian Zhuang }; 25*32e9fc1aSHaojian Zhuang 26*32e9fc1aSHaojian Zhuang enum MCU_IMAGE_SEC_LOAD_ENUM { 27*32e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_LOAD_STATIC = 0, 28*32e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_LOAD_DYNAMIC, 29*32e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_LOAD_BUFFER, 30*32e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_LOAD_MODEM_ENTRY, 31*32e9fc1aSHaojian Zhuang MCU_IMAGE_SEC_LOAD_BUTT 32*32e9fc1aSHaojian Zhuang }; 33*32e9fc1aSHaojian Zhuang 34*32e9fc1aSHaojian Zhuang struct mcu_image_sec { 35*32e9fc1aSHaojian Zhuang unsigned short serial; 36*32e9fc1aSHaojian Zhuang char type; 37*32e9fc1aSHaojian Zhuang char load_attr; 38*32e9fc1aSHaojian Zhuang uint32_t src_offset; /* offset in image */ 39*32e9fc1aSHaojian Zhuang uint32_t dst_offset; /* offset in memory */ 40*32e9fc1aSHaojian Zhuang uint32_t size; 41*32e9fc1aSHaojian Zhuang }; 42*32e9fc1aSHaojian Zhuang 43*32e9fc1aSHaojian Zhuang struct mcu_image_head { 44*32e9fc1aSHaojian Zhuang char time_stamp[24]; 45*32e9fc1aSHaojian Zhuang uint32_t image_size; 46*32e9fc1aSHaojian Zhuang uint32_t secs_num; 47*32e9fc1aSHaojian Zhuang struct mcu_image_sec secs[MCU_SECTION_MAX]; 48*32e9fc1aSHaojian Zhuang }; 49*32e9fc1aSHaojian Zhuang 50*32e9fc1aSHaojian Zhuang #define SOC_SRAM_M3_BASE_ADDR (0xF6000000) 51*32e9fc1aSHaojian Zhuang 52*32e9fc1aSHaojian Zhuang #define MCU_SRAM_SIZE (0x0000C000) 53*32e9fc1aSHaojian Zhuang #define MCU_CACHE_SIZE (0x00004000) 54*32e9fc1aSHaojian Zhuang #define MCU_CODE_SIZE (MCU_SRAM_SIZE - MCU_CACHE_SIZE) 55*32e9fc1aSHaojian Zhuang 56*32e9fc1aSHaojian Zhuang #define MCU_SYS_MEM_ADDR (0x05E00000) 57*32e9fc1aSHaojian Zhuang #define MCU_SYS_MEM_SIZE (0x00100000) 58*32e9fc1aSHaojian Zhuang 59*32e9fc1aSHaojian Zhuang static uint32_t mcu2ap_addr(uint32_t mcu_addr) 60*32e9fc1aSHaojian Zhuang { 61*32e9fc1aSHaojian Zhuang if (mcu_addr < MCU_CODE_SIZE) 62*32e9fc1aSHaojian Zhuang return (mcu_addr + SOC_SRAM_M3_BASE_ADDR); 63*32e9fc1aSHaojian Zhuang else if ((mcu_addr >= MCU_SRAM_SIZE) && 64*32e9fc1aSHaojian Zhuang (mcu_addr < MCU_SRAM_SIZE + MCU_SYS_MEM_SIZE)) 65*32e9fc1aSHaojian Zhuang return mcu_addr - MCU_SRAM_SIZE + MCU_SYS_MEM_ADDR; 66*32e9fc1aSHaojian Zhuang else 67*32e9fc1aSHaojian Zhuang return mcu_addr; 68*32e9fc1aSHaojian Zhuang } 69*32e9fc1aSHaojian Zhuang 70*32e9fc1aSHaojian Zhuang static int is_binary_header_invalid(struct mcu_image_head *head, 71*32e9fc1aSHaojian Zhuang unsigned int length) 72*32e9fc1aSHaojian Zhuang { 73*32e9fc1aSHaojian Zhuang /* invalid cases */ 74*32e9fc1aSHaojian Zhuang if ((head->image_size == 0) || 75*32e9fc1aSHaojian Zhuang (head->image_size > length) || 76*32e9fc1aSHaojian Zhuang (head->secs_num > MCU_SECTION_MAX) || 77*32e9fc1aSHaojian Zhuang (head->secs_num == 0)) 78*32e9fc1aSHaojian Zhuang return 1; 79*32e9fc1aSHaojian Zhuang 80*32e9fc1aSHaojian Zhuang return 0; 81*32e9fc1aSHaojian Zhuang } 82*32e9fc1aSHaojian Zhuang 83*32e9fc1aSHaojian Zhuang static int is_binary_section_invalid(struct mcu_image_sec *sec, 84*32e9fc1aSHaojian Zhuang struct mcu_image_head *head) 85*32e9fc1aSHaojian Zhuang { 86*32e9fc1aSHaojian Zhuang unsigned long ap_dst_offset = 0; 87*32e9fc1aSHaojian Zhuang 88*32e9fc1aSHaojian Zhuang if ((sec->serial >= head->secs_num) || 89*32e9fc1aSHaojian Zhuang (sec->src_offset + sec->size > head->image_size)) 90*32e9fc1aSHaojian Zhuang return 1; 91*32e9fc1aSHaojian Zhuang 92*32e9fc1aSHaojian Zhuang if ((sec->type >= MCU_IMAGE_SEC_TYPE_BUTT) || 93*32e9fc1aSHaojian Zhuang (sec->load_attr >= MCU_IMAGE_SEC_LOAD_BUTT)) 94*32e9fc1aSHaojian Zhuang return 1; 95*32e9fc1aSHaojian Zhuang 96*32e9fc1aSHaojian Zhuang ap_dst_offset = mcu2ap_addr(sec->dst_offset); 97*32e9fc1aSHaojian Zhuang if ((ap_dst_offset >= SOC_SRAM_M3_BASE_ADDR) && 98*32e9fc1aSHaojian Zhuang (ap_dst_offset < SOC_SRAM_M3_BASE_ADDR + 0x20000 - sec->size)) 99*32e9fc1aSHaojian Zhuang return 0; 100*32e9fc1aSHaojian Zhuang else if ((ap_dst_offset >= MCU_SYS_MEM_ADDR) && 101*32e9fc1aSHaojian Zhuang (ap_dst_offset < MCU_SYS_MEM_ADDR + MCU_SYS_MEM_SIZE - sec->size)) 102*32e9fc1aSHaojian Zhuang return 0; 103*32e9fc1aSHaojian Zhuang else if ((ap_dst_offset >= 0xfff8e000) && 104*32e9fc1aSHaojian Zhuang (ap_dst_offset < 0xfff91c00 - sec->size)) 105*32e9fc1aSHaojian Zhuang return 0; 106*32e9fc1aSHaojian Zhuang 107*32e9fc1aSHaojian Zhuang ERROR("%s: mcu destination address invalid.\n", __func__); 108*32e9fc1aSHaojian Zhuang ERROR("%s: number=%d, dst offset=%d size=%d\n", 109*32e9fc1aSHaojian Zhuang __func__, sec->serial, sec->dst_offset, sec->size); 110*32e9fc1aSHaojian Zhuang return 1; 111*32e9fc1aSHaojian Zhuang } 112*32e9fc1aSHaojian Zhuang 113*32e9fc1aSHaojian Zhuang void hisi_mcu_enable_sram(void) 114*32e9fc1aSHaojian Zhuang { 115*32e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_PERIPH_CLKEN4, 116*32e9fc1aSHaojian Zhuang AO_SC_PERIPH_CLKEN4_HCLK_IPC_S | 117*32e9fc1aSHaojian Zhuang AO_SC_PERIPH_CLKEN4_HCLK_IPC_NS); 118*32e9fc1aSHaojian Zhuang 119*32e9fc1aSHaojian Zhuang /* set register to enable dvfs which is used by mcu */ 120*32e9fc1aSHaojian Zhuang mmio_write_32(PERI_SC_RESERVED8_ADDR, 0x0A001022); 121*32e9fc1aSHaojian Zhuang 122*32e9fc1aSHaojian Zhuang /* mcu mem is powered on, need de-assert reset */ 123*32e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_PERIPH_RSTDIS4, 124*32e9fc1aSHaojian Zhuang AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N); 125*32e9fc1aSHaojian Zhuang 126*32e9fc1aSHaojian Zhuang /* enable mcu hclk */ 127*32e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_PERIPH_CLKEN4, 128*32e9fc1aSHaojian Zhuang AO_SC_PERIPH_CLKEN4_HCLK_MCU | 129*32e9fc1aSHaojian Zhuang AO_SC_PERIPH_CLKEN4_CLK_MCU_DAP); 130*32e9fc1aSHaojian Zhuang } 131*32e9fc1aSHaojian Zhuang 132*32e9fc1aSHaojian Zhuang void hisi_mcu_start_run(void) 133*32e9fc1aSHaojian Zhuang { 134*32e9fc1aSHaojian Zhuang unsigned int val; 135*32e9fc1aSHaojian Zhuang 136*32e9fc1aSHaojian Zhuang /* set mcu ddr remap configuration */ 137*32e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_MCU_SUBSYS_CTRL2, MCU_SYS_MEM_ADDR); 138*32e9fc1aSHaojian Zhuang 139*32e9fc1aSHaojian Zhuang /* de-assert reset for mcu and to run */ 140*32e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_PERIPH_RSTDIS4, 141*32e9fc1aSHaojian Zhuang AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N | 142*32e9fc1aSHaojian Zhuang AO_SC_PERIPH_RSTDIS4_RESET_MCU_SYS_N | 143*32e9fc1aSHaojian Zhuang AO_SC_PERIPH_RSTDIS4_RESET_MCU_POR_N | 144*32e9fc1aSHaojian Zhuang AO_SC_PERIPH_RSTDIS4_RESET_MCU_DAP_N); 145*32e9fc1aSHaojian Zhuang 146*32e9fc1aSHaojian Zhuang val = mmio_read_32(AO_SC_SYS_CTRL2); 147*32e9fc1aSHaojian Zhuang mmio_write_32(AO_SC_SYS_CTRL2, 148*32e9fc1aSHaojian Zhuang val | AO_SC_SYS_CTRL2_GLB_SRST_STAT_CLEAR); 149*32e9fc1aSHaojian Zhuang 150*32e9fc1aSHaojian Zhuang INFO("%s: AO_SC_SYS_CTRL2=%x\n", __func__, 151*32e9fc1aSHaojian Zhuang mmio_read_32(AO_SC_SYS_CTRL2)); 152*32e9fc1aSHaojian Zhuang } 153*32e9fc1aSHaojian Zhuang 154*32e9fc1aSHaojian Zhuang int hisi_mcu_load_image(uintptr_t image_base, uint32_t image_size) 155*32e9fc1aSHaojian Zhuang { 156*32e9fc1aSHaojian Zhuang unsigned int i; 157*32e9fc1aSHaojian Zhuang struct mcu_image_head *head; 158*32e9fc1aSHaojian Zhuang char *buf; 159*32e9fc1aSHaojian Zhuang 160*32e9fc1aSHaojian Zhuang head = (struct mcu_image_head *)image_base; 161*32e9fc1aSHaojian Zhuang if (is_binary_header_invalid(head, image_size)) { 162*32e9fc1aSHaojian Zhuang ERROR("Invalid %s image header.\n", head->time_stamp); 163*32e9fc1aSHaojian Zhuang return -1; 164*32e9fc1aSHaojian Zhuang } 165*32e9fc1aSHaojian Zhuang 166*32e9fc1aSHaojian Zhuang buf = (char *)head; 167*32e9fc1aSHaojian Zhuang for (i = 0; i < head->secs_num; i++) { 168*32e9fc1aSHaojian Zhuang 169*32e9fc1aSHaojian Zhuang int *src, *dst; 170*32e9fc1aSHaojian Zhuang 171*32e9fc1aSHaojian Zhuang /* check the sections */ 172*32e9fc1aSHaojian Zhuang if (is_binary_section_invalid(&head->secs[i], head)) { 173*32e9fc1aSHaojian Zhuang ERROR("Invalid mcu section.\n"); 174*32e9fc1aSHaojian Zhuang return -1; 175*32e9fc1aSHaojian Zhuang } 176*32e9fc1aSHaojian Zhuang 177*32e9fc1aSHaojian Zhuang /* check if the section is static-loaded */ 178*32e9fc1aSHaojian Zhuang if (head->secs[i].load_attr != MCU_IMAGE_SEC_LOAD_STATIC) 179*32e9fc1aSHaojian Zhuang continue; 180*32e9fc1aSHaojian Zhuang 181*32e9fc1aSHaojian Zhuang /* copy the sections */ 182*32e9fc1aSHaojian Zhuang src = (int *)(intptr_t)(buf + head->secs[i].src_offset); 183*32e9fc1aSHaojian Zhuang dst = (int *)(intptr_t)mcu2ap_addr(head->secs[i].dst_offset); 184*32e9fc1aSHaojian Zhuang 185*32e9fc1aSHaojian Zhuang memcpy((void *)dst, (void *)src, head->secs[i].size); 186*32e9fc1aSHaojian Zhuang 187*32e9fc1aSHaojian Zhuang INFO("%s: mcu sections %d:\n", __func__, i); 188*32e9fc1aSHaojian Zhuang INFO("%s: src = 0x%x\n", 189*32e9fc1aSHaojian Zhuang __func__, (unsigned int)(uintptr_t)src); 190*32e9fc1aSHaojian Zhuang INFO("%s: dst = 0x%x\n", 191*32e9fc1aSHaojian Zhuang __func__, (unsigned int)(uintptr_t)dst); 192*32e9fc1aSHaojian Zhuang INFO("%s: size = %d\n", __func__, head->secs[i].size); 193*32e9fc1aSHaojian Zhuang 194*32e9fc1aSHaojian Zhuang INFO("%s: [SRC 0x%x] 0x%x 0x%x 0x%x 0x%x\n", 195*32e9fc1aSHaojian Zhuang __func__, (unsigned int)(uintptr_t)src, 196*32e9fc1aSHaojian Zhuang src[0], src[1], src[2], src[3]); 197*32e9fc1aSHaojian Zhuang INFO("%s: [DST 0x%x] 0x%x 0x%x 0x%x 0x%x\n", 198*32e9fc1aSHaojian Zhuang __func__, (unsigned int)(uintptr_t)dst, 199*32e9fc1aSHaojian Zhuang dst[0], dst[1], dst[2], dst[3]); 200*32e9fc1aSHaojian Zhuang } 201*32e9fc1aSHaojian Zhuang 202*32e9fc1aSHaojian Zhuang return 0; 203*32e9fc1aSHaojian Zhuang } 204