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