aboutsummaryrefslogtreecommitdiff
path: root/plat/hisilicon/hikey/hisi_mcu.c
blob: 359b94d7b1d093bcf1c58386d8dfa6ea6131e758 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/*
 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <arch_helpers.h>
#include <assert.h>
#include <bl_common.h>
#include <console.h>
#include <debug.h>
#include <hi6220.h>
#include <mmio.h>
#include <platform.h>
#include <platform_def.h>
#include <string.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)

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 int 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, 0x0A001022);

	/* 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;

	/* 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__, (unsigned int)(uintptr_t)src);
		INFO("%s:  dst  = 0x%x\n",
		     __func__, (unsigned int)(uintptr_t)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__, (unsigned int)(uintptr_t)src,
		     src[0], src[1], src[2], src[3]);
		INFO("%s:  [DST 0x%x] 0x%x 0x%x 0x%x 0x%x\n",
		     __func__, (unsigned int)(uintptr_t)dst,
		     dst[0], dst[1], dst[2], dst[3]);
	}

	return 0;
}