blob: a0dadd7a97f1c775e904d8cc0a13137b7aa65b94 [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([
137 'setenv _init "echo Init EMMC; mmc rescan 0"',
138 'setenv _erase "echo Erase EMMC; "',
139 'setenv _write "echo Write EMMC; mmc write 0 ${address} 0 ' \
140 '${blocks} boot1"',
141 'setenv _read "echo Read EMMC; mmc read 0 ${address} 0 ' \
142 '${blocks} boot1"',
143 ])
Doug Anderson37ae2292011-09-15 17:41:57 -0700144 else:
145 cmds.extend([
Simon Glass3d9a6c62012-03-15 20:38:04 -0700146 'setenv _init "echo Init SPI; sf probe %s"' % bus,
Doug Anderson37ae2292011-09-15 17:41:57 -0700147 'setenv _erase "echo Erase SPI; sf erase 0 ${length}"',
148 'setenv _write "echo Write SPI; sf write ${address} 0 ${length}"',
149 'setenv _read "echo Read SPI; sf read ${address} 0 ${length}"',
150 'setenv _update "echo Update SPI; sf update ${address} 0 ${length}"',
151 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700152
Doug Anderson37ae2292011-09-15 17:41:57 -0700153 cmds.extend([
Simon Glassa3f29ec2011-07-17 09:36:49 -0700154 'echo Firmware loaded to ${address}, size ${firmware_size}, '
155 'length ${length}',
Simon Glass8bd05ec2012-03-22 11:09:04 -0700156 'if run _crc; then',
Simon Glassa3f29ec2011-07-17 09:36:49 -0700157 'run _init',
Doug Anderson37ae2292011-09-15 17:41:57 -0700158 ])
Simon Glass5b5fd642011-08-17 12:24:01 -0700159 if update:
160 cmds += ['time run _update']
161 else:
162 cmds += ['run _erase', 'run _write']
Vadim Bendebury2b719452013-02-12 17:00:06 -0800163 if self.verify:
Simon Glass5b5fd642011-08-17 12:24:01 -0700164 cmds += [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700165 'run _clear',
166 'run _read',
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800167 'if run _crc; then',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800168 'echo "%s"' % self._WRITE_SUCCESS_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800169 'else',
170 'echo',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800171 'echo "%s"' % self._WRITE_FAILURE_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800172 'echo',
173 'fi',
Simon Glass5b5fd642011-08-17 12:24:01 -0700174 ]
175 else:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800176 cmds += ['echo %s' % self._SKIP_VERIFY_MESSAGE]
Simon Glass8bd05ec2012-03-22 11:09:04 -0700177 cmds.extend([
178 'else',
179 'echo',
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800180 'echo "%s"' % self._DOWNLOAD_FAILURE_MESSAGE,
Simon Glass8bd05ec2012-03-22 11:09:04 -0700181 'fi',
182 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700183 script = '; '.join(cmds)
184 return script, replace_me
185
Vadim Bendebury2b719452013-02-12 17:00:06 -0800186 def _PrepareFlasher(self, uboot, payload, boot_type, bus):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700187 """Get a flasher ready for sending to the board.
188
189 The flasher is an executable image consisting of:
190
191 - U-Boot (u-boot.bin);
192 - a special FDT to tell it what to do in the form of a run command;
193 - (we could add some empty space here, in case U-Boot is not built to
194 be relocatable);
195 - the payload (which is a full flash image, or signed U-Boot + fdt).
196
197 Args:
198 uboot: Full path to u-boot.bin.
199 payload: Full path to payload.
Simon Glass0dcbecb2012-03-22 21:38:55 -0700200 boot_type: the src for bootdevice (nand, sdmmc, or spi)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700201
202 Returns:
Simon Glass290a1802011-07-17 13:54:32 -0700203 Filename of the flasher binary created.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700204 """
Simon Glass951a2db2011-07-17 15:58:58 -0700205 fdt = self._fdt.Copy(os.path.join(self._tools.outdir, 'flasher.dtb'))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700206 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700207
Simon Glass8bd05ec2012-03-22 11:09:04 -0700208 # Make sure that the checksum is not negative
209 checksum = binascii.crc32(payload_data) & 0xffffffff
210
Vadim Bendebury2b719452013-02-12 17:00:06 -0800211 script, replace_me = self._GetFlashScript(len(payload_data), boot_type,
212 checksum, bus)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700213 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800214 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700215 fdt_data = self._tools.ReadFile(fdt.fname)
216
217 # Work out where to place the payload in memory. This is a chicken-and-egg
218 # problem (although in case you haven't heard, it was the chicken that
219 # came first), so we resolve it by replacing the string after
220 # fdt.PutString has done its job.
221 #
222 # Correction: Technically, the egg came first. Whatever genetic mutation
223 # created the new species would have been present in the egg, but not the
224 # parent (since if it was in the parent, it would have been present in the
225 # parent when it was an egg).
226 #
227 # Question: ok so who laid the egg then?
228 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700229
230 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
231 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700232 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700233
Simon Glass2c4b3e52011-11-15 14:45:43 -0800234 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700235 new_str = '%08x' % load_address
236 if len(replace_me) is not len(new_str):
237 raise ValueError("Internal error: replacement string '%s' length does "
238 "not match new string '%s'" % (replace_me, new_str))
Vadim Bendebury19a77122013-01-24 17:38:00 -0800239 matches = len(re.findall(replace_me, fdt_data))
240 if matches != 1:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700241 raise ValueError("Internal error: replacement string '%s' already "
242 "exists in the fdt (%d matches)" % (replace_me, matches))
243 fdt_data = re.sub(replace_me, new_str, fdt_data)
244
245 # Now put it together.
246 data += fdt_data
247 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700248 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700249 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700250 self._tools.WriteFile(flasher, data)
251
252 # Tell the user about a few things.
253 self._tools.OutputSize('U-Boot', uboot)
254 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700255 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700256 self._tools.OutputSize('Flasher', flasher)
257 return flasher
258
Vadim Bendebury19a77122013-01-24 17:38:00 -0800259 def NvidiaFlashImage(self, flash_dest, uboot, bct, payload, bootstub):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700260 """Flash the image to SPI flash.
261
262 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000263 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700264
265 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700266 flash_dest: Destination for flasher, or None to not create a flasher
267 Valid options are spi, sdmmc
Simon Glassa3f29ec2011-07-17 09:36:49 -0700268 uboot: Full path to u-boot.bin.
269 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
270 payload: Full path to payload.
Simon Glass89ecf712012-06-07 12:20:15 -0700271 bootstub: Full path to bootstub, which is the payload without the
272 signing information (i.e. bootstub is u-boot.bin + the FDT)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700273
274 Returns:
275 True if ok, False if failed.
276 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800277 # Use a Regex to pull Boot type from BCT file.
278 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
279 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700280
281 # TODO(sjg): The boot type is currently selected by the bct, rather than
282 # flash_dest selecting which bct to use. This is a bit backwards. For now
283 # we go with the bct's idea.
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800284 boot_type = filter(match.match, bct_dumped)
Simon Glass0dcbecb2012-03-22 21:38:55 -0700285 boot_type = match.match(boot_type[0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700286
Simon Glass89ecf712012-06-07 12:20:15 -0700287 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800288 image = self._PrepareFlasher(uboot, payload, boot_type, 0)
Simon Glasse1824db2012-07-11 17:38:40 +0200289 elif bootstub:
Simon Glass89ecf712012-06-07 12:20:15 -0700290 image = bootstub
Simon Glassa3f29ec2011-07-17 09:36:49 -0700291
Simon Glasse1824db2012-07-11 17:38:40 +0200292 else:
293 image = payload
294 # If we don't know the textbase, extract it from the payload.
295 if self.text_base == -1:
296 data = self._tools.ReadFile(payload)
297 # Skip the BCT which is the first 64KB
298 self.text_base = self._bundle.DecodeTextBase(data[0x10000:])
299
Simon Glass89ecf712012-06-07 12:20:15 -0700300 self._out.Notice('TEXT_BASE is %#x' % self.text_base)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700301 self._out.Progress('Uploading flasher image')
302 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700303 '--bct', bct,
Allen Martinb3aa2672012-03-23 15:55:25 +0000304 '--bootloader', image,
305 '--loadaddr', "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700306 ]
307
308 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
309 last_err = None
Vadim Bendebury19a77122013-01-24 17:38:00 -0800310 for _ in range(10):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700311 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700312 # TODO(sjg): Use Chromite library so we can monitor output
Allen Martinb3aa2672012-03-23 15:55:25 +0000313 self._tools.Run('tegrarcm', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700314 self._out.Notice('Flasher downloaded - please see serial output '
315 'for progress.')
316 return True
317
318 except CmdError as err:
319 if not self._out.stdout_is_tty:
320 return False
321
322 # Only show the error output once unless it changes.
323 err = str(err)
Simon Glass22190ff2012-07-11 14:52:26 +0200324 if not 'could not open USB device' in err:
Allen Martinb3aa2672012-03-23 15:55:25 +0000325 raise CmdError('tegrarcm failed: %s' % err)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700326
327 if err != last_err:
328 self._out.Notice(err)
329 last_err = err
330 self._out.Progress('Please connect USB A-A cable and do a '
331 'recovery-reset', True)
332 time.sleep(1)
333
334 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700335
Simon Glass27a9c142012-03-15 21:08:29 -0700336 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
337 """Wait until we see a device on the USB bus.
338
339 Args:
340 name: Board type name
341 vendor_id: USB vendor ID to look for
342 product_id: USB product ID to look for
343 timeout: Timeout to wait in seconds
344
345 Returns
346 True if the device was found, False if we timed out.
347 """
348 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass4968a472012-05-23 13:52:19 -0700349 start_time = time.time()
350 while time.time() - start_time < timeout:
Simon Glass27a9c142012-03-15 21:08:29 -0700351 try:
352 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
353 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700354 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700355 return True
356
Vadim Bendebury19a77122013-01-24 17:38:00 -0800357 except CmdError:
Simon Glass27a9c142012-03-15 21:08:29 -0700358 pass
359
Simon Glass3381a1a2012-03-22 11:13:19 -0700360 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700361
Vadim Bendebury2b719452013-02-12 17:00:06 -0800362 def DutControl(self, args):
Simon Glass6a616c12012-09-24 18:13:46 -0700363 """Run dut-control with supplied arguments.
364
Simon Glass2065a742013-02-09 13:39:26 -0800365 The correct servo will be used based on self._servo_port. If servo use is
366 disabled, this function does nothing.
Simon Glass6a616c12012-09-24 18:13:46 -0700367
368 Args:
369 args: List of arguments to dut-control.
370
Simon Glass2065a742013-02-09 13:39:26 -0800371 Returns:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800372 a string, stdout generated by running the command
Simon Glass6a616c12012-09-24 18:13:46 -0700373 """
374 if self._servo_port is None:
Simon Glass2065a742013-02-09 13:39:26 -0800375 return '' # User has requested not to use servo
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800376 if self._servo_port:
Simon Glass6a616c12012-09-24 18:13:46 -0700377 args.extend(['-p', '%s' % self._servo_port])
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800378 return self._tools.Run('dut-control', args)
Simon Glass6a616c12012-09-24 18:13:46 -0700379
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800380 def WaitForCompletion(self):
Vadim Bendebury2b719452013-02-12 17:00:06 -0800381 """Verify flash programming operation success.
382
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800383 The DUT is presumed to be programming flash with console capture mode on.
384 This function scans console output for the success or failure strings.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800385
386 Raises:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800387 CmdError if the following cases:
388 - none of the strings show up in the allotted time (2 minutes)
389 - console goes silent for more than 10 seconds
390 - one of the error messages seen in the stream
391 - misformatted output is seen in the stream
Vadim Bendebury2b719452013-02-12 17:00:06 -0800392 """
393
394 _SOFT_DEADLINE_LIMIT = 10
395 _HARD_DEADLINE_LIMIT = 120
396 string_leftover = ''
397 soft_deadline = time.time() + _SOFT_DEADLINE_LIMIT
398 hard_deadline = soft_deadline + _HARD_DEADLINE_LIMIT - _SOFT_DEADLINE_LIMIT
399
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800400 if self.verify:
401 done_line = self._WRITE_SUCCESS_MESSAGE
402 else:
403 done_line = self._SKIP_VERIFY_MESSAGE
404
Vadim Bendebury2b719452013-02-12 17:00:06 -0800405 while True:
406 now = time.time()
407 if now > hard_deadline:
408 raise CmdError('Target console flooded, programming failed')
409 if now > soft_deadline:
410 raise CmdError('Target console dead, programming failed')
411 stream = self.DutControl(['cpu_uart_stream',])
412 match = re.search("^cpu_uart_stream:'(.*)'\n", stream)
413 if not match:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800414 raise CmdError('Misformatted console output: \n%s\n' % stream)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800415
416 text = string_leftover + match.group(1)
417 strings = text.split('\\r')
418 string_leftover = strings.pop()
419 if strings:
420 soft_deadline = now + _SOFT_DEADLINE_LIMIT
421 for string in strings:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800422 if done_line in string:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800423 return True
424 if self._WRITE_FAILURE_MESSAGE in string:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800425 raise CmdError('Readback verification failed!')
426 if self._DOWNLOAD_FAILURE_MESSAGE in string:
427 raise CmdError('Download failed!')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800428
Simon Glass4c54a912013-02-18 16:56:29 -0800429 def _ExtractPayloadParts(self, payload, truncate_to_fdt):
Simon Glass3c5b35b2012-05-23 13:22:23 -0700430 """Extract the BL1, BL2 and U-Boot parts from a payload.
431
432 An exynos image consists of 3 parts: BL1, BL2 and U-Boot/FDT.
433
434 This pulls out the various parts, puts them into files and returns
435 these files.
436
437 Args:
438 payload: Full path to payload.
Simon Glass4c54a912013-02-18 16:56:29 -0800439 truncate_to_fdt: Truncate the U-Boot image at the start of its
440 embedded FDT
Simon Glass3c5b35b2012-05-23 13:22:23 -0700441
442 Returns:
443 (bl1, bl2, image) where:
444 bl1 is the filename of the extracted BL1
445 bl2 is the filename of the extracted BL2
446 image is the filename of the extracted U-Boot image
447 """
448 # Pull out the parts from the payload
449 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
450 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
451 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
452 data = self._tools.ReadFile(payload)
453
454 # The BL1 is always 8KB - extract that part into a new file
455 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
Simon Glasse86f3132013-01-08 16:10:43 -0800456 bl1_size = 0x2000
457 self._tools.WriteFile(bl1, data[:bl1_size])
Simon Glass3c5b35b2012-05-23 13:22:23 -0700458
Simon Glasse86f3132013-01-08 16:10:43 -0800459 # Try to detect the BL2 size. We look for 0xea000014 which is the
Tom Wai-Hong Tamf67046f2013-02-06 09:23:26 +0800460 # 'B reset' instruction at the start of U-Boot. When U-Boot is LZO
461 # compressed, we look for a LZO magic instead.
Simon Glasse86f3132013-01-08 16:10:43 -0800462 first_instr = struct.pack('<L', 0xea000014)
Tom Wai-Hong Tamf67046f2013-02-06 09:23:26 +0800463 lzo_magic = struct.pack('>B3s', 0x89, 'LZO')
464 first_instr_offset = data.find(first_instr, bl1_size + 0x3800)
465 lzo_magic_offset = data.find(lzo_magic, bl1_size + 0x3800)
466 uboot_offset = min(first_instr_offset, lzo_magic_offset)
467 if uboot_offset == -1:
468 uboot_offset = max(first_instr_offset, lzo_magic_offset)
Simon Glasse86f3132013-01-08 16:10:43 -0800469 if uboot_offset == -1:
Vadim Bendebury19a77122013-01-24 17:38:00 -0800470 raise ValueError('Could not locate start of U-Boot')
Simon Glasse86f3132013-01-08 16:10:43 -0800471 bl2_size = uboot_offset - bl1_size - 0x800 # 2KB gap after BL2
Simon Glass3c5b35b2012-05-23 13:22:23 -0700472
Simon Glasse86f3132013-01-08 16:10:43 -0800473 # Sanity check: At present we only allow 14KB and 30KB for SPL
474 allowed = [14, 30]
475 if (bl2_size >> 10) not in allowed:
Vadim Bendebury19a77122013-01-24 17:38:00 -0800476 raise ValueError('BL2 size is %dK - only %s supported' %
477 (bl2_size >> 10, ', '.join(
478 [str(size) for size in allowed])))
Simon Glasse86f3132013-01-08 16:10:43 -0800479 self._out.Notice('BL2 size is %dKB' % (bl2_size >> 10))
480
481 # The BL2 (U-Boot SPL) follows BL1. After that there is a 2KB gap
482 bl2_end = uboot_offset - 0x800
483 self._tools.WriteFile(bl2, data[0x2000:bl2_end])
484
Simon Glassbc0d8d42013-02-09 11:59:36 -0800485 # U-Boot itself starts at 24KB, after the gap. As a hack, truncate it
Simon Glass4c54a912013-02-18 16:56:29 -0800486 # to an assumed maximum size. As a secondary hack, locate the FDT
487 # and truncate U-Boot from that point. The correct FDT will be added
488 # when the image is written to the board.
Simon Glassbc0d8d42013-02-09 11:59:36 -0800489 # TODO(sjg@chromium.org): Get a proper flash map here so we know how
490 # large it is
Simon Glass4c54a912013-02-18 16:56:29 -0800491 uboot_data = data[uboot_offset:uboot_offset + 0xa0000]
492 if truncate_to_fdt:
493 fdt_magic = struct.pack('>L', 0xd00dfeed)
494 fdt_offset = uboot_data.rfind(fdt_magic)
495 uboot_data = uboot_data[:fdt_offset]
496
497 self._tools.WriteFile(image, uboot_data)
Simon Glass3c5b35b2012-05-23 13:22:23 -0700498 return bl1, bl2, image
499
Vadim Bendebury19a77122013-01-24 17:38:00 -0800500 def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
Simon Glassde9c8072012-07-02 22:29:02 -0700501 kernel):
Simon Glass27a9c142012-03-15 21:08:29 -0700502 """Flash the image to SPI flash.
503
504 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000505 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glass27a9c142012-03-15 21:08:29 -0700506
507 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700508 flash_dest: Destination for flasher, or None to not create a flasher
509 Valid options are spi, sdmmc.
510 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700511 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700512 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700513 payload: Full path to payload.
Simon Glassde9c8072012-07-02 22:29:02 -0700514 kernel: Kernel to send after the payload, or None.
Simon Glass27a9c142012-03-15 21:08:29 -0700515
516 Returns:
517 True if ok, False if failed.
518 """
Simon Glassbc0d8d42013-02-09 11:59:36 -0800519 tools = self._tools
520 payload_bl1, payload_bl2, payload_image = (
Simon Glass4c54a912013-02-18 16:56:29 -0800521 self._ExtractPayloadParts(payload, flash_dest is not None))
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700522 if flash_dest:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800523 # If we don't have some bits, get them from the image
524 if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
525 self._out.Warning('Extracting U-Boot from payload')
526 flash_uboot = payload_image
527 if not bl1 or not os.path.exists(tools.Filename(bl1)):
528 self._out.Warning('Extracting BL1 from payload')
529 bl1 = payload_bl1
530 if not bl2 or not os.path.exists(tools.Filename(bl2)):
531 self._out.Warning('Extracting BL2 from payload')
532 bl2 = payload_bl2
Vadim Bendebury2b719452013-02-12 17:00:06 -0800533 image = self._PrepareFlasher(flash_uboot, payload, flash_dest, '1:0')
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700534 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800535 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700536
537 vendor_id = 0x04e8
538 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700539
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800540 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800541 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
542 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800543 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800544 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700545 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800546 if preserved_dut_hub_sel != required_dut_hub_sel:
547 # Need to set it to get the port properly powered up.
548 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800549 self._out.Progress('Reseting board via servo')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800550 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700551
Simon Glassde9c8072012-07-02 22:29:02 -0700552 # If we have a kernel to write, create a new image with that added.
553 if kernel:
554 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
555 data = self._tools.ReadFile(image)
556
557 # Pad the original payload out to the original length
558 data += '\0' * (os.stat(payload).st_size - len(data))
559 data += self._tools.ReadFile(kernel)
560 self._tools.WriteFile(dl_image, data)
561 else:
562 dl_image = image
563
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700564 self._out.Progress('Uploading image')
Simon Glass27a9c142012-03-15 21:08:29 -0700565 download_list = [
Simon Glass3c5b35b2012-05-23 13:22:23 -0700566 # The numbers are the download addresses (in SRAM) for each piece
567 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
Simon Glass27a9c142012-03-15 21:08:29 -0700568 ['bl1', 0x02021400, bl1],
569 ['bl2', 0x02023400, bl2],
Simon Glassde9c8072012-07-02 22:29:02 -0700570 ['u-boot', 0x43e00000, dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700571 ]
Simon Glass3381a1a2012-03-22 11:13:19 -0700572 try:
Simon Glass4968a472012-05-23 13:52:19 -0700573 for upto in range(len(download_list)):
574 item = download_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700575 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700576 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700577 raise CmdError('Could not find Exynos board on USB port')
578 raise CmdError("Stage '%s' did not complete" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700579 self._out.Notice(item[2])
Simon Glass27a9c142012-03-15 21:08:29 -0700580 self._out.Progress("Uploading stage '%s'" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700581
Simon Glass4968a472012-05-23 13:52:19 -0700582 if upto == 0:
583 # The IROM needs roughly 200ms here to be ready for USB download
584 time.sleep(.5)
585
Simon Glass79e3dd02012-08-28 20:08:50 -0700586 args = ['-a', '%#x' % item[1], '-f', item[2]]
587 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700588
Simon Glass3381a1a2012-03-22 11:13:19 -0700589 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800590 # Make sure that the power button is released and dut_sel_hub state is
591 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700592 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800593 if preserved_dut_hub_sel != required_dut_hub_sel:
594 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800595 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700596
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800597 if flash_dest is None:
598 self._out.Notice('Image downloaded - please see serial output '
599 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700600 return True
601
Simon Glass0c2ba482012-03-22 21:57:51 -0700602 def _GetDiskInfo(self, disk, item):
603 """Returns information about a SCSI disk device.
604
605 Args:
606 disk: a block device name in sys/block, like '/sys/block/sdf'.
607 item: the item of disk information that is required.
608
609 Returns:
610 The information obtained, as a string, or '[Unknown]' if not found
611 """
612 dev_path = os.path.join(disk, 'device')
613
614 # Search upwards and through symlinks looking for the item.
615 while os.path.isdir(dev_path) and dev_path != '/sys':
616 fname = os.path.join(dev_path, item)
617 if os.path.exists(fname):
618 with open(fname, 'r') as fd:
619 return fd.readline().rstrip()
620
621 # Move up a level and follow any symlink.
622 new_path = os.path.join(dev_path, '..')
623 if os.path.islink(new_path):
624 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
625 dev_path = new_path
626 return '[Unknown]'
627
628 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700629 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700630
631 Args:
632 device: Device to check, like '/dev/sdf'.
633
634 Returns:
635 Capacity of device in GB, or 0 if not known.
636 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700637 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700638 args = ['-l', device]
639 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700640 for line in stdout.splitlines():
641 m = re_capacity.match(line)
642 if m:
643 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700644 return 0
645
646 def _ListUsbDisks(self):
647 """Return a list of available removable USB disks.
648
649 Returns:
650 List of USB devices, each element is itself a list containing:
651 device ('/dev/sdx')
652 manufacturer name
653 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700654 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700655 """
656 disk_list = []
657 for disk in glob.glob('/sys/block/sd*'):
658 with open(disk + '/removable', 'r') as fd:
659 if int(fd.readline()) == 1:
660 device = '/dev/%s' % disk.split('/')[-1]
661 manuf = self._GetDiskInfo(disk, 'manufacturer')
662 product = self._GetDiskInfo(disk, 'product')
663 capacity = self._GetDiskCapacity(device)
664 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700665 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700666 return disk_list
667
668 def WriteToSd(self, flash_dest, disk, uboot, payload):
669 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800670 raw_image = self._PrepareFlasher(uboot, payload, flash_dest, '1:0')
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700671 bl1, bl2, _ = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700672 spl_load_size = os.stat(raw_image).st_size
673 bl2 = self._bundle.ConfigureExynosBl2(self._fdt, spl_load_size, bl2,
674 'flasher')
675
676 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2)
677
678 # Pad BL2 out to the required size.
679 # We require that it be 24KB, but data will only contain 8KB + 14KB.
680 # Add the extra padding to bring it to 24KB.
681 data += '\0' * (0x6000 - len(data))
682 data += self._tools.ReadFile(raw_image)
683 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
684 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700685 self._out.Progress('Writing flasher to %s' % disk)
686 else:
687 image = payload
688 self._out.Progress('Writing image to %s' % disk)
689
690 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
691 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700692 self._out.Progress('Syncing')
693 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700694
695 def SendToSdCard(self, dest, flash_dest, uboot, payload):
696 """Write a flasher to an SD card.
697
698 Args:
699 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700700 ':.' selects the only available device, fails if more than one option
701 ':<device>' select deivce
702
703 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700704 ':.'
705 ':/dev/sdd'
706
707 flash_dest: Destination for flasher, or None to not create a flasher:
708 Valid options are spi, sdmmc.
709 uboot: Full path to u-boot.bin.
710 payload: Full path to payload.
711 """
712 disk = None
713 disks = self._ListUsbDisks()
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700714
715 if not disks:
716 self._out.Error('No removable devices found')
717 self._out.Error('Did you forget to plug in the SD card?')
718 return
719
720 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700721 name = dest[1:]
722
723 # A '.' just means to use the only available disk.
724 if name == '.' and len(disks) == 1:
725 disk = disks[0][0]
726 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700727 # Use the device name.
728 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700729 disk = disk_info[0]
730
731 if disk:
732 self.WriteToSd(flash_dest, disk, uboot, payload)
733 else:
734 self._out.Error("Please specify destination -w 'sd:<disk_description>':")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700735 self._out.Error(' - description can be . for the only disk, or')
736 self._out.Error(' the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700737 msg = 'Found %d available disks.' % len(disks)
738 if not disks:
739 msg += ' Please insert an SD card and try again.'
740 self._out.UserOutput(msg)
741
742 # List available disks as a convenience.
743 for disk in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700744 self._out.UserOutput(' %s: %s %d.%d GB' % (
745 disk[0],
746 ' '.join(str(x) for x in disk[1:3]),
747 disk[3] / 10, # Integer number of GBs
748 disk[3] % 10, # Decimal number of GBs
749 ))
Simon Glass0c2ba482012-03-22 21:57:51 -0700750
Vadim Bendebury19a77122013-01-24 17:38:00 -0800751 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700752 """Send an image to an attached EM100 device.
753
754 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
755 to do the SPI emulation, then write the image, then boot the board.
756 All going well, this is enough to get U-Boot running.
757
758 Args:
759 image_fname: Filename of image to send
760 """
761 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
762 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800763 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700764
765 # TODO(sjg@chromium.org): This is for link. We could make this
766 # configurable from the fdt.
767 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
768 self._out.Progress('Writing image to em100')
769 self._tools.Run('em100', args, sudo=True)
770
771 self._out.Progress('Resetting board')
772 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
773 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
Vadim Bendebury2b719452013-02-12 17:00:06 -0800774 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700775
Simon Glass0c2ba482012-03-22 21:57:51 -0700776
Simon Glass27a9c142012-03-15 21:08:29 -0700777def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass60a40af2012-06-07 11:54:17 -0700778 bundle, update=True, verify=False, dest=None,
Vadim Bendebury19a77122013-01-24 17:38:00 -0800779 flash_dest=None, kernel=None, bootstub=None, servo='any',
Simon Glass4b8b3bd2012-11-06 12:31:01 -0800780 method='tegra'):
Simon Glasse0b61442012-03-13 15:29:51 -0700781 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700782
783 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700784 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700785
786 Args:
787 output: cros_output object to use.
788 tools: Tools object to use.
789 fdt: Fdt object to use as our device tree.
790 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700791 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700792 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700793 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800794 update: Use faster update algorithm rather then full device erase.
795 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700796 dest: Destination device to write firmware to (usb, sd).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700797 flash_dest: Destination device for flasher to program payload into.
Simon Glassde9c8072012-07-02 22:29:02 -0700798 kernel: Kernel file to write after U-Boot
Vadim Bendebury19a77122013-01-24 17:38:00 -0800799 bootstub: string, file name of the boot stub, if present
Simon Glass6a616c12012-09-24 18:13:46 -0700800 servo: Describes the servo unit to use: none=none; any=any; otherwise
801 port number of servo to use.
Simon Glass710dedc2011-08-09 14:08:52 -0700802 """
Vadim Bendebury2b719452013-02-12 17:00:06 -0800803 write = WriteFirmware(tools, fdt, output, bundle, update, verify)
Simon Glass6a616c12012-09-24 18:13:46 -0700804 write.SelectServo(servo)
Simon Glassd65f65f2013-03-28 17:03:41 -0700805 if flash_dest:
806 write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
807 elif bootstub:
808 write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
Simon Glasse0b61442012-03-13 15:29:51 -0700809 if dest == 'usb':
Vadim Bendebury2b719452013-02-12 17:00:06 -0800810 try:
811 write.DutControl(['cpu_uart_capture:on',])
812 method = fdt.GetString('/chromeos-config', 'flash-method', method)
813 if method == 'tegra':
814 tools.CheckTool('tegrarcm')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800815 ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
816 image_fname, bootstub)
817 elif method == 'exynos':
818 tools.CheckTool('lsusb', 'usbutils')
819 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
820 ok = write.ExynosFlashImage(flash_dest, flasher,
821 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
822 kernel)
823 else:
824 raise CmdError("Unknown flash method '%s'" % method)
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800825
Vadim Bendebury2b719452013-02-12 17:00:06 -0800826 if not ok:
827 raise CmdError('Image upload failed - please check board connection')
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800828 output.Progress('Image uploaded, waiting for completion')
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800829
830 if flash_dest is not None and servo != 'none':
831 write.WaitForCompletion()
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800832 output.Progress('Done!')
833
Vadim Bendebury2b719452013-02-12 17:00:06 -0800834 finally:
835 write.DutControl(['cpu_uart_capture:off',])
Simon Glass9eb8c722012-06-07 13:34:31 -0700836 elif dest == 'em100':
837 # crosbug.com/31625
838 tools.CheckTool('em100')
Vadim Bendebury19a77122013-01-24 17:38:00 -0800839 write.Em100FlashImage(image_fname)
Simon Glass0c2ba482012-03-22 21:57:51 -0700840 elif dest.startswith('sd'):
841 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -0700842 else:
Simon Glasse0b61442012-03-13 15:29:51 -0700843 raise CmdError("Unknown destination device '%s'" % dest)