blob: 43636061ec713e7cdb4e19ea438d521a7d766109 [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
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -070011
12from exynos import ExynosBl2
Simon Glassa3f29ec2011-07-17 09:36:49 -070013from tools import CmdError
14
15def RoundUp(value, boundary):
16 """Align a value to the next power of 2 boundary.
17
18 Args:
19 value: The value to align.
20 boundary: The boundary value, e.g. 4096. Must be a power of 2.
21
22 Returns:
23 The rounded-up value.
24 """
25 return (value + boundary - 1) & ~(boundary - 1)
26
27
28class WriteFirmware:
29 """Write firmware to a Tegra 2 board using USB A-A cable.
30
31 This class handles re-reflashing a board with new firmware using the Tegra's
32 built-in boot ROM feature. This works by putting the chip into a special mode
33 where it ignores any available firmware and instead reads it from a connected
34 host machine over USB.
35
36 In our case we use that feature to send U-Boot along with a suitable payload
37 and instructions to flash it to SPI flash. The payload is itself normally a
38 full Chrome OS image consisting of U-Boot, some keys and verification
39 information, images and a map of the flash memory.
Simon Glass6a616c12012-09-24 18:13:46 -070040
41 Private attributes:
42 _servo_port: Port number to use to talk to servo with dut-control.
43 Special values are:
44 None: servo is not available.
45 0: any servo will do.
46
Simon Glassa3f29ec2011-07-17 09:36:49 -070047 """
Vadim Bendebury2b719452013-02-12 17:00:06 -080048
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080049 _DOWNLOAD_FAILURE_MESSAGE = '** Load checksum error: check download tool **'
50 _SKIP_VERIFY_MESSAGE = 'Skipping verify'
Vadim Bendebury2b719452013-02-12 17:00:06 -080051 _WRITE_FAILURE_MESSAGE = '** Readback checksum error, programming failed!! **'
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080052 _WRITE_SUCCESS_MESSAGE = 'Image Programmed Successfully'
Vadim Bendebury2b719452013-02-12 17:00:06 -080053
54 def __init__(self, tools, fdt, output, bundle, update, verify):
Simon Glassa3f29ec2011-07-17 09:36:49 -070055 """Set up a new WriteFirmware object.
56
57 Args:
58 tools: A tools library for us to use.
59 fdt: An fdt which gives us some info that we need.
60 output: An output object to use for printing progress and messages.
Simon Glass0191a882012-05-23 13:15:06 -070061 bundle: A BundleFirmware object which created the image.
Vadim Bendebury2b719452013-02-12 17:00:06 -080062 update: Use faster update algorithm rather then full device erase.
63 verify: Verify the write by doing a readback and CRC.
Simon Glassa3f29ec2011-07-17 09:36:49 -070064 """
65 self._tools = tools
66 self._fdt = fdt
67 self._out = output
Simon Glass0191a882012-05-23 13:15:06 -070068 self._bundle = bundle
Vadim Bendebury19a77122013-01-24 17:38:00 -080069 self.text_base = self._fdt.GetInt('/chromeos-config', 'textbase', -1)
Simon Glassa3f29ec2011-07-17 09:36:49 -070070
Simon Glass5b5fd642011-08-17 12:24:01 -070071 # For speed, use the 'update' algorithm and don't verify
Vadim Bendebury2b719452013-02-12 17:00:06 -080072 self.update = update
73 self.verify = verify
Simon Glass5b5fd642011-08-17 12:24:01 -070074
Simon Glass6a616c12012-09-24 18:13:46 -070075 # Use default servo port
76 self._servo_port = 0
77
78 def SelectServo(self, servo):
79 """Select the servo to use for writing firmware.
80
81 Args:
82 servo: String containing description of servo to use:
83 'none' : Don't use servo, generate an error on any attempt.
84 'any' : Use any available servo.
85 '<port>': Use servo with that port number.
86 """
87 if servo == 'none':
88 self._servo_port = None
89 elif servo == 'any':
90 self._servo_port = 0
91 else:
92 self._servo_port = int(servo)
93 self._out.Notice('Servo port %s' % str(self._servo_port))
94
Vadim Bendebury2b719452013-02-12 17:00:06 -080095 def _GetFlashScript(self, payload_size, boot_type, checksum, bus='0'):
Simon Glassa3f29ec2011-07-17 09:36:49 -070096 """Get the U-Boot boot command needed to flash U-Boot.
97
98 We leave a marker in the string for the load address of the image,
99 since this depends on the size of this script. This can be replaced by
100 the caller provided that the marker length is unchanged.
101
102 Args:
103 payload_size: Size of payload in bytes.
Simon Glass0dcbecb2012-03-22 21:38:55 -0700104 boot_type: The source for bootdevice (nand, sdmmc, or spi)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700105 checksum: The checksum of the payload (an integer)
106 bus: The bus number
Simon Glassa3f29ec2011-07-17 09:36:49 -0700107
108 Returns:
109 A tuple containing:
110 The script, as a string ready to use as a U-Boot boot command, with an
111 embedded marker for the load address.
112 The marker string, which the caller should replace with the correct
113 load address as 8 hex digits, without changing its length.
114 """
115 replace_me = 'zsHEXYla'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800116 page_size = 4096
Simon Glass0dcbecb2012-03-22 21:38:55 -0700117 if boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800118 page_size = 512
Vadim Bendebury2b719452013-02-12 17:00:06 -0800119 update = self.update and boot_type == 'spi'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800120
Simon Glassa3f29ec2011-07-17 09:36:49 -0700121 cmds = [
122 'setenv address 0x%s' % replace_me,
123 'setenv firmware_size %#x' % payload_size,
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800124 'setenv length %#x' % RoundUp(payload_size, page_size),
125 'setenv blocks %#x' % (RoundUp(payload_size, page_size) / page_size),
Simon Glass5b51b472013-03-28 13:06:05 -0700126 'setenv _crc "crc32 -v ${address} ${firmware_size} %08x"' %
Simon Glass8bd05ec2012-03-22 11:09:04 -0700127 checksum,
Simon Glass5b5fd642011-08-17 12:24:01 -0700128 'setenv _clear "echo Clearing RAM; mw.b ${address} 0 ${length}"',
Doug Anderson37ae2292011-09-15 17:41:57 -0700129 ]
Simon Glass0dcbecb2012-03-22 21:38:55 -0700130 if boot_type == 'nand':
Doug Anderson37ae2292011-09-15 17:41:57 -0700131 cmds.extend([
132 'setenv _init "echo Init NAND; nand info"',
133 'setenv _erase "echo Erase NAND; nand erase 0 ${length}"',
134 'setenv _write "echo Write NAND; nand write ${address} 0 ${length}"',
135 'setenv _read "echo Read NAND; nand read ${address} 0 ${length}"',
136 ])
Simon Glass0dcbecb2012-03-22 21:38:55 -0700137 elif boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800138 cmds.extend([
Allen Martinc4e25b42013-04-05 17:05:39 -0700139 'setenv _init "echo Init EMMC; mmc rescan 0"',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800140 'setenv _erase "echo Erase EMMC; "',
Allen Martinc4e25b42013-04-05 17:05:39 -0700141 'setenv _write "echo Write EMMC; mmc open 0 1;' \
142 ' mmc write ${address} 0 ' \
143 '${blocks};' \
144 ' mmc close 0 1"',
145 'setenv _read "echo Read EMMC; mmc open 0 1;' \
146 ' mmc read ${address} 0 ' \
147 '${blocks};' \
148 ' mmc close 0 1"',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800149 ])
Doug Anderson37ae2292011-09-15 17:41:57 -0700150 else:
151 cmds.extend([
Simon Glass3d9a6c62012-03-15 20:38:04 -0700152 'setenv _init "echo Init SPI; sf probe %s"' % bus,
Doug Anderson37ae2292011-09-15 17:41:57 -0700153 'setenv _erase "echo Erase SPI; sf erase 0 ${length}"',
154 'setenv _write "echo Write SPI; sf write ${address} 0 ${length}"',
155 'setenv _read "echo Read SPI; sf read ${address} 0 ${length}"',
156 'setenv _update "echo Update SPI; sf update ${address} 0 ${length}"',
157 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700158
Doug Anderson37ae2292011-09-15 17:41:57 -0700159 cmds.extend([
Simon Glassa3f29ec2011-07-17 09:36:49 -0700160 'echo Firmware loaded to ${address}, size ${firmware_size}, '
161 'length ${length}',
Simon Glass8bd05ec2012-03-22 11:09:04 -0700162 'if run _crc; then',
Simon Glassa3f29ec2011-07-17 09:36:49 -0700163 'run _init',
Doug Anderson37ae2292011-09-15 17:41:57 -0700164 ])
Simon Glass5b5fd642011-08-17 12:24:01 -0700165 if update:
166 cmds += ['time run _update']
167 else:
168 cmds += ['run _erase', 'run _write']
Vadim Bendebury2b719452013-02-12 17:00:06 -0800169 if self.verify:
Simon Glass5b5fd642011-08-17 12:24:01 -0700170 cmds += [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700171 'run _clear',
172 'run _read',
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800173 'if run _crc; then',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800174 'echo "%s"' % self._WRITE_SUCCESS_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800175 'else',
176 'echo',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800177 'echo "%s"' % self._WRITE_FAILURE_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800178 'echo',
179 'fi',
Simon Glass5b5fd642011-08-17 12:24:01 -0700180 ]
181 else:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800182 cmds += ['echo %s' % self._SKIP_VERIFY_MESSAGE]
Simon Glass8bd05ec2012-03-22 11:09:04 -0700183 cmds.extend([
184 'else',
185 'echo',
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800186 'echo "%s"' % self._DOWNLOAD_FAILURE_MESSAGE,
Simon Glass8bd05ec2012-03-22 11:09:04 -0700187 'fi',
188 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700189 script = '; '.join(cmds)
190 return script, replace_me
191
Vadim Bendebury2b719452013-02-12 17:00:06 -0800192 def _PrepareFlasher(self, uboot, payload, boot_type, bus):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700193 """Get a flasher ready for sending to the board.
194
195 The flasher is an executable image consisting of:
196
197 - U-Boot (u-boot.bin);
198 - a special FDT to tell it what to do in the form of a run command;
199 - (we could add some empty space here, in case U-Boot is not built to
200 be relocatable);
201 - the payload (which is a full flash image, or signed U-Boot + fdt).
202
203 Args:
204 uboot: Full path to u-boot.bin.
205 payload: Full path to payload.
Simon Glass0dcbecb2012-03-22 21:38:55 -0700206 boot_type: the src for bootdevice (nand, sdmmc, or spi)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700207
208 Returns:
Simon Glass290a1802011-07-17 13:54:32 -0700209 Filename of the flasher binary created.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700210 """
Simon Glass951a2db2011-07-17 15:58:58 -0700211 fdt = self._fdt.Copy(os.path.join(self._tools.outdir, 'flasher.dtb'))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700212 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700213
Simon Glass8bd05ec2012-03-22 11:09:04 -0700214 # Make sure that the checksum is not negative
215 checksum = binascii.crc32(payload_data) & 0xffffffff
216
Vadim Bendebury2b719452013-02-12 17:00:06 -0800217 script, replace_me = self._GetFlashScript(len(payload_data), boot_type,
218 checksum, bus)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700219 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800220 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700221 fdt_data = self._tools.ReadFile(fdt.fname)
222
223 # Work out where to place the payload in memory. This is a chicken-and-egg
224 # problem (although in case you haven't heard, it was the chicken that
225 # came first), so we resolve it by replacing the string after
226 # fdt.PutString has done its job.
227 #
228 # Correction: Technically, the egg came first. Whatever genetic mutation
229 # created the new species would have been present in the egg, but not the
230 # parent (since if it was in the parent, it would have been present in the
231 # parent when it was an egg).
232 #
233 # Question: ok so who laid the egg then?
234 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700235
236 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
237 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700238 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700239
Simon Glass2c4b3e52011-11-15 14:45:43 -0800240 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700241 new_str = '%08x' % load_address
242 if len(replace_me) is not len(new_str):
243 raise ValueError("Internal error: replacement string '%s' length does "
244 "not match new string '%s'" % (replace_me, new_str))
Vadim Bendebury19a77122013-01-24 17:38:00 -0800245 matches = len(re.findall(replace_me, fdt_data))
246 if matches != 1:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700247 raise ValueError("Internal error: replacement string '%s' already "
248 "exists in the fdt (%d matches)" % (replace_me, matches))
249 fdt_data = re.sub(replace_me, new_str, fdt_data)
250
251 # Now put it together.
252 data += fdt_data
253 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700254 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700255 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700256 self._tools.WriteFile(flasher, data)
257
258 # Tell the user about a few things.
259 self._tools.OutputSize('U-Boot', uboot)
260 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700261 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700262 self._tools.OutputSize('Flasher', flasher)
263 return flasher
264
Vadim Bendebury19a77122013-01-24 17:38:00 -0800265 def NvidiaFlashImage(self, flash_dest, uboot, bct, payload, bootstub):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700266 """Flash the image to SPI flash.
267
268 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000269 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700270
271 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700272 flash_dest: Destination for flasher, or None to not create a flasher
273 Valid options are spi, sdmmc
Simon Glassa3f29ec2011-07-17 09:36:49 -0700274 uboot: Full path to u-boot.bin.
275 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
276 payload: Full path to payload.
Simon Glass89ecf712012-06-07 12:20:15 -0700277 bootstub: Full path to bootstub, which is the payload without the
278 signing information (i.e. bootstub is u-boot.bin + the FDT)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700279
280 Returns:
281 True if ok, False if failed.
282 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800283 # Use a Regex to pull Boot type from BCT file.
284 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
285 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700286
287 # TODO(sjg): The boot type is currently selected by the bct, rather than
288 # flash_dest selecting which bct to use. This is a bit backwards. For now
289 # we go with the bct's idea.
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800290 boot_type = filter(match.match, bct_dumped)
Simon Glass0dcbecb2012-03-22 21:38:55 -0700291 boot_type = match.match(boot_type[0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700292
Simon Glass89ecf712012-06-07 12:20:15 -0700293 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800294 image = self._PrepareFlasher(uboot, payload, boot_type, 0)
Simon Glasse1824db2012-07-11 17:38:40 +0200295 elif bootstub:
Simon Glass89ecf712012-06-07 12:20:15 -0700296 image = bootstub
Simon Glassa3f29ec2011-07-17 09:36:49 -0700297
Simon Glasse1824db2012-07-11 17:38:40 +0200298 else:
299 image = payload
300 # If we don't know the textbase, extract it from the payload.
301 if self.text_base == -1:
302 data = self._tools.ReadFile(payload)
303 # Skip the BCT which is the first 64KB
304 self.text_base = self._bundle.DecodeTextBase(data[0x10000:])
305
Simon Glass89ecf712012-06-07 12:20:15 -0700306 self._out.Notice('TEXT_BASE is %#x' % self.text_base)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700307 self._out.Progress('Uploading flasher image')
308 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700309 '--bct', bct,
Allen Martinb3aa2672012-03-23 15:55:25 +0000310 '--bootloader', image,
311 '--loadaddr', "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700312 ]
313
314 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
315 last_err = None
Vadim Bendebury19a77122013-01-24 17:38:00 -0800316 for _ in range(10):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700317 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700318 # TODO(sjg): Use Chromite library so we can monitor output
Allen Martinb3aa2672012-03-23 15:55:25 +0000319 self._tools.Run('tegrarcm', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700320 self._out.Notice('Flasher downloaded - please see serial output '
321 'for progress.')
322 return True
323
324 except CmdError as err:
325 if not self._out.stdout_is_tty:
326 return False
327
328 # Only show the error output once unless it changes.
329 err = str(err)
Simon Glass22190ff2012-07-11 14:52:26 +0200330 if not 'could not open USB device' in err:
Allen Martinb3aa2672012-03-23 15:55:25 +0000331 raise CmdError('tegrarcm failed: %s' % err)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700332
333 if err != last_err:
334 self._out.Notice(err)
335 last_err = err
336 self._out.Progress('Please connect USB A-A cable and do a '
337 'recovery-reset', True)
338 time.sleep(1)
339
340 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700341
Simon Glass27a9c142012-03-15 21:08:29 -0700342 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
343 """Wait until we see a device on the USB bus.
344
345 Args:
346 name: Board type name
347 vendor_id: USB vendor ID to look for
348 product_id: USB product ID to look for
349 timeout: Timeout to wait in seconds
350
351 Returns
352 True if the device was found, False if we timed out.
353 """
354 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass4968a472012-05-23 13:52:19 -0700355 start_time = time.time()
356 while time.time() - start_time < timeout:
Simon Glass27a9c142012-03-15 21:08:29 -0700357 try:
358 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
359 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700360 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700361 return True
362
Vadim Bendebury19a77122013-01-24 17:38:00 -0800363 except CmdError:
Simon Glass27a9c142012-03-15 21:08:29 -0700364 pass
365
Simon Glass3381a1a2012-03-22 11:13:19 -0700366 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700367
Vadim Bendebury2b719452013-02-12 17:00:06 -0800368 def DutControl(self, args):
Simon Glass6a616c12012-09-24 18:13:46 -0700369 """Run dut-control with supplied arguments.
370
Simon Glass2065a742013-02-09 13:39:26 -0800371 The correct servo will be used based on self._servo_port. If servo use is
372 disabled, this function does nothing.
Simon Glass6a616c12012-09-24 18:13:46 -0700373
374 Args:
375 args: List of arguments to dut-control.
376
Simon Glass2065a742013-02-09 13:39:26 -0800377 Returns:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800378 a string, stdout generated by running the command
Simon Glass6a616c12012-09-24 18:13:46 -0700379 """
380 if self._servo_port is None:
Simon Glass2065a742013-02-09 13:39:26 -0800381 return '' # User has requested not to use servo
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800382 if self._servo_port:
Simon Glass6a616c12012-09-24 18:13:46 -0700383 args.extend(['-p', '%s' % self._servo_port])
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800384 return self._tools.Run('dut-control', args)
Simon Glass6a616c12012-09-24 18:13:46 -0700385
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800386 def WaitForCompletion(self):
Vadim Bendebury2b719452013-02-12 17:00:06 -0800387 """Verify flash programming operation success.
388
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800389 The DUT is presumed to be programming flash with console capture mode on.
390 This function scans console output for the success or failure strings.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800391
392 Raises:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800393 CmdError if the following cases:
394 - none of the strings show up in the allotted time (2 minutes)
395 - console goes silent for more than 10 seconds
396 - one of the error messages seen in the stream
397 - misformatted output is seen in the stream
Vadim Bendebury2b719452013-02-12 17:00:06 -0800398 """
399
400 _SOFT_DEADLINE_LIMIT = 10
401 _HARD_DEADLINE_LIMIT = 120
402 string_leftover = ''
403 soft_deadline = time.time() + _SOFT_DEADLINE_LIMIT
404 hard_deadline = soft_deadline + _HARD_DEADLINE_LIMIT - _SOFT_DEADLINE_LIMIT
405
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800406 if self.verify:
407 done_line = self._WRITE_SUCCESS_MESSAGE
408 else:
409 done_line = self._SKIP_VERIFY_MESSAGE
410
Vadim Bendebury2b719452013-02-12 17:00:06 -0800411 while True:
412 now = time.time()
413 if now > hard_deadline:
414 raise CmdError('Target console flooded, programming failed')
415 if now > soft_deadline:
416 raise CmdError('Target console dead, programming failed')
417 stream = self.DutControl(['cpu_uart_stream',])
418 match = re.search("^cpu_uart_stream:'(.*)'\n", stream)
419 if not match:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800420 raise CmdError('Misformatted console output: \n%s\n' % stream)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800421
422 text = string_leftover + match.group(1)
423 strings = text.split('\\r')
424 string_leftover = strings.pop()
425 if strings:
426 soft_deadline = now + _SOFT_DEADLINE_LIMIT
427 for string in strings:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800428 if done_line in string:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800429 return True
430 if self._WRITE_FAILURE_MESSAGE in string:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800431 raise CmdError('Readback verification failed!')
432 if self._DOWNLOAD_FAILURE_MESSAGE in string:
433 raise CmdError('Download failed!')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800434
Simon Glass4c54a912013-02-18 16:56:29 -0800435 def _ExtractPayloadParts(self, payload, truncate_to_fdt):
Simon Glass3c5b35b2012-05-23 13:22:23 -0700436 """Extract the BL1, BL2 and U-Boot parts from a payload.
437
438 An exynos image consists of 3 parts: BL1, BL2 and U-Boot/FDT.
439
440 This pulls out the various parts, puts them into files and returns
441 these files.
442
443 Args:
444 payload: Full path to payload.
Simon Glass4c54a912013-02-18 16:56:29 -0800445 truncate_to_fdt: Truncate the U-Boot image at the start of its
446 embedded FDT
Simon Glass3c5b35b2012-05-23 13:22:23 -0700447
448 Returns:
449 (bl1, bl2, image) where:
450 bl1 is the filename of the extracted BL1
451 bl2 is the filename of the extracted BL2
452 image is the filename of the extracted U-Boot image
453 """
454 # Pull out the parts from the payload
455 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
456 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
457 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
458 data = self._tools.ReadFile(payload)
459
460 # The BL1 is always 8KB - extract that part into a new file
461 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
Simon Glasse86f3132013-01-08 16:10:43 -0800462 bl1_size = 0x2000
463 self._tools.WriteFile(bl1, data[:bl1_size])
Simon Glass3c5b35b2012-05-23 13:22:23 -0700464
Simon Glassb345a5a2013-05-11 15:02:21 -0700465 # Try to detect the BL2 size. We look for 0xea000014 or 0xea000013
466 # which is the 'B reset' instruction at the start of U-Boot. When
467 # U-Boot is LZO compressed, we look for a LZO magic instead.
468 start_data = [struct.pack('<L', 0xea000014),
469 struct.pack('<L', 0xea000013),
470 struct.pack('>B3s', 0x89, 'LZO')]
471 starts = [data.find(magic, bl1_size + 0x3800) for magic in start_data]
472 uboot_offset = None
473 for start in starts:
474 if start != -1 and (not uboot_offset or start < uboot_offset):
475 uboot_offset = start
476 if not uboot_offset:
Vadim Bendebury19a77122013-01-24 17:38:00 -0800477 raise ValueError('Could not locate start of U-Boot')
Simon Glasse86f3132013-01-08 16:10:43 -0800478 bl2_size = uboot_offset - bl1_size - 0x800 # 2KB gap after BL2
Simon Glass3c5b35b2012-05-23 13:22:23 -0700479
Simon Glasse86f3132013-01-08 16:10:43 -0800480 # Sanity check: At present we only allow 14KB and 30KB for SPL
481 allowed = [14, 30]
482 if (bl2_size >> 10) not in allowed:
Vadim Bendebury19a77122013-01-24 17:38:00 -0800483 raise ValueError('BL2 size is %dK - only %s supported' %
484 (bl2_size >> 10, ', '.join(
485 [str(size) for size in allowed])))
Simon Glasse86f3132013-01-08 16:10:43 -0800486 self._out.Notice('BL2 size is %dKB' % (bl2_size >> 10))
487
488 # The BL2 (U-Boot SPL) follows BL1. After that there is a 2KB gap
489 bl2_end = uboot_offset - 0x800
490 self._tools.WriteFile(bl2, data[0x2000:bl2_end])
491
Simon Glassbc0d8d42013-02-09 11:59:36 -0800492 # U-Boot itself starts at 24KB, after the gap. As a hack, truncate it
Simon Glass4c54a912013-02-18 16:56:29 -0800493 # to an assumed maximum size. As a secondary hack, locate the FDT
494 # and truncate U-Boot from that point. The correct FDT will be added
495 # when the image is written to the board.
Simon Glassbc0d8d42013-02-09 11:59:36 -0800496 # TODO(sjg@chromium.org): Get a proper flash map here so we know how
497 # large it is
Simon Glass4c54a912013-02-18 16:56:29 -0800498 uboot_data = data[uboot_offset:uboot_offset + 0xa0000]
499 if truncate_to_fdt:
500 fdt_magic = struct.pack('>L', 0xd00dfeed)
501 fdt_offset = uboot_data.rfind(fdt_magic)
502 uboot_data = uboot_data[:fdt_offset]
503
504 self._tools.WriteFile(image, uboot_data)
Simon Glass3c5b35b2012-05-23 13:22:23 -0700505 return bl1, bl2, image
506
Vadim Bendebury19a77122013-01-24 17:38:00 -0800507 def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
Simon Glassde9c8072012-07-02 22:29:02 -0700508 kernel):
Simon Glass27a9c142012-03-15 21:08:29 -0700509 """Flash the image to SPI flash.
510
511 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000512 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glass27a9c142012-03-15 21:08:29 -0700513
514 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700515 flash_dest: Destination for flasher, or None to not create a flasher
516 Valid options are spi, sdmmc.
517 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700518 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700519 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700520 payload: Full path to payload.
Simon Glassde9c8072012-07-02 22:29:02 -0700521 kernel: Kernel to send after the payload, or None.
Simon Glass27a9c142012-03-15 21:08:29 -0700522
523 Returns:
524 True if ok, False if failed.
525 """
Simon Glassbc0d8d42013-02-09 11:59:36 -0800526 tools = self._tools
527 payload_bl1, payload_bl2, payload_image = (
Simon Glass4c54a912013-02-18 16:56:29 -0800528 self._ExtractPayloadParts(payload, flash_dest is not None))
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700529 if flash_dest:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800530 # If we don't have some bits, get them from the image
531 if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
532 self._out.Warning('Extracting U-Boot from payload')
533 flash_uboot = payload_image
534 if not bl1 or not os.path.exists(tools.Filename(bl1)):
535 self._out.Warning('Extracting BL1 from payload')
536 bl1 = payload_bl1
537 if not bl2 or not os.path.exists(tools.Filename(bl2)):
538 self._out.Warning('Extracting BL2 from payload')
539 bl2 = payload_bl2
Vadim Bendebury2b719452013-02-12 17:00:06 -0800540 image = self._PrepareFlasher(flash_uboot, payload, flash_dest, '1:0')
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700541 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800542 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700543
544 vendor_id = 0x04e8
545 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700546
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800547 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800548 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
549 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800550 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800551 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700552 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800553 if preserved_dut_hub_sel != required_dut_hub_sel:
554 # Need to set it to get the port properly powered up.
555 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Simon Glass93673cf2013-04-26 17:55:55 -0700556 if self._servo_port is not None:
557 self._out.Progress('Reseting board via servo')
558 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700559
Simon Glassde9c8072012-07-02 22:29:02 -0700560 # If we have a kernel to write, create a new image with that added.
561 if kernel:
562 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
563 data = self._tools.ReadFile(image)
564
565 # Pad the original payload out to the original length
566 data += '\0' * (os.stat(payload).st_size - len(data))
567 data += self._tools.ReadFile(kernel)
568 self._tools.WriteFile(dl_image, data)
569 else:
570 dl_image = image
571
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700572 self._out.Progress('Uploading image')
Simon Glass27a9c142012-03-15 21:08:29 -0700573 download_list = [
Simon Glass3c5b35b2012-05-23 13:22:23 -0700574 # The numbers are the download addresses (in SRAM) for each piece
575 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
Simon Glass27a9c142012-03-15 21:08:29 -0700576 ['bl1', 0x02021400, bl1],
577 ['bl2', 0x02023400, bl2],
Simon Glassde9c8072012-07-02 22:29:02 -0700578 ['u-boot', 0x43e00000, dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700579 ]
Simon Glass3381a1a2012-03-22 11:13:19 -0700580 try:
Simon Glass4968a472012-05-23 13:52:19 -0700581 for upto in range(len(download_list)):
582 item = download_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700583 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700584 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700585 raise CmdError('Could not find Exynos board on USB port')
586 raise CmdError("Stage '%s' did not complete" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700587 self._out.Notice(item[2])
Simon Glass27a9c142012-03-15 21:08:29 -0700588 self._out.Progress("Uploading stage '%s'" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700589
Simon Glass4968a472012-05-23 13:52:19 -0700590 if upto == 0:
591 # The IROM needs roughly 200ms here to be ready for USB download
592 time.sleep(.5)
593
Simon Glass79e3dd02012-08-28 20:08:50 -0700594 args = ['-a', '%#x' % item[1], '-f', item[2]]
595 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700596
Simon Glass3381a1a2012-03-22 11:13:19 -0700597 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800598 # Make sure that the power button is released and dut_sel_hub state is
599 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700600 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800601 if preserved_dut_hub_sel != required_dut_hub_sel:
602 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800603 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700604
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800605 if flash_dest is None:
606 self._out.Notice('Image downloaded - please see serial output '
607 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700608 return True
609
Simon Glass0c2ba482012-03-22 21:57:51 -0700610 def _GetDiskInfo(self, disk, item):
611 """Returns information about a SCSI disk device.
612
613 Args:
614 disk: a block device name in sys/block, like '/sys/block/sdf'.
615 item: the item of disk information that is required.
616
617 Returns:
618 The information obtained, as a string, or '[Unknown]' if not found
619 """
620 dev_path = os.path.join(disk, 'device')
621
622 # Search upwards and through symlinks looking for the item.
623 while os.path.isdir(dev_path) and dev_path != '/sys':
624 fname = os.path.join(dev_path, item)
625 if os.path.exists(fname):
626 with open(fname, 'r') as fd:
627 return fd.readline().rstrip()
628
629 # Move up a level and follow any symlink.
630 new_path = os.path.join(dev_path, '..')
631 if os.path.islink(new_path):
632 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
633 dev_path = new_path
634 return '[Unknown]'
635
636 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700637 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700638
639 Args:
640 device: Device to check, like '/dev/sdf'.
641
642 Returns:
643 Capacity of device in GB, or 0 if not known.
644 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700645 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700646 args = ['-l', device]
647 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700648 for line in stdout.splitlines():
649 m = re_capacity.match(line)
650 if m:
651 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700652 return 0
653
654 def _ListUsbDisks(self):
655 """Return a list of available removable USB disks.
656
657 Returns:
658 List of USB devices, each element is itself a list containing:
659 device ('/dev/sdx')
660 manufacturer name
661 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700662 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700663 """
664 disk_list = []
665 for disk in glob.glob('/sys/block/sd*'):
666 with open(disk + '/removable', 'r') as fd:
667 if int(fd.readline()) == 1:
668 device = '/dev/%s' % disk.split('/')[-1]
669 manuf = self._GetDiskInfo(disk, 'manufacturer')
670 product = self._GetDiskInfo(disk, 'product')
671 capacity = self._GetDiskCapacity(device)
672 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700673 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700674 return disk_list
675
676 def WriteToSd(self, flash_dest, disk, uboot, payload):
677 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800678 raw_image = self._PrepareFlasher(uboot, payload, flash_dest, '1:0')
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700679 bl1, bl2, _ = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700680 spl_load_size = os.stat(raw_image).st_size
Simon Glass559b6612012-05-23 13:28:45 -0700681
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700682 bl2_handler = ExynosBl2(self._tools, self._out)
Vadim Bendebury0c961a72013-06-11 13:35:07 -0700683 bl2_file = bl2_handler.Configure(self._fdt, spl_load_size,
684 bl2, 'flasher', False)
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700685 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2_file)
Simon Glass559b6612012-05-23 13:28:45 -0700686
687 # Pad BL2 out to the required size.
688 # We require that it be 24KB, but data will only contain 8KB + 14KB.
689 # Add the extra padding to bring it to 24KB.
690 data += '\0' * (0x6000 - len(data))
691 data += self._tools.ReadFile(raw_image)
692 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
693 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700694 self._out.Progress('Writing flasher to %s' % disk)
695 else:
696 image = payload
697 self._out.Progress('Writing image to %s' % disk)
698
699 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
700 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700701 self._out.Progress('Syncing')
702 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700703
704 def SendToSdCard(self, dest, flash_dest, uboot, payload):
705 """Write a flasher to an SD card.
706
707 Args:
708 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700709 ':.' selects the only available device, fails if more than one option
710 ':<device>' select deivce
711
712 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700713 ':.'
714 ':/dev/sdd'
715
716 flash_dest: Destination for flasher, or None to not create a flasher:
717 Valid options are spi, sdmmc.
718 uboot: Full path to u-boot.bin.
719 payload: Full path to payload.
720 """
721 disk = None
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700722
Vadim Bendebury223af572013-04-27 13:25:13 -0700723 # If no removable devices found - prompt user and wait for one to appear.
724 disks = self._ListUsbDisks()
725 try:
726 spinner = '|/-\\'
727 index = 0
728 while not disks:
729 self._out.ClearProgress()
730 self._out.Progress('No removable devices found, plug something in %s '
731 % spinner[index], trailer='')
732 index = (index + 1) % len(spinner)
733 disks = self._ListUsbDisks()
734 time.sleep(.2)
735 except KeyboardInterrupt:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700736 raise CmdError("No removable device found, interrupted")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700737
738 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700739 name = dest[1:]
740
741 # A '.' just means to use the only available disk.
742 if name == '.' and len(disks) == 1:
743 disk = disks[0][0]
744 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700745 # Use the device name.
746 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700747 disk = disk_info[0]
748
749 if disk:
750 self.WriteToSd(flash_dest, disk, uboot, payload)
751 else:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700752 msg = ["Please specify destination as '-w sd:<disk_description>'",]
753 msg.append(' - <disk_description> can be either . for the only disk,')
754 msg.append(' or the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700755 # List available disks as a convenience.
756 for disk in disks:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700757 msg.append(' %s - %s %.1f GB' % (
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700758 disk[0],
759 ' '.join(str(x) for x in disk[1:3]),
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700760 disk[3] / 10.0))
761 raise CmdError('\n'.join(msg))
Simon Glass0c2ba482012-03-22 21:57:51 -0700762
Vadim Bendebury19a77122013-01-24 17:38:00 -0800763 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700764 """Send an image to an attached EM100 device.
765
766 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
767 to do the SPI emulation, then write the image, then boot the board.
768 All going well, this is enough to get U-Boot running.
769
770 Args:
771 image_fname: Filename of image to send
772 """
773 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
774 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800775 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700776
777 # TODO(sjg@chromium.org): This is for link. We could make this
778 # configurable from the fdt.
779 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
780 self._out.Progress('Writing image to em100')
781 self._tools.Run('em100', args, sudo=True)
782
Simon Glass93673cf2013-04-26 17:55:55 -0700783 if self._servo_port is not None:
784 self._out.Progress('Resetting board via servo')
785 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
786 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
787 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)