]>
Commit | Line | Data |
---|---|---|
cb383cd2 ŁM |
1 | /* |
2 | * dfu.c -- DFU back-end routines | |
3 | * | |
4 | * Copyright (C) 2012 Samsung Electronics | |
5 | * author: Lukasz Majewski <l.majewski@samsung.com> | |
6 | * | |
1a459660 | 7 | * SPDX-License-Identifier: GPL-2.0+ |
cb383cd2 ŁM |
8 | */ |
9 | ||
10 | #include <common.h> | |
11 | #include <malloc.h> | |
1b6ca18b | 12 | #include <errno.h> |
ea2453d5 | 13 | #include <div64.h> |
cb383cd2 ŁM |
14 | #include <dfu.h> |
15 | ||
16 | enum dfu_mmc_op { | |
17 | DFU_OP_READ = 1, | |
18 | DFU_OP_WRITE, | |
19 | }; | |
20 | ||
ea2453d5 PA |
21 | static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE) |
22 | dfu_file_buf[CONFIG_SYS_DFU_MAX_FILE_SIZE]; | |
23 | static long dfu_file_buf_len; | |
24 | ||
cb383cd2 | 25 | static int mmc_block_op(enum dfu_mmc_op op, struct dfu_entity *dfu, |
ea2453d5 | 26 | u64 offset, void *buf, long *len) |
cb383cd2 ŁM |
27 | { |
28 | char cmd_buf[DFU_CMD_BUF_SIZE]; | |
ea2453d5 PA |
29 | u32 blk_start, blk_count; |
30 | ||
31 | /* | |
32 | * We must ensure that we work in lba_blk_size chunks, so ALIGN | |
33 | * this value. | |
34 | */ | |
35 | *len = ALIGN(*len, dfu->data.mmc.lba_blk_size); | |
36 | ||
37 | blk_start = dfu->data.mmc.lba_start + | |
38 | (u32)lldiv(offset, dfu->data.mmc.lba_blk_size); | |
39 | blk_count = *len / dfu->data.mmc.lba_blk_size; | |
40 | if (blk_start + blk_count > | |
41 | dfu->data.mmc.lba_start + dfu->data.mmc.lba_size) { | |
42 | puts("Request would exceed designated area!\n"); | |
43 | return -EINVAL; | |
44 | } | |
cb383cd2 | 45 | |
ea2453d5 | 46 | sprintf(cmd_buf, "mmc %s %p %x %x", |
cb383cd2 | 47 | op == DFU_OP_READ ? "read" : "write", |
ea2453d5 | 48 | buf, blk_start, blk_count); |
cb383cd2 ŁM |
49 | |
50 | debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf); | |
51 | return run_command(cmd_buf, 0); | |
52 | } | |
53 | ||
ea2453d5 | 54 | static int mmc_file_buffer(struct dfu_entity *dfu, void *buf, long *len) |
cb383cd2 | 55 | { |
ea2453d5 PA |
56 | if (dfu_file_buf_len + *len > CONFIG_SYS_DFU_MAX_FILE_SIZE) { |
57 | dfu_file_buf_len = 0; | |
58 | return -EINVAL; | |
59 | } | |
cb383cd2 | 60 | |
ea2453d5 PA |
61 | /* Add to the current buffer. */ |
62 | memcpy(dfu_file_buf + dfu_file_buf_len, buf, *len); | |
63 | dfu_file_buf_len += *len; | |
64 | ||
65 | return 0; | |
cb383cd2 ŁM |
66 | } |
67 | ||
68 | static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu, | |
69 | void *buf, long *len) | |
70 | { | |
71 | char cmd_buf[DFU_CMD_BUF_SIZE]; | |
72 | char *str_env; | |
73 | int ret; | |
74 | ||
43e66272 ŁM |
75 | switch (dfu->layout) { |
76 | case DFU_FS_FAT: | |
ea2453d5 | 77 | sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s", |
43e66272 ŁM |
78 | op == DFU_OP_READ ? "load" : "write", |
79 | dfu->data.mmc.dev, dfu->data.mmc.part, | |
ea2453d5 PA |
80 | (unsigned int) buf, dfu->name); |
81 | if (op == DFU_OP_WRITE) | |
82 | sprintf(cmd_buf + strlen(cmd_buf), " %lx", *len); | |
43e66272 ŁM |
83 | break; |
84 | case DFU_FS_EXT4: | |
ea2453d5 | 85 | sprintf(cmd_buf, "ext4%s mmc %d:%d 0x%x /%s", |
43e66272 ŁM |
86 | op == DFU_OP_READ ? "load" : "write", |
87 | dfu->data.mmc.dev, dfu->data.mmc.part, | |
ea2453d5 | 88 | (unsigned int) buf, dfu->name); |
051f9a3e ŁM |
89 | if (op == DFU_OP_WRITE) |
90 | sprintf(cmd_buf + strlen(cmd_buf), " %ld", *len); | |
43e66272 ŁM |
91 | break; |
92 | default: | |
93 | printf("%s: Layout (%s) not (yet) supported!\n", __func__, | |
94 | dfu_get_layout(dfu->layout)); | |
ea2453d5 | 95 | return -1; |
43e66272 | 96 | } |
cb383cd2 ŁM |
97 | |
98 | debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf); | |
99 | ||
100 | ret = run_command(cmd_buf, 0); | |
101 | if (ret) { | |
102 | puts("dfu: Read error!\n"); | |
103 | return ret; | |
104 | } | |
105 | ||
81c1d7b6 | 106 | if (dfu->layout != DFU_RAW_ADDR && op == DFU_OP_READ) { |
cb383cd2 ŁM |
107 | str_env = getenv("filesize"); |
108 | if (str_env == NULL) { | |
109 | puts("dfu: Wrong file size!\n"); | |
110 | return -1; | |
111 | } | |
112 | *len = simple_strtoul(str_env, NULL, 16); | |
113 | } | |
114 | ||
115 | return ret; | |
116 | } | |
117 | ||
ea2453d5 PA |
118 | int dfu_write_medium_mmc(struct dfu_entity *dfu, |
119 | u64 offset, void *buf, long *len) | |
cb383cd2 ŁM |
120 | { |
121 | int ret = -1; | |
122 | ||
123 | switch (dfu->layout) { | |
124 | case DFU_RAW_ADDR: | |
ea2453d5 | 125 | ret = mmc_block_op(DFU_OP_WRITE, dfu, offset, buf, len); |
cb383cd2 ŁM |
126 | break; |
127 | case DFU_FS_FAT: | |
43e66272 | 128 | case DFU_FS_EXT4: |
ea2453d5 | 129 | ret = mmc_file_buffer(dfu, buf, len); |
cb383cd2 ŁM |
130 | break; |
131 | default: | |
132 | printf("%s: Layout (%s) not (yet) supported!\n", __func__, | |
133 | dfu_get_layout(dfu->layout)); | |
134 | } | |
135 | ||
136 | return ret; | |
137 | } | |
138 | ||
ea2453d5 PA |
139 | int dfu_flush_medium_mmc(struct dfu_entity *dfu) |
140 | { | |
141 | int ret = 0; | |
142 | ||
143 | if (dfu->layout != DFU_RAW_ADDR) { | |
144 | /* Do stuff here. */ | |
145 | ret = mmc_file_op(DFU_OP_WRITE, dfu, &dfu_file_buf, | |
146 | &dfu_file_buf_len); | |
147 | ||
148 | /* Now that we're done */ | |
149 | dfu_file_buf_len = 0; | |
150 | } | |
151 | ||
152 | return ret; | |
153 | } | |
154 | ||
155 | int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf, | |
156 | long *len) | |
cb383cd2 ŁM |
157 | { |
158 | int ret = -1; | |
159 | ||
160 | switch (dfu->layout) { | |
161 | case DFU_RAW_ADDR: | |
ea2453d5 | 162 | ret = mmc_block_op(DFU_OP_READ, dfu, offset, buf, len); |
cb383cd2 ŁM |
163 | break; |
164 | case DFU_FS_FAT: | |
43e66272 | 165 | case DFU_FS_EXT4: |
ea2453d5 | 166 | ret = mmc_file_op(DFU_OP_READ, dfu, buf, len); |
cb383cd2 ŁM |
167 | break; |
168 | default: | |
169 | printf("%s: Layout (%s) not (yet) supported!\n", __func__, | |
170 | dfu_get_layout(dfu->layout)); | |
171 | } | |
172 | ||
173 | return ret; | |
174 | } | |
175 | ||
176 | int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) | |
177 | { | |
1b6ca18b PA |
178 | int dev, part; |
179 | struct mmc *mmc; | |
180 | block_dev_desc_t *blk_dev; | |
181 | disk_partition_t partinfo; | |
cb383cd2 ŁM |
182 | char *st; |
183 | ||
184 | dfu->dev_type = DFU_DEV_MMC; | |
185 | st = strsep(&s, " "); | |
186 | if (!strcmp(st, "mmc")) { | |
187 | dfu->layout = DFU_RAW_ADDR; | |
188 | dfu->data.mmc.lba_start = simple_strtoul(s, &s, 16); | |
189 | dfu->data.mmc.lba_size = simple_strtoul(++s, &s, 16); | |
190 | dfu->data.mmc.lba_blk_size = get_mmc_blk_size(dfu->dev_num); | |
191 | } else if (!strcmp(st, "fat")) { | |
192 | dfu->layout = DFU_FS_FAT; | |
43e66272 ŁM |
193 | } else if (!strcmp(st, "ext4")) { |
194 | dfu->layout = DFU_FS_EXT4; | |
1b6ca18b PA |
195 | } else if (!strcmp(st, "part")) { |
196 | ||
197 | dfu->layout = DFU_RAW_ADDR; | |
198 | ||
199 | dev = simple_strtoul(s, &s, 10); | |
200 | s++; | |
201 | part = simple_strtoul(s, &s, 10); | |
202 | ||
203 | mmc = find_mmc_device(dev); | |
204 | if (mmc == NULL || mmc_init(mmc)) { | |
ea2453d5 PA |
205 | printf("%s: could not find mmc device #%d!\n", |
206 | __func__, dev); | |
1b6ca18b PA |
207 | return -ENODEV; |
208 | } | |
209 | ||
210 | blk_dev = &mmc->block_dev; | |
211 | if (get_partition_info(blk_dev, part, &partinfo) != 0) { | |
212 | printf("%s: could not find partition #%d on mmc device #%d!\n", | |
ea2453d5 | 213 | __func__, part, dev); |
1b6ca18b PA |
214 | return -ENODEV; |
215 | } | |
216 | ||
217 | dfu->data.mmc.lba_start = partinfo.start; | |
218 | dfu->data.mmc.lba_size = partinfo.size; | |
219 | dfu->data.mmc.lba_blk_size = partinfo.blksz; | |
220 | ||
cb383cd2 ŁM |
221 | } else { |
222 | printf("%s: Memory layout (%s) not supported!\n", __func__, st); | |
1b6ca18b | 223 | return -ENODEV; |
cb383cd2 ŁM |
224 | } |
225 | ||
43e66272 ŁM |
226 | if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) { |
227 | dfu->data.mmc.dev = simple_strtoul(s, &s, 10); | |
228 | dfu->data.mmc.part = simple_strtoul(++s, &s, 10); | |
229 | } | |
230 | ||
cb383cd2 ŁM |
231 | dfu->read_medium = dfu_read_medium_mmc; |
232 | dfu->write_medium = dfu_write_medium_mmc; | |
ea2453d5 PA |
233 | dfu->flush_medium = dfu_flush_medium_mmc; |
234 | ||
235 | /* initial state */ | |
236 | dfu->inited = 0; | |
cb383cd2 ŁM |
237 | |
238 | return 0; | |
239 | } |