blob: c721a3a09f74ff2772d6d46e9f938756e993c571 [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
Simon Glass0c2ba482012-03-22 21:57:51 -0700387 def _GetDiskInfo(self, disk, item):
388 """Returns information about a SCSI disk device.
389
390 Args:
391 disk: a block device name in sys/block, like '/sys/block/sdf'.
392 item: the item of disk information that is required.
393
394 Returns:
395 The information obtained, as a string, or '[Unknown]' if not found
396 """
397 dev_path = os.path.join(disk, 'device')
398
399 # Search upwards and through symlinks looking for the item.
400 while os.path.isdir(dev_path) and dev_path != '/sys':
401 fname = os.path.join(dev_path, item)
402 if os.path.exists(fname):
403 with open(fname, 'r') as fd:
404 return fd.readline().rstrip()
405
406 # Move up a level and follow any symlink.
407 new_path = os.path.join(dev_path, '..')
408 if os.path.islink(new_path):
409 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
410 dev_path = new_path
411 return '[Unknown]'
412
413 def _GetDiskCapacity(self, device):
414 """Returns the disk capacity in GB, or 0 if not known.
415
416 Args:
417 device: Device to check, like '/dev/sdf'.
418
419 Returns:
420 Capacity of device in GB, or 0 if not known.
421 """
422 args = ['-l', device]
423 stdout = self._tools.Run('fdisk', args, sudo=True)
424 if stdout:
425 # Seach for the line with capacity information.
426 re_capacity = re.compile('Disk .*: (\d+) \w+,')
427 lines = filter(re_capacity.match, stdout.splitlines())
428 if len(lines):
429 m = re_capacity.match(lines[0])
430
431 # We get something like 7859 MB, so turn into bytes, then GB
432 return int(m.group(1)) * 1024 * 1024 / 1e9
433 return 0
434
435 def _ListUsbDisks(self):
436 """Return a list of available removable USB disks.
437
438 Returns:
439 List of USB devices, each element is itself a list containing:
440 device ('/dev/sdx')
441 manufacturer name
442 product name
443 capacity in GB (an integer)
444 full description (all of the above concatenated).
445 """
446 disk_list = []
447 for disk in glob.glob('/sys/block/sd*'):
448 with open(disk + '/removable', 'r') as fd:
449 if int(fd.readline()) == 1:
450 device = '/dev/%s' % disk.split('/')[-1]
451 manuf = self._GetDiskInfo(disk, 'manufacturer')
452 product = self._GetDiskInfo(disk, 'product')
453 capacity = self._GetDiskCapacity(device)
454 if capacity:
455 desc = '%s: %s %s %d GB' % (device, manuf, product, capacity)
456 disk_list.append([device, manuf, product, capacity, desc])
457 return disk_list
458
459 def WriteToSd(self, flash_dest, disk, uboot, payload):
460 if flash_dest:
461 image = self.PrepareFlasher(uboot, payload, self.update, self.verify,
462 flash_dest, '1:0')
463 self._out.Progress('Writing flasher to %s' % disk)
464 else:
465 image = payload
466 self._out.Progress('Writing image to %s' % disk)
467
468 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
469 self._tools.Run('dd', args, sudo=True)
470
471 def SendToSdCard(self, dest, flash_dest, uboot, payload):
472 """Write a flasher to an SD card.
473
474 Args:
475 dest: Destination in one of these forms:
476 ':<full description of device>'
477 ':.' selects the only available device, fails if more than one option
478 ':<device>' select deivce
479
480 Examples:
481 ':/dev/sdd: Generic Flash Card Reader/Writer 8 GB'
482 ':.'
483 ':/dev/sdd'
484
485 flash_dest: Destination for flasher, or None to not create a flasher:
486 Valid options are spi, sdmmc.
487 uboot: Full path to u-boot.bin.
488 payload: Full path to payload.
489 """
490 disk = None
491 disks = self._ListUsbDisks()
492 if dest[:1] == ':':
493 name = dest[1:]
494
495 # A '.' just means to use the only available disk.
496 if name == '.' and len(disks) == 1:
497 disk = disks[0][0]
498 for disk_info in disks:
499 # Use the full name or the device name.
500 if disk_info[4] == name or disk_info[1] == name:
501 disk = disk_info[0]
502
503 if disk:
504 self.WriteToSd(flash_dest, disk, uboot, payload)
505 else:
506 self._out.Error("Please specify destination -w 'sd:<disk_description>':")
507 self._out.Error(' - description can be . for the only disk, SCSI '
508 'device letter')
509 self._out.Error(' or the full description listed here')
510 msg = 'Found %d available disks.' % len(disks)
511 if not disks:
512 msg += ' Please insert an SD card and try again.'
513 self._out.UserOutput(msg)
514
515 # List available disks as a convenience.
516 for disk in disks:
517 self._out.UserOutput(' %s' % disk[4])
518
519
Simon Glass27a9c142012-03-15 21:08:29 -0700520def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700521 text_base=None, update=True, verify=False, dest=None,
522 flash_dest=None):
Simon Glasse0b61442012-03-13 15:29:51 -0700523 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700524
525 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700526 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700527
528 Args:
529 output: cros_output object to use.
530 tools: Tools object to use.
531 fdt: Fdt object to use as our device tree.
532 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700533 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700534 image_fname: Filename of image to write.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800535 text_base: U-Boot text base (base of executable image), None for default.
536 update: Use faster update algorithm rather then full device erase.
537 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700538 dest: Destination device to write firmware to (usb, sd).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700539 flash_dest: Destination device for flasher to program payload into.
Simon Glass710dedc2011-08-09 14:08:52 -0700540 """
541 write = WriteFirmware(tools, fdt, output)
Simon Glass2c4b3e52011-11-15 14:45:43 -0800542 if text_base:
543 write.text_base = text_base
Simon Glass5b5fd642011-08-17 12:24:01 -0700544 write.update = update
545 write.verify = verify
Simon Glasse0b61442012-03-13 15:29:51 -0700546 if dest == 'usb':
547 method = fdt.GetString('/chromeos-config', 'flash-method', 'tegra')
548 if method == 'tegra':
Simon Glass2c389062012-04-09 13:09:01 -0700549 tools.CheckTool('nvflash')
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700550 ok = write._NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
551 image_fname)
Simon Glass27a9c142012-03-15 21:08:29 -0700552 elif method == 'exynos':
Simon Glass2c389062012-04-09 13:09:01 -0700553 tools.CheckTool('lsusb', 'usbutils')
554 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700555 ok = write._ExynosFlashImage(flash_dest, flasher,
556 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname)
Simon Glasse0b61442012-03-13 15:29:51 -0700557 else:
558 raise CmdError("Unknown flash method '%s'" % method)
559 if ok:
560 output.Progress('Image uploaded - please wait for flashing to '
561 'complete')
562 else:
563 raise CmdError('Image upload failed - please check board connection')
Simon Glass0c2ba482012-03-22 21:57:51 -0700564 elif dest.startswith('sd'):
565 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -0700566 else:
Simon Glasse0b61442012-03-13 15:29:51 -0700567 raise CmdError("Unknown destination device '%s'" % dest)