• 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 #include <config.h>
24 #include <asm/arch/platform.h>
25 #include <compiler.h>
26 
27 #ifndef CONFIG_ASIC
28 #define DELAY_US        10
29 #else
30 #define DELAY_US        1000
31 #endif
32 
33 #define MMC_BLK_SZ      512
34 
35 /* mmc.h */
36 #define MMC_CMD_GO_IDLE_STATE       0
37 #define MMC_CMD_SEND_OP_COND        1
38 #define MMC_CMD_ALL_SEND_CID        2
39 #define MMC_CMD_SET_RELATIVE_ADDR   3
40 #define MMC_CMD_SET_DSR         4
41 #define MMC_CMD_SWITCH          6
42 #define MMC_CMD_SELECT_CARD     7
43 #define MMC_CMD_SEND_EXT_CSD        8
44 #define MMC_CMD_SEND_CSD        9
45 #define MMC_CMD_SEND_CID        10
46 #define MMC_CMD_STOP_TRANSMISSION   12
47 #define MMC_CMD_SEND_STATUS     13
48 #define MMC_CMD_SET_BLOCKLEN        16
49 #define MMC_CMD_READ_SINGLE_BLOCK   17
50 #define MMC_CMD_READ_MULTIPLE_BLOCK 18
51 #define MMC_CMD_WRITE_SINGLE_BLOCK  24
52 #define MMC_CMD_WRITE_MULTIPLE_BLOCK    25
53 #define MMC_CMD_APP_CMD         55
54 #define SD_CMD_SEND_IF_COND     8
55 #define SD_CMD_APP_SEND_OP_COND     41
56 #define SD_CMD_APP_SET_BUS_WIDTH    6
57 
58 #define OCR_BUSY        0x80000000
59 #define OCR_HCS         0x40000000
60 
61 #define MMC_VDD_32_33       0x00100000  /* VDD voltage 3.2 ~ 3.3 */
62 #define MMC_VDD_33_34       0x00200000  /* VDD voltage 3.3 ~ 3.4 */
63 
64 #define MMC_SWITCH_MODE_WRITE_BYTE  0x03 /* Set target byte to value */
65 
66 #define EXT_CSD_BUS_WIDTH   183 /* R/W */
67 #define EXT_CSD_HS_TIMING   185 /* R/W */
68 
69 #define EXT_CSD_BUS_WIDTH_1 0   /* Card is in 1 bit mode */
70 #define EXT_CSD_BUS_WIDTH_4 1   /* Card is in 4 bit mode */
71 #define EXT_CSD_BUS_WIDTH_8 2   /* Card is in 8 bit mode */
72 
delay(unsigned int cnt)73 static inline void delay(unsigned int cnt)
74 {
75 	while (cnt--)
76 		__asm__ __volatile__("nop");
77 }
78 
79 #ifdef CONFIG_SDHCI
80 #define SDHCI_BUFFER            0x20
81 #define SDHCI_INT_STATUS        0x30
82 #define SDHCI_INT_DATA_AVAIL    0x00000020
83 #define SDHCI_INT_ERROR_MASK    0xFFFF8000
84 
85 #define debug_printf(fmt, args...) ;
86 
sdhci_readl(unsigned addr)87 static inline unsigned int sdhci_readl(unsigned addr)
88 {
89 	uintptr_t reg_addr  = EMMC_BASE_REG + addr;
90 	return *((volatile unsigned *) (reg_addr));
91 }
92 
sdhci_writel(unsigned val,unsigned addr)93 static inline void sdhci_writel(unsigned val, unsigned addr)
94 {
95 	uintptr_t reg_addr  = EMMC_BASE_REG + addr;
96 	(*(volatile unsigned *) (reg_addr)) = (val);
97 }
98 
sdhci_read_block_pio(void * data_addr,unsigned int block)99 static void sdhci_read_block_pio(void *data_addr, unsigned int block)
100 {
101 	const unsigned int offset = sizeof(unsigned int);
102 	unsigned int size;
103 	unsigned char *buf;
104 
105 	size = MMC_BLK_SZ;
106 	buf = (unsigned char *)data_addr + MMC_BLK_SZ * block;
107 	while (size) {
108 		*(unsigned int *)buf = sdhci_readl(SDHCI_BUFFER);
109 		buf += offset;
110 		size -= offset;
111 	}
112 }
113 
sdhci_check_int_status(unsigned int mask,unsigned int timeout)114 int sdhci_check_int_status(unsigned int mask, unsigned int timeout)
115 {
116 	unsigned int reg;
117 
118 	for (;;) {
119 		reg = sdhci_readl(SDHCI_INT_STATUS);
120 		if (reg & mask)
121 			break;
122 		if (!(--timeout)) {
123 			debug_printf("wait int status time out, reg = 0x%x, mask = 0x%x\n",
124 						 reg, mask);
125 			return -1;
126 		}
127 		if (reg & SDHCI_INT_ERROR_MASK) {
128 			debug_printf("int err: reg = 0x%x\n", reg);
129 			return -1;
130 		}
131 
132 		delay(1000 * DELAY_US); /* ms converted to us multiplied by 1000 */
133 	}
134 
135 	return 0;
136 }
137 
copy_step1_to_ddr(unsigned int * dst,unsigned int * src,unsigned int size)138 static void copy_step1_to_ddr(unsigned int *dst, unsigned int *src, unsigned int size)
139 {
140 	const unsigned int cycle = size / sizeof(unsigned int);
141 	unsigned int i;
142 
143 	for (i = 0; i < cycle; i++)
144 		*dst++ = *src++;
145 }
146 
147 #define CP_STEP1_SIZE 0x8000
sdhci_read_boot_data(void * data_addr,unsigned int data_size)148 int sdhci_read_boot_data(void *data_addr, unsigned int data_size)
149 {
150 	const unsigned int timeout = 2000; /* 2s timeout: 2000000 * 1us */
151 	unsigned int blocks = 0;
152 	unsigned int read_block;
153 	int ret;
154 
155 	if (data_size <= CP_STEP1_SIZE) {
156 		copy_step1_to_ddr((void *)data_addr, (void *)RAM_START_ADRS, data_size);
157 		return 0;
158 	} else {
159 		copy_step1_to_ddr((void *)data_addr, (void *)RAM_START_ADRS, CP_STEP1_SIZE);
160 		data_addr += CP_STEP1_SIZE;
161 		data_size -= CP_STEP1_SIZE;
162 	}
163 
164 	if (data_size % MMC_BLK_SZ) {
165 		debug_printf("sdhci_read_boot_data error\n");
166 		debug_printf("data_size:%d not round by block size\n", data_size);
167 		read_block = data_size / MMC_BLK_SZ + 1;
168 	} else {
169 		read_block = data_size / MMC_BLK_SZ;
170 	}
171 
172 	while (1) {
173 		ret = sdhci_check_int_status(SDHCI_INT_DATA_AVAIL, timeout);
174 		if (ret) {
175 			debug_printf("wait data available int time out\n");
176 			return -1;
177 		}
178 
179 		sdhci_writel(SDHCI_INT_DATA_AVAIL, SDHCI_INT_STATUS);
180 		sdhci_read_block_pio(data_addr, blocks);
181 
182 		blocks++;
183 		if (blocks == read_block)
184 			break;
185 	}
186 
187 	return 0;
188 }
emmc_boot_read(void * ptr,unsigned int size)189 void emmc_boot_read(void *ptr, unsigned int size)
190 {
191 	sdhci_read_boot_data(ptr, size);
192 }
193 #endif
194