blob: 10c769310cfef1c4ca762c67359d2cb7ca581463 [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 Glasse86f3132013-01-08 16:10:43 -0800463 # Try to detect the BL2 size. We look for 0xea000014 which is the
Tom Wai-Hong Tamf67046f2013-02-06 09:23:26 +0800464 # 'B reset' instruction at the start of U-Boot. When U-Boot is LZO
465 # compressed, we look for a LZO magic instead.
Simon Glasse86f3132013-01-08 16:10:43 -0800466 first_instr = struct.pack('<L', 0xea000014)
Tom Wai-Hong Tamf67046f2013-02-06 09:23:26 +0800467 lzo_magic = struct.pack('>B3s', 0x89, 'LZO')
468 first_instr_offset = data.find(first_instr, bl1_size + 0x3800)
469 lzo_magic_offset = data.find(lzo_magic, bl1_size + 0x3800)
470 uboot_offset = min(first_instr_offset, lzo_magic_offset)
471 if uboot_offset == -1:
472 uboot_offset = max(first_instr_offset, lzo_magic_offset)
Simon Glasse86f3132013-01-08 16:10:43 -0800473 if uboot_offset == -1:
Vadim Bendebury19a77122013-01-24 17:38:00 -0800474 raise ValueError('Could not locate start of U-Boot')
Simon Glasse86f3132013-01-08 16:10:43 -0800475 bl2_size = uboot_offset - bl1_size - 0x800 # 2KB gap after BL2
Simon Glass3c5b35b2012-05-23 13:22:23 -0700476
Simon Glasse86f3132013-01-08 16:10:43 -0800477 # Sanity check: At present we only allow 14KB and 30KB for SPL
478 allowed = [14, 30]
479 if (bl2_size >> 10) not in allowed:
Vadim Bendebury19a77122013-01-24 17:38:00 -0800480 raise ValueError('BL2 size is %dK - only %s supported' %
481 (bl2_size >> 10, ', '.join(
482 [str(size) for size in allowed])))
Simon Glasse86f3132013-01-08 16:10:43 -0800483 self._out.Notice('BL2 size is %dKB' % (bl2_size >> 10))
484
485 # The BL2 (U-Boot SPL) follows BL1. After that there is a 2KB gap
486 bl2_end = uboot_offset - 0x800
487 self._tools.WriteFile(bl2, data[0x2000:bl2_end])
488
Simon Glassbc0d8d42013-02-09 11:59:36 -0800489 # U-Boot itself starts at 24KB, after the gap. As a hack, truncate it
Simon Glass4c54a912013-02-18 16:56:29 -0800490 # to an assumed maximum size. As a secondary hack, locate the FDT
491 # and truncate U-Boot from that point. The correct FDT will be added
492 # when the image is written to the board.
Simon Glassbc0d8d42013-02-09 11:59:36 -0800493 # TODO(sjg@chromium.org): Get a proper flash map here so we know how
494 # large it is
Simon Glass4c54a912013-02-18 16:56:29 -0800495 uboot_data = data[uboot_offset:uboot_offset + 0xa0000]
496 if truncate_to_fdt:
497 fdt_magic = struct.pack('>L', 0xd00dfeed)
498 fdt_offset = uboot_data.rfind(fdt_magic)
499 uboot_data = uboot_data[:fdt_offset]
500
501 self._tools.WriteFile(image, uboot_data)
Simon Glass3c5b35b2012-05-23 13:22:23 -0700502 return bl1, bl2, image
503
Vadim Bendebury19a77122013-01-24 17:38:00 -0800504 def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
Simon Glassde9c8072012-07-02 22:29:02 -0700505 kernel):
Simon Glass27a9c142012-03-15 21:08:29 -0700506 """Flash the image to SPI flash.
507
508 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000509 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glass27a9c142012-03-15 21:08:29 -0700510
511 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700512 flash_dest: Destination for flasher, or None to not create a flasher
513 Valid options are spi, sdmmc.
514 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700515 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700516 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700517 payload: Full path to payload.
Simon Glassde9c8072012-07-02 22:29:02 -0700518 kernel: Kernel to send after the payload, or None.
Simon Glass27a9c142012-03-15 21:08:29 -0700519
520 Returns:
521 True if ok, False if failed.
522 """
Simon Glassbc0d8d42013-02-09 11:59:36 -0800523 tools = self._tools
524 payload_bl1, payload_bl2, payload_image = (
Simon Glass4c54a912013-02-18 16:56:29 -0800525 self._ExtractPayloadParts(payload, flash_dest is not None))
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700526 if flash_dest:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800527 # If we don't have some bits, get them from the image
528 if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
529 self._out.Warning('Extracting U-Boot from payload')
530 flash_uboot = payload_image
531 if not bl1 or not os.path.exists(tools.Filename(bl1)):
532 self._out.Warning('Extracting BL1 from payload')
533 bl1 = payload_bl1
534 if not bl2 or not os.path.exists(tools.Filename(bl2)):
535 self._out.Warning('Extracting BL2 from payload')
536 bl2 = payload_bl2
Vadim Bendebury2b719452013-02-12 17:00:06 -0800537 image = self._PrepareFlasher(flash_uboot, payload, flash_dest, '1:0')
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700538 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800539 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700540
541 vendor_id = 0x04e8
542 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700543
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800544 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800545 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
546 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800547 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800548 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700549 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800550 if preserved_dut_hub_sel != required_dut_hub_sel:
551 # Need to set it to get the port properly powered up.
552 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800553 self._out.Progress('Reseting board via servo')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800554 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700555
Simon Glassde9c8072012-07-02 22:29:02 -0700556 # If we have a kernel to write, create a new image with that added.
557 if kernel:
558 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
559 data = self._tools.ReadFile(image)
560
561 # Pad the original payload out to the original length
562 data += '\0' * (os.stat(payload).st_size - len(data))
563 data += self._tools.ReadFile(kernel)
564 self._tools.WriteFile(dl_image, data)
565 else:
566 dl_image = image
567
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700568 self._out.Progress('Uploading image')
Simon Glass27a9c142012-03-15 21:08:29 -0700569 download_list = [
Simon Glass3c5b35b2012-05-23 13:22:23 -0700570 # The numbers are the download addresses (in SRAM) for each piece
571 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
Simon Glass27a9c142012-03-15 21:08:29 -0700572 ['bl1', 0x02021400, bl1],
573 ['bl2', 0x02023400, bl2],
Simon Glassde9c8072012-07-02 22:29:02 -0700574 ['u-boot', 0x43e00000, dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700575 ]
Simon Glass3381a1a2012-03-22 11:13:19 -0700576 try:
Simon Glass4968a472012-05-23 13:52:19 -0700577 for upto in range(len(download_list)):
578 item = download_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700579 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700580 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700581 raise CmdError('Could not find Exynos board on USB port')
582 raise CmdError("Stage '%s' did not complete" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700583 self._out.Notice(item[2])
Simon Glass27a9c142012-03-15 21:08:29 -0700584 self._out.Progress("Uploading stage '%s'" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700585
Simon Glass4968a472012-05-23 13:52:19 -0700586 if upto == 0:
587 # The IROM needs roughly 200ms here to be ready for USB download
588 time.sleep(.5)
589
Simon Glass79e3dd02012-08-28 20:08:50 -0700590 args = ['-a', '%#x' % item[1], '-f', item[2]]
591 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700592
Simon Glass3381a1a2012-03-22 11:13:19 -0700593 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800594 # Make sure that the power button is released and dut_sel_hub state is
595 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700596 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800597 if preserved_dut_hub_sel != required_dut_hub_sel:
598 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800599 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700600
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800601 if flash_dest is None:
602 self._out.Notice('Image downloaded - please see serial output '
603 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700604 return True
605
Simon Glass0c2ba482012-03-22 21:57:51 -0700606 def _GetDiskInfo(self, disk, item):
607 """Returns information about a SCSI disk device.
608
609 Args:
610 disk: a block device name in sys/block, like '/sys/block/sdf'.
611 item: the item of disk information that is required.
612
613 Returns:
614 The information obtained, as a string, or '[Unknown]' if not found
615 """
616 dev_path = os.path.join(disk, 'device')
617
618 # Search upwards and through symlinks looking for the item.
619 while os.path.isdir(dev_path) and dev_path != '/sys':
620 fname = os.path.join(dev_path, item)
621 if os.path.exists(fname):
622 with open(fname, 'r') as fd:
623 return fd.readline().rstrip()
624
625 # Move up a level and follow any symlink.
626 new_path = os.path.join(dev_path, '..')
627 if os.path.islink(new_path):
628 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
629 dev_path = new_path
630 return '[Unknown]'
631
632 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700633 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700634
635 Args:
636 device: Device to check, like '/dev/sdf'.
637
638 Returns:
639 Capacity of device in GB, or 0 if not known.
640 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700641 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700642 args = ['-l', device]
643 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700644 for line in stdout.splitlines():
645 m = re_capacity.match(line)
646 if m:
647 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700648 return 0
649
650 def _ListUsbDisks(self):
651 """Return a list of available removable USB disks.
652
653 Returns:
654 List of USB devices, each element is itself a list containing:
655 device ('/dev/sdx')
656 manufacturer name
657 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700658 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700659 """
660 disk_list = []
661 for disk in glob.glob('/sys/block/sd*'):
662 with open(disk + '/removable', 'r') as fd:
663 if int(fd.readline()) == 1:
664 device = '/dev/%s' % disk.split('/')[-1]
665 manuf = self._GetDiskInfo(disk, 'manufacturer')
666 product = self._GetDiskInfo(disk, 'product')
667 capacity = self._GetDiskCapacity(device)
668 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700669 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700670 return disk_list
671
672 def WriteToSd(self, flash_dest, disk, uboot, payload):
673 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800674 raw_image = self._PrepareFlasher(uboot, payload, flash_dest, '1:0')
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700675 bl1, bl2, _ = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700676 spl_load_size = os.stat(raw_image).st_size
677 bl2 = self._bundle.ConfigureExynosBl2(self._fdt, spl_load_size, bl2,
678 'flasher')
679
680 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2)
681
682 # Pad BL2 out to the required size.
683 # We require that it be 24KB, but data will only contain 8KB + 14KB.
684 # Add the extra padding to bring it to 24KB.
685 data += '\0' * (0x6000 - len(data))
686 data += self._tools.ReadFile(raw_image)
687 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
688 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700689 self._out.Progress('Writing flasher to %s' % disk)
690 else:
691 image = payload
692 self._out.Progress('Writing image to %s' % disk)
693
694 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
695 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700696 self._out.Progress('Syncing')
697 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700698
699 def SendToSdCard(self, dest, flash_dest, uboot, payload):
700 """Write a flasher to an SD card.
701
702 Args:
703 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700704 ':.' selects the only available device, fails if more than one option
705 ':<device>' select deivce
706
707 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700708 ':.'
709 ':/dev/sdd'
710
711 flash_dest: Destination for flasher, or None to not create a flasher:
712 Valid options are spi, sdmmc.
713 uboot: Full path to u-boot.bin.
714 payload: Full path to payload.
715 """
716 disk = None
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700717
Vadim Bendebury223af572013-04-27 13:25:13 -0700718 # If no removable devices found - prompt user and wait for one to appear.
719 disks = self._ListUsbDisks()
720 try:
721 spinner = '|/-\\'
722 index = 0
723 while not disks:
724 self._out.ClearProgress()
725 self._out.Progress('No removable devices found, plug something in %s '
726 % spinner[index], trailer='')
727 index = (index + 1) % len(spinner)
728 disks = self._ListUsbDisks()
729 time.sleep(.2)
730 except KeyboardInterrupt:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700731 return
732
733 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700734 name = dest[1:]
735
736 # A '.' just means to use the only available disk.
737 if name == '.' and len(disks) == 1:
738 disk = disks[0][0]
739 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700740 # Use the device name.
741 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700742 disk = disk_info[0]
743
744 if disk:
745 self.WriteToSd(flash_dest, disk, uboot, payload)
746 else:
747 self._out.Error("Please specify destination -w 'sd:<disk_description>':")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700748 self._out.Error(' - description can be . for the only disk, or')
749 self._out.Error(' the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700750 msg = 'Found %d available disks.' % len(disks)
751 if not disks:
752 msg += ' Please insert an SD card and try again.'
753 self._out.UserOutput(msg)
754
755 # List available disks as a convenience.
756 for disk in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700757 self._out.UserOutput(' %s: %s %d.%d GB' % (
758 disk[0],
759 ' '.join(str(x) for x in disk[1:3]),
760 disk[3] / 10, # Integer number of GBs
761 disk[3] % 10, # Decimal number of GBs
762 ))
Simon Glass0c2ba482012-03-22 21:57:51 -0700763
Vadim Bendebury19a77122013-01-24 17:38:00 -0800764 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700765 """Send an image to an attached EM100 device.
766
767 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
768 to do the SPI emulation, then write the image, then boot the board.
769 All going well, this is enough to get U-Boot running.
770
771 Args:
772 image_fname: Filename of image to send
773 """
774 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
775 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800776 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700777
778 # TODO(sjg@chromium.org): This is for link. We could make this
779 # configurable from the fdt.
780 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
781 self._out.Progress('Writing image to em100')
782 self._tools.Run('em100', args, sudo=True)
783
784 self._out.Progress('Resetting board')
785 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
786 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
Vadim Bendebury2b719452013-02-12 17:00:06 -0800787 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700788
Simon Glass0c2ba482012-03-22 21:57:51 -0700789
Simon Glass27a9c142012-03-15 21:08:29 -0700790def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass60a40af2012-06-07 11:54:17 -0700791 bundle, update=True, verify=False, dest=None,
Vadim Bendebury19a77122013-01-24 17:38:00 -0800792 flash_dest=None, kernel=None, bootstub=None, servo='any',
Simon Glass4b8b3bd2012-11-06 12:31:01 -0800793 method='tegra'):
Simon Glasse0b61442012-03-13 15:29:51 -0700794 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700795
796 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700797 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700798
799 Args:
800 output: cros_output object to use.
801 tools: Tools object to use.
802 fdt: Fdt object to use as our device tree.
803 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700804 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700805 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700806 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800807 update: Use faster update algorithm rather then full device erase.
808 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700809 dest: Destination device to write firmware to (usb, sd).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700810 flash_dest: Destination device for flasher to program payload into.
Simon Glassde9c8072012-07-02 22:29:02 -0700811 kernel: Kernel file to write after U-Boot
Vadim Bendebury19a77122013-01-24 17:38:00 -0800812 bootstub: string, file name of the boot stub, if present
Simon Glass6a616c12012-09-24 18:13:46 -0700813 servo: Describes the servo unit to use: none=none; any=any; otherwise
814 port number of servo to use.
Simon Glass710dedc2011-08-09 14:08:52 -0700815 """
Vadim Bendebury2b719452013-02-12 17:00:06 -0800816 write = WriteFirmware(tools, fdt, output, bundle, update, verify)
Simon Glass6a616c12012-09-24 18:13:46 -0700817 write.SelectServo(servo)
Simon Glassd65f65f2013-03-28 17:03:41 -0700818 if flash_dest:
819 write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
820 elif bootstub:
821 write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
Simon Glasse0b61442012-03-13 15:29:51 -0700822 if dest == 'usb':
Vadim Bendebury2b719452013-02-12 17:00:06 -0800823 try:
824 write.DutControl(['cpu_uart_capture:on',])
825 method = fdt.GetString('/chromeos-config', 'flash-method', method)
826 if method == 'tegra':
827 tools.CheckTool('tegrarcm')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800828 ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
829 image_fname, bootstub)
830 elif method == 'exynos':
831 tools.CheckTool('lsusb', 'usbutils')
832 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
833 ok = write.ExynosFlashImage(flash_dest, flasher,
834 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
835 kernel)
836 else:
837 raise CmdError("Unknown flash method '%s'" % method)
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800838
Vadim Bendebury2b719452013-02-12 17:00:06 -0800839 if not ok:
840 raise CmdError('Image upload failed - please check board connection')
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800841 output.Progress('Image uploaded, waiting for completion')
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800842
843 if flash_dest is not None and servo != 'none':
844 write.WaitForCompletion()
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800845 output.Progress('Done!')
846
Vadim Bendebury2b719452013-02-12 17:00:06 -0800847 finally:
848 write.DutControl(['cpu_uart_capture:off',])
Simon Glass9eb8c722012-06-07 13:34:31 -0700849 elif dest == 'em100':
850 # crosbug.com/31625
851 tools.CheckTool('em100')
Vadim Bendebury19a77122013-01-24 17:38:00 -0800852 write.Em100FlashImage(image_fname)
Simon Glass0c2ba482012-03-22 21:57:51 -0700853 elif dest.startswith('sd'):
854 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -0700855 else:
Simon Glasse0b61442012-03-13 15:29:51 -0700856 raise CmdError("Unknown destination device '%s'" % dest)