xref: /rk3399_ARM-atf/plat/hisilicon/hikey/hisi_mcu.c (revision 32e9fc1a325952738af33b2b3e73fd0448636034)
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