tizen 2.3.1 release
[platform/kernel/u-boot.git] / drivers / mobile / fota.c
1 /*
2  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
3  * Sanghee Kim <sh0130.kim@samsung.com>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25 #include <malloc.h>
26 #include <asm/errno.h>
27 #include <mobile/header.h>
28 #include <mobile/pit.h>
29 #include <mobile/fota.h>
30 #include <mobile/secure.h>
31 #include <image.h>
32 #include <fat.h>
33
34 #ifndef CONFIG_CMD_PIT
35 #error "mobile misc need to define the CONFIG_CMD_PIT"
36 #endif
37
38 #ifndef CONFIG_SECURE_BOOTING
39 #define SECURE_KEY_SIZE         0
40 #endif
41
42 enum {
43         OPS_READ,
44         OPS_WRITE,
45         OPS_ERASE,
46 };
47
48 extern struct pitpart_data pitparts[];
49
50 #ifdef CONFIG_CMD_ONENAND
51 extern int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc,
52                       char *const argv[]);
53 static int nand_cmd(int ops, u32 addr, u32 ofs, u32 len)
54 {
55         int ret;
56         char cmd[8], arg1[12], arg2[12], arg3[12];
57         char *const argv[] = { "onenand", cmd, arg1, arg2, arg3 };
58         int argc = 0;
59
60         sprintf(arg1, "%x", addr);
61         sprintf(arg2, "%x", ofs);
62         sprintf(arg3, "%x", len);
63
64         switch (ops) {
65         case OPS_ERASE:
66                 sprintf(cmd, "erase");
67                 argc = 4;
68                 break;
69         case OPS_READ:
70                 sprintf(cmd, "read");
71                 argc = 5;
72                 break;
73         case OPS_WRITE:
74                 sprintf(cmd, "write");
75                 argc = 5;
76                 break;
77         default:
78                 printf("Error: wrong cmd on OneNAND\n");
79                 break;
80         }
81
82         ret = do_onenand(NULL, 0, argc, argv);
83         if (ret)
84                 printf("Error: NAND Command\n");
85
86         return ret;
87 }
88 #endif
89
90 #ifdef CONFIG_GENERIC_MMC
91 #include <mmc.h>
92
93 static struct mmc *mmc;
94
95 static int mmc_cmd(int ops, u64 start, u64 cnt, void *addr)
96 {
97         int ret;
98         int dev_num = CONFIG_MMC_DEFAULT_DEV;
99
100         mmc = find_mmc_device(dev_num);
101         if (mmc == NULL) {
102                 printf("error: mmc isn't exist\n");
103                 return 1;
104         }
105
106         start /= mmc->read_bl_len;
107         cnt /= mmc->read_bl_len;
108
109         /*printf("mmc %s 0x%llx 0x%llx\n", ops ? "write" : "read", start, cnt); */
110
111         if (ops)
112                 ret =
113                     mmc->block_dev.block_write(dev_num, (u32) start, (u32) cnt,
114                                                addr);
115         else
116                 ret =
117                     mmc->block_dev.block_read(dev_num, (u32) start, (u32) cnt,
118                                               addr);
119
120         if (ret > 0)
121                 ret = 0;
122         else
123                 ret = 1;
124
125         return ret;
126 }
127 #endif
128
129 int set_valid_flag(int index, u32 addr, int valid)
130 {
131         int ret = 0;
132         struct boot_header *bh;
133         image_header_t *hdr;
134
135         printf("flag %s on %s\n", valid ? "set" : "clear",
136                pitparts[index].name);
137
138         switch (pitparts[index].dev_type) {
139         case PIT_DEVTYPE_ONENAND:
140                 bh = (struct boot_header *)addr;
141                 if (bh->magic == HDR_BOOT_MAGIC)
142                         bh->valid = valid;
143                 else if (bh->magic == HDR_KERNEL_MAGIC)
144                         bh->valid = valid;
145                 else
146                         ret = 1;
147                 break;
148         case PIT_DEVTYPE_MMC:
149         case PIT_DEVTYPE_FILE:
150                 if (!strncmp(pitparts[index].name, PARTS_BOOTLOADER, 6)) {
151                         bh = (struct boot_header *)
152                             (addr + (u32) pitparts[index].size - HDR_SIZE);
153                 } else if (!strncmp(pitparts[index].name, PARTS_KERNEL, 6)) {
154                         hdr = (image_header_t *)addr;
155                         bh = (struct boot_header *)(addr +
156                                 ALIGN(image_get_data_size(hdr) + image_get_header_size(), FS_BLOCK_SIZE) +
157                                 SECURE_KEY_SIZE);
158                 }
159
160                 if (bh->magic == HDR_BOOT_MAGIC)
161                         bh->valid = valid;
162                 else if (bh->magic == HDR_KERNEL_MAGIC)
163                         bh->valid = valid;
164                 else
165                         ret = 1;
166                 break;
167         default:
168                 break;
169         }
170
171         if (ret)
172                 printf("error: can't found magic code(0x%08x) at 0x%x for %s",
173                        bh->magic, (u32) bh, pitparts[index].name);
174
175         return ret;
176 }
177
178 static int check_valid_flag(int index, char *opt)
179 {
180         int ret;
181         u64 offset;
182         u32 length;
183         char cmd[64];
184         u32 ramaddr = CONFIG_SYS_DOWN_ADDR;
185         u8 buf[FS_BLOCK_SIZE];
186         struct boot_header *bh = (struct boot_header *)buf;
187         image_header_t *hdr = (image_header_t *)buf;
188
189         /* caution! support only mmc */
190         if (pitparts[index].dev_type == PIT_DEVTYPE_MMC) {
191                 offset = pitparts[index].offset;
192
193                 if (!strncmp(pitparts[index].name, PARTS_BOOTLOADER, 6))
194                         length = ((u32) pitparts[index].size) - FS_BLOCK_SIZE;
195                 else if (!strncmp(pitparts[index].name, PARTS_KERNEL, 6)) {
196                         mmc_cmd(OPS_READ, offset , sizeof(image_header_t),
197                                 (void *)hdr);
198                         length = ALIGN(image_get_data_size(hdr) +
199                                         image_get_header_size(), FS_BLOCK_SIZE);
200                         length = ALIGN(length + SECURE_KEY_SIZE, FS_BLOCK_SIZE);
201                 }
202
203                 mmc_cmd(OPS_READ, offset + length, FS_BLOCK_SIZE, (void *)buf);
204
205                 if ((bh->magic == HDR_BOOT_MAGIC) && bh->valid) {
206                         debug("found header: ");
207                         debug("board (%s) version (%s) date (%s)\n",
208                               bh->boardname, bh->version, bh->date);
209                         return 0;
210                 }
211         }
212
213         if (pitparts[index].dev_type == PIT_DEVTYPE_FILE) {
214                 sprintf(cmd, "ext4load mmc %d:%s %x /%s%s",
215                         CONFIG_MMC_DEFAULT_DEV, getenv("mmcbootpart"),
216                         ramaddr, pitparts[index].file_name, opt);
217
218                 ret = run_command(cmd, 0);
219                 if (ret < 0) {
220                         printf("cmd: %s\n", cmd);
221                         return 1;
222                 }
223
224                 length = (u32)simple_strtoul(getenv("filesize"), NULL, 16);
225                 bh = (struct boot_header *)(ramaddr + length - FS_BLOCK_SIZE);
226
227                 if ((bh->magic == HDR_KERNEL_MAGIC) && bh->valid) {
228                         debug("found header: ");
229                         debug("board (%s) version (%s) date (%s)\n",
230                               bh->boardname, bh->version, bh->date);
231                         return 0;
232                 }
233         }
234
235         printf("Error: can't found bootable partition for %s%s\n",
236                pitparts[index].file_name, opt);
237
238         return 1;
239 }
240
241 int backup_bootable_part(void)
242 {
243         int ret;
244         int index, index_bak;
245         u32 length;
246         char cmd[64];
247         u32 ramaddr = CONFIG_SYS_DOWN_ADDR;
248         u8 buf[FS_BLOCK_SIZE];
249         image_header_t *hdr = (image_header_t *)buf;
250
251         printf("\nbackup start\n");
252
253         /* bootloader */
254         index = get_pitpart_id(PARTS_BOOTLOADER "-mmc");
255         index_bak = get_pitpart_id(PARTS_BOOTLOADER "-mmc-bak");
256         if (!check_valid_flag(index, "")) {
257                 printf("bootloader backup from 1st to 2nd\n");
258                 mmc_cmd(OPS_READ,
259                         pitparts[index].offset, pitparts[index].size,
260                         (void *)ramaddr);
261
262                 mmc_cmd(OPS_WRITE,
263                         pitparts[index_bak].offset, pitparts[index_bak].size,
264                         (void *)ramaddr);
265
266                 /* clear the valid flag for origin */
267                 set_valid_flag(index, ramaddr, 0);
268                 mmc_cmd(OPS_WRITE,
269                         pitparts[index].offset, pitparts[index].size,
270                         (void *)ramaddr);
271         } else if (!check_valid_flag(index_bak, "-bak")) {
272                 printf("bootloader restore from 2nd to 1st\n");
273                 mmc_cmd(OPS_READ,
274                         pitparts[index_bak].offset, pitparts[index_bak].size,
275                         (void *)ramaddr);
276
277                 /* clear the valid flag for origin */
278                 set_valid_flag(index, ramaddr, 0);
279                 mmc_cmd(OPS_WRITE,
280                         pitparts[index].offset, pitparts[index].size,
281                         (void *)ramaddr);
282         } else {
283                 printf("bootloader fail..\n");
284         }
285
286         /* kernel */
287         index = get_pitpart_id(PARTS_KERNEL);
288         if (!check_valid_flag(index, "")) {
289                 printf("kernel backup from 1st to 2nd\n");
290
291                 /* already loaded */
292
293                 length = (u32)simple_strtoul(getenv("filesize"), NULL, 16);
294
295                 sprintf(cmd, "ext4write mmc %d:%s /%s-bak 0x%x %d",
296                         CONFIG_MMC_DEFAULT_DEV, getenv("mmcbootpart"),
297                         pitparts[index].file_name, ramaddr, length);
298
299                 ret = run_command(cmd, 0);
300                 if (ret < 0) {
301                         printf("cmd: %s\n", cmd);
302                         return 1;
303                 }
304
305                 /* clear the valid flag for origin */
306                 set_valid_flag(index, ramaddr, 0);
307                 sprintf(cmd, "ext4write mmc %d:%s /%s 0x%x %d",
308                         CONFIG_MMC_DEFAULT_DEV, getenv("mmcbootpart"),
309                         pitparts[index].file_name, ramaddr, length);
310
311                 ret = run_command(cmd, 0);
312                 if (ret < 0) {
313                         printf("cmd: %s\n", cmd);
314                         return 1;
315                 }
316         } else if (!check_valid_flag(index, "-bak")) {
317                 printf("kernel restore from 2nd to 1st\n");
318
319                 /* already loaded */
320
321                 length = (u32)simple_strtoul(getenv("filesize"), NULL, 16);
322
323                 /* clear the valid flag for origin */
324                 set_valid_flag(index, ramaddr, 0);
325                 sprintf(cmd, "fatwrite mmc %d:%s 0x%x %s 0x%x",
326                         CONFIG_MMC_DEFAULT_DEV, getenv("mmcbootpart"), ramaddr,
327                         pitparts[index].file_name, length);
328
329                 ret = run_command(cmd, 0);
330                 if (ret < 0) {
331                         printf("cmd: %s\n", cmd);
332                         return 1;
333                 }
334         } else {
335                 printf("kernel fail..\n");
336         }
337
338         printf("\nbackup done\n");
339         return 0;
340 }
341
342 int check_kernel_part(void)
343 {
344         int index = get_pitpart_id(PARTS_KERNEL);
345         char buf[16];
346
347         if (!check_valid_flag(index, "")) {
348                 /* do nothing */
349         } else if (!check_valid_flag(index, "-bak")) {
350                 sprintf(buf, "%s%s", pitparts[index].file_name, "-bak");
351                 setenv("kernelname", buf);
352         } else {
353                 printf("Can't found bootable kernel\n");
354                 /* XXX: this will be enabled on May 2011 */
355                 /* setenv("loaduimage", NULL);
356                    return 1; */
357         }
358
359         return 0;
360 }