• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * himci_boot.c
3  *
4  * This file is only for emmc boot.
5  *
6  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
7  *
8  * This program is free software; you can redistribute  it and/or modify it
9  * under  the terms of  the GNU General  Public License as published by the
10  * Free Software Foundation;  either version 2 of the  License, or (at your
11  * option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 /*
24 * this file is only for emmc start.
25 */
26 
27 #include <config.h>
28 #include <asm/arch/platform.h>
29 #include <compiler.h>
30 
31 #ifndef CONFIG_ASIC
32 #define DELAY_US        10
33 #else
34 #define DELAY_US        1000
35 #endif
36 
37 #define MMC_BLK_SZ	512
38 #define CP_STEP1_SIZE	0x7800
39 
40 /*
41  * Controller registers
42  */
43 #define SDHCI_DMA_ADDRESS       0x00
44 #define SDHCI_BLOCK_SIZE        0x04
45 #define SDHCI_BLOCK_COUNT       0x06
46 #define SDHCI_ARGUMENT          0x08
47 
48 #define SDHCI_TRANSFER_MODE     0x0C
49 #define  SDHCI_TRNS_DMA         0x0001
50 #define  SDHCI_TRNS_BLK_CNT_EN  0x0002
51 #define  SDHCI_TRNS_READ        0x0010
52 #define  SDHCI_TRNS_MULTI       0x0020
53 
54 #define SDHCI_COMMAND           0x0E
55 #define  SDHCI_CMD_RESP_NONE    0x0000
56 #define  SDHCI_CMD_RESP_LONG    0x0001
57 #define  SDHCI_CMD_RESP_SHORT   0x0002
58 #define  SDHCI_CMD_CRC          0x0008
59 #define  SDHCI_CMD_DATA         0x0020
60 
61 #define SDHCI_RESPONSE          0x10
62 #define SDHCI_BUFFER            0x20
63 
64 #define SDHCI_PRESENT_STATE     0x24
65 #define  SDHCI_PSTATE_DAT_0     0x00100000
66 
67 #define SDHCI_HOST_CONTROL      0x28
68 #define  SDHCI_CTRL_4BITBUS     0x02
69 #define  SDHCI_CTRL_8BITBUS     0x20
70 
71 #define SDHCI_POWER_CONTROL     0x29
72 #define  SDHCI_POWER_ON         0x01
73 #define  SDHCI_POWER_180        0x0A
74 #define  SDHCI_POWER_300        0x0C
75 #define  SDHCI_POWER_330        0x0E
76 
77 #define SDHCI_CLOCK_CONTROL     0x2C
78 #define  SDHCI_CLOCK_INT_EN     0x0001
79 #define  SDHCI_CLOCK_INT_STABLE 0x0002
80 #define  SDHCI_CLOCK_CARD_EN    0x0004
81 
82 #define SDHCI_TIMEOUT_CONTROL   0x2E
83 
84 #define SDHCI_SOFTWARE_RESET    0x2F
85 #define  SDHCI_RESET_ALL        0x01
86 #define  SDHCI_RESET_CMD        0x02
87 #define  SDHCI_RESET_DATA       0x04
88 
89 #define SDHCI_INT_STATUS        0x30
90 #define  SDHCI_INT_RESPONSE     0x00000001
91 #define  SDHCI_INT_DATA_END     0x00000002
92 #define  SDHCI_INT_DMA          0x00000008
93 #define  SDHCI_INT_DATA_AVAIL   0x00000020
94 #define  SDHCI_INT_NORMAL_MASK  0x00007FFF
95 #define  SDHCI_INT_ERROR_MASK   0xFFFF8000
96 
97 #define SDHCI_INT_ENABLE        0x34
98 
99 #define SDHCI_EMMC_CTRL         0x52C
100 #define  SDHCI_CARD_IS_EMMC     0x0001
101 
102 #define SDHCI_BOOT_CTRL         0x52E
103 #define  MAN_BOOT_EN            0x0001
104 #define  VALIDATE_BOOT          0x0080
105 
106 #define SDHCI_EMMC_HW_RESET     0x534
107 
108 #define sdhci_make_cmd(idx, param)   ((((idx) & 0xFF) << 8) | ((param) & 0xFF))
109 #define sdhci_make_blksz(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF))
110 
111 #define MMC_CMD_GO_IDLE_STATE       0
112 #define MMC_CMD_SEND_OP_COND        1
113 #define MMC_CMD_ALL_SEND_CID        2
114 #define MMC_CMD_SET_RELATIVE_ADDR   3
115 #define MMC_CMD_SWITCH              6
116 #define MMC_CMD_SELECT_CARD         7
117 #define MMC_CMD_SEND_CSD            9
118 #define MMC_CMD_STOP_TRANSMISSION   12
119 #define MMC_CMD_SET_BLOCKLEN        16
120 #define MMC_CMD_READ_SINGLE_BLOCK   17
121 #define MMC_CMD_READ_MULTIPLE_BLOCK 18
122 #define MMC_CMD_SET_BLOCK_COUNT     23
123 
124 #define MMC_SWITCH_MODE_WRITE_BYTE  0x3
125 #define MMC_SWITCH_ACCESS_SHIFT     24
126 #define MMC_SWITCH_INDEX_SHIFT      16
127 #define MMC_SWITCH_VALUE_SHIFT      8
128 
129 /* SDMA Configuration */
130 #define BOUNDARY_SIZE               (512 * 1024) /* 512K */
131 #define BOUNDARY_ARG                (0x7 << 12)  /* 512K */
132 #define MMC_SDMA_ENABLE	            1
133 
134 #define OCR_BUSY                    0x80000000
135 #define OCR_HCS                     0x40000000
136 
137 #define debug_printf(fmt, args...) ;
138 #define reg_get(addr) (*(volatile unsigned int *)((uintptr_t)(addr)))
139 
is_bootmode(void)140 static unsigned int is_bootmode(void)
141 {
142 	return !(reg_get(REG_BASE_SCTL + REG_PERI_EMMC_STAT) & EMMC_NORMAL_MODE);
143 }
144 
get_hcs(void)145 static unsigned int get_hcs(void)
146 {
147 	return reg_get(REG_SAVE_HCS) & OCR_HCS;
148 }
149 
delay(unsigned int cnt)150 static inline void delay(unsigned int cnt)
151 {
152 	while (cnt--)
153 		__asm__ __volatile__("nop");
154 }
155 
sdhci_readb(unsigned addr)156 static inline unsigned int sdhci_readb(unsigned addr)
157 {
158 	return *((volatile unsigned char *) (uintptr_t)(EMMC_BASE_REG + addr));
159 }
160 
sdhci_writeb(unsigned val,unsigned addr)161 static inline void sdhci_writeb(unsigned val, unsigned addr)
162 {
163 	(*(volatile unsigned char *) (uintptr_t)(EMMC_BASE_REG + addr)) = (val);
164 }
165 
sdhci_readw(unsigned addr)166 static inline unsigned int sdhci_readw(unsigned addr)
167 {
168 	return *((volatile unsigned short *) (uintptr_t)(EMMC_BASE_REG + addr));
169 }
170 
sdhci_writew(unsigned val,unsigned addr)171 static inline void sdhci_writew(unsigned val, unsigned addr)
172 {
173 	(*(volatile unsigned short *) (uintptr_t)(EMMC_BASE_REG + addr)) = (val);
174 }
175 
sdhci_readl(unsigned addr)176 static inline unsigned int sdhci_readl(unsigned addr)
177 {
178 	return *((volatile unsigned int *) (uintptr_t)(EMMC_BASE_REG + addr));
179 }
180 
sdhci_writel(unsigned val,unsigned addr)181 static inline void sdhci_writel(unsigned val, unsigned addr)
182 {
183 	(*(volatile unsigned int *) (uintptr_t)(EMMC_BASE_REG + addr)) = (val);
184 }
185 
sdhci_read_block_pio(void * data_addr,unsigned int block)186 static int sdhci_read_block_pio(void *data_addr, unsigned int block)
187 {
188 	const unsigned int offset = sizeof(unsigned int);
189 	unsigned int size;
190 	unsigned char *buf;
191 
192 	size = MMC_BLK_SZ;
193 	buf = (unsigned char *)data_addr + MMC_BLK_SZ * block;
194 	while (size) {
195 		*(unsigned int *)buf = sdhci_readl(SDHCI_BUFFER);
196 		buf += offset;
197 		size -= offset;
198 	}
199 
200 	return 0;
201 }
202 
sdhci_check_int_status(unsigned int mask,unsigned int timeout)203 static int sdhci_check_int_status(unsigned int mask, unsigned int timeout)
204 {
205 	unsigned int reg;
206 
207 	timeout *= 1000; /* ms is converted to us multiplied by 1000 */
208 	for (;;) {
209 		reg = sdhci_readl(SDHCI_INT_STATUS);
210 		if (reg & mask) {
211 			break;
212 		}
213 		if (!(--timeout)) {
214 			debug_printf("wait int status time out, reg = 0x%x, mask = 0x%x\n",
215 					reg, mask);
216 			return -1;
217 		}
218 		if (reg & SDHCI_INT_ERROR_MASK) {
219 			debug_printf("int err: reg = 0x%x\n", reg);
220 			return -1;
221 		}
222 
223 		delay(DELAY_US);
224 	}
225 
226 	return 0;
227 }
228 
sdhci_boot_read(void * data_addr,unsigned int read_block)229 static int sdhci_boot_read(void *data_addr, unsigned int read_block)
230 {
231 	const unsigned int timeout = 2000; /* 2s timeout: 2000000 * 1us */
232 	int ret;
233 	unsigned int blocks = 0;
234 
235 	while (1) {
236 		ret = sdhci_check_int_status(SDHCI_INT_DATA_AVAIL, timeout);
237 		if (ret) {
238 			debug_printf("wait data available int time out\n");
239 			return ret;
240 		}
241 
242 		sdhci_writel(SDHCI_INT_DATA_AVAIL, SDHCI_INT_STATUS);
243 		sdhci_read_block_pio(data_addr, blocks);
244 
245 		blocks++;
246 		if (blocks == read_block)
247 			break;
248 	}
249 
250 	return 0;
251 }
252 
mmc_send_cmd(unsigned int cmd,unsigned int arg)253 static int mmc_send_cmd(unsigned int cmd, unsigned int arg)
254 {
255 	const unsigned int timeout = 3000; /* 3s timeout: 3000000 * 1us */
256 
257 	sdhci_writel(0xFFFFFFFF, SDHCI_INT_STATUS);
258 	sdhci_writel(arg, SDHCI_ARGUMENT);
259 	sdhci_writew(cmd, SDHCI_COMMAND);
260 
261 	if (sdhci_check_int_status(SDHCI_INT_RESPONSE, timeout)) {
262 		debug_printf("send cmd error\n");
263 		return -1;
264 	}
265 
266 	return 0;
267 }
268 
mmc_read_cmd(unsigned long int start_addr,unsigned int src,unsigned int size,unsigned int dma)269 static void mmc_read_cmd(unsigned long int start_addr, unsigned int src,
270 		unsigned int size, unsigned int dma)
271 {
272 	unsigned int cmd, hcs;
273 	unsigned short mode;
274 
275 	/* Send CMD16 to set blocksize */
276 	cmd = sdhci_make_cmd(MMC_CMD_SET_BLOCKLEN, SDHCI_CMD_CRC |
277 				SDHCI_CMD_RESP_SHORT);
278 	mmc_send_cmd(cmd, MMC_BLK_SZ);
279 
280 	/* set data timeout */
281 	sdhci_writeb(0xE, SDHCI_TIMEOUT_CONTROL);
282 
283 	/* set host count */
284 	sdhci_writew(size, SDHCI_BLOCK_COUNT);
285 
286 	/* Send CMD23 to set blockcount */
287 	cmd = sdhci_make_cmd(MMC_CMD_SET_BLOCK_COUNT,
288 		SDHCI_CMD_CRC | SDHCI_CMD_RESP_SHORT);
289 	mmc_send_cmd(cmd, size);
290 
291 	/* set transfer mode */
292 	mode = SDHCI_TRNS_READ | SDHCI_TRNS_MULTI | SDHCI_TRNS_BLK_CNT_EN;
293 	if (dma)
294 		mode |= SDHCI_TRNS_DMA;
295 
296 	sdhci_writew(mode, SDHCI_TRANSFER_MODE);
297 
298 	/* set SDMA address */
299 	if (dma)
300 		sdhci_writel(start_addr, SDHCI_DMA_ADDRESS);
301 
302 	/* Send CMD18 for multiple block read */
303 	hcs = get_hcs();
304 	if (hcs) {
305 		cmd = sdhci_make_cmd(MMC_CMD_READ_MULTIPLE_BLOCK,
306 			SDHCI_CMD_CRC | SDHCI_CMD_RESP_SHORT | SDHCI_CMD_DATA);
307 		mmc_send_cmd(cmd, src / MMC_BLK_SZ);
308 	} else {
309 		cmd = sdhci_make_cmd(MMC_CMD_READ_MULTIPLE_BLOCK,
310 			SDHCI_CMD_CRC | SDHCI_CMD_RESP_SHORT | SDHCI_CMD_DATA);
311 		mmc_send_cmd(cmd, src);
312 	}
313 }
314 
sdhci_normal_read_sdma(void * dst,unsigned int src,unsigned int size)315 static int sdhci_normal_read_sdma(void *dst, unsigned int src,
316 			unsigned int size)
317 {
318 	unsigned int stat;
319 	unsigned int timeout;
320 	unsigned long int start_addr;
321 
322 	start_addr = (uintptr_t)dst;
323 
324 	/* set host block size 512 */
325 	sdhci_writew(MMC_BLK_SZ | BOUNDARY_ARG, SDHCI_BLOCK_SIZE);
326 
327 	mmc_read_cmd(start_addr, src, size, MMC_SDMA_ENABLE);
328 
329 	sdhci_writel(SDHCI_INT_RESPONSE, SDHCI_INT_STATUS);
330 
331 	timeout = 300000; /* 3s timeout: 300000 * 10us */
332 	do {
333 		stat = sdhci_readl(SDHCI_INT_STATUS);
334 		if (stat & SDHCI_INT_ERROR_MASK) {
335 			debug_printf("interrupt error\n");
336 			return -1;
337 		}
338 
339 		if (stat & SDHCI_INT_DMA) {
340 			sdhci_writel(SDHCI_INT_DMA, SDHCI_INT_STATUS);
341 			start_addr &= ~(BOUNDARY_SIZE - 1);
342 			start_addr += BOUNDARY_SIZE;
343 			sdhci_writel(start_addr, SDHCI_DMA_ADDRESS);
344 		}
345 
346 		if (timeout > 0) {
347 			delay(10 * DELAY_US); /* delay 10us */
348 			timeout -= 1;
349 		} else {
350 			debug_printf("read timeout!\n");
351 			return -1;
352 		}
353 	} while (!(stat & SDHCI_INT_DATA_END));
354 
355 	sdhci_writel(SDHCI_INT_DATA_END, SDHCI_INT_STATUS);
356 
357 	return 0;
358 }
359 
copy_step1_to_ddr(unsigned int * dst,unsigned int * src,unsigned int size)360 static void copy_step1_to_ddr(unsigned int *dst, unsigned int *src, unsigned int size)
361 {
362 	unsigned int cycle = size / sizeof(unsigned int);
363 	unsigned int i;
364 
365 	for (i = 0; i < cycle; i++)
366 		*dst++ = *src++;
367 }
368 
emmc_read_boot_data(void * data_addr,unsigned int data_size)369 static int emmc_read_boot_data(void *data_addr, unsigned int data_size)
370 {
371 	unsigned int read_block;
372 	int bootmode;
373 
374 	if (data_size <= CP_STEP1_SIZE) {
375 		copy_step1_to_ddr((void *)data_addr, (void *)CP_STEP1_ADDR, data_size);
376 		return 0;
377 	} else {
378 		copy_step1_to_ddr((void *)data_addr, (void *)CP_STEP1_ADDR, CP_STEP1_SIZE);
379 		data_addr += CP_STEP1_SIZE;
380 		data_size -= CP_STEP1_SIZE;
381 	}
382 
383 	if (data_size % MMC_BLK_SZ) {
384 		debug_printf("sdhci_read_boot_data error\n");
385 		debug_printf("data_size:%d not round by block size\n", data_size);
386 		read_block = data_size / MMC_BLK_SZ + 1;
387 	} else {
388 		read_block = data_size / MMC_BLK_SZ;
389 	}
390 
391 	bootmode = is_bootmode();
392 	if (bootmode)
393 		return sdhci_boot_read(data_addr, read_block);
394 
395 	return sdhci_normal_read_sdma(data_addr, CP_STEP1_SIZE, read_block);
396 }
397 
emmc_boot_read(void * ptr,unsigned int size)398 int emmc_boot_read(void *ptr, unsigned int size)
399 {
400 	int ret;
401 
402 	ret = emmc_read_boot_data(ptr, size);
403 	return ret;
404 }
405