blob: ba60b413062266e1f827439a8249f9ee0b0f6bc6 [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) write support code.
9 * This code is controller independent.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 */
21
Lee Leahyeef40eb2017-03-23 10:54:57 -070022#include "sd_mmc.h"
23#include "storage.h"
24#include <string.h>
25
26static uint32_t storage_write(struct storage_media *media, uint32_t start,
27 uint64_t block_count, const void *src)
28{
29 struct mmc_command cmd;
30 struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
31
32 cmd.resp_type = CARD_RSP_R1;
33 cmd.flags = 0;
34
35 if (block_count > 1)
36 cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
37 else
38 cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
39
40 if (media->high_capacity)
41 cmd.cmdarg = start;
42 else
43 cmd.cmdarg = start * media->write_bl_len;
44
45 struct mmc_data data;
46 data.src = src;
47 data.blocks = block_count;
48 data.blocksize = media->write_bl_len;
49 data.flags = DATA_FLAG_WRITE;
50
51 if (ctrlr->send_cmd(ctrlr, &cmd, &data)) {
52 sd_mmc_error("Write failed\n");
53 return 0;
54 }
55
56 /* SPI multiblock writes terminate using a special
57 * token, not a STOP_TRANSMISSION request.
58 */
59 if ((block_count > 1) && !(ctrlr->caps
60 & DRVR_CAP_AUTO_CMD12)) {
61 cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
62 cmd.cmdarg = 0;
63 cmd.resp_type = CARD_RSP_R1b;
64 cmd.flags = CMD_FLAG_IGNORE_INHIBIT;
65 if (ctrlr->send_cmd(ctrlr, &cmd, NULL)) {
66 sd_mmc_error("Failed to send stop cmd\n");
67 return 0;
68 }
69
70 /* Waiting for the ready status */
71 sd_mmc_send_status(media, SD_MMC_IO_RETRIES);
72 }
73
74 return block_count;
75}
76
77uint64_t storage_block_write(struct storage_media *media, uint64_t start,
78 uint64_t count, const void *buffer)
79{
80 const uint8_t *src = (const uint8_t *)buffer;
81
82 if (storage_block_setup(media, start, count, 0) == 0)
83 return 0;
84
85 uint64_t todo = count;
86 struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
87 do {
88 uint64_t cur = MIN(todo, ctrlr->b_max);
89 if (storage_write(media, start, cur, src) != cur)
90 return 0;
91 todo -= cur;
92 start += cur;
93 src += cur * media->write_bl_len;
94 } while (todo > 0);
95 return count;
96}
97
98uint64_t storage_block_fill_write(struct storage_media *media, uint64_t start,
99 uint64_t count, uint32_t fill_pattern)
100{
101 if (storage_block_setup(media, start, count, 0) == 0)
102 return 0;
103
104 struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
105 uint64_t block_size = media->write_bl_len;
106 /*
107 * We allocate max 4 MiB buffer on heap and set it to fill_pattern and
108 * perform mmc_write operation using this 4MiB buffer until requested
109 * size on disk is written by the fill byte.
110 *
111 * 4MiB was chosen after repeating several experiments with the max
112 * buffer size to be used. Using 1 lba i.e. block_size buffer results in
113 * very large fill_write time. On the other hand, choosing 4MiB, 8MiB or
114 * even 128 Mib resulted in similar write times. With 2MiB, the
115 * fill_write time increased by several seconds. So, 4MiB was chosen as
116 * the default max buffer size.
117 */
118 uint64_t heap_lba = (4 * MiB) / block_size;
119 /*
120 * Actual allocated buffer size is minimum of three entities:
121 * 1) 4MiB equivalent in lba
122 * 2) count: Number of lbas to overwrite
123 * 3) ctrlr->b_max: Max lbas that the block device allows write
124 * operation on at a time.
125 */
126 uint64_t buffer_lba = MIN(MIN(heap_lba, count), ctrlr->b_max);
127
128 uint64_t buffer_bytes = buffer_lba * block_size;
129 uint64_t buffer_words = buffer_bytes / sizeof(uint32_t);
130 uint32_t *buffer = malloc(buffer_bytes);
131 uint32_t *ptr = buffer;
132
133 for ( ; buffer_words ; buffer_words--)
134 *ptr++ = fill_pattern;
135
136 uint64_t todo = count;
137 int ret = 0;
138
139 do {
140 uint64_t curr_lba = MIN(buffer_lba, todo);
141
142 if (storage_write(media, start, curr_lba, buffer) != curr_lba)
143 goto cleanup;
144 todo -= curr_lba;
145 start += curr_lba;
146 } while (todo > 0);
147
148 ret = count;
149
150cleanup:
151 free(buffer);
152 return ret;
153}