blob: a0c118d1defd0f59cd67f4e61fc3ee5c134394f7 [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 Glass0191a882012-05-23 13:15:06 -070039 def __init__(self, tools, fdt, output, bundle):
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 Glass0191a882012-05-23 13:15:06 -070046 bundle: A BundleFirmware object which created the image.
Simon Glassa3f29ec2011-07-17 09:36:49 -070047 """
48 self._tools = tools
49 self._fdt = fdt
50 self._out = output
Simon Glass0191a882012-05-23 13:15:06 -070051 self._bundle = bundle
Simon Glass02d124a2012-03-02 14:47:20 -080052 self.text_base = self._fdt.GetInt('/chromeos-config', 'textbase');
Simon Glassa3f29ec2011-07-17 09:36:49 -070053
Simon Glass5b5fd642011-08-17 12:24:01 -070054 # For speed, use the 'update' algorithm and don't verify
55 self.update = True
56 self.verify = False
57
Simon Glass8bd05ec2012-03-22 11:09:04 -070058 def _GetFlashScript(self, payload_size, update, verify, boot_type, checksum,
59 bus='0'):
Simon Glassa3f29ec2011-07-17 09:36:49 -070060 """Get the U-Boot boot command needed to flash U-Boot.
61
62 We leave a marker in the string for the load address of the image,
63 since this depends on the size of this script. This can be replaced by
64 the caller provided that the marker length is unchanged.
65
66 Args:
67 payload_size: Size of payload in bytes.
Simon Glass5b5fd642011-08-17 12:24:01 -070068 update: Use faster update algorithm rather then full device erase
69 verify: Verify the write by doing a readback and CRC
Simon Glass0dcbecb2012-03-22 21:38:55 -070070 boot_type: The source for bootdevice (nand, sdmmc, or spi)
Simon Glass8bd05ec2012-03-22 11:09:04 -070071 checksum: The checksum of the payload (an integer)
72 bus: The bus number
Simon Glassa3f29ec2011-07-17 09:36:49 -070073
74 Returns:
75 A tuple containing:
76 The script, as a string ready to use as a U-Boot boot command, with an
77 embedded marker for the load address.
78 The marker string, which the caller should replace with the correct
79 load address as 8 hex digits, without changing its length.
80 """
81 replace_me = 'zsHEXYla'
Rhyland Kleinc5c87282012-03-08 16:40:54 -080082 page_size = 4096
Simon Glass0dcbecb2012-03-22 21:38:55 -070083 if boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -080084 page_size = 512
Simon Glass0dcbecb2012-03-22 21:38:55 -070085 if boot_type != 'spi':
Rhyland Kleinc5c87282012-03-08 16:40:54 -080086 update = False
87
Simon Glassa3f29ec2011-07-17 09:36:49 -070088 cmds = [
89 'setenv address 0x%s' % replace_me,
90 'setenv firmware_size %#x' % payload_size,
Rhyland Kleinc5c87282012-03-08 16:40:54 -080091 'setenv length %#x' % RoundUp(payload_size, page_size),
92 'setenv blocks %#x' % (RoundUp(payload_size, page_size) / page_size),
Simon Glass8bd05ec2012-03-22 11:09:04 -070093 'setenv _crc "crc32 -v ${address} ${firmware_size} %#08x"' %
94 checksum,
Simon Glass5b5fd642011-08-17 12:24:01 -070095 'setenv _clear "echo Clearing RAM; mw.b ${address} 0 ${length}"',
Doug Anderson37ae2292011-09-15 17:41:57 -070096 ]
Simon Glass0dcbecb2012-03-22 21:38:55 -070097 if boot_type == 'nand':
Doug Anderson37ae2292011-09-15 17:41:57 -070098 cmds.extend([
99 'setenv _init "echo Init NAND; nand info"',
100 'setenv _erase "echo Erase NAND; nand erase 0 ${length}"',
101 'setenv _write "echo Write NAND; nand write ${address} 0 ${length}"',
102 'setenv _read "echo Read NAND; nand read ${address} 0 ${length}"',
103 ])
Simon Glass0dcbecb2012-03-22 21:38:55 -0700104 elif boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800105 cmds.extend([
106 'setenv _init "echo Init EMMC; mmc rescan 0"',
107 'setenv _erase "echo Erase EMMC; "',
108 'setenv _write "echo Write EMMC; mmc write 0 ${address} 0 ' \
109 '${blocks} boot1"',
110 'setenv _read "echo Read EMMC; mmc read 0 ${address} 0 ' \
111 '${blocks} boot1"',
112 ])
Doug Anderson37ae2292011-09-15 17:41:57 -0700113 else:
114 cmds.extend([
Simon Glass3d9a6c62012-03-15 20:38:04 -0700115 'setenv _init "echo Init SPI; sf probe %s"' % bus,
Doug Anderson37ae2292011-09-15 17:41:57 -0700116 'setenv _erase "echo Erase SPI; sf erase 0 ${length}"',
117 'setenv _write "echo Write SPI; sf write ${address} 0 ${length}"',
118 'setenv _read "echo Read SPI; sf read ${address} 0 ${length}"',
119 'setenv _update "echo Update SPI; sf update ${address} 0 ${length}"',
120 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700121
Doug Anderson37ae2292011-09-15 17:41:57 -0700122 cmds.extend([
Simon Glassa3f29ec2011-07-17 09:36:49 -0700123 'echo Firmware loaded to ${address}, size ${firmware_size}, '
124 'length ${length}',
Simon Glass8bd05ec2012-03-22 11:09:04 -0700125 'if run _crc; then',
Simon Glassa3f29ec2011-07-17 09:36:49 -0700126 'run _init',
Doug Anderson37ae2292011-09-15 17:41:57 -0700127 ])
Simon Glass5b5fd642011-08-17 12:24:01 -0700128 if update:
129 cmds += ['time run _update']
130 else:
131 cmds += ['run _erase', 'run _write']
132 if verify:
133 cmds += [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700134 'run _clear',
135 'run _read',
136 'run _crc',
Simon Glass5b5fd642011-08-17 12:24:01 -0700137 ]
138 else:
139 cmds += ['echo Skipping verify']
Simon Glass8bd05ec2012-03-22 11:09:04 -0700140 cmds.extend([
141 'else',
142 'echo',
143 'echo "** Checksum error on load: please check download tool **"',
144 'fi',
145 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700146 script = '; '.join(cmds)
147 return script, replace_me
148
Simon Glass3d9a6c62012-03-15 20:38:04 -0700149 def PrepareFlasher(self, uboot, payload, update, verify, boot_type, bus):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700150 """Get a flasher ready for sending to the board.
151
152 The flasher is an executable image consisting of:
153
154 - U-Boot (u-boot.bin);
155 - a special FDT to tell it what to do in the form of a run command;
156 - (we could add some empty space here, in case U-Boot is not built to
157 be relocatable);
158 - the payload (which is a full flash image, or signed U-Boot + fdt).
159
160 Args:
161 uboot: Full path to u-boot.bin.
162 payload: Full path to payload.
Simon Glass5b5fd642011-08-17 12:24:01 -0700163 update: Use faster update algorithm rather then full device erase
164 verify: Verify the write by doing a readback and CRC
Simon Glass0dcbecb2012-03-22 21:38:55 -0700165 boot_type: the src for bootdevice (nand, sdmmc, or spi)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700166
167 Returns:
Simon Glass290a1802011-07-17 13:54:32 -0700168 Filename of the flasher binary created.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700169 """
Simon Glass951a2db2011-07-17 15:58:58 -0700170 fdt = self._fdt.Copy(os.path.join(self._tools.outdir, 'flasher.dtb'))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700171 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700172 payload_size = os.stat(payload).st_size
173
Simon Glass8bd05ec2012-03-22 11:09:04 -0700174 # Make sure that the checksum is not negative
175 checksum = binascii.crc32(payload_data) & 0xffffffff
176
177 script, replace_me = self._GetFlashScript(len(payload_data), update,
178 verify, boot_type, checksum, bus)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700179 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800180 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700181 fdt_data = self._tools.ReadFile(fdt.fname)
182
183 # Work out where to place the payload in memory. This is a chicken-and-egg
184 # problem (although in case you haven't heard, it was the chicken that
185 # came first), so we resolve it by replacing the string after
186 # fdt.PutString has done its job.
187 #
188 # Correction: Technically, the egg came first. Whatever genetic mutation
189 # created the new species would have been present in the egg, but not the
190 # parent (since if it was in the parent, it would have been present in the
191 # parent when it was an egg).
192 #
193 # Question: ok so who laid the egg then?
194 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700195
196 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
197 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700198 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700199
Simon Glass2c4b3e52011-11-15 14:45:43 -0800200 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700201 new_str = '%08x' % load_address
202 if len(replace_me) is not len(new_str):
203 raise ValueError("Internal error: replacement string '%s' length does "
204 "not match new string '%s'" % (replace_me, new_str))
205 if len(re.findall(replace_me, fdt_data)) != 1:
206 raise ValueError("Internal error: replacement string '%s' already "
207 "exists in the fdt (%d matches)" % (replace_me, matches))
208 fdt_data = re.sub(replace_me, new_str, fdt_data)
209
210 # Now put it together.
211 data += fdt_data
212 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700213 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700214 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700215 self._tools.WriteFile(flasher, data)
216
217 # Tell the user about a few things.
218 self._tools.OutputSize('U-Boot', uboot)
219 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700220 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700221 self._tools.OutputSize('Flasher', flasher)
222 return flasher
223
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700224 def _NvidiaFlashImage(self, flash_dest, uboot, bct, payload):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700225 """Flash the image to SPI flash.
226
227 This creates a special Flasher binary, with the image to be flashed as
228 a payload. This is then sent to the board using the nvflash utility.
229
230 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700231 flash_dest: Destination for flasher, or None to not create a flasher
232 Valid options are spi, sdmmc
Simon Glassa3f29ec2011-07-17 09:36:49 -0700233 uboot: Full path to u-boot.bin.
234 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
235 payload: Full path to payload.
236
237 Returns:
238 True if ok, False if failed.
239 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800240 # Use a Regex to pull Boot type from BCT file.
241 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
242 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700243
244 # TODO(sjg): The boot type is currently selected by the bct, rather than
245 # flash_dest selecting which bct to use. This is a bit backwards. For now
246 # we go with the bct's idea.
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800247 boot_type = filter(match.match, bct_dumped)
Simon Glass0dcbecb2012-03-22 21:38:55 -0700248 boot_type = match.match(boot_type[0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700249
250 flasher = self.PrepareFlasher(uboot, payload, self.update, self.verify,
Simon Glass3d9a6c62012-03-15 20:38:04 -0700251 boot_type, 0)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700252
253 self._out.Progress('Uploading flasher image')
254 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700255 '--bct', bct,
256 '--setbct',
257 '--bl', flasher,
258 '--go',
Simon Glass2c4b3e52011-11-15 14:45:43 -0800259 '--setentry', "%#x" % self.text_base, "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700260 ]
261
262 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
263 last_err = None
264 for tries in range(10):
265 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700266 # TODO(sjg): Use Chromite library so we can monitor output
Simon Glass86d16aa2012-03-09 15:29:05 -0800267 self._tools.Run('nvflash', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700268 self._out.Notice('Flasher downloaded - please see serial output '
269 'for progress.')
270 return True
271
272 except CmdError as err:
273 if not self._out.stdout_is_tty:
274 return False
275
276 # Only show the error output once unless it changes.
277 err = str(err)
278 if not 'USB device not found' in err:
279 raise CmdError('nvflash failed: %s' % err)
280
281 if err != last_err:
282 self._out.Notice(err)
283 last_err = err
284 self._out.Progress('Please connect USB A-A cable and do a '
285 'recovery-reset', True)
286 time.sleep(1)
287
288 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700289
Simon Glass27a9c142012-03-15 21:08:29 -0700290 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
291 """Wait until we see a device on the USB bus.
292
293 Args:
294 name: Board type name
295 vendor_id: USB vendor ID to look for
296 product_id: USB product ID to look for
297 timeout: Timeout to wait in seconds
298
299 Returns
300 True if the device was found, False if we timed out.
301 """
302 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass3381a1a2012-03-22 11:13:19 -0700303 for tries in range(timeout * 2):
Simon Glass27a9c142012-03-15 21:08:29 -0700304 try:
305 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
306 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700307 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700308 return True
309
310 except CmdError as err:
311 pass
312
Simon Glass3381a1a2012-03-22 11:13:19 -0700313 time.sleep(.5)
Simon Glass27a9c142012-03-15 21:08:29 -0700314
Simon Glass3381a1a2012-03-22 11:13:19 -0700315 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700316
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700317 def _ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload):
Simon Glass27a9c142012-03-15 21:08:29 -0700318 """Flash the image to SPI flash.
319
320 This creates a special Flasher binary, with the image to be flashed as
321 a payload. This is then sent to the board using the nvflash utility.
322
323 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700324 flash_dest: Destination for flasher, or None to not create a flasher
325 Valid options are spi, sdmmc.
326 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700327 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700328 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700329 payload: Full path to payload.
330
331 Returns:
332 True if ok, False if failed.
333 """
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700334 if flash_dest:
335 image = self.PrepareFlasher(flash_uboot, payload, self.update,
336 self.verify, flash_dest, '1:0')
337 else:
338 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
339 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
340 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
341 data = self._tools.ReadFile(payload)
342 self._tools.WriteFile(bl1, data[:0x2000])
343 self._tools.WriteFile(bl2, data[0x2000:0x6000])
344 self._tools.WriteFile(image, data[0x6000:])
Simon Glass27a9c142012-03-15 21:08:29 -0700345
346 vendor_id = 0x04e8
347 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700348
349 self._out.Progress('Reseting board via servo')
350 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.1',
351 'warm_reset:off']
352 # TODO(sjg) If the board is bricked a reset does not seem to bring it
353 # back to life.
354 # BUG=chromium-os:28229
355 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off'] + args
356 self._tools.Run('dut-control', args)
357 time.sleep(2)
Simon Glass27a9c142012-03-15 21:08:29 -0700358
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700359 self._out.Progress('Uploading image')
Simon Glass27a9c142012-03-15 21:08:29 -0700360 download_list = [
361 ['bl1', 0x02021400, bl1],
362 ['bl2', 0x02023400, bl2],
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700363 ['u-boot', 0x43e00000, image]
Simon Glass27a9c142012-03-15 21:08:29 -0700364 ]
Simon Glass3381a1a2012-03-22 11:13:19 -0700365 first = True
366 try:
367 for item in download_list:
368 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
369 if first:
370 raise CmdError('Could not find Exynos board on USB port')
371 raise CmdError("Stage '%s' did not complete" % item[0])
372 args = ['-a', '%#x' % item[1], '-f', item[2]]
373 first = False
374 self._out.Notice(item[2])
Simon Glass27a9c142012-03-15 21:08:29 -0700375 self._out.Progress("Uploading stage '%s'" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700376
377 # TODO(sjg): Remove this delay, once the need for it is understood.
378 time.sleep(1)
Simon Glass27a9c142012-03-15 21:08:29 -0700379 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass27a9c142012-03-15 21:08:29 -0700380
Simon Glass3381a1a2012-03-22 11:13:19 -0700381 finally:
382 args = ['fw_up:off', 'pwr_button:release']
383 self._tools.Run('dut-control', args)
Simon Glass27a9c142012-03-15 21:08:29 -0700384
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700385 self._out.Notice('Image downloaded - please see serial output '
Simon Glass3381a1a2012-03-22 11:13:19 -0700386 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700387 return True
388
Simon Glass0c2ba482012-03-22 21:57:51 -0700389 def _GetDiskInfo(self, disk, item):
390 """Returns information about a SCSI disk device.
391
392 Args:
393 disk: a block device name in sys/block, like '/sys/block/sdf'.
394 item: the item of disk information that is required.
395
396 Returns:
397 The information obtained, as a string, or '[Unknown]' if not found
398 """
399 dev_path = os.path.join(disk, 'device')
400
401 # Search upwards and through symlinks looking for the item.
402 while os.path.isdir(dev_path) and dev_path != '/sys':
403 fname = os.path.join(dev_path, item)
404 if os.path.exists(fname):
405 with open(fname, 'r') as fd:
406 return fd.readline().rstrip()
407
408 # Move up a level and follow any symlink.
409 new_path = os.path.join(dev_path, '..')
410 if os.path.islink(new_path):
411 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
412 dev_path = new_path
413 return '[Unknown]'
414
415 def _GetDiskCapacity(self, device):
416 """Returns the disk capacity in GB, or 0 if not known.
417
418 Args:
419 device: Device to check, like '/dev/sdf'.
420
421 Returns:
422 Capacity of device in GB, or 0 if not known.
423 """
424 args = ['-l', device]
425 stdout = self._tools.Run('fdisk', args, sudo=True)
426 if stdout:
427 # Seach for the line with capacity information.
428 re_capacity = re.compile('Disk .*: (\d+) \w+,')
429 lines = filter(re_capacity.match, stdout.splitlines())
430 if len(lines):
431 m = re_capacity.match(lines[0])
432
433 # We get something like 7859 MB, so turn into bytes, then GB
434 return int(m.group(1)) * 1024 * 1024 / 1e9
435 return 0
436
437 def _ListUsbDisks(self):
438 """Return a list of available removable USB disks.
439
440 Returns:
441 List of USB devices, each element is itself a list containing:
442 device ('/dev/sdx')
443 manufacturer name
444 product name
445 capacity in GB (an integer)
446 full description (all of the above concatenated).
447 """
448 disk_list = []
449 for disk in glob.glob('/sys/block/sd*'):
450 with open(disk + '/removable', 'r') as fd:
451 if int(fd.readline()) == 1:
452 device = '/dev/%s' % disk.split('/')[-1]
453 manuf = self._GetDiskInfo(disk, 'manufacturer')
454 product = self._GetDiskInfo(disk, 'product')
455 capacity = self._GetDiskCapacity(device)
456 if capacity:
457 desc = '%s: %s %s %d GB' % (device, manuf, product, capacity)
458 disk_list.append([device, manuf, product, capacity, desc])
459 return disk_list
460
461 def WriteToSd(self, flash_dest, disk, uboot, payload):
462 if flash_dest:
463 image = self.PrepareFlasher(uboot, payload, self.update, self.verify,
464 flash_dest, '1:0')
465 self._out.Progress('Writing flasher to %s' % disk)
466 else:
467 image = payload
468 self._out.Progress('Writing image to %s' % disk)
469
470 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
471 self._tools.Run('dd', args, sudo=True)
472
473 def SendToSdCard(self, dest, flash_dest, uboot, payload):
474 """Write a flasher to an SD card.
475
476 Args:
477 dest: Destination in one of these forms:
478 ':<full description of device>'
479 ':.' selects the only available device, fails if more than one option
480 ':<device>' select deivce
481
482 Examples:
483 ':/dev/sdd: Generic Flash Card Reader/Writer 8 GB'
484 ':.'
485 ':/dev/sdd'
486
487 flash_dest: Destination for flasher, or None to not create a flasher:
488 Valid options are spi, sdmmc.
489 uboot: Full path to u-boot.bin.
490 payload: Full path to payload.
491 """
492 disk = None
493 disks = self._ListUsbDisks()
494 if dest[:1] == ':':
495 name = dest[1:]
496
497 # A '.' just means to use the only available disk.
498 if name == '.' and len(disks) == 1:
499 disk = disks[0][0]
500 for disk_info in disks:
501 # Use the full name or the device name.
502 if disk_info[4] == name or disk_info[1] == name:
503 disk = disk_info[0]
504
505 if disk:
506 self.WriteToSd(flash_dest, disk, uboot, payload)
507 else:
508 self._out.Error("Please specify destination -w 'sd:<disk_description>':")
509 self._out.Error(' - description can be . for the only disk, SCSI '
510 'device letter')
511 self._out.Error(' or the full description listed here')
512 msg = 'Found %d available disks.' % len(disks)
513 if not disks:
514 msg += ' Please insert an SD card and try again.'
515 self._out.UserOutput(msg)
516
517 # List available disks as a convenience.
518 for disk in disks:
519 self._out.UserOutput(' %s' % disk[4])
520
521
Simon Glass27a9c142012-03-15 21:08:29 -0700522def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass0191a882012-05-23 13:15:06 -0700523 bundle, text_base=None, update=True, verify=False,
524 dest=None, flash_dest=None):
Simon Glasse0b61442012-03-13 15:29:51 -0700525 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700526
527 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700528 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700529
530 Args:
531 output: cros_output object to use.
532 tools: Tools object to use.
533 fdt: Fdt object to use as our device tree.
534 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700535 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700536 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700537 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800538 text_base: U-Boot text base (base of executable image), None for default.
539 update: Use faster update algorithm rather then full device erase.
540 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700541 dest: Destination device to write firmware to (usb, sd).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700542 flash_dest: Destination device for flasher to program payload into.
Simon Glass710dedc2011-08-09 14:08:52 -0700543 """
Simon Glass0191a882012-05-23 13:15:06 -0700544 write = WriteFirmware(tools, fdt, output, bundle)
Simon Glass2c4b3e52011-11-15 14:45:43 -0800545 if text_base:
546 write.text_base = text_base
Simon Glass5b5fd642011-08-17 12:24:01 -0700547 write.update = update
548 write.verify = verify
Simon Glasse0b61442012-03-13 15:29:51 -0700549 if dest == 'usb':
550 method = fdt.GetString('/chromeos-config', 'flash-method', 'tegra')
551 if method == 'tegra':
Simon Glass2c389062012-04-09 13:09:01 -0700552 tools.CheckTool('nvflash')
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700553 ok = write._NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
554 image_fname)
Simon Glass27a9c142012-03-15 21:08:29 -0700555 elif method == 'exynos':
Simon Glass2c389062012-04-09 13:09:01 -0700556 tools.CheckTool('lsusb', 'usbutils')
557 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700558 ok = write._ExynosFlashImage(flash_dest, flasher,
559 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname)
Simon Glasse0b61442012-03-13 15:29:51 -0700560 else:
561 raise CmdError("Unknown flash method '%s'" % method)
562 if ok:
563 output.Progress('Image uploaded - please wait for flashing to '
564 'complete')
565 else:
566 raise CmdError('Image upload failed - please check board connection')
Simon Glass0c2ba482012-03-22 21:57:51 -0700567 elif dest.startswith('sd'):
568 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -0700569 else:
Simon Glasse0b61442012-03-13 15:29:51 -0700570 raise CmdError("Unknown destination device '%s'" % dest)