blob: 3b205f416a4ec13948804f3fb177712516205ead [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
Simon Glasse86f3132013-01-08 16:10:43 -08009import struct
Simon Glassa3f29ec2011-07-17 09:36:49 -070010import time
Simon Glassa3f29ec2011-07-17 09:36:49 -070011from 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.
Simon Glass6a616c12012-09-24 18:13:46 -070038
39 Private attributes:
40 _servo_port: Port number to use to talk to servo with dut-control.
41 Special values are:
42 None: servo is not available.
43 0: any servo will do.
44
Simon Glassa3f29ec2011-07-17 09:36:49 -070045 """
Vadim Bendebury2b719452013-02-12 17:00:06 -080046
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080047 _DOWNLOAD_FAILURE_MESSAGE = '** Load checksum error: check download tool **'
48 _SKIP_VERIFY_MESSAGE = 'Skipping verify'
Vadim Bendebury2b719452013-02-12 17:00:06 -080049 _WRITE_FAILURE_MESSAGE = '** Readback checksum error, programming failed!! **'
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080050 _WRITE_SUCCESS_MESSAGE = 'Image Programmed Successfully'
Vadim Bendebury2b719452013-02-12 17:00:06 -080051
52 def __init__(self, tools, fdt, output, bundle, update, verify):
Simon Glassa3f29ec2011-07-17 09:36:49 -070053 """Set up a new WriteFirmware object.
54
55 Args:
56 tools: A tools library for us to use.
57 fdt: An fdt which gives us some info that we need.
58 output: An output object to use for printing progress and messages.
Simon Glass0191a882012-05-23 13:15:06 -070059 bundle: A BundleFirmware object which created the image.
Vadim Bendebury2b719452013-02-12 17:00:06 -080060 update: Use faster update algorithm rather then full device erase.
61 verify: Verify the write by doing a readback and CRC.
Simon Glassa3f29ec2011-07-17 09:36:49 -070062 """
63 self._tools = tools
64 self._fdt = fdt
65 self._out = output
Simon Glass0191a882012-05-23 13:15:06 -070066 self._bundle = bundle
Vadim Bendebury19a77122013-01-24 17:38:00 -080067 self.text_base = self._fdt.GetInt('/chromeos-config', 'textbase', -1)
Simon Glassa3f29ec2011-07-17 09:36:49 -070068
Simon Glass5b5fd642011-08-17 12:24:01 -070069 # For speed, use the 'update' algorithm and don't verify
Vadim Bendebury2b719452013-02-12 17:00:06 -080070 self.update = update
71 self.verify = verify
Simon Glass5b5fd642011-08-17 12:24:01 -070072
Simon Glass6a616c12012-09-24 18:13:46 -070073 # Use default servo port
74 self._servo_port = 0
75
76 def SelectServo(self, servo):
77 """Select the servo to use for writing firmware.
78
79 Args:
80 servo: String containing description of servo to use:
81 'none' : Don't use servo, generate an error on any attempt.
82 'any' : Use any available servo.
83 '<port>': Use servo with that port number.
84 """
85 if servo == 'none':
86 self._servo_port = None
87 elif servo == 'any':
88 self._servo_port = 0
89 else:
90 self._servo_port = int(servo)
91 self._out.Notice('Servo port %s' % str(self._servo_port))
92
Vadim Bendebury2b719452013-02-12 17:00:06 -080093 def _GetFlashScript(self, payload_size, boot_type, checksum, bus='0'):
Simon Glassa3f29ec2011-07-17 09:36:49 -070094 """Get the U-Boot boot command needed to flash U-Boot.
95
96 We leave a marker in the string for the load address of the image,
97 since this depends on the size of this script. This can be replaced by
98 the caller provided that the marker length is unchanged.
99
100 Args:
101 payload_size: Size of payload in bytes.
Simon Glass0dcbecb2012-03-22 21:38:55 -0700102 boot_type: The source for bootdevice (nand, sdmmc, or spi)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700103 checksum: The checksum of the payload (an integer)
104 bus: The bus number
Simon Glassa3f29ec2011-07-17 09:36:49 -0700105
106 Returns:
107 A tuple containing:
108 The script, as a string ready to use as a U-Boot boot command, with an
109 embedded marker for the load address.
110 The marker string, which the caller should replace with the correct
111 load address as 8 hex digits, without changing its length.
112 """
113 replace_me = 'zsHEXYla'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800114 page_size = 4096
Simon Glass0dcbecb2012-03-22 21:38:55 -0700115 if boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800116 page_size = 512
Vadim Bendebury2b719452013-02-12 17:00:06 -0800117 update = self.update and boot_type == 'spi'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800118
Simon Glassa3f29ec2011-07-17 09:36:49 -0700119 cmds = [
120 'setenv address 0x%s' % replace_me,
121 'setenv firmware_size %#x' % payload_size,
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800122 'setenv length %#x' % RoundUp(payload_size, page_size),
123 'setenv blocks %#x' % (RoundUp(payload_size, page_size) / page_size),
Simon Glass5b51b472013-03-28 13:06:05 -0700124 'setenv _crc "crc32 -v ${address} ${firmware_size} %08x"' %
Simon Glass8bd05ec2012-03-22 11:09:04 -0700125 checksum,
Simon Glass5b5fd642011-08-17 12:24:01 -0700126 'setenv _clear "echo Clearing RAM; mw.b ${address} 0 ${length}"',
Doug Anderson37ae2292011-09-15 17:41:57 -0700127 ]
Simon Glass0dcbecb2012-03-22 21:38:55 -0700128 if boot_type == 'nand':
Doug Anderson37ae2292011-09-15 17:41:57 -0700129 cmds.extend([
130 'setenv _init "echo Init NAND; nand info"',
131 'setenv _erase "echo Erase NAND; nand erase 0 ${length}"',
132 'setenv _write "echo Write NAND; nand write ${address} 0 ${length}"',
133 'setenv _read "echo Read NAND; nand read ${address} 0 ${length}"',
134 ])
Simon Glass0dcbecb2012-03-22 21:38:55 -0700135 elif boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800136 cmds.extend([
Allen Martinc4e25b42013-04-05 17:05:39 -0700137 'setenv _init "echo Init EMMC; mmc rescan 0"',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800138 'setenv _erase "echo Erase EMMC; "',
Allen Martinc4e25b42013-04-05 17:05:39 -0700139 'setenv _write "echo Write EMMC; mmc open 0 1;' \
140 ' mmc write ${address} 0 ' \
141 '${blocks};' \
142 ' mmc close 0 1"',
143 'setenv _read "echo Read EMMC; mmc open 0 1;' \
144 ' mmc read ${address} 0 ' \
145 '${blocks};' \
146 ' mmc close 0 1"',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800147 ])
Doug Anderson37ae2292011-09-15 17:41:57 -0700148 else:
149 cmds.extend([
Simon Glass3d9a6c62012-03-15 20:38:04 -0700150 'setenv _init "echo Init SPI; sf probe %s"' % bus,
Doug Anderson37ae2292011-09-15 17:41:57 -0700151 'setenv _erase "echo Erase SPI; sf erase 0 ${length}"',
152 'setenv _write "echo Write SPI; sf write ${address} 0 ${length}"',
153 'setenv _read "echo Read SPI; sf read ${address} 0 ${length}"',
154 'setenv _update "echo Update SPI; sf update ${address} 0 ${length}"',
155 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700156
Doug Anderson37ae2292011-09-15 17:41:57 -0700157 cmds.extend([
Simon Glassa3f29ec2011-07-17 09:36:49 -0700158 'echo Firmware loaded to ${address}, size ${firmware_size}, '
159 'length ${length}',
Simon Glass8bd05ec2012-03-22 11:09:04 -0700160 'if run _crc; then',
Simon Glassa3f29ec2011-07-17 09:36:49 -0700161 'run _init',
Doug Anderson37ae2292011-09-15 17:41:57 -0700162 ])
Simon Glass5b5fd642011-08-17 12:24:01 -0700163 if update:
164 cmds += ['time run _update']
165 else:
166 cmds += ['run _erase', 'run _write']
Vadim Bendebury2b719452013-02-12 17:00:06 -0800167 if self.verify:
Simon Glass5b5fd642011-08-17 12:24:01 -0700168 cmds += [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700169 'run _clear',
170 'run _read',
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800171 'if run _crc; then',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800172 'echo "%s"' % self._WRITE_SUCCESS_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800173 'else',
174 'echo',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800175 'echo "%s"' % self._WRITE_FAILURE_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800176 'echo',
177 'fi',
Simon Glass5b5fd642011-08-17 12:24:01 -0700178 ]
179 else:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800180 cmds += ['echo %s' % self._SKIP_VERIFY_MESSAGE]
Simon Glass8bd05ec2012-03-22 11:09:04 -0700181 cmds.extend([
182 'else',
183 'echo',
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800184 'echo "%s"' % self._DOWNLOAD_FAILURE_MESSAGE,
Simon Glass8bd05ec2012-03-22 11:09:04 -0700185 'fi',
186 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700187 script = '; '.join(cmds)
188 return script, replace_me
189
Vadim Bendebury2b719452013-02-12 17:00:06 -0800190 def _PrepareFlasher(self, uboot, payload, boot_type, bus):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700191 """Get a flasher ready for sending to the board.
192
193 The flasher is an executable image consisting of:
194
195 - U-Boot (u-boot.bin);
196 - a special FDT to tell it what to do in the form of a run command;
197 - (we could add some empty space here, in case U-Boot is not built to
198 be relocatable);
199 - the payload (which is a full flash image, or signed U-Boot + fdt).
200
201 Args:
202 uboot: Full path to u-boot.bin.
203 payload: Full path to payload.
Simon Glass0dcbecb2012-03-22 21:38:55 -0700204 boot_type: the src for bootdevice (nand, sdmmc, or spi)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700205
206 Returns:
Simon Glass290a1802011-07-17 13:54:32 -0700207 Filename of the flasher binary created.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700208 """
Simon Glass951a2db2011-07-17 15:58:58 -0700209 fdt = self._fdt.Copy(os.path.join(self._tools.outdir, 'flasher.dtb'))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700210 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700211
Simon Glass8bd05ec2012-03-22 11:09:04 -0700212 # Make sure that the checksum is not negative
213 checksum = binascii.crc32(payload_data) & 0xffffffff
214
Vadim Bendebury2b719452013-02-12 17:00:06 -0800215 script, replace_me = self._GetFlashScript(len(payload_data), boot_type,
216 checksum, bus)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700217 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800218 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700219 fdt_data = self._tools.ReadFile(fdt.fname)
220
221 # Work out where to place the payload in memory. This is a chicken-and-egg
222 # problem (although in case you haven't heard, it was the chicken that
223 # came first), so we resolve it by replacing the string after
224 # fdt.PutString has done its job.
225 #
226 # Correction: Technically, the egg came first. Whatever genetic mutation
227 # created the new species would have been present in the egg, but not the
228 # parent (since if it was in the parent, it would have been present in the
229 # parent when it was an egg).
230 #
231 # Question: ok so who laid the egg then?
232 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700233
234 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
235 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700236 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700237
Simon Glass2c4b3e52011-11-15 14:45:43 -0800238 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700239 new_str = '%08x' % load_address
240 if len(replace_me) is not len(new_str):
241 raise ValueError("Internal error: replacement string '%s' length does "
242 "not match new string '%s'" % (replace_me, new_str))
Vadim Bendebury19a77122013-01-24 17:38:00 -0800243 matches = len(re.findall(replace_me, fdt_data))
244 if matches != 1:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700245 raise ValueError("Internal error: replacement string '%s' already "
246 "exists in the fdt (%d matches)" % (replace_me, matches))
247 fdt_data = re.sub(replace_me, new_str, fdt_data)
248
249 # Now put it together.
250 data += fdt_data
251 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700252 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700253 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700254 self._tools.WriteFile(flasher, data)
255
256 # Tell the user about a few things.
257 self._tools.OutputSize('U-Boot', uboot)
258 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700259 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700260 self._tools.OutputSize('Flasher', flasher)
261 return flasher
262
Vadim Bendebury19a77122013-01-24 17:38:00 -0800263 def NvidiaFlashImage(self, flash_dest, uboot, bct, payload, bootstub):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700264 """Flash the image to SPI flash.
265
266 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000267 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700268
269 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700270 flash_dest: Destination for flasher, or None to not create a flasher
271 Valid options are spi, sdmmc
Simon Glassa3f29ec2011-07-17 09:36:49 -0700272 uboot: Full path to u-boot.bin.
273 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
274 payload: Full path to payload.
Simon Glass89ecf712012-06-07 12:20:15 -0700275 bootstub: Full path to bootstub, which is the payload without the
276 signing information (i.e. bootstub is u-boot.bin + the FDT)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700277
278 Returns:
279 True if ok, False if failed.
280 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800281 # Use a Regex to pull Boot type from BCT file.
282 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
283 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700284
285 # TODO(sjg): The boot type is currently selected by the bct, rather than
286 # flash_dest selecting which bct to use. This is a bit backwards. For now
287 # we go with the bct's idea.
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800288 boot_type = filter(match.match, bct_dumped)
Simon Glass0dcbecb2012-03-22 21:38:55 -0700289 boot_type = match.match(boot_type[0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700290
Simon Glass89ecf712012-06-07 12:20:15 -0700291 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800292 image = self._PrepareFlasher(uboot, payload, boot_type, 0)
Simon Glasse1824db2012-07-11 17:38:40 +0200293 elif bootstub:
Simon Glass89ecf712012-06-07 12:20:15 -0700294 image = bootstub
Simon Glassa3f29ec2011-07-17 09:36:49 -0700295
Simon Glasse1824db2012-07-11 17:38:40 +0200296 else:
297 image = payload
298 # If we don't know the textbase, extract it from the payload.
299 if self.text_base == -1:
300 data = self._tools.ReadFile(payload)
301 # Skip the BCT which is the first 64KB
302 self.text_base = self._bundle.DecodeTextBase(data[0x10000:])
303
Simon Glass89ecf712012-06-07 12:20:15 -0700304 self._out.Notice('TEXT_BASE is %#x' % self.text_base)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700305 self._out.Progress('Uploading flasher image')
306 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700307 '--bct', bct,
Allen Martinb3aa2672012-03-23 15:55:25 +0000308 '--bootloader', image,
309 '--loadaddr', "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700310 ]
311
312 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
313 last_err = None
Vadim Bendebury19a77122013-01-24 17:38:00 -0800314 for _ in range(10):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700315 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700316 # TODO(sjg): Use Chromite library so we can monitor output
Allen Martinb3aa2672012-03-23 15:55:25 +0000317 self._tools.Run('tegrarcm', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700318 self._out.Notice('Flasher downloaded - please see serial output '
319 'for progress.')
320 return True
321
322 except CmdError as err:
323 if not self._out.stdout_is_tty:
324 return False
325
326 # Only show the error output once unless it changes.
327 err = str(err)
Simon Glass22190ff2012-07-11 14:52:26 +0200328 if not 'could not open USB device' in err:
Allen Martinb3aa2672012-03-23 15:55:25 +0000329 raise CmdError('tegrarcm failed: %s' % err)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700330
331 if err != last_err:
332 self._out.Notice(err)
333 last_err = err
334 self._out.Progress('Please connect USB A-A cable and do a '
335 'recovery-reset', True)
336 time.sleep(1)
337
338 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700339
Simon Glass27a9c142012-03-15 21:08:29 -0700340 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
341 """Wait until we see a device on the USB bus.
342
343 Args:
344 name: Board type name
345 vendor_id: USB vendor ID to look for
346 product_id: USB product ID to look for
347 timeout: Timeout to wait in seconds
348
349 Returns
350 True if the device was found, False if we timed out.
351 """
352 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass4968a472012-05-23 13:52:19 -0700353 start_time = time.time()
354 while time.time() - start_time < timeout:
Simon Glass27a9c142012-03-15 21:08:29 -0700355 try:
356 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
357 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700358 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700359 return True
360
Vadim Bendebury19a77122013-01-24 17:38:00 -0800361 except CmdError:
Simon Glass27a9c142012-03-15 21:08:29 -0700362 pass
363
Simon Glass3381a1a2012-03-22 11:13:19 -0700364 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700365
Vadim Bendebury2b719452013-02-12 17:00:06 -0800366 def DutControl(self, args):
Simon Glass6a616c12012-09-24 18:13:46 -0700367 """Run dut-control with supplied arguments.
368
Simon Glass2065a742013-02-09 13:39:26 -0800369 The correct servo will be used based on self._servo_port. If servo use is
370 disabled, this function does nothing.
Simon Glass6a616c12012-09-24 18:13:46 -0700371
372 Args:
373 args: List of arguments to dut-control.
374
Simon Glass2065a742013-02-09 13:39:26 -0800375 Returns:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800376 a string, stdout generated by running the command
Simon Glass6a616c12012-09-24 18:13:46 -0700377 """
378 if self._servo_port is None:
Simon Glass2065a742013-02-09 13:39:26 -0800379 return '' # User has requested not to use servo
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800380 if self._servo_port:
Simon Glass6a616c12012-09-24 18:13:46 -0700381 args.extend(['-p', '%s' % self._servo_port])
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800382 return self._tools.Run('dut-control', args)
Simon Glass6a616c12012-09-24 18:13:46 -0700383
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800384 def WaitForCompletion(self):
Vadim Bendebury2b719452013-02-12 17:00:06 -0800385 """Verify flash programming operation success.
386
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800387 The DUT is presumed to be programming flash with console capture mode on.
388 This function scans console output for the success or failure strings.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800389
390 Raises:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800391 CmdError if the following cases:
392 - none of the strings show up in the allotted time (2 minutes)
393 - console goes silent for more than 10 seconds
394 - one of the error messages seen in the stream
395 - misformatted output is seen in the stream
Vadim Bendebury2b719452013-02-12 17:00:06 -0800396 """
397
398 _SOFT_DEADLINE_LIMIT = 10
399 _HARD_DEADLINE_LIMIT = 120
400 string_leftover = ''
401 soft_deadline = time.time() + _SOFT_DEADLINE_LIMIT
402 hard_deadline = soft_deadline + _HARD_DEADLINE_LIMIT - _SOFT_DEADLINE_LIMIT
403
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800404 if self.verify:
405 done_line = self._WRITE_SUCCESS_MESSAGE
406 else:
407 done_line = self._SKIP_VERIFY_MESSAGE
408
Vadim Bendebury2b719452013-02-12 17:00:06 -0800409 while True:
410 now = time.time()
411 if now > hard_deadline:
412 raise CmdError('Target console flooded, programming failed')
413 if now > soft_deadline:
414 raise CmdError('Target console dead, programming failed')
415 stream = self.DutControl(['cpu_uart_stream',])
416 match = re.search("^cpu_uart_stream:'(.*)'\n", stream)
417 if not match:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800418 raise CmdError('Misformatted console output: \n%s\n' % stream)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800419
420 text = string_leftover + match.group(1)
421 strings = text.split('\\r')
422 string_leftover = strings.pop()
423 if strings:
424 soft_deadline = now + _SOFT_DEADLINE_LIMIT
425 for string in strings:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800426 if done_line in string:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800427 return True
428 if self._WRITE_FAILURE_MESSAGE in string:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800429 raise CmdError('Readback verification failed!')
430 if self._DOWNLOAD_FAILURE_MESSAGE in string:
431 raise CmdError('Download failed!')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800432
Simon Glass4c54a912013-02-18 16:56:29 -0800433 def _ExtractPayloadParts(self, payload, truncate_to_fdt):
Simon Glass3c5b35b2012-05-23 13:22:23 -0700434 """Extract the BL1, BL2 and U-Boot parts from a payload.
435
436 An exynos image consists of 3 parts: BL1, BL2 and U-Boot/FDT.
437
438 This pulls out the various parts, puts them into files and returns
439 these files.
440
441 Args:
442 payload: Full path to payload.
Simon Glass4c54a912013-02-18 16:56:29 -0800443 truncate_to_fdt: Truncate the U-Boot image at the start of its
444 embedded FDT
Simon Glass3c5b35b2012-05-23 13:22:23 -0700445
446 Returns:
447 (bl1, bl2, image) where:
448 bl1 is the filename of the extracted BL1
449 bl2 is the filename of the extracted BL2
450 image is the filename of the extracted U-Boot image
451 """
452 # Pull out the parts from the payload
453 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
454 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
455 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
456 data = self._tools.ReadFile(payload)
457
458 # The BL1 is always 8KB - extract that part into a new file
459 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
Simon Glasse86f3132013-01-08 16:10:43 -0800460 bl1_size = 0x2000
461 self._tools.WriteFile(bl1, data[:bl1_size])
Simon Glass3c5b35b2012-05-23 13:22:23 -0700462
Simon Glassb345a5a2013-05-11 15:02:21 -0700463 # Try to detect the BL2 size. We look for 0xea000014 or 0xea000013
464 # which is the 'B reset' instruction at the start of U-Boot. When
465 # U-Boot is LZO compressed, we look for a LZO magic instead.
466 start_data = [struct.pack('<L', 0xea000014),
467 struct.pack('<L', 0xea000013),
468 struct.pack('>B3s', 0x89, 'LZO')]
469 starts = [data.find(magic, bl1_size + 0x3800) for magic in start_data]
470 uboot_offset = None
471 for start in starts:
472 if start != -1 and (not uboot_offset or start < uboot_offset):
473 uboot_offset = start
474 if not uboot_offset:
Vadim Bendebury19a77122013-01-24 17:38:00 -0800475 raise ValueError('Could not locate start of U-Boot')
Simon Glasse86f3132013-01-08 16:10:43 -0800476 bl2_size = uboot_offset - bl1_size - 0x800 # 2KB gap after BL2
Simon Glass3c5b35b2012-05-23 13:22:23 -0700477
Simon Glasse86f3132013-01-08 16:10:43 -0800478 # Sanity check: At present we only allow 14KB and 30KB for SPL
479 allowed = [14, 30]
480 if (bl2_size >> 10) not in allowed:
Vadim Bendebury19a77122013-01-24 17:38:00 -0800481 raise ValueError('BL2 size is %dK - only %s supported' %
482 (bl2_size >> 10, ', '.join(
483 [str(size) for size in allowed])))
Simon Glasse86f3132013-01-08 16:10:43 -0800484 self._out.Notice('BL2 size is %dKB' % (bl2_size >> 10))
485
486 # The BL2 (U-Boot SPL) follows BL1. After that there is a 2KB gap
487 bl2_end = uboot_offset - 0x800
488 self._tools.WriteFile(bl2, data[0x2000:bl2_end])
489
Simon Glassbc0d8d42013-02-09 11:59:36 -0800490 # U-Boot itself starts at 24KB, after the gap. As a hack, truncate it
Simon Glass4c54a912013-02-18 16:56:29 -0800491 # to an assumed maximum size. As a secondary hack, locate the FDT
492 # and truncate U-Boot from that point. The correct FDT will be added
493 # when the image is written to the board.
Simon Glassbc0d8d42013-02-09 11:59:36 -0800494 # TODO(sjg@chromium.org): Get a proper flash map here so we know how
495 # large it is
Simon Glass4c54a912013-02-18 16:56:29 -0800496 uboot_data = data[uboot_offset:uboot_offset + 0xa0000]
497 if truncate_to_fdt:
498 fdt_magic = struct.pack('>L', 0xd00dfeed)
499 fdt_offset = uboot_data.rfind(fdt_magic)
500 uboot_data = uboot_data[:fdt_offset]
501
502 self._tools.WriteFile(image, uboot_data)
Simon Glass3c5b35b2012-05-23 13:22:23 -0700503 return bl1, bl2, image
504
Vadim Bendebury19a77122013-01-24 17:38:00 -0800505 def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
Simon Glassde9c8072012-07-02 22:29:02 -0700506 kernel):
Simon Glass27a9c142012-03-15 21:08:29 -0700507 """Flash the image to SPI flash.
508
509 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000510 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glass27a9c142012-03-15 21:08:29 -0700511
512 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700513 flash_dest: Destination for flasher, or None to not create a flasher
514 Valid options are spi, sdmmc.
515 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700516 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700517 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700518 payload: Full path to payload.
Simon Glassde9c8072012-07-02 22:29:02 -0700519 kernel: Kernel to send after the payload, or None.
Simon Glass27a9c142012-03-15 21:08:29 -0700520
521 Returns:
522 True if ok, False if failed.
523 """
Simon Glassbc0d8d42013-02-09 11:59:36 -0800524 tools = self._tools
525 payload_bl1, payload_bl2, payload_image = (
Simon Glass4c54a912013-02-18 16:56:29 -0800526 self._ExtractPayloadParts(payload, flash_dest is not None))
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700527 if flash_dest:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800528 # If we don't have some bits, get them from the image
529 if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
530 self._out.Warning('Extracting U-Boot from payload')
531 flash_uboot = payload_image
532 if not bl1 or not os.path.exists(tools.Filename(bl1)):
533 self._out.Warning('Extracting BL1 from payload')
534 bl1 = payload_bl1
535 if not bl2 or not os.path.exists(tools.Filename(bl2)):
536 self._out.Warning('Extracting BL2 from payload')
537 bl2 = payload_bl2
Vadim Bendebury2b719452013-02-12 17:00:06 -0800538 image = self._PrepareFlasher(flash_uboot, payload, flash_dest, '1:0')
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700539 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800540 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700541
542 vendor_id = 0x04e8
543 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700544
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800545 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800546 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
547 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800548 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800549 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700550 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800551 if preserved_dut_hub_sel != required_dut_hub_sel:
552 # Need to set it to get the port properly powered up.
553 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Simon Glass93673cf2013-04-26 17:55:55 -0700554 if self._servo_port is not None:
555 self._out.Progress('Reseting board via servo')
556 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700557
Simon Glassde9c8072012-07-02 22:29:02 -0700558 # If we have a kernel to write, create a new image with that added.
559 if kernel:
560 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
561 data = self._tools.ReadFile(image)
562
563 # Pad the original payload out to the original length
564 data += '\0' * (os.stat(payload).st_size - len(data))
565 data += self._tools.ReadFile(kernel)
566 self._tools.WriteFile(dl_image, data)
567 else:
568 dl_image = image
569
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700570 self._out.Progress('Uploading image')
Simon Glass27a9c142012-03-15 21:08:29 -0700571 download_list = [
Simon Glass3c5b35b2012-05-23 13:22:23 -0700572 # The numbers are the download addresses (in SRAM) for each piece
573 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
Simon Glass27a9c142012-03-15 21:08:29 -0700574 ['bl1', 0x02021400, bl1],
575 ['bl2', 0x02023400, bl2],
Simon Glassde9c8072012-07-02 22:29:02 -0700576 ['u-boot', 0x43e00000, dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700577 ]
Simon Glass3381a1a2012-03-22 11:13:19 -0700578 try:
Simon Glass4968a472012-05-23 13:52:19 -0700579 for upto in range(len(download_list)):
580 item = download_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700581 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700582 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700583 raise CmdError('Could not find Exynos board on USB port')
584 raise CmdError("Stage '%s' did not complete" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700585 self._out.Notice(item[2])
Simon Glass27a9c142012-03-15 21:08:29 -0700586 self._out.Progress("Uploading stage '%s'" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700587
Simon Glass4968a472012-05-23 13:52:19 -0700588 if upto == 0:
589 # The IROM needs roughly 200ms here to be ready for USB download
590 time.sleep(.5)
591
Simon Glass79e3dd02012-08-28 20:08:50 -0700592 args = ['-a', '%#x' % item[1], '-f', item[2]]
593 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700594
Simon Glass3381a1a2012-03-22 11:13:19 -0700595 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800596 # Make sure that the power button is released and dut_sel_hub state is
597 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700598 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800599 if preserved_dut_hub_sel != required_dut_hub_sel:
600 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800601 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700602
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800603 if flash_dest is None:
604 self._out.Notice('Image downloaded - please see serial output '
605 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700606 return True
607
Simon Glass0c2ba482012-03-22 21:57:51 -0700608 def _GetDiskInfo(self, disk, item):
609 """Returns information about a SCSI disk device.
610
611 Args:
612 disk: a block device name in sys/block, like '/sys/block/sdf'.
613 item: the item of disk information that is required.
614
615 Returns:
616 The information obtained, as a string, or '[Unknown]' if not found
617 """
618 dev_path = os.path.join(disk, 'device')
619
620 # Search upwards and through symlinks looking for the item.
621 while os.path.isdir(dev_path) and dev_path != '/sys':
622 fname = os.path.join(dev_path, item)
623 if os.path.exists(fname):
624 with open(fname, 'r') as fd:
625 return fd.readline().rstrip()
626
627 # Move up a level and follow any symlink.
628 new_path = os.path.join(dev_path, '..')
629 if os.path.islink(new_path):
630 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
631 dev_path = new_path
632 return '[Unknown]'
633
634 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700635 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700636
637 Args:
638 device: Device to check, like '/dev/sdf'.
639
640 Returns:
641 Capacity of device in GB, or 0 if not known.
642 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700643 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700644 args = ['-l', device]
645 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700646 for line in stdout.splitlines():
647 m = re_capacity.match(line)
648 if m:
649 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700650 return 0
651
652 def _ListUsbDisks(self):
653 """Return a list of available removable USB disks.
654
655 Returns:
656 List of USB devices, each element is itself a list containing:
657 device ('/dev/sdx')
658 manufacturer name
659 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700660 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700661 """
662 disk_list = []
663 for disk in glob.glob('/sys/block/sd*'):
664 with open(disk + '/removable', 'r') as fd:
665 if int(fd.readline()) == 1:
666 device = '/dev/%s' % disk.split('/')[-1]
667 manuf = self._GetDiskInfo(disk, 'manufacturer')
668 product = self._GetDiskInfo(disk, 'product')
669 capacity = self._GetDiskCapacity(device)
670 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700671 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700672 return disk_list
673
674 def WriteToSd(self, flash_dest, disk, uboot, payload):
675 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800676 raw_image = self._PrepareFlasher(uboot, payload, flash_dest, '1:0')
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700677 bl1, bl2, _ = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700678 spl_load_size = os.stat(raw_image).st_size
679 bl2 = self._bundle.ConfigureExynosBl2(self._fdt, spl_load_size, bl2,
680 'flasher')
681
682 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2)
683
684 # Pad BL2 out to the required size.
685 # We require that it be 24KB, but data will only contain 8KB + 14KB.
686 # Add the extra padding to bring it to 24KB.
687 data += '\0' * (0x6000 - len(data))
688 data += self._tools.ReadFile(raw_image)
689 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
690 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700691 self._out.Progress('Writing flasher to %s' % disk)
692 else:
693 image = payload
694 self._out.Progress('Writing image to %s' % disk)
695
696 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
697 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700698 self._out.Progress('Syncing')
699 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700700
701 def SendToSdCard(self, dest, flash_dest, uboot, payload):
702 """Write a flasher to an SD card.
703
704 Args:
705 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700706 ':.' selects the only available device, fails if more than one option
707 ':<device>' select deivce
708
709 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700710 ':.'
711 ':/dev/sdd'
712
713 flash_dest: Destination for flasher, or None to not create a flasher:
714 Valid options are spi, sdmmc.
715 uboot: Full path to u-boot.bin.
716 payload: Full path to payload.
717 """
718 disk = None
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700719
Vadim Bendebury223af572013-04-27 13:25:13 -0700720 # If no removable devices found - prompt user and wait for one to appear.
721 disks = self._ListUsbDisks()
722 try:
723 spinner = '|/-\\'
724 index = 0
725 while not disks:
726 self._out.ClearProgress()
727 self._out.Progress('No removable devices found, plug something in %s '
728 % spinner[index], trailer='')
729 index = (index + 1) % len(spinner)
730 disks = self._ListUsbDisks()
731 time.sleep(.2)
732 except KeyboardInterrupt:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700733 raise CmdError("No removable device found, interrupted")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700734
735 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700736 name = dest[1:]
737
738 # A '.' just means to use the only available disk.
739 if name == '.' and len(disks) == 1:
740 disk = disks[0][0]
741 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700742 # Use the device name.
743 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700744 disk = disk_info[0]
745
746 if disk:
747 self.WriteToSd(flash_dest, disk, uboot, payload)
748 else:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700749 msg = ["Please specify destination as '-w sd:<disk_description>'",]
750 msg.append(' - <disk_description> can be either . for the only disk,')
751 msg.append(' or the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700752 # List available disks as a convenience.
753 for disk in disks:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700754 msg.append(' %s - %s %.1f GB' % (
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700755 disk[0],
756 ' '.join(str(x) for x in disk[1:3]),
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700757 disk[3] / 10.0))
758 raise CmdError('\n'.join(msg))
Simon Glass0c2ba482012-03-22 21:57:51 -0700759
Vadim Bendebury19a77122013-01-24 17:38:00 -0800760 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700761 """Send an image to an attached EM100 device.
762
763 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
764 to do the SPI emulation, then write the image, then boot the board.
765 All going well, this is enough to get U-Boot running.
766
767 Args:
768 image_fname: Filename of image to send
769 """
770 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
771 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800772 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700773
774 # TODO(sjg@chromium.org): This is for link. We could make this
775 # configurable from the fdt.
776 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
777 self._out.Progress('Writing image to em100')
778 self._tools.Run('em100', args, sudo=True)
779
Simon Glass93673cf2013-04-26 17:55:55 -0700780 if self._servo_port is not None:
781 self._out.Progress('Resetting board via servo')
782 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
783 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
784 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700785
Simon Glass0c2ba482012-03-22 21:57:51 -0700786
Simon Glass27a9c142012-03-15 21:08:29 -0700787def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass60a40af2012-06-07 11:54:17 -0700788 bundle, update=True, verify=False, dest=None,
Vadim Bendebury19a77122013-01-24 17:38:00 -0800789 flash_dest=None, kernel=None, bootstub=None, servo='any',
Simon Glass4b8b3bd2012-11-06 12:31:01 -0800790 method='tegra'):
Simon Glasse0b61442012-03-13 15:29:51 -0700791 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700792
793 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700794 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700795
796 Args:
797 output: cros_output object to use.
798 tools: Tools object to use.
799 fdt: Fdt object to use as our device tree.
800 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700801 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700802 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700803 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800804 update: Use faster update algorithm rather then full device erase.
805 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700806 dest: Destination device to write firmware to (usb, sd).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700807 flash_dest: Destination device for flasher to program payload into.
Simon Glassde9c8072012-07-02 22:29:02 -0700808 kernel: Kernel file to write after U-Boot
Vadim Bendebury19a77122013-01-24 17:38:00 -0800809 bootstub: string, file name of the boot stub, if present
Simon Glass6a616c12012-09-24 18:13:46 -0700810 servo: Describes the servo unit to use: none=none; any=any; otherwise
811 port number of servo to use.
Simon Glass710dedc2011-08-09 14:08:52 -0700812 """
Vadim Bendebury2b719452013-02-12 17:00:06 -0800813 write = WriteFirmware(tools, fdt, output, bundle, update, verify)
Simon Glass6a616c12012-09-24 18:13:46 -0700814 write.SelectServo(servo)
Simon Glassd65f65f2013-03-28 17:03:41 -0700815 if flash_dest:
816 write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
817 elif bootstub:
818 write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
Simon Glasse0b61442012-03-13 15:29:51 -0700819 if dest == 'usb':
Vadim Bendebury2b719452013-02-12 17:00:06 -0800820 try:
821 write.DutControl(['cpu_uart_capture:on',])
822 method = fdt.GetString('/chromeos-config', 'flash-method', method)
823 if method == 'tegra':
824 tools.CheckTool('tegrarcm')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800825 ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
826 image_fname, bootstub)
827 elif method == 'exynos':
828 tools.CheckTool('lsusb', 'usbutils')
829 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
830 ok = write.ExynosFlashImage(flash_dest, flasher,
831 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
832 kernel)
833 else:
834 raise CmdError("Unknown flash method '%s'" % method)
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800835
Vadim Bendebury2b719452013-02-12 17:00:06 -0800836 if not ok:
837 raise CmdError('Image upload failed - please check board connection')
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800838 output.Progress('Image uploaded, waiting for completion')
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800839
840 if flash_dest is not None and servo != 'none':
841 write.WaitForCompletion()
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800842 output.Progress('Done!')
843
Vadim Bendebury2b719452013-02-12 17:00:06 -0800844 finally:
845 write.DutControl(['cpu_uart_capture:off',])
Simon Glass9eb8c722012-06-07 13:34:31 -0700846 elif dest == 'em100':
847 # crosbug.com/31625
848 tools.CheckTool('em100')
Vadim Bendebury19a77122013-01-24 17:38:00 -0800849 write.Em100FlashImage(image_fname)
Simon Glass0c2ba482012-03-22 21:57:51 -0700850 elif dest.startswith('sd'):
851 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -0700852 else:
Simon Glasse0b61442012-03-13 15:29:51 -0700853 raise CmdError("Unknown destination device '%s'" % dest)