blob: d2b566f71e4aa82f7fc88177eafd973534f3ef14 [file] [log] [blame]
Lee Leahyeef40eb2017-03-23 10:54:57 -07001/*
2 * Copyright 2008, Freescale Semiconductor, Inc
3 * Andy Fleming
4 *
5 * Copyright 2013 Google Inc. All rights reserved.
6 * Copyright 2017 Intel Corporation
7 *
8 * MultiMediaCard (MMC), eMMC and Secure Digital (SD) common code which
9 * transitions the card from the standby state to the transfer state. The
10 * common code supports read operations, erase and write operations are in
11 * a separate modules. This code is controller independent.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of
16 * the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 */
23
24#include <assert.h>
Lee Leahy48dbc662017-05-08 16:56:03 -070025#include <commonlib/storage.h>
Lee Leahyeef40eb2017-03-23 10:54:57 -070026#include "sd_mmc.h"
27#include "storage.h"
28#include <string.h>
29
30#define DECIMAL_CAPACITY_MULTIPLIER 1000ULL
31#define HEX_CAPACITY_MULTIPLIER 1024ULL
32
Lee Leahybf5d5092017-05-09 16:37:58 -070033struct capacity {
34 const char * const units;
35 uint64_t bytes;
Lee Leahyeef40eb2017-03-23 10:54:57 -070036};
37
38static void display_capacity(struct storage_media *media, int partition_number)
39{
40 uint64_t capacity;
41 uint64_t decimal_divisor;
42 const char *decimal_units;
43 uint64_t hex_divisor;
44 const char *hex_units;
45 int index;
46 const char *name;
47 const char *separator;
Lee Leahybf5d5092017-05-09 16:37:58 -070048 const struct capacity decimal_list[] = {
49 {"TB", DECIMAL_CAPACITY_MULTIPLIER * DECIMAL_CAPACITY_MULTIPLIER
50 * DECIMAL_CAPACITY_MULTIPLIER
51 * DECIMAL_CAPACITY_MULTIPLIER},
52 {"GB", DECIMAL_CAPACITY_MULTIPLIER * DECIMAL_CAPACITY_MULTIPLIER
53 * DECIMAL_CAPACITY_MULTIPLIER},
54 {"MB", DECIMAL_CAPACITY_MULTIPLIER
55 * DECIMAL_CAPACITY_MULTIPLIER},
56 {"KB", DECIMAL_CAPACITY_MULTIPLIER},
57 {"B", 1}
58 };
59 const struct capacity hex_list[] = {
60 {"TiB", HEX_CAPACITY_MULTIPLIER * HEX_CAPACITY_MULTIPLIER
61 * HEX_CAPACITY_MULTIPLIER * HEX_CAPACITY_MULTIPLIER},
62 {"GiB", HEX_CAPACITY_MULTIPLIER * HEX_CAPACITY_MULTIPLIER
63 * HEX_CAPACITY_MULTIPLIER},
64 {"MiB", HEX_CAPACITY_MULTIPLIER * HEX_CAPACITY_MULTIPLIER},
65 {"KiB", HEX_CAPACITY_MULTIPLIER},
66 {"B", 1}
67 };
Lee Leahyeef40eb2017-03-23 10:54:57 -070068
69 /* Get the partition name */
70 capacity = media->capacity[partition_number];
71 name = storage_partition_name(media, partition_number);
72 separator = "";
Lee Leahy48dbc662017-05-08 16:56:03 -070073 if (IS_ENABLED(CONFIG_COMMONLIB_STORAGE_MMC) && !IS_SD(media))
Lee Leahyeef40eb2017-03-23 10:54:57 -070074 separator = ": ";
75
76 /* Determine the decimal divisor for the capacity */
Lee Leahybf5d5092017-05-09 16:37:58 -070077 for (index = 0; index < ARRAY_SIZE(decimal_list) - 1; index++) {
78 if (capacity >= decimal_list[index].bytes)
Lee Leahyeef40eb2017-03-23 10:54:57 -070079 break;
80 }
Lee Leahybf5d5092017-05-09 16:37:58 -070081 decimal_divisor = decimal_list[index].bytes;
82 decimal_units = decimal_list[index].units;
Lee Leahyeef40eb2017-03-23 10:54:57 -070083
84 /* Determine the hex divisor for the capacity */
Lee Leahybf5d5092017-05-09 16:37:58 -070085 for (index = 0; index < ARRAY_SIZE(hex_list) - 1; index++) {
86 if (capacity >= hex_list[index].bytes)
Lee Leahyeef40eb2017-03-23 10:54:57 -070087 break;
88 }
Lee Leahybf5d5092017-05-09 16:37:58 -070089 hex_divisor = hex_list[index].bytes;
90 hex_units = hex_list[index].units;
Lee Leahyeef40eb2017-03-23 10:54:57 -070091
92 /* Display the capacity */
93 sdhc_debug("%3lld.%03lld %sytes (%3lld.%03lld %sytes)%s%s\n",
94 capacity / decimal_divisor,
95 (capacity / (decimal_divisor / 1000)) % 1000,
96 decimal_units,
97 capacity / hex_divisor,
98 ((capacity / (hex_divisor / 1024)) * 1000 / 1024) % 1000,
99 hex_units,
100 separator,
101 name);
102}
103
104void storage_display_setup(struct storage_media *media)
105{
106 int partition_number;
107
108 /* Display the device info */
109 sd_mmc_debug("Man %06x Snr %u ",
110 media->cid[0] >> 24,
111 (((media->cid[2] & 0xffff) << 16) |
112 ((media->cid[3] >> 16) & 0xffff)));
113 sd_mmc_debug("Product %c%c%c%c", media->cid[0] & 0xff,
114 (media->cid[1] >> 24), (media->cid[1] >> 16) & 0xff,
115 (media->cid[1] >> 8) & 0xff);
116 if (!IS_SD(media)) /* eMMC product string is longer */
117 sd_mmc_debug("%c%c", media->cid[1] & 0xff,
118 (media->cid[2] >> 24) & 0xff);
119 sd_mmc_debug(" Revision %d.%d\n", (media->cid[2] >> 20) & 0xf,
120 (media->cid[2] >> 16) & 0xf);
121
122 /* Display the erase block size */
123 sdhc_debug("Erase block size: 0x%08x\n", media->erase_blocks
124 * media->write_bl_len);
125
126 /* Display the partition capacities */
127 if (IS_ENABLED(CONFIG_SDHC_DEBUG)) {
128 for (partition_number = 0; partition_number
129 < ARRAY_SIZE(media->capacity); partition_number++) {
130 if (!media->capacity[partition_number])
131 continue;
132 display_capacity(media, partition_number);
133 }
134 }
135}
136
137int storage_startup(struct storage_media *media)
138{
139 int err;
140 uint64_t capacity;
141 uint64_t cmult, csize;
142 struct mmc_command cmd;
143 struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
144
145 /* Determine the storage capacity */
146 if (media->high_capacity) {
147 cmult = 8;
148 csize = sd_mmc_extract_uint32_bits(media->csd, 58, 22);
149 } else {
150 csize = sd_mmc_extract_uint32_bits(media->csd, 54, 12);
151 cmult = sd_mmc_extract_uint32_bits(media->csd, 78, 3);
152 }
153 capacity = (csize + 1) << (cmult + 2);
154 capacity *= media->read_bl_len;
155 media->capacity[0] = capacity;
156
157 /* Limit the block size to 512 bytes */
158 if (media->read_bl_len > 512)
159 media->read_bl_len = 512;
160 if (media->write_bl_len > 512)
161 media->write_bl_len = 512;
162
163 /* Get the erase size in blocks */
164 media->erase_blocks =
165 (sd_mmc_extract_uint32_bits(media->csd, 47, 3) + 1)
166 * (sd_mmc_extract_uint32_bits(media->csd, 42, 5) + 1);
167
168 /* Select the card, and put it into Transfer Mode */
169 cmd.cmdidx = MMC_CMD_SELECT_CARD;
170 cmd.resp_type = CARD_RSP_R1;
171 cmd.cmdarg = media->rca << 16;
172 cmd.flags = 0;
173 err = ctrlr->send_cmd(ctrlr, &cmd, NULL);
174 if (err)
175 return err;
176
177 /* Increase the bus frequency */
Lee Leahy48dbc662017-05-08 16:56:03 -0700178 if (IS_ENABLED(CONFIG_COMMONLIB_STORAGE_SD) && IS_SD(media))
Lee Leahyeef40eb2017-03-23 10:54:57 -0700179 err = sd_change_freq(media);
Lee Leahy48dbc662017-05-08 16:56:03 -0700180 else if (IS_ENABLED(CONFIG_COMMONLIB_STORAGE_MMC)) {
Lee Leahyeef40eb2017-03-23 10:54:57 -0700181 err = mmc_change_freq(media);
182 if (!err)
183 mmc_update_capacity(media);
184 }
185 if (err)
186 return err;
187
188 /* Restrict card's capabilities by what the controller can do */
189 media->caps &= ctrlr->caps;
190
191 /* Increase the bus width if possible */
Lee Leahy48dbc662017-05-08 16:56:03 -0700192 if (IS_ENABLED(CONFIG_COMMONLIB_STORAGE_SD) && IS_SD(media))
Lee Leahyeef40eb2017-03-23 10:54:57 -0700193 err = sd_set_bus_width(media);
Lee Leahy48dbc662017-05-08 16:56:03 -0700194 else if (IS_ENABLED(CONFIG_COMMONLIB_STORAGE_MMC))
Lee Leahyeef40eb2017-03-23 10:54:57 -0700195 err = mmc_set_bus_width(media);
196 if (err)
197 return err;
198
199 /* Display the card setup */
200 storage_display_setup(media);
201 return 0;
202}
203
204int storage_setup_media(struct storage_media *media, struct sd_mmc_ctrlr *ctrlr)
205{
206 int err;
207
208 memset(media, 0, sizeof(*media));
209 media->ctrlr = ctrlr;
210
211 err = sd_mmc_enter_standby(media);
212 if (err)
213 return err;
214 return storage_startup(media);
215}
216
217static int storage_read(struct storage_media *media, void *dest, uint32_t start,
218 uint32_t block_count)
219{
220 struct mmc_command cmd;
221 struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
222
223 cmd.resp_type = CARD_RSP_R1;
224 cmd.flags = 0;
225
226 if (block_count > 1)
227 cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
228 else
229 cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
230
231 if (media->high_capacity)
232 cmd.cmdarg = start;
233 else
234 cmd.cmdarg = start * media->read_bl_len;
235
236 struct mmc_data data;
237 data.dest = dest;
238 data.blocks = block_count;
239 data.blocksize = media->read_bl_len;
240 data.flags = DATA_FLAG_READ;
241
242 if (ctrlr->send_cmd(ctrlr, &cmd, &data))
243 return 0;
244
245 if ((block_count > 1) && !(ctrlr->caps
246 & DRVR_CAP_AUTO_CMD12)) {
247 cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
248 cmd.cmdarg = 0;
249 cmd.resp_type = CARD_RSP_R1b;
250 cmd.flags = CMD_FLAG_IGNORE_INHIBIT;
251 if (ctrlr->send_cmd(ctrlr, &cmd, NULL)) {
252 sd_mmc_error("Failed to send stop cmd\n");
253 return 0;
254 }
255
256 /* Waiting for the ready status */
257 sd_mmc_send_status(media, SD_MMC_IO_RETRIES);
258 }
259
260 return block_count;
261}
262
263/////////////////////////////////////////////////////////////////////////////
264// BlockDevice utilities and callbacks
265
266int storage_block_setup(struct storage_media *media, uint64_t start,
267 uint64_t count, int is_read)
268{
269 struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
270 int partition_number;
271
272 if (count == 0)
273 return 0;
274
275 uint32_t bl_len = is_read ? media->read_bl_len :
276 media->write_bl_len;
277
278 /* Validate the block range */
279 partition_number = media->partition_config & EXT_CSD_PART_ACCESS_MASK;
280 if (((start * bl_len) > media->capacity[partition_number])
281 || (((start + count) * bl_len) >
282 media->capacity[partition_number])) {
283 sd_mmc_error("Block range exceeds device capacity\n");
284 return 0;
285 }
286
287 /*
288 * CMD16 only applies to single data rate mode, and block
289 * length for double data rate is always 512 bytes.
290 */
291 if ((ctrlr->timing == BUS_TIMING_UHS_DDR50) ||
292 (ctrlr->timing == BUS_TIMING_MMC_DDR52) ||
293 (ctrlr->timing == BUS_TIMING_MMC_HS400) ||
294 (ctrlr->timing == BUS_TIMING_MMC_HS400ES))
295 return 1;
296 if (sd_mmc_set_blocklen(ctrlr, bl_len))
297 return 0;
298
299 return 1;
300}
301
302uint64_t storage_block_read(struct storage_media *media, uint64_t start,
303 uint64_t count, void *buffer)
304{
305 uint8_t *dest = (uint8_t *)buffer;
306
307 if (storage_block_setup(media, start, count, 1) == 0)
308 return 0;
309
310 uint64_t todo = count;
311 struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
312 do {
313 uint32_t cur = (uint32_t)MIN(todo, ctrlr->b_max);
314 if (storage_read(media, dest, start, cur) != cur)
315 return 0;
316 todo -= cur;
317 sd_mmc_trace("%s: Got %d blocks, more %d (total %d) to go.\n",
318 __func__, (int)cur, (int)todo, (int)count);
319 start += cur;
320 dest += cur * media->read_bl_len;
321 } while (todo > 0);
322 return count;
323}
324
325int storage_set_partition(struct storage_media *media,
326 unsigned int partition_number)
327{
328 int err;
329
330 /* Select the partition */
331 err = -1;
Lee Leahy48dbc662017-05-08 16:56:03 -0700332 if (IS_ENABLED(CONFIG_COMMONLIB_STORAGE_SD) && IS_SD(media))
Lee Leahyeef40eb2017-03-23 10:54:57 -0700333 err = sd_set_partition(media, partition_number);
Lee Leahy48dbc662017-05-08 16:56:03 -0700334 else if (IS_ENABLED(CONFIG_COMMONLIB_STORAGE_MMC))
Lee Leahyeef40eb2017-03-23 10:54:57 -0700335 err = mmc_set_partition(media, partition_number);
336 if (err)
337 sd_mmc_error("Invalid partition number!\n");
338 return err;
339}
340
341const char *storage_partition_name(struct storage_media *media,
342 unsigned int partition_number)
343{
344 const char *name;
345
346 /* Get the partition name */
347 name = NULL;
Lee Leahy48dbc662017-05-08 16:56:03 -0700348 if (IS_ENABLED(CONFIG_COMMONLIB_STORAGE_SD) && IS_SD(media))
Lee Leahyeef40eb2017-03-23 10:54:57 -0700349 name = sd_partition_name(media, partition_number);
Lee Leahy48dbc662017-05-08 16:56:03 -0700350 else if (IS_ENABLED(CONFIG_COMMONLIB_STORAGE_MMC))
Lee Leahyeef40eb2017-03-23 10:54:57 -0700351 name = mmc_partition_name(media, partition_number);
352 return name;
353}
354
355unsigned int storage_get_current_partition(struct storage_media *media)
356{
357 return media->partition_config & EXT_CSD_PART_ACCESS_MASK;
358}