Merge branch 'master' of git://git.denx.de/u-boot-at91
[platform/kernel/u-boot.git] / board / cm5200 / fwupdate.c
1 /*
2  * (C) Copyright 2007 Schindler Lift Inc.
3  * (C) Copyright 2007 DENX Software Engineering
4  *
5  * Author: Michel Marti <mma@objectxp.com>
6  * Adapted for U-Boot 1.2 by Piotr Kruszynski <ppk@semihalf.com>:
7  *   - code clean-up
8  *   - bugfix for overwriting bootargs by user
9  *
10  * See file CREDITS for list of people who contributed to this
11  * project.
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  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26  * MA 02111-1307 USA
27  */
28
29 #include <common.h>
30 #include <command.h>
31 #include <malloc.h>
32 #include <image.h>
33 #include <usb.h>
34 #include <fat.h>
35
36 #include "fwupdate.h"
37
38 extern int do_bootm(cmd_tbl_t *, int, int, char *[]);
39 extern long do_fat_read(const char *, void *, unsigned long, int);
40 extern int do_fat_fsload(cmd_tbl_t *, int, int, char *[]);
41
42 static int load_rescue_image(ulong);
43
44 void cm5200_fwupdate(void)
45 {
46         cmd_tbl_t *bcmd;
47         char *rsargs;
48         char *tmp = NULL;
49         char ka[16];
50         char *argv[3] = { "bootm", ka, NULL };
51
52         /* Check if rescue system is disabled... */
53         if (getenv("norescue")) {
54                 printf(LOG_PREFIX "Rescue System disabled.\n");
55                 return;
56         }
57
58         /* Check if we have a USB storage device and load image */
59         if (load_rescue_image(LOAD_ADDR))
60                 return;
61
62         bcmd = find_cmd("bootm");
63         if (!bcmd)
64                 return;
65
66         sprintf(ka, "%lx", (ulong)LOAD_ADDR);
67
68         /* prepare our bootargs */
69         rsargs = getenv("rs-args");
70         if (!rsargs)
71                 rsargs = RS_BOOTARGS;
72         else {
73                 tmp = malloc(strlen(rsargs+1));
74                 if (!tmp) {
75                         printf(LOG_PREFIX "Memory allocation failed\n");
76                         return;
77                 }
78                 strcpy(tmp, rsargs);
79                 rsargs = tmp;
80         }
81
82         setenv("bootargs", rsargs);
83
84         if (rsargs == tmp)
85                 free(rsargs);
86
87         printf(LOG_PREFIX "Starting update system (bootargs=%s)...\n", rsargs);
88         do_bootm(bcmd, 0, 2, argv);
89 }
90
91 static int load_rescue_image(ulong addr)
92 {
93         disk_partition_t info;
94         int devno;
95         int partno;
96         int i;
97         char fwdir[64];
98         char nxri[128];
99         char *tmp;
100         char dev[7];
101         char addr_str[16];
102         char *argv[6] = { "fatload", "usb", dev, addr_str, nxri, NULL };
103         block_dev_desc_t *stor_dev = NULL;
104         cmd_tbl_t *bcmd;
105
106         /* Get name of firmware directory */
107         tmp = getenv("fw-dir");
108
109         /* Copy it into fwdir */
110         strncpy(fwdir, tmp ? tmp : FW_DIR, sizeof(fwdir));
111         fwdir[sizeof(fwdir) - 1] = 0; /* Terminate string */
112
113         printf(LOG_PREFIX "Checking for firmware image directory '%s' on USB"
114                 " storage...\n", fwdir);
115         usb_stop();
116         if (usb_init() != 0)
117                 return 1;
118
119         /* Check for storage device */
120         if (usb_stor_scan(1) != 0) {
121                 usb_stop();
122                 return 1;
123         }
124
125         /* Detect storage device */
126         for (devno = 0; devno < USB_MAX_STOR_DEV; devno++) {
127                 stor_dev = usb_stor_get_dev(devno);
128                 if (stor_dev->type != DEV_TYPE_UNKNOWN)
129                         break;
130         }
131         if (!stor_dev || stor_dev->type == DEV_TYPE_UNKNOWN) {
132                 printf(LOG_PREFIX "No valid storage device found...\n");
133                 usb_stop();
134                 return 1;
135         }
136
137         /* Detect partition */
138         for (partno = -1, i = 0; i < 6; i++) {
139                 if (get_partition_info(stor_dev, i, &info) == 0) {
140                         if (fat_register_device(stor_dev, i) == 0) {
141                                 /* Check if rescue image is present */
142                                 FW_DEBUG("Looking for firmware directory '%s'"
143                                         " on partition %d\n", fwdir, i);
144                                 if (do_fat_read(fwdir, NULL, 0, LS_NO) == -1) {
145                                         FW_DEBUG("No NX rescue image on "
146                                                 "partition %d.\n", i);
147                                         partno = -2;
148                                 } else {
149                                         partno = i;
150                                         FW_DEBUG("Partition %d contains "
151                                                 "firmware directory\n", partno);
152                                         break;
153                                 }
154                         }
155                 }
156         }
157
158         if (partno < 0) {
159                 switch (partno) {
160                 case -1:
161                         printf(LOG_PREFIX "Error: No valid (FAT) partition "
162                                 "detected\n");
163                         break;
164                 case -2:
165                         printf(LOG_PREFIX "Error: No NX rescue image on FAT "
166                                 "partition\n");
167                         break;
168                 default:
169                         printf(LOG_PREFIX "Error: Failed with code %d\n",
170                                 partno);
171                 }
172                 usb_stop();
173                 return 1;
174         }
175
176         /* Load the rescue image */
177         bcmd = find_cmd("fatload");
178         if (!bcmd) {
179                 printf(LOG_PREFIX "Error - 'fatload' command not present.\n");
180                 usb_stop();
181                 return 1;
182         }
183
184         tmp = getenv("nx-rescue-image");
185         sprintf(nxri, "%s/%s", fwdir, tmp ? tmp : RESCUE_IMAGE);
186         sprintf(dev, "%d:%d", devno, partno);
187         sprintf(addr_str, "%lx", addr);
188
189         FW_DEBUG("fat_fsload device='%s', addr='%s', file: %s\n",
190                 dev, addr_str, nxri);
191
192         if (do_fat_fsload(bcmd, 0, 5, argv) != 0) {
193                 usb_stop();
194                 return 1;
195         }
196
197         /* Stop USB */
198         usb_stop();
199         return 0;
200 }