blob: 5d800bd4e2b7147ab6809f36579f4d00334285bc [file] [log] [blame]
Simon Glassa3f29ec2011-07-17 09:36:49 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Simon Glass8bd05ec2012-03-22 11:09:04 -07005import binascii
Simon Glass3381a1a2012-03-22 11:13:19 -07006import glob
Simon Glassa3f29ec2011-07-17 09:36:49 -07007import os
8import re
9import time
10import tools
11from tools import CmdError
12
13def RoundUp(value, boundary):
14 """Align a value to the next power of 2 boundary.
15
16 Args:
17 value: The value to align.
18 boundary: The boundary value, e.g. 4096. Must be a power of 2.
19
20 Returns:
21 The rounded-up value.
22 """
23 return (value + boundary - 1) & ~(boundary - 1)
24
25
26class WriteFirmware:
27 """Write firmware to a Tegra 2 board using USB A-A cable.
28
29 This class handles re-reflashing a board with new firmware using the Tegra's
30 built-in boot ROM feature. This works by putting the chip into a special mode
31 where it ignores any available firmware and instead reads it from a connected
32 host machine over USB.
33
34 In our case we use that feature to send U-Boot along with a suitable payload
35 and instructions to flash it to SPI flash. The payload is itself normally a
36 full Chrome OS image consisting of U-Boot, some keys and verification
37 information, images and a map of the flash memory.
38 """
Simon Glass290a1802011-07-17 13:54:32 -070039 def __init__(self, tools, fdt, output):
Simon Glassa3f29ec2011-07-17 09:36:49 -070040 """Set up a new WriteFirmware object.
41
42 Args:
43 tools: A tools library for us to use.
44 fdt: An fdt which gives us some info that we need.
45 output: An output object to use for printing progress and messages.
Simon Glassa3f29ec2011-07-17 09:36:49 -070046 """
47 self._tools = tools
48 self._fdt = fdt
49 self._out = output
Simon Glass02d124a2012-03-02 14:47:20 -080050 self.text_base = self._fdt.GetInt('/chromeos-config', 'textbase');
Simon Glassa3f29ec2011-07-17 09:36:49 -070051
Simon Glass5b5fd642011-08-17 12:24:01 -070052 # For speed, use the 'update' algorithm and don't verify
53 self.update = True
54 self.verify = False
55
Simon Glass8bd05ec2012-03-22 11:09:04 -070056 def _GetFlashScript(self, payload_size, update, verify, boot_type, checksum,
57 bus='0'):
Simon Glassa3f29ec2011-07-17 09:36:49 -070058 """Get the U-Boot boot command needed to flash U-Boot.
59
60 We leave a marker in the string for the load address of the image,
61 since this depends on the size of this script. This can be replaced by
62 the caller provided that the marker length is unchanged.
63
64 Args:
65 payload_size: Size of payload in bytes.
Simon Glass5b5fd642011-08-17 12:24:01 -070066 update: Use faster update algorithm rather then full device erase
67 verify: Verify the write by doing a readback and CRC
Simon Glass0dcbecb2012-03-22 21:38:55 -070068 boot_type: The source for bootdevice (nand, sdmmc, or spi)
Simon Glass8bd05ec2012-03-22 11:09:04 -070069 checksum: The checksum of the payload (an integer)
70 bus: The bus number
Simon Glassa3f29ec2011-07-17 09:36:49 -070071
72 Returns:
73 A tuple containing:
74 The script, as a string ready to use as a U-Boot boot command, with an
75 embedded marker for the load address.
76 The marker string, which the caller should replace with the correct
77 load address as 8 hex digits, without changing its length.
78 """
79 replace_me = 'zsHEXYla'
Rhyland Kleinc5c87282012-03-08 16:40:54 -080080 page_size = 4096
Simon Glass0dcbecb2012-03-22 21:38:55 -070081 if boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -080082 page_size = 512
Simon Glass0dcbecb2012-03-22 21:38:55 -070083 if boot_type != 'spi':
Rhyland Kleinc5c87282012-03-08 16:40:54 -080084 update = False
85
Simon Glassa3f29ec2011-07-17 09:36:49 -070086 cmds = [
87 'setenv address 0x%s' % replace_me,
88 'setenv firmware_size %#x' % payload_size,
Rhyland Kleinc5c87282012-03-08 16:40:54 -080089 'setenv length %#x' % RoundUp(payload_size, page_size),
90 'setenv blocks %#x' % (RoundUp(payload_size, page_size) / page_size),
Simon Glass8bd05ec2012-03-22 11:09:04 -070091 'setenv _crc "crc32 -v ${address} ${firmware_size} %#08x"' %
92 checksum,
Simon Glass5b5fd642011-08-17 12:24:01 -070093 'setenv _clear "echo Clearing RAM; mw.b ${address} 0 ${length}"',
Doug Anderson37ae2292011-09-15 17:41:57 -070094 ]
Simon Glass0dcbecb2012-03-22 21:38:55 -070095 if boot_type == 'nand':
Doug Anderson37ae2292011-09-15 17:41:57 -070096 cmds.extend([
97 'setenv _init "echo Init NAND; nand info"',
98 'setenv _erase "echo Erase NAND; nand erase 0 ${length}"',
99 'setenv _write "echo Write NAND; nand write ${address} 0 ${length}"',
100 'setenv _read "echo Read NAND; nand read ${address} 0 ${length}"',
101 ])
Simon Glass0dcbecb2012-03-22 21:38:55 -0700102 elif boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800103 cmds.extend([
104 'setenv _init "echo Init EMMC; mmc rescan 0"',
105 'setenv _erase "echo Erase EMMC; "',
106 'setenv _write "echo Write EMMC; mmc write 0 ${address} 0 ' \
107 '${blocks} boot1"',
108 'setenv _read "echo Read EMMC; mmc read 0 ${address} 0 ' \
109 '${blocks} boot1"',
110 ])
Doug Anderson37ae2292011-09-15 17:41:57 -0700111 else:
112 cmds.extend([
Simon Glass3d9a6c62012-03-15 20:38:04 -0700113 'setenv _init "echo Init SPI; sf probe %s"' % bus,
Doug Anderson37ae2292011-09-15 17:41:57 -0700114 'setenv _erase "echo Erase SPI; sf erase 0 ${length}"',
115 'setenv _write "echo Write SPI; sf write ${address} 0 ${length}"',
116 'setenv _read "echo Read SPI; sf read ${address} 0 ${length}"',
117 'setenv _update "echo Update SPI; sf update ${address} 0 ${length}"',
118 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700119
Doug Anderson37ae2292011-09-15 17:41:57 -0700120 cmds.extend([
Simon Glassa3f29ec2011-07-17 09:36:49 -0700121 'echo Firmware loaded to ${address}, size ${firmware_size}, '
122 'length ${length}',
Simon Glass8bd05ec2012-03-22 11:09:04 -0700123 'if run _crc; then',
Simon Glassa3f29ec2011-07-17 09:36:49 -0700124 'run _init',
Doug Anderson37ae2292011-09-15 17:41:57 -0700125 ])
Simon Glass5b5fd642011-08-17 12:24:01 -0700126 if update:
127 cmds += ['time run _update']
128 else:
129 cmds += ['run _erase', 'run _write']
130 if verify:
131 cmds += [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700132 'run _clear',
133 'run _read',
134 'run _crc',
Simon Glass5b5fd642011-08-17 12:24:01 -0700135 ]
136 else:
137 cmds += ['echo Skipping verify']
Simon Glass8bd05ec2012-03-22 11:09:04 -0700138 cmds.extend([
139 'else',
140 'echo',
141 'echo "** Checksum error on load: please check download tool **"',
142 'fi',
143 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700144 script = '; '.join(cmds)
145 return script, replace_me
146
Simon Glass3d9a6c62012-03-15 20:38:04 -0700147 def PrepareFlasher(self, uboot, payload, update, verify, boot_type, bus):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700148 """Get a flasher ready for sending to the board.
149
150 The flasher is an executable image consisting of:
151
152 - U-Boot (u-boot.bin);
153 - a special FDT to tell it what to do in the form of a run command;
154 - (we could add some empty space here, in case U-Boot is not built to
155 be relocatable);
156 - the payload (which is a full flash image, or signed U-Boot + fdt).
157
158 Args:
159 uboot: Full path to u-boot.bin.
160 payload: Full path to payload.
Simon Glass5b5fd642011-08-17 12:24:01 -0700161 update: Use faster update algorithm rather then full device erase
162 verify: Verify the write by doing a readback and CRC
Simon Glass0dcbecb2012-03-22 21:38:55 -0700163 boot_type: the src for bootdevice (nand, sdmmc, or spi)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700164
165 Returns:
Simon Glass290a1802011-07-17 13:54:32 -0700166 Filename of the flasher binary created.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700167 """
Simon Glass951a2db2011-07-17 15:58:58 -0700168 fdt = self._fdt.Copy(os.path.join(self._tools.outdir, 'flasher.dtb'))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700169 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700170 payload_size = os.stat(payload).st_size
171
Simon Glass8bd05ec2012-03-22 11:09:04 -0700172 # Make sure that the checksum is not negative
173 checksum = binascii.crc32(payload_data) & 0xffffffff
174
175 script, replace_me = self._GetFlashScript(len(payload_data), update,
176 verify, boot_type, checksum, bus)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700177 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800178 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700179 fdt_data = self._tools.ReadFile(fdt.fname)
180
181 # Work out where to place the payload in memory. This is a chicken-and-egg
182 # problem (although in case you haven't heard, it was the chicken that
183 # came first), so we resolve it by replacing the string after
184 # fdt.PutString has done its job.
185 #
186 # Correction: Technically, the egg came first. Whatever genetic mutation
187 # created the new species would have been present in the egg, but not the
188 # parent (since if it was in the parent, it would have been present in the
189 # parent when it was an egg).
190 #
191 # Question: ok so who laid the egg then?
192 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700193
194 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
195 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700196 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700197
Simon Glass2c4b3e52011-11-15 14:45:43 -0800198 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700199 new_str = '%08x' % load_address
200 if len(replace_me) is not len(new_str):
201 raise ValueError("Internal error: replacement string '%s' length does "
202 "not match new string '%s'" % (replace_me, new_str))
203 if len(re.findall(replace_me, fdt_data)) != 1:
204 raise ValueError("Internal error: replacement string '%s' already "
205 "exists in the fdt (%d matches)" % (replace_me, matches))
206 fdt_data = re.sub(replace_me, new_str, fdt_data)
207
208 # Now put it together.
209 data += fdt_data
210 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700211 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700212 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700213 self._tools.WriteFile(flasher, data)
214
215 # Tell the user about a few things.
216 self._tools.OutputSize('U-Boot', uboot)
217 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700218 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700219 self._tools.OutputSize('Flasher', flasher)
220 return flasher
221
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700222 def _NvidiaFlashImage(self, flash_dest, uboot, bct, payload):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700223 """Flash the image to SPI flash.
224
225 This creates a special Flasher binary, with the image to be flashed as
226 a payload. This is then sent to the board using the nvflash utility.
227
228 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700229 flash_dest: Destination for flasher, or None to not create a flasher
230 Valid options are spi, sdmmc
Simon Glassa3f29ec2011-07-17 09:36:49 -0700231 uboot: Full path to u-boot.bin.
232 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
233 payload: Full path to payload.
234
235 Returns:
236 True if ok, False if failed.
237 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800238 # Use a Regex to pull Boot type from BCT file.
239 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
240 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700241
242 # TODO(sjg): The boot type is currently selected by the bct, rather than
243 # flash_dest selecting which bct to use. This is a bit backwards. For now
244 # we go with the bct's idea.
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800245 boot_type = filter(match.match, bct_dumped)
Simon Glass0dcbecb2012-03-22 21:38:55 -0700246 boot_type = match.match(boot_type[0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700247
248 flasher = self.PrepareFlasher(uboot, payload, self.update, self.verify,
Simon Glass3d9a6c62012-03-15 20:38:04 -0700249 boot_type, 0)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700250
251 self._out.Progress('Uploading flasher image')
252 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700253 '--bct', bct,
254 '--setbct',
255 '--bl', flasher,
256 '--go',
Simon Glass2c4b3e52011-11-15 14:45:43 -0800257 '--setentry', "%#x" % self.text_base, "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700258 ]
259
260 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
261 last_err = None
262 for tries in range(10):
263 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700264 # TODO(sjg): Use Chromite library so we can monitor output
Simon Glass86d16aa2012-03-09 15:29:05 -0800265 self._tools.Run('nvflash', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700266 self._out.Notice('Flasher downloaded - please see serial output '
267 'for progress.')
268 return True
269
270 except CmdError as err:
271 if not self._out.stdout_is_tty:
272 return False
273
274 # Only show the error output once unless it changes.
275 err = str(err)
276 if not 'USB device not found' in err:
277 raise CmdError('nvflash failed: %s' % err)
278
279 if err != last_err:
280 self._out.Notice(err)
281 last_err = err
282 self._out.Progress('Please connect USB A-A cable and do a '
283 'recovery-reset', True)
284 time.sleep(1)
285
286 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700287
Simon Glass27a9c142012-03-15 21:08:29 -0700288 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
289 """Wait until we see a device on the USB bus.
290
291 Args:
292 name: Board type name
293 vendor_id: USB vendor ID to look for
294 product_id: USB product ID to look for
295 timeout: Timeout to wait in seconds
296
297 Returns
298 True if the device was found, False if we timed out.
299 """
300 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass3381a1a2012-03-22 11:13:19 -0700301 for tries in range(timeout * 2):
Simon Glass27a9c142012-03-15 21:08:29 -0700302 try:
303 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
304 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700305 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700306 return True
307
308 except CmdError as err:
309 pass
310
Simon Glass3381a1a2012-03-22 11:13:19 -0700311 time.sleep(.5)
Simon Glass27a9c142012-03-15 21:08:29 -0700312
Simon Glass3381a1a2012-03-22 11:13:19 -0700313 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700314
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700315 def _ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload):
Simon Glass27a9c142012-03-15 21:08:29 -0700316 """Flash the image to SPI flash.
317
318 This creates a special Flasher binary, with the image to be flashed as
319 a payload. This is then sent to the board using the nvflash utility.
320
321 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700322 flash_dest: Destination for flasher, or None to not create a flasher
323 Valid options are spi, sdmmc.
324 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700325 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700326 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700327 payload: Full path to payload.
328
329 Returns:
330 True if ok, False if failed.
331 """
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700332 if flash_dest:
333 image = self.PrepareFlasher(flash_uboot, payload, self.update,
334 self.verify, flash_dest, '1:0')
335 else:
336 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
337 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
338 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
339 data = self._tools.ReadFile(payload)
340 self._tools.WriteFile(bl1, data[:0x2000])
341 self._tools.WriteFile(bl2, data[0x2000:0x6000])
342 self._tools.WriteFile(image, data[0x6000:])
Simon Glass27a9c142012-03-15 21:08:29 -0700343
344 vendor_id = 0x04e8
345 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700346
347 self._out.Progress('Reseting board via servo')
348 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.1',
349 'warm_reset:off']
350 # TODO(sjg) If the board is bricked a reset does not seem to bring it
351 # back to life.
352 # BUG=chromium-os:28229
353 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off'] + args
354 self._tools.Run('dut-control', args)
355 time.sleep(2)
Simon Glass27a9c142012-03-15 21:08:29 -0700356
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700357 self._out.Progress('Uploading image')
Simon Glass27a9c142012-03-15 21:08:29 -0700358 download_list = [
359 ['bl1', 0x02021400, bl1],
360 ['bl2', 0x02023400, bl2],
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700361 ['u-boot', 0x43e00000, image]
Simon Glass27a9c142012-03-15 21:08:29 -0700362 ]
Simon Glass3381a1a2012-03-22 11:13:19 -0700363 first = True
364 try:
365 for item in download_list:
366 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
367 if first:
368 raise CmdError('Could not find Exynos board on USB port')
369 raise CmdError("Stage '%s' did not complete" % item[0])
370 args = ['-a', '%#x' % item[1], '-f', item[2]]
371 first = False
372 self._out.Notice(item[2])
Simon Glass27a9c142012-03-15 21:08:29 -0700373 self._out.Progress("Uploading stage '%s'" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700374
375 # TODO(sjg): Remove this delay, once the need for it is understood.
376 time.sleep(1)
Simon Glass27a9c142012-03-15 21:08:29 -0700377 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass27a9c142012-03-15 21:08:29 -0700378
Simon Glass3381a1a2012-03-22 11:13:19 -0700379 finally:
380 args = ['fw_up:off', 'pwr_button:release']
381 self._tools.Run('dut-control', args)
Simon Glass27a9c142012-03-15 21:08:29 -0700382
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700383 self._out.Notice('Image downloaded - please see serial output '
Simon Glass3381a1a2012-03-22 11:13:19 -0700384 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700385 return True
386
387def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700388 text_base=None, update=True, verify=False, dest=None,
389 flash_dest=None):
Simon Glasse0b61442012-03-13 15:29:51 -0700390 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700391
392 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700393 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700394
395 Args:
396 output: cros_output object to use.
397 tools: Tools object to use.
398 fdt: Fdt object to use as our device tree.
399 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700400 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700401 image_fname: Filename of image to write.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800402 text_base: U-Boot text base (base of executable image), None for default.
403 update: Use faster update algorithm rather then full device erase.
404 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700405 dest: Destination device to write firmware to (usb, sd).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700406 flash_dest: Destination device for flasher to program payload into.
Simon Glass710dedc2011-08-09 14:08:52 -0700407 """
408 write = WriteFirmware(tools, fdt, output)
Simon Glass2c4b3e52011-11-15 14:45:43 -0800409 if text_base:
410 write.text_base = text_base
Simon Glass5b5fd642011-08-17 12:24:01 -0700411 write.update = update
412 write.verify = verify
Simon Glasse0b61442012-03-13 15:29:51 -0700413 if dest == 'usb':
414 method = fdt.GetString('/chromeos-config', 'flash-method', 'tegra')
415 if method == 'tegra':
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700416 ok = write._NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
417 image_fname)
Simon Glass27a9c142012-03-15 21:08:29 -0700418 elif method == 'exynos':
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700419 ok = write._ExynosFlashImage(flash_dest, flasher,
420 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname)
Simon Glasse0b61442012-03-13 15:29:51 -0700421 else:
422 raise CmdError("Unknown flash method '%s'" % method)
423 if ok:
424 output.Progress('Image uploaded - please wait for flashing to '
425 'complete')
426 else:
427 raise CmdError('Image upload failed - please check board connection')
428 elif dest == 'sd':
429 pass
Simon Glass710dedc2011-08-09 14:08:52 -0700430 else:
Simon Glasse0b61442012-03-13 15:29:51 -0700431 raise CmdError("Unknown destination device '%s'" % dest)