blob: 5fe28efc031b3a15353230b644f5b6d8c1c51248 [file] [log] [blame]
Haojian Zhuangfffe9e72016-03-18 22:08:26 +08001/*
2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Defines a simple and generic interface to access eMMC device.
31 */
32
33#include <arch_helpers.h>
34#include <assert.h>
35#include <debug.h>
36#include <emmc.h>
37#include <errno.h>
38#include <string.h>
39
40static const emmc_ops_t *ops;
41static unsigned int emmc_ocr_value;
42static emmc_csd_t emmc_csd;
43
44static int emmc_device_state(void)
45{
46 emmc_cmd_t cmd;
47 int ret;
48
49 do {
50 memset(&cmd, 0, sizeof(emmc_cmd_t));
51 cmd.cmd_idx = EMMC_CMD13;
52 cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
53 cmd.resp_type = EMMC_RESPONSE_R1;
54 ret = ops->send_cmd(&cmd);
55 assert(ret == 0);
56 assert((cmd.resp_data[0] & STATUS_SWITCH_ERROR) == 0);
57 /* Ignore improbable errors in release builds */
58 (void)ret;
59 } while ((cmd.resp_data[0] & STATUS_READY_FOR_DATA) == 0);
60 return EMMC_GET_STATE(cmd.resp_data[0]);
61}
62
63static void emmc_set_ext_csd(unsigned int ext_cmd, unsigned int value)
64{
65 emmc_cmd_t cmd;
66 int ret, state;
67
68 memset(&cmd, 0, sizeof(emmc_cmd_t));
69 cmd.cmd_idx = EMMC_CMD6;
70 cmd.cmd_arg = EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) |
71 EXTCSD_VALUE(value) | 1;
72 ret = ops->send_cmd(&cmd);
73 assert(ret == 0);
74
75 /* wait to exit PRG state */
76 do {
77 state = emmc_device_state();
78 } while (state == EMMC_STATE_PRG);
79 /* Ignore improbable errors in release builds */
80 (void)ret;
81}
82
83static void emmc_set_ios(int clk, int bus_width)
84{
85 int ret;
86
87 /* set IO speed & IO bus width */
88 if (emmc_csd.spec_vers == 4)
89 emmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH, bus_width);
90 ret = ops->set_ios(clk, bus_width);
91 assert(ret == 0);
92 /* Ignore improbable errors in release builds */
93 (void)ret;
94}
95
96static int emmc_enumerate(int clk, int bus_width)
97{
98 emmc_cmd_t cmd;
99 int ret, state;
100
101 ops->init();
102
103 /* CMD0: reset to IDLE */
104 memset(&cmd, 0, sizeof(emmc_cmd_t));
105 cmd.cmd_idx = EMMC_CMD0;
106 ret = ops->send_cmd(&cmd);
107 assert(ret == 0);
108
109 while (1) {
110 /* CMD1: get OCR register */
111 memset(&cmd, 0, sizeof(emmc_cmd_t));
112 cmd.cmd_idx = EMMC_CMD1;
113 cmd.cmd_arg = OCR_SECTOR_MODE | OCR_VDD_MIN_2V7 |
114 OCR_VDD_MIN_1V7;
115 cmd.resp_type = EMMC_RESPONSE_R3;
116 ret = ops->send_cmd(&cmd);
117 assert(ret == 0);
118 emmc_ocr_value = cmd.resp_data[0];
119 if (emmc_ocr_value & OCR_POWERUP)
120 break;
121 }
122
123 /* CMD2: Card Identification */
124 memset(&cmd, 0, sizeof(emmc_cmd_t));
125 cmd.cmd_idx = EMMC_CMD2;
126 cmd.resp_type = EMMC_RESPONSE_R2;
127 ret = ops->send_cmd(&cmd);
128 assert(ret == 0);
129
130 /* CMD3: Set Relative Address */
131 memset(&cmd, 0, sizeof(emmc_cmd_t));
132 cmd.cmd_idx = EMMC_CMD3;
133 cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
134 cmd.resp_type = EMMC_RESPONSE_R1;
135 ret = ops->send_cmd(&cmd);
136 assert(ret == 0);
137
138 /* CMD9: CSD Register */
139 memset(&cmd, 0, sizeof(emmc_cmd_t));
140 cmd.cmd_idx = EMMC_CMD9;
141 cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
142 cmd.resp_type = EMMC_RESPONSE_R2;
143 ret = ops->send_cmd(&cmd);
144 assert(ret == 0);
145 memcpy(&emmc_csd, &cmd.resp_data, sizeof(cmd.resp_data));
146
147 /* CMD7: Select Card */
148 memset(&cmd, 0, sizeof(emmc_cmd_t));
149 cmd.cmd_idx = EMMC_CMD7;
150 cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
151 cmd.resp_type = EMMC_RESPONSE_R1;
152 ret = ops->send_cmd(&cmd);
153 assert(ret == 0);
154 /* wait to TRAN state */
155 do {
156 state = emmc_device_state();
157 } while (state != EMMC_STATE_TRAN);
158
159 emmc_set_ios(clk, bus_width);
160 return ret;
161}
162
163size_t emmc_read_blocks(int lba, uintptr_t buf, size_t size)
164{
165 emmc_cmd_t cmd;
166 int ret;
167
168 assert((ops != 0) &&
169 (ops->read != 0) &&
170 ((buf & EMMC_BLOCK_MASK) == 0) &&
171 ((size & EMMC_BLOCK_MASK) == 0));
172
173 inv_dcache_range(buf, size);
174 ret = ops->prepare(lba, buf, size);
175 assert(ret == 0);
176
177 memset(&cmd, 0, sizeof(emmc_cmd_t));
178 if (size > EMMC_BLOCK_SIZE)
179 cmd.cmd_idx = EMMC_CMD18;
180 else
181 cmd.cmd_idx = EMMC_CMD17;
182 if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE)
183 cmd.cmd_arg = lba * EMMC_BLOCK_SIZE;
184 else
185 cmd.cmd_arg = lba;
186 cmd.resp_type = EMMC_RESPONSE_R1;
187 ret = ops->send_cmd(&cmd);
188 assert(ret == 0);
189
190 ret = ops->read(lba, buf, size);
191 assert(ret == 0);
192
193 /* wait buffer empty */
194 emmc_device_state();
195
196 if (size > EMMC_BLOCK_SIZE) {
197 memset(&cmd, 0, sizeof(emmc_cmd_t));
198 cmd.cmd_idx = EMMC_CMD12;
199 ret = ops->send_cmd(&cmd);
200 assert(ret == 0);
201 }
202 /* Ignore improbable errors in release builds */
203 (void)ret;
204 return size;
205}
206
207size_t emmc_write_blocks(int lba, const uintptr_t buf, size_t size)
208{
209 emmc_cmd_t cmd;
210 int ret;
211
212 assert((ops != 0) &&
213 (ops->write != 0) &&
214 ((buf & EMMC_BLOCK_MASK) == 0) &&
215 ((size & EMMC_BLOCK_MASK) == 0));
216
217 clean_dcache_range(buf, size);
218 ret = ops->prepare(lba, buf, size);
219 assert(ret == 0);
220
221 memset(&cmd, 0, sizeof(emmc_cmd_t));
222 if (size > EMMC_BLOCK_SIZE)
223 cmd.cmd_idx = EMMC_CMD25;
224 else
225 cmd.cmd_idx = EMMC_CMD24;
226 if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE)
227 cmd.cmd_arg = lba * EMMC_BLOCK_SIZE;
228 else
229 cmd.cmd_arg = lba;
230 cmd.resp_type = EMMC_RESPONSE_R1;
231 ret = ops->send_cmd(&cmd);
232 assert(ret == 0);
233
234 ret = ops->write(lba, buf, size);
235 assert(ret == 0);
236
237 /* wait buffer empty */
238 emmc_device_state();
239
240 if (size > EMMC_BLOCK_SIZE) {
241 memset(&cmd, 0, sizeof(emmc_cmd_t));
242 cmd.cmd_idx = EMMC_CMD12;
243 ret = ops->send_cmd(&cmd);
244 assert(ret == 0);
245 }
246 /* Ignore improbable errors in release builds */
247 (void)ret;
248 return size;
249}
250
251size_t emmc_erase_blocks(int lba, size_t size)
252{
253 emmc_cmd_t cmd;
254 int ret, state;
255
256 assert(ops != 0);
257 assert((size != 0) && ((size % EMMC_BLOCK_SIZE) == 0));
258
259 memset(&cmd, 0, sizeof(emmc_cmd_t));
260 cmd.cmd_idx = EMMC_CMD35;
261 cmd.cmd_arg = lba;
262 cmd.resp_type = EMMC_RESPONSE_R1;
263 ret = ops->send_cmd(&cmd);
264 assert(ret == 0);
265
266 memset(&cmd, 0, sizeof(emmc_cmd_t));
267 cmd.cmd_idx = EMMC_CMD36;
268 cmd.cmd_arg = lba + (size / EMMC_BLOCK_SIZE) - 1;
269 cmd.resp_type = EMMC_RESPONSE_R1;
270 ret = ops->send_cmd(&cmd);
271 assert(ret == 0);
272
273 memset(&cmd, 0, sizeof(emmc_cmd_t));
274 cmd.cmd_idx = EMMC_CMD38;
275 cmd.resp_type = EMMC_RESPONSE_R1B;
276 ret = ops->send_cmd(&cmd);
277 assert(ret == 0);
278
279 /* wait to TRAN state */
280 do {
281 state = emmc_device_state();
282 } while (state != EMMC_STATE_TRAN);
283 /* Ignore improbable errors in release builds */
284 (void)ret;
285 return size;
286}
287
288static inline void emmc_rpmb_enable(void)
289{
290 emmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
291 PART_CFG_BOOT_PARTITION1_ENABLE |
292 PART_CFG_PARTITION1_ACCESS);
293}
294
295static inline void emmc_rpmb_disable(void)
296{
297 emmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
298 PART_CFG_BOOT_PARTITION1_ENABLE);
299}
300
301size_t emmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size)
302{
303 size_t size_read;
304
305 emmc_rpmb_enable();
306 size_read = emmc_read_blocks(lba, buf, size);
307 emmc_rpmb_disable();
308 return size_read;
309}
310
311size_t emmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size)
312{
313 size_t size_written;
314
315 emmc_rpmb_enable();
316 size_written = emmc_write_blocks(lba, buf, size);
317 emmc_rpmb_disable();
318 return size_written;
319}
320
321size_t emmc_rpmb_erase_blocks(int lba, size_t size)
322{
323 size_t size_erased;
324
325 emmc_rpmb_enable();
326 size_erased = emmc_erase_blocks(lba, size);
327 emmc_rpmb_disable();
328 return size_erased;
329}
330
331void emmc_init(const emmc_ops_t *ops_ptr, int clk, int width)
332{
333 assert((ops_ptr != 0) &&
334 (ops_ptr->init != 0) &&
335 (ops_ptr->send_cmd != 0) &&
336 (ops_ptr->set_ios != 0) &&
337 (ops_ptr->prepare != 0) &&
338 (ops_ptr->read != 0) &&
339 (ops_ptr->write != 0) &&
340 (clk != 0) &&
341 ((width == EMMC_BUS_WIDTH_1) ||
342 (width == EMMC_BUS_WIDTH_4) ||
343 (width == EMMC_BUS_WIDTH_8)));
344 ops = ops_ptr;
345
346 emmc_enumerate(clk, width);
347}