Add mcu image loading driver.
Signed-off-by: Leo Yan leo.yan@linaro.org --- plat/hikey/drivers/hisi_mcu.c | 247 ++++++++++++++++++++++++++++++++++++++++++ plat/hikey/include/hisi_mcu.h | 41 +++++++ 2 files changed, 288 insertions(+) create mode 100644 plat/hikey/drivers/hisi_mcu.c create mode 100644 plat/hikey/include/hisi_mcu.h
diff --git a/plat/hikey/drivers/hisi_mcu.c b/plat/hikey/drivers/hisi_mcu.c new file mode 100644 index 0000000..ac71f4c --- /dev/null +++ b/plat/hikey/drivers/hisi_mcu.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2014-2015, Linaro Ltd and Contributors. All rights reserved. + * Copyright (c) 2014-2015, Hisilicon Ltd and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <console.h> +#include <debug.h> +#include <partitions.h> +#include <platform.h> +#include <platform_def.h> +#include <string.h> +#include <mmio.h> +#include <hi6220.h> + +#define MCU_SECTION_MAX 30 + +enum MCU_IMAGE_SEC_TYPE_ENUM { + MCU_IMAGE_SEC_TYPE_TEXT = 0, /* text section */ + MCU_IMAGE_SEC_TYPE_DATA, /* data section */ + MCU_IMAGE_SEC_TYPE_BUTT +}; + +enum MCU_IMAGE_SEC_LOAD_ENUM { + MCU_IMAGE_SEC_LOAD_STATIC = 0, + MCU_IMAGE_SEC_LOAD_DYNAMIC, + MCU_IMAGE_SEC_LOAD_BUFFER, + MCU_IMAGE_SEC_LOAD_MODEM_ENTRY, + MCU_IMAGE_SEC_LOAD_BUTT +}; + +struct mcu_image_sec { + unsigned short serial; + char type; + char load_attr; + uint32_t src_offset; /* offset in image */ + uint32_t dst_offset; /* offset in memory */ + uint32_t size; +}; + +struct mcu_image_head { + char time_stamp[24]; + uint32_t image_size; + uint32_t secs_num; + struct mcu_image_sec secs[MCU_SECTION_MAX]; +}; + +#define SOC_SRAM_M3_BASE_ADDR (0xF6000000) + +#define MCU_SRAM_SIZE (0x0000C000) +#define MCU_CACHE_SIZE (0x00004000) +#define MCU_CODE_SIZE (MCU_SRAM_SIZE - MCU_CACHE_SIZE) + +#define MCU_SYS_MEM_ADDR (0x05E00000) +#define MCU_SYS_MEM_SIZE (0x00100000) + +#if 0 +static uint32_t ap2mcu_addr(uint32_t ap_addr) +{ + if (ap_addr >= SOC_SRAM_M3_BASE_ADDR && + ap_addr < SOC_SRAM_M3_BASE_ADDR + MCU_SRAM_SIZE) + return ap_addr - SOC_SRAM_M3_BASE_ADDR; + else if (ap_addr >= MCU_SYS_MEM_ADDR && + ap_addr < MCU_SYS_MEM_ADDR + MCU_SYS_MEM_SIZE ) + return ap_addr - MCU_SYS_MEM_ADDR + MCU_SRAM_SIZE; + else + return ap_addr; +} +#endif + +static uint32_t mcu2ap_addr(uint32_t mcu_addr) +{ + if (mcu_addr < MCU_CODE_SIZE) + return (mcu_addr + SOC_SRAM_M3_BASE_ADDR); + else if ((mcu_addr >= MCU_SRAM_SIZE) && + (mcu_addr < MCU_SRAM_SIZE + MCU_SYS_MEM_SIZE)) + return mcu_addr - MCU_SRAM_SIZE + MCU_SYS_MEM_ADDR; + else + return mcu_addr; +} + +static int is_binary_header_invalid(struct mcu_image_head *head, + unsigned length) +{ + /* invalid cases */ + if ((head->image_size == 0) || + (head->image_size > length) || + (head->secs_num > MCU_SECTION_MAX) || + (head->secs_num == 0)) + return 1; + + return 0; +} + +static int is_binary_section_invalid(struct mcu_image_sec *sec, + struct mcu_image_head *head) +{ + unsigned long ap_dst_offset = 0; + + if ((sec->serial >= head->secs_num) || + (sec->src_offset + sec->size > head->image_size)) + return 1; + + if ((sec->type >= MCU_IMAGE_SEC_TYPE_BUTT) || + (sec->load_attr >= MCU_IMAGE_SEC_LOAD_BUTT)) + return 1; + + ap_dst_offset = mcu2ap_addr(sec->dst_offset); + if ((ap_dst_offset >= SOC_SRAM_M3_BASE_ADDR) && + (ap_dst_offset < SOC_SRAM_M3_BASE_ADDR + 0x20000 - sec->size)) + return 0; + else if ((ap_dst_offset >= MCU_SYS_MEM_ADDR) && + (ap_dst_offset < MCU_SYS_MEM_ADDR + MCU_SYS_MEM_SIZE - sec->size)) + return 0; + else if ((ap_dst_offset >= 0xfff8e000) && + (ap_dst_offset < 0xfff91c00 - sec->size)) + return 0; + + ERROR("%s: mcu destination address invalid.\n", __func__); + ERROR("%s: number=%d, dst offset=%d size=%d\n", + __func__, sec->serial, sec->dst_offset, sec->size); + return 1; +} + +void hisi_mcu_enable_sram(void) +{ + mmio_write_32(AO_SC_PERIPH_CLKEN4, + AO_SC_PERIPH_CLKEN4_HCLK_IPC_S | + AO_SC_PERIPH_CLKEN4_HCLK_IPC_NS); + + /* set register to enable dvfs which is used by mcu */ + mmio_write_32(PERI_SC_RESERVED8_ADDR, 0x02000020); + + /* mcu mem is powered on, need de-assert reset */ + mmio_write_32(AO_SC_PERIPH_RSTDIS4, + AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N); + + /* enable mcu hclk */ + mmio_write_32(AO_SC_PERIPH_CLKEN4, + AO_SC_PERIPH_CLKEN4_HCLK_MCU | + AO_SC_PERIPH_CLKEN4_CLK_MCU_DAP); +} + +void hisi_mcu_start_run(void) +{ + unsigned int val; + +#if 0 + /* set mcu's self loop instruction 0xE7FE at entry point */ + val = mmio_read_32((SOC_SRAM_M3_BASE_ADDR + 0x200)); + val &= 0xFFFF0000; + val |= 0xE7FE; + mmio_write_32((SOC_SRAM_M3_BASE_ADDR + 0x200), val); +#endif + + /* set mcu ddr remap configuration */ + mmio_write_32(AO_SC_MCU_SUBSYS_CTRL2, MCU_SYS_MEM_ADDR); + + /* de-assert reset for mcu and to run */ + mmio_write_32(AO_SC_PERIPH_RSTDIS4, + AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N | + AO_SC_PERIPH_RSTDIS4_RESET_MCU_SYS_N | + AO_SC_PERIPH_RSTDIS4_RESET_MCU_POR_N | + AO_SC_PERIPH_RSTDIS4_RESET_MCU_DAP_N); + + val = mmio_read_32(AO_SC_SYS_CTRL2); + mmio_write_32(AO_SC_SYS_CTRL2, + val | AO_SC_SYS_CTRL2_GLB_SRST_STAT_CLEAR); + + INFO("%s: AO_SC_SYS_CTRL2=%x\n", __func__, + mmio_read_32(AO_SC_SYS_CTRL2)); +} + +int hisi_mcu_load_image(uintptr_t image_base, uint32_t image_size) +{ + unsigned int i; + struct mcu_image_head *head; + char *buf; + + head = (struct mcu_image_head *)image_base; + if (is_binary_header_invalid(head, image_size)) { + ERROR("Invalid %s image header.\n", head->time_stamp); + return -1; + } + + buf = (char *)head; + for (i = 0; i < head->secs_num; i++) { + + int *src, *dst; + + /* check the sections */ + if (is_binary_section_invalid(&head->secs[i], head)) { + ERROR("Invalid mcu section.\n"); + return -1; + } + + /* check if the section is static-loaded */ + if (head->secs[i].load_attr != MCU_IMAGE_SEC_LOAD_STATIC) + continue; + + /* copy the sections */ + src = (int *)(intptr_t)(buf + head->secs[i].src_offset); + dst = (int *)(intptr_t)mcu2ap_addr(head->secs[i].dst_offset); + + memcpy((void *)dst, (void *)src, head->secs[i].size); + + INFO("%s: mcu sections %d:\n", __func__, i); + INFO("%s: src = 0x%x\n", __func__, src); + INFO("%s: dst = 0x%x\n", __func__, dst); + INFO("%s: size = %d\n", __func__, head->secs[i].size); + + INFO("%s: [SRC 0x%x] 0x%x 0x%x 0x%x 0x%x\n", __func__, + src, src[0], src[1], src[2], src[3]); + INFO("%s: [DST 0x%x] 0x%x 0x%x 0x%x 0x%x\n", __func__, + dst, dst[0], dst[1], dst[2], dst[3]); + } + + return 0; +} diff --git a/plat/hikey/include/hisi_mcu.h b/plat/hikey/include/hisi_mcu.h new file mode 100644 index 0000000..74dbf17 --- /dev/null +++ b/plat/hikey/include/hisi_mcu.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014-2015, Linaro Ltd and Contributors. All rights reserved. + * Copyright (c) 2014-2015, Hisilicon Ltd and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MCU_H__ +#define __MCU_H__ + +#include <stdint.h> + +extern void hisi_mcu_enable_sram(void); +extern void hisi_mcu_start_run(void); +extern int hisi_mcu_load_image(uintptr_t image_base, uint32_t image_size); + +#endif /* __MCU_H__ */