]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/dfu/dfu_mmc.c
Merge branch 'u-boot-samsung/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / drivers / dfu / dfu_mmc.c
1 /*
2  * dfu.c -- DFU back-end routines
3  *
4  * Copyright (C) 2012 Samsung Electronics
5  * author: Lukasz Majewski <l.majewski@samsung.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <common.h>
23 #include <malloc.h>
24 #include <errno.h>
25 #include <dfu.h>
26
27 enum dfu_mmc_op {
28         DFU_OP_READ = 1,
29         DFU_OP_WRITE,
30 };
31
32 static int mmc_block_op(enum dfu_mmc_op op, struct dfu_entity *dfu,
33                         void *buf, long *len)
34 {
35         char cmd_buf[DFU_CMD_BUF_SIZE];
36
37         sprintf(cmd_buf, "mmc %s 0x%x %x %x",
38                 op == DFU_OP_READ ? "read" : "write",
39                 (unsigned int) buf,
40                 dfu->data.mmc.lba_start,
41                 dfu->data.mmc.lba_size);
42
43         if (op == DFU_OP_READ)
44                 *len = dfu->data.mmc.lba_blk_size * dfu->data.mmc.lba_size;
45
46         debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf);
47         return run_command(cmd_buf, 0);
48 }
49
50 static inline int mmc_block_write(struct dfu_entity *dfu, void *buf, long *len)
51 {
52         return mmc_block_op(DFU_OP_WRITE, dfu, buf, len);
53 }
54
55 static inline int mmc_block_read(struct dfu_entity *dfu, void *buf, long *len)
56 {
57         return mmc_block_op(DFU_OP_READ, dfu, buf, len);
58 }
59
60 static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu,
61                         void *buf, long *len)
62 {
63         char cmd_buf[DFU_CMD_BUF_SIZE];
64         char *str_env;
65         int ret;
66
67         switch (dfu->layout) {
68         case DFU_FS_FAT:
69                 sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s %lx",
70                         op == DFU_OP_READ ? "load" : "write",
71                         dfu->data.mmc.dev, dfu->data.mmc.part,
72                         (unsigned int) buf, dfu->name, *len);
73                 break;
74         case DFU_FS_EXT4:
75                 sprintf(cmd_buf, "ext4%s mmc %d:%d /%s 0x%x %ld",
76                         op == DFU_OP_READ ? "load" : "write",
77                         dfu->data.mmc.dev, dfu->data.mmc.part,
78                         dfu->name, (unsigned int) buf, *len);
79                 break;
80         default:
81                 printf("%s: Layout (%s) not (yet) supported!\n", __func__,
82                        dfu_get_layout(dfu->layout));
83         }
84
85         debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf);
86
87         ret = run_command(cmd_buf, 0);
88         if (ret) {
89                 puts("dfu: Read error!\n");
90                 return ret;
91         }
92
93         if (dfu->layout != DFU_RAW_ADDR && op == DFU_OP_READ) {
94                 str_env = getenv("filesize");
95                 if (str_env == NULL) {
96                         puts("dfu: Wrong file size!\n");
97                         return -1;
98                 }
99                 *len = simple_strtoul(str_env, NULL, 16);
100         }
101
102         return ret;
103 }
104
105 static inline int mmc_file_write(struct dfu_entity *dfu, void *buf, long *len)
106 {
107         return mmc_file_op(DFU_OP_WRITE, dfu, buf, len);
108 }
109
110 static inline int mmc_file_read(struct dfu_entity *dfu, void *buf, long *len)
111 {
112         return mmc_file_op(DFU_OP_READ, dfu, buf, len);
113 }
114
115 int dfu_write_medium_mmc(struct dfu_entity *dfu, void *buf, long *len)
116 {
117         int ret = -1;
118
119         switch (dfu->layout) {
120         case DFU_RAW_ADDR:
121                 ret = mmc_block_write(dfu, buf, len);
122                 break;
123         case DFU_FS_FAT:
124         case DFU_FS_EXT4:
125                 ret = mmc_file_write(dfu, buf, len);
126                 break;
127         default:
128                 printf("%s: Layout (%s) not (yet) supported!\n", __func__,
129                        dfu_get_layout(dfu->layout));
130         }
131
132         return ret;
133 }
134
135 int dfu_read_medium_mmc(struct dfu_entity *dfu, void *buf, long *len)
136 {
137         int ret = -1;
138
139         switch (dfu->layout) {
140         case DFU_RAW_ADDR:
141                 ret = mmc_block_read(dfu, buf, len);
142                 break;
143         case DFU_FS_FAT:
144         case DFU_FS_EXT4:
145                 ret = mmc_file_read(dfu, buf, len);
146                 break;
147         default:
148                 printf("%s: Layout (%s) not (yet) supported!\n", __func__,
149                        dfu_get_layout(dfu->layout));
150         }
151
152         return ret;
153 }
154
155 int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
156 {
157         int dev, part;
158         struct mmc *mmc;
159         block_dev_desc_t *blk_dev;
160         disk_partition_t partinfo;
161         char *st;
162
163         dfu->dev_type = DFU_DEV_MMC;
164         st = strsep(&s, " ");
165         if (!strcmp(st, "mmc")) {
166                 dfu->layout = DFU_RAW_ADDR;
167                 dfu->data.mmc.lba_start = simple_strtoul(s, &s, 16);
168                 dfu->data.mmc.lba_size = simple_strtoul(++s, &s, 16);
169                 dfu->data.mmc.lba_blk_size = get_mmc_blk_size(dfu->dev_num);
170         } else if (!strcmp(st, "fat")) {
171                 dfu->layout = DFU_FS_FAT;
172         } else if (!strcmp(st, "ext4")) {
173                 dfu->layout = DFU_FS_EXT4;
174         } else if (!strcmp(st, "part")) {
175
176                 dfu->layout = DFU_RAW_ADDR;
177
178                 dev = simple_strtoul(s, &s, 10);
179                 s++;
180                 part = simple_strtoul(s, &s, 10);
181
182                 mmc = find_mmc_device(dev);
183                 if (mmc == NULL || mmc_init(mmc)) {
184                         printf("%s: could not find mmc device #%d!\n", __func__, dev);
185                         return -ENODEV;
186                 }
187
188                 blk_dev = &mmc->block_dev;
189                 if (get_partition_info(blk_dev, part, &partinfo) != 0) {
190                         printf("%s: could not find partition #%d on mmc device #%d!\n",
191                                         __func__, part, dev);
192                         return -ENODEV;
193                 }
194
195                 dfu->data.mmc.lba_start = partinfo.start;
196                 dfu->data.mmc.lba_size = partinfo.size;
197                 dfu->data.mmc.lba_blk_size = partinfo.blksz;
198
199         } else {
200                 printf("%s: Memory layout (%s) not supported!\n", __func__, st);
201                 return -ENODEV;
202         }
203
204         if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) {
205                 dfu->data.mmc.dev = simple_strtoul(s, &s, 10);
206                 dfu->data.mmc.part = simple_strtoul(++s, &s, 10);
207         }
208
209         dfu->read_medium = dfu_read_medium_mmc;
210         dfu->write_medium = dfu_write_medium_mmc;
211
212         return 0;
213 }