blob: 96332ee29eecd289b4a8dcf9f544d2a91284c9fe [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
Simon Glassb4c14af2013-07-04 11:56:33 +090015# The numbers are the download addresses (in SRAM) for each piece
16exynos_addresses = {
17 'samsung,exynos5250': {
18 'bl1': 0x02021400,
19 'bl2': 0x02023400,
20 'u-boot': 0x43e00000,
21 },
22 'samsung,exynos5420': {
23 'bl1': 0x02022400,
24 'bl2': 0x02024400,
25 'u-boot': 0x23e00000,
26 },
27 }
28
29
Simon Glassa3f29ec2011-07-17 09:36:49 -070030def RoundUp(value, boundary):
31 """Align a value to the next power of 2 boundary.
32
33 Args:
34 value: The value to align.
35 boundary: The boundary value, e.g. 4096. Must be a power of 2.
36
37 Returns:
38 The rounded-up value.
39 """
40 return (value + boundary - 1) & ~(boundary - 1)
41
42
43class WriteFirmware:
44 """Write firmware to a Tegra 2 board using USB A-A cable.
45
46 This class handles re-reflashing a board with new firmware using the Tegra's
47 built-in boot ROM feature. This works by putting the chip into a special mode
48 where it ignores any available firmware and instead reads it from a connected
49 host machine over USB.
50
51 In our case we use that feature to send U-Boot along with a suitable payload
52 and instructions to flash it to SPI flash. The payload is itself normally a
53 full Chrome OS image consisting of U-Boot, some keys and verification
54 information, images and a map of the flash memory.
Simon Glass6a616c12012-09-24 18:13:46 -070055
56 Private attributes:
57 _servo_port: Port number to use to talk to servo with dut-control.
58 Special values are:
59 None: servo is not available.
60 0: any servo will do.
61
Simon Glassa3f29ec2011-07-17 09:36:49 -070062 """
Vadim Bendebury2b719452013-02-12 17:00:06 -080063
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080064 _DOWNLOAD_FAILURE_MESSAGE = '** Load checksum error: check download tool **'
65 _SKIP_VERIFY_MESSAGE = 'Skipping verify'
Vadim Bendebury2b719452013-02-12 17:00:06 -080066 _WRITE_FAILURE_MESSAGE = '** Readback checksum error, programming failed!! **'
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080067 _WRITE_SUCCESS_MESSAGE = 'Image Programmed Successfully'
Vadim Bendebury2b719452013-02-12 17:00:06 -080068
69 def __init__(self, tools, fdt, output, bundle, update, verify):
Simon Glassa3f29ec2011-07-17 09:36:49 -070070 """Set up a new WriteFirmware object.
71
72 Args:
73 tools: A tools library for us to use.
74 fdt: An fdt which gives us some info that we need.
75 output: An output object to use for printing progress and messages.
Simon Glass0191a882012-05-23 13:15:06 -070076 bundle: A BundleFirmware object which created the image.
Vadim Bendebury2b719452013-02-12 17:00:06 -080077 update: Use faster update algorithm rather then full device erase.
78 verify: Verify the write by doing a readback and CRC.
Simon Glassa3f29ec2011-07-17 09:36:49 -070079 """
80 self._tools = tools
81 self._fdt = fdt
82 self._out = output
Simon Glass0191a882012-05-23 13:15:06 -070083 self._bundle = bundle
Vadim Bendebury19a77122013-01-24 17:38:00 -080084 self.text_base = self._fdt.GetInt('/chromeos-config', 'textbase', -1)
Simon Glassa3f29ec2011-07-17 09:36:49 -070085
Simon Glass5b5fd642011-08-17 12:24:01 -070086 # For speed, use the 'update' algorithm and don't verify
Vadim Bendebury2b719452013-02-12 17:00:06 -080087 self.update = update
88 self.verify = verify
Simon Glass5b5fd642011-08-17 12:24:01 -070089
Simon Glass6a616c12012-09-24 18:13:46 -070090 # Use default servo port
91 self._servo_port = 0
92
93 def SelectServo(self, servo):
94 """Select the servo to use for writing firmware.
95
96 Args:
97 servo: String containing description of servo to use:
98 'none' : Don't use servo, generate an error on any attempt.
99 'any' : Use any available servo.
100 '<port>': Use servo with that port number.
101 """
102 if servo == 'none':
103 self._servo_port = None
104 elif servo == 'any':
105 self._servo_port = 0
106 else:
107 self._servo_port = int(servo)
108 self._out.Notice('Servo port %s' % str(self._servo_port))
109
Andrew Chew919858c2013-07-22 15:39:56 -0700110 def _GetFlashScript(self, payload_size, flash_dest, checksum):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700111 """Get the U-Boot boot command needed to flash U-Boot.
112
113 We leave a marker in the string for the load address of the image,
114 since this depends on the size of this script. This can be replaced by
115 the caller provided that the marker length is unchanged.
116
117 Args:
118 payload_size: Size of payload in bytes.
Andrew Chew919858c2013-07-22 15:39:56 -0700119 flash_dest: A dictionary of strings keyed by 'type' (nand, sdmmc,
120 or spi), 'bus', and 'dev'.
Simon Glass8bd05ec2012-03-22 11:09:04 -0700121 checksum: The checksum of the payload (an integer)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700122
123 Returns:
124 A tuple containing:
125 The script, as a string ready to use as a U-Boot boot command, with an
126 embedded marker for the load address.
127 The marker string, which the caller should replace with the correct
128 load address as 8 hex digits, without changing its length.
129 """
130 replace_me = 'zsHEXYla'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800131 page_size = 4096
Andrew Chew919858c2013-07-22 15:39:56 -0700132 boot_type = flash_dest['type']
Simon Glass0dcbecb2012-03-22 21:38:55 -0700133 if boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800134 page_size = 512
Vadim Bendebury2b719452013-02-12 17:00:06 -0800135 update = self.update and boot_type == 'spi'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800136
Simon Glassa3f29ec2011-07-17 09:36:49 -0700137 cmds = [
138 'setenv address 0x%s' % replace_me,
139 'setenv firmware_size %#x' % payload_size,
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800140 'setenv length %#x' % RoundUp(payload_size, page_size),
141 'setenv blocks %#x' % (RoundUp(payload_size, page_size) / page_size),
Simon Glass5b51b472013-03-28 13:06:05 -0700142 'setenv _crc "crc32 -v ${address} ${firmware_size} %08x"' %
Simon Glass8bd05ec2012-03-22 11:09:04 -0700143 checksum,
Simon Glass5b5fd642011-08-17 12:24:01 -0700144 'setenv _clear "echo Clearing RAM; mw.b ${address} 0 ${length}"',
Doug Anderson37ae2292011-09-15 17:41:57 -0700145 ]
Simon Glass0dcbecb2012-03-22 21:38:55 -0700146 if boot_type == 'nand':
Doug Anderson37ae2292011-09-15 17:41:57 -0700147 cmds.extend([
148 'setenv _init "echo Init NAND; nand info"',
149 'setenv _erase "echo Erase NAND; nand erase 0 ${length}"',
150 'setenv _write "echo Write NAND; nand write ${address} 0 ${length}"',
151 'setenv _read "echo Read NAND; nand read ${address} 0 ${length}"',
152 ])
Simon Glass0dcbecb2012-03-22 21:38:55 -0700153 elif boot_type == 'sdmmc':
Michael Pratt54aaeed2013-07-12 13:42:47 -0700154 # In U-Boot, strings in double quotes have variables expanded to actual
155 # values. For reasons unclear, this expansion splits the single quoted
156 # argument into separate arguements for each word, which on exynos
157 # boards causes the command to exceed the maximum configured argument
158 # count. Passing the string in single quotes prevents this expansion,
159 # allowing variables to be expanded when run is called.
160 # crbug.com/260294
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800161 cmds.extend([
Michael Pratt54aaeed2013-07-12 13:42:47 -0700162 'setenv _init "echo Init EMMC; mmc rescan"',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800163 'setenv _erase "echo Erase EMMC; "',
Michael Pratt54aaeed2013-07-12 13:42:47 -0700164 "setenv _write 'echo Write EMMC; mmc open 0 1;" \
165 " mmc write ${address} 0 " \
166 "${blocks};" \
167 " mmc close 0 1'",
168 "setenv _read 'echo Read EMMC; mmc open 0 1;" \
169 " mmc read ${address} 0 " \
170 "${blocks};" \
171 " mmc close 0 1'",
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800172 ])
Doug Anderson37ae2292011-09-15 17:41:57 -0700173 else:
Andrew Chew919858c2013-07-22 15:39:56 -0700174 if flash_dest['bus'] is None:
175 flash_dest['bus'] = '0'
176 if flash_dest['dev'] is None:
177 flash_dest['dev'] = '0'
Doug Anderson37ae2292011-09-15 17:41:57 -0700178 cmds.extend([
Andrew Chew919858c2013-07-22 15:39:56 -0700179 'setenv _init "echo Init SPI; sf probe %s:%s"' %
180 (flash_dest['bus'], flash_dest['dev']),
Doug Anderson37ae2292011-09-15 17:41:57 -0700181 'setenv _erase "echo Erase SPI; sf erase 0 ${length}"',
182 'setenv _write "echo Write SPI; sf write ${address} 0 ${length}"',
183 'setenv _read "echo Read SPI; sf read ${address} 0 ${length}"',
184 'setenv _update "echo Update SPI; sf update ${address} 0 ${length}"',
185 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700186
Doug Anderson37ae2292011-09-15 17:41:57 -0700187 cmds.extend([
Simon Glassa3f29ec2011-07-17 09:36:49 -0700188 'echo Firmware loaded to ${address}, size ${firmware_size}, '
189 'length ${length}',
Simon Glass8bd05ec2012-03-22 11:09:04 -0700190 'if run _crc; then',
Simon Glassa3f29ec2011-07-17 09:36:49 -0700191 'run _init',
Doug Anderson37ae2292011-09-15 17:41:57 -0700192 ])
Simon Glass5b5fd642011-08-17 12:24:01 -0700193 if update:
194 cmds += ['time run _update']
195 else:
196 cmds += ['run _erase', 'run _write']
Vadim Bendebury2b719452013-02-12 17:00:06 -0800197 if self.verify:
Simon Glass5b5fd642011-08-17 12:24:01 -0700198 cmds += [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700199 'run _clear',
200 'run _read',
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800201 'if run _crc; then',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800202 'echo "%s"' % self._WRITE_SUCCESS_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800203 'else',
204 'echo',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800205 'echo "%s"' % self._WRITE_FAILURE_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800206 'echo',
207 'fi',
Simon Glass5b5fd642011-08-17 12:24:01 -0700208 ]
209 else:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800210 cmds += ['echo %s' % self._SKIP_VERIFY_MESSAGE]
Simon Glass8bd05ec2012-03-22 11:09:04 -0700211 cmds.extend([
212 'else',
213 'echo',
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800214 'echo "%s"' % self._DOWNLOAD_FAILURE_MESSAGE,
Simon Glass8bd05ec2012-03-22 11:09:04 -0700215 'fi',
216 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700217 script = '; '.join(cmds)
218 return script, replace_me
219
Andrew Chew919858c2013-07-22 15:39:56 -0700220 def _PrepareFlasher(self, uboot, payload, flash_dest):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700221 """Get a flasher ready for sending to the board.
222
223 The flasher is an executable image consisting of:
224
225 - U-Boot (u-boot.bin);
226 - a special FDT to tell it what to do in the form of a run command;
227 - (we could add some empty space here, in case U-Boot is not built to
228 be relocatable);
229 - the payload (which is a full flash image, or signed U-Boot + fdt).
230
231 Args:
232 uboot: Full path to u-boot.bin.
233 payload: Full path to payload.
Andrew Chew919858c2013-07-22 15:39:56 -0700234 flash_dest: A dictionary of strings keyed by 'type' (nand, sdmmc,
235 or spi), 'bus', and 'dev'.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700236
237 Returns:
Simon Glass290a1802011-07-17 13:54:32 -0700238 Filename of the flasher binary created.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700239 """
Simon Glass951a2db2011-07-17 15:58:58 -0700240 fdt = self._fdt.Copy(os.path.join(self._tools.outdir, 'flasher.dtb'))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700241 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700242
Simon Glass8bd05ec2012-03-22 11:09:04 -0700243 # Make sure that the checksum is not negative
244 checksum = binascii.crc32(payload_data) & 0xffffffff
245
Andrew Chew919858c2013-07-22 15:39:56 -0700246 script, replace_me = self._GetFlashScript(len(payload_data), flash_dest,
247 checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700248 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800249 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700250 fdt_data = self._tools.ReadFile(fdt.fname)
251
252 # Work out where to place the payload in memory. This is a chicken-and-egg
253 # problem (although in case you haven't heard, it was the chicken that
254 # came first), so we resolve it by replacing the string after
255 # fdt.PutString has done its job.
256 #
257 # Correction: Technically, the egg came first. Whatever genetic mutation
258 # created the new species would have been present in the egg, but not the
259 # parent (since if it was in the parent, it would have been present in the
260 # parent when it was an egg).
261 #
262 # Question: ok so who laid the egg then?
263 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700264
265 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
266 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700267 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700268
Simon Glass2c4b3e52011-11-15 14:45:43 -0800269 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700270 new_str = '%08x' % load_address
271 if len(replace_me) is not len(new_str):
272 raise ValueError("Internal error: replacement string '%s' length does "
273 "not match new string '%s'" % (replace_me, new_str))
Vadim Bendebury19a77122013-01-24 17:38:00 -0800274 matches = len(re.findall(replace_me, fdt_data))
275 if matches != 1:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700276 raise ValueError("Internal error: replacement string '%s' already "
277 "exists in the fdt (%d matches)" % (replace_me, matches))
278 fdt_data = re.sub(replace_me, new_str, fdt_data)
279
280 # Now put it together.
281 data += fdt_data
282 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700283 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700284 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700285 self._tools.WriteFile(flasher, data)
286
287 # Tell the user about a few things.
288 self._tools.OutputSize('U-Boot', uboot)
289 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700290 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700291 self._tools.OutputSize('Flasher', flasher)
292 return flasher
293
Vadim Bendebury19a77122013-01-24 17:38:00 -0800294 def NvidiaFlashImage(self, flash_dest, uboot, bct, payload, bootstub):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700295 """Flash the image to SPI flash.
296
297 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000298 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700299
300 Args:
Andrew Chew919858c2013-07-22 15:39:56 -0700301 flash_dest: Destination for flasher, or None to not create a flasher.
302 This value is a dictionary of strings keyed by 'type', 'bus', and
303 'dev'.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700304 uboot: Full path to u-boot.bin.
305 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
306 payload: Full path to payload.
Simon Glass89ecf712012-06-07 12:20:15 -0700307 bootstub: Full path to bootstub, which is the payload without the
308 signing information (i.e. bootstub is u-boot.bin + the FDT)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700309
310 Returns:
311 True if ok, False if failed.
312 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800313 # Use a Regex to pull Boot type from BCT file.
314 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
315 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700316
317 # TODO(sjg): The boot type is currently selected by the bct, rather than
Andrew Chew919858c2013-07-22 15:39:56 -0700318 # flash_dest['type'] selecting which bct to use. This is a bit backwards.
319 # For now we go with the bct's idea.
320 flash_dest['type'] = filter(match.match, bct_dumped)
321 flash_dest['type'] = match.match(
322 flash_dest['type'][0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700323
Simon Glass89ecf712012-06-07 12:20:15 -0700324 if flash_dest:
Andrew Chew919858c2013-07-22 15:39:56 -0700325 image = self._PrepareFlasher(uboot, payload, flash_dest)
Simon Glasse1824db2012-07-11 17:38:40 +0200326 elif bootstub:
Simon Glass89ecf712012-06-07 12:20:15 -0700327 image = bootstub
Simon Glassa3f29ec2011-07-17 09:36:49 -0700328
Simon Glasse1824db2012-07-11 17:38:40 +0200329 else:
330 image = payload
331 # If we don't know the textbase, extract it from the payload.
332 if self.text_base == -1:
333 data = self._tools.ReadFile(payload)
334 # Skip the BCT which is the first 64KB
335 self.text_base = self._bundle.DecodeTextBase(data[0x10000:])
336
Simon Glass89ecf712012-06-07 12:20:15 -0700337 self._out.Notice('TEXT_BASE is %#x' % self.text_base)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700338 self._out.Progress('Uploading flasher image')
339 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700340 '--bct', bct,
Allen Martinb3aa2672012-03-23 15:55:25 +0000341 '--bootloader', image,
342 '--loadaddr', "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700343 ]
344
345 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
346 last_err = None
Vadim Bendebury19a77122013-01-24 17:38:00 -0800347 for _ in range(10):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700348 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700349 # TODO(sjg): Use Chromite library so we can monitor output
Allen Martinb3aa2672012-03-23 15:55:25 +0000350 self._tools.Run('tegrarcm', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700351 self._out.Notice('Flasher downloaded - please see serial output '
352 'for progress.')
353 return True
354
355 except CmdError as err:
356 if not self._out.stdout_is_tty:
357 return False
358
359 # Only show the error output once unless it changes.
360 err = str(err)
Simon Glass22190ff2012-07-11 14:52:26 +0200361 if not 'could not open USB device' in err:
Allen Martinb3aa2672012-03-23 15:55:25 +0000362 raise CmdError('tegrarcm failed: %s' % err)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700363
364 if err != last_err:
365 self._out.Notice(err)
366 last_err = err
367 self._out.Progress('Please connect USB A-A cable and do a '
368 'recovery-reset', True)
369 time.sleep(1)
370
371 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700372
Simon Glass27a9c142012-03-15 21:08:29 -0700373 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
374 """Wait until we see a device on the USB bus.
375
376 Args:
377 name: Board type name
378 vendor_id: USB vendor ID to look for
379 product_id: USB product ID to look for
380 timeout: Timeout to wait in seconds
381
382 Returns
383 True if the device was found, False if we timed out.
384 """
385 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass4968a472012-05-23 13:52:19 -0700386 start_time = time.time()
387 while time.time() - start_time < timeout:
Simon Glass27a9c142012-03-15 21:08:29 -0700388 try:
389 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
390 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700391 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700392 return True
393
Vadim Bendebury19a77122013-01-24 17:38:00 -0800394 except CmdError:
Simon Glass27a9c142012-03-15 21:08:29 -0700395 pass
396
Simon Glass3381a1a2012-03-22 11:13:19 -0700397 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700398
Vadim Bendebury2b719452013-02-12 17:00:06 -0800399 def DutControl(self, args):
Simon Glass6a616c12012-09-24 18:13:46 -0700400 """Run dut-control with supplied arguments.
401
Simon Glass2065a742013-02-09 13:39:26 -0800402 The correct servo will be used based on self._servo_port. If servo use is
403 disabled, this function does nothing.
Simon Glass6a616c12012-09-24 18:13:46 -0700404
405 Args:
406 args: List of arguments to dut-control.
407
Simon Glass2065a742013-02-09 13:39:26 -0800408 Returns:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800409 a string, stdout generated by running the command
Simon Glass6a616c12012-09-24 18:13:46 -0700410 """
411 if self._servo_port is None:
Simon Glass2065a742013-02-09 13:39:26 -0800412 return '' # User has requested not to use servo
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800413 if self._servo_port:
Simon Glass6a616c12012-09-24 18:13:46 -0700414 args.extend(['-p', '%s' % self._servo_port])
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800415 return self._tools.Run('dut-control', args)
Simon Glass6a616c12012-09-24 18:13:46 -0700416
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800417 def WaitForCompletion(self):
Vadim Bendebury2b719452013-02-12 17:00:06 -0800418 """Verify flash programming operation success.
419
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800420 The DUT is presumed to be programming flash with console capture mode on.
421 This function scans console output for the success or failure strings.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800422
423 Raises:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800424 CmdError if the following cases:
425 - none of the strings show up in the allotted time (2 minutes)
426 - console goes silent for more than 10 seconds
427 - one of the error messages seen in the stream
428 - misformatted output is seen in the stream
Vadim Bendebury2b719452013-02-12 17:00:06 -0800429 """
430
431 _SOFT_DEADLINE_LIMIT = 10
432 _HARD_DEADLINE_LIMIT = 120
433 string_leftover = ''
434 soft_deadline = time.time() + _SOFT_DEADLINE_LIMIT
435 hard_deadline = soft_deadline + _HARD_DEADLINE_LIMIT - _SOFT_DEADLINE_LIMIT
436
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800437 if self.verify:
438 done_line = self._WRITE_SUCCESS_MESSAGE
439 else:
440 done_line = self._SKIP_VERIFY_MESSAGE
441
Vadim Bendebury2b719452013-02-12 17:00:06 -0800442 while True:
443 now = time.time()
444 if now > hard_deadline:
445 raise CmdError('Target console flooded, programming failed')
446 if now > soft_deadline:
447 raise CmdError('Target console dead, programming failed')
448 stream = self.DutControl(['cpu_uart_stream',])
449 match = re.search("^cpu_uart_stream:'(.*)'\n", stream)
450 if not match:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800451 raise CmdError('Misformatted console output: \n%s\n' % stream)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800452
453 text = string_leftover + match.group(1)
454 strings = text.split('\\r')
455 string_leftover = strings.pop()
456 if strings:
457 soft_deadline = now + _SOFT_DEADLINE_LIMIT
458 for string in strings:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800459 if done_line in string:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800460 return True
461 if self._WRITE_FAILURE_MESSAGE in string:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800462 raise CmdError('Readback verification failed!')
463 if self._DOWNLOAD_FAILURE_MESSAGE in string:
464 raise CmdError('Download failed!')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800465
Simon Glass4c54a912013-02-18 16:56:29 -0800466 def _ExtractPayloadParts(self, payload, truncate_to_fdt):
Simon Glass3c5b35b2012-05-23 13:22:23 -0700467 """Extract the BL1, BL2 and U-Boot parts from a payload.
468
469 An exynos image consists of 3 parts: BL1, BL2 and U-Boot/FDT.
470
471 This pulls out the various parts, puts them into files and returns
472 these files.
473
474 Args:
475 payload: Full path to payload.
Simon Glass4c54a912013-02-18 16:56:29 -0800476 truncate_to_fdt: Truncate the U-Boot image at the start of its
477 embedded FDT
Simon Glass3c5b35b2012-05-23 13:22:23 -0700478
479 Returns:
480 (bl1, bl2, image) where:
481 bl1 is the filename of the extracted BL1
482 bl2 is the filename of the extracted BL2
483 image is the filename of the extracted U-Boot image
484 """
485 # Pull out the parts from the payload
486 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
487 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
488 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
489 data = self._tools.ReadFile(payload)
490
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700491 try:
492 bl1_size = int(self._fdt.GetProps('/flash/pre-boot')['size'])
493 bl2_size = int(self._fdt.GetProps('/flash/spl')['size'])
494 uboot_offset = bl1_size + bl2_size
Simon Glass496c8302013-07-20 18:04:02 -0600495 except (CmdError, KeyError):
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700496 self._out.Warning('No component nodes in the device tree')
497 # The BL1 is always 8KB - extract that part into a new file
498 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
499 bl1_size = 0x2000
Simon Glass3c5b35b2012-05-23 13:22:23 -0700500
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700501 # Try to detect the BL2 size. We look for 0xea000014 or 0xea000013
502 # which is the 'B reset' instruction at the start of U-Boot. When
503 # U-Boot is LZO compressed, we look for a LZO magic instead.
504 start_data = [struct.pack('<L', 0xea000014),
505 struct.pack('<L', 0xea000013),
506 struct.pack('>B3s', 0x89, 'LZO')]
507 starts = [data.find(magic, bl1_size + 0x3800) for magic in start_data]
508 uboot_offset = None
509 for start in starts:
510 if start != -1 and (not uboot_offset or start < uboot_offset):
511 uboot_offset = start
512 if not uboot_offset:
513 raise ValueError('Could not locate start of U-Boot')
514 bl2_size = uboot_offset - bl1_size - 0x800 # 2KB gap after BL2
Simon Glass3c5b35b2012-05-23 13:22:23 -0700515
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700516 # Sanity check: At present we only allow 14KB and 30KB for SPL
517 allowed = [14, 30]
518 if (bl2_size >> 10) not in allowed:
519 raise ValueError('BL2 size is %dK - only %s supported' %
520 (bl2_size >> 10, ', '.join(
521 [str(size) for size in allowed])))
Simon Glasse86f3132013-01-08 16:10:43 -0800522 self._out.Notice('BL2 size is %dKB' % (bl2_size >> 10))
523
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700524 self._tools.WriteFile(bl1, data[:bl1_size])
525 self._tools.WriteFile(bl2, data[bl1_size:bl1_size + bl2_size])
Simon Glasse86f3132013-01-08 16:10:43 -0800526
Simon Glassbc0d8d42013-02-09 11:59:36 -0800527 # U-Boot itself starts at 24KB, after the gap. As a hack, truncate it
Simon Glass4c54a912013-02-18 16:56:29 -0800528 # to an assumed maximum size. As a secondary hack, locate the FDT
529 # and truncate U-Boot from that point. The correct FDT will be added
530 # when the image is written to the board.
Simon Glassbc0d8d42013-02-09 11:59:36 -0800531 # TODO(sjg@chromium.org): Get a proper flash map here so we know how
532 # large it is
Simon Glass4c54a912013-02-18 16:56:29 -0800533 uboot_data = data[uboot_offset:uboot_offset + 0xa0000]
534 if truncate_to_fdt:
535 fdt_magic = struct.pack('>L', 0xd00dfeed)
536 fdt_offset = uboot_data.rfind(fdt_magic)
537 uboot_data = uboot_data[:fdt_offset]
538
539 self._tools.WriteFile(image, uboot_data)
Simon Glass3c5b35b2012-05-23 13:22:23 -0700540 return bl1, bl2, image
541
Vadim Bendebury19a77122013-01-24 17:38:00 -0800542 def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
Simon Glassde9c8072012-07-02 22:29:02 -0700543 kernel):
Simon Glass27a9c142012-03-15 21:08:29 -0700544 """Flash the image to SPI flash.
545
546 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000547 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glass27a9c142012-03-15 21:08:29 -0700548
549 Args:
Andrew Chew919858c2013-07-22 15:39:56 -0700550 flash_dest: Destination for flasher, or None to not create a flasher.
551 This is a dictionary of strings keyed by 'type', 'bus', and 'dev'.
552 Valid options for 'type' are spi, sdmmc.
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700553 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700554 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700555 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700556 payload: Full path to payload.
Simon Glassde9c8072012-07-02 22:29:02 -0700557 kernel: Kernel to send after the payload, or None.
Simon Glass27a9c142012-03-15 21:08:29 -0700558
559 Returns:
560 True if ok, False if failed.
Simon Glassb4c14af2013-07-04 11:56:33 +0900561
562 Raises:
563 CmdError if a supported Exynos model is not detected in the device tree.
Simon Glass27a9c142012-03-15 21:08:29 -0700564 """
Simon Glassbc0d8d42013-02-09 11:59:36 -0800565 tools = self._tools
566 payload_bl1, payload_bl2, payload_image = (
Simon Glass4c54a912013-02-18 16:56:29 -0800567 self._ExtractPayloadParts(payload, flash_dest is not None))
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700568 if flash_dest:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800569 # If we don't have some bits, get them from the image
570 if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
571 self._out.Warning('Extracting U-Boot from payload')
572 flash_uboot = payload_image
573 if not bl1 or not os.path.exists(tools.Filename(bl1)):
574 self._out.Warning('Extracting BL1 from payload')
575 bl1 = payload_bl1
576 if not bl2 or not os.path.exists(tools.Filename(bl2)):
577 self._out.Warning('Extracting BL2 from payload')
578 bl2 = payload_bl2
Michael Pratt24e7c162013-07-12 09:35:28 -0700579 else:
580 # Update BL2 machine parameters, as
581 # the BL2 passed in may not be updated
582 spl_load_size = os.stat(tools.Filename(bl2)).st_size
583 bl2_handler = ExynosBl2(tools, self._out)
584 bl2 = bl2_handler.Configure(self._fdt, spl_load_size,
585 bl2, 'flasher', True)
Andrew Chew919858c2013-07-22 15:39:56 -0700586 # Set default values for Exynos targets.
587 if flash_dest['bus'] is None:
588 flash_dest['bus'] = 1
589 if flash_dest['dev'] is None:
590 flash_dest['dev'] = 0
591 image = self._PrepareFlasher(flash_uboot, payload, flash_dest)
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700592 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800593 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700594
595 vendor_id = 0x04e8
596 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700597
Simon Glassb4c14af2013-07-04 11:56:33 +0900598 # Work out the exynos model we are talking to,
599 compatible = self._fdt.GetString('/', 'compatible')
600
601 for model in compatible.split():
602 addresses = exynos_addresses.get(model)
603 if addresses:
604 break
605 else:
606 # TODO(sjg@chromium.org): Remove this when upstream U-Boot has the
607 # 'samsung,exynos5250' compatible string.
608 addresses = exynos_addresses.get('samsung,exynos5250')
609 self._out.Warning('No exynos compatible string, assuming Exynos 5250')
610
611 if not addresses:
612 raise CmdError("Unable to determine USB download addresses, compatible" +
613 "string is '%s'" % compatible)
614
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800615 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800616 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
617 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800618 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800619 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700620 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800621 if preserved_dut_hub_sel != required_dut_hub_sel:
622 # Need to set it to get the port properly powered up.
623 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Simon Glass93673cf2013-04-26 17:55:55 -0700624 if self._servo_port is not None:
625 self._out.Progress('Reseting board via servo')
626 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700627
Simon Glassde9c8072012-07-02 22:29:02 -0700628 # If we have a kernel to write, create a new image with that added.
629 if kernel:
630 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
631 data = self._tools.ReadFile(image)
632
633 # Pad the original payload out to the original length
634 data += '\0' * (os.stat(payload).st_size - len(data))
635 data += self._tools.ReadFile(kernel)
636 self._tools.WriteFile(dl_image, data)
637 else:
638 dl_image = image
639
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700640 self._out.Progress('Uploading image')
Simon Glass27a9c142012-03-15 21:08:29 -0700641 download_list = [
Simon Glassb4c14af2013-07-04 11:56:33 +0900642 ['bl1', bl1],
643 ['bl2', bl2],
644 ['u-boot', dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700645 ]
Simon Glassb4c14af2013-07-04 11:56:33 +0900646
Simon Glass3381a1a2012-03-22 11:13:19 -0700647 try:
Simon Glass4968a472012-05-23 13:52:19 -0700648 for upto in range(len(download_list)):
649 item = download_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700650 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700651 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700652 raise CmdError('Could not find Exynos board on USB port')
653 raise CmdError("Stage '%s' did not complete" % item[0])
Simon Glassb4c14af2013-07-04 11:56:33 +0900654 self._out.Notice(item[1])
Simon Glass27a9c142012-03-15 21:08:29 -0700655 self._out.Progress("Uploading stage '%s'" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700656
Simon Glass4968a472012-05-23 13:52:19 -0700657 if upto == 0:
658 # The IROM needs roughly 200ms here to be ready for USB download
659 time.sleep(.5)
660
Simon Glassb4c14af2013-07-04 11:56:33 +0900661 args = ['-a', '%#x' % addresses[item[0]], '-f', item[1]]
Simon Glass79e3dd02012-08-28 20:08:50 -0700662 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700663
Simon Glass3381a1a2012-03-22 11:13:19 -0700664 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800665 # Make sure that the power button is released and dut_sel_hub state is
666 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700667 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800668 if preserved_dut_hub_sel != required_dut_hub_sel:
669 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800670 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700671
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800672 if flash_dest is None:
673 self._out.Notice('Image downloaded - please see serial output '
674 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700675 return True
676
Simon Glass0c2ba482012-03-22 21:57:51 -0700677 def _GetDiskInfo(self, disk, item):
678 """Returns information about a SCSI disk device.
679
680 Args:
681 disk: a block device name in sys/block, like '/sys/block/sdf'.
682 item: the item of disk information that is required.
683
684 Returns:
685 The information obtained, as a string, or '[Unknown]' if not found
686 """
687 dev_path = os.path.join(disk, 'device')
688
689 # Search upwards and through symlinks looking for the item.
690 while os.path.isdir(dev_path) and dev_path != '/sys':
691 fname = os.path.join(dev_path, item)
692 if os.path.exists(fname):
693 with open(fname, 'r') as fd:
694 return fd.readline().rstrip()
695
696 # Move up a level and follow any symlink.
697 new_path = os.path.join(dev_path, '..')
698 if os.path.islink(new_path):
699 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
700 dev_path = new_path
701 return '[Unknown]'
702
703 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700704 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700705
706 Args:
707 device: Device to check, like '/dev/sdf'.
708
709 Returns:
710 Capacity of device in GB, or 0 if not known.
711 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700712 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700713 args = ['-l', device]
714 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700715 for line in stdout.splitlines():
716 m = re_capacity.match(line)
717 if m:
718 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700719 return 0
720
721 def _ListUsbDisks(self):
722 """Return a list of available removable USB disks.
723
724 Returns:
725 List of USB devices, each element is itself a list containing:
726 device ('/dev/sdx')
727 manufacturer name
728 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700729 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700730 """
731 disk_list = []
732 for disk in glob.glob('/sys/block/sd*'):
733 with open(disk + '/removable', 'r') as fd:
734 if int(fd.readline()) == 1:
735 device = '/dev/%s' % disk.split('/')[-1]
736 manuf = self._GetDiskInfo(disk, 'manufacturer')
737 product = self._GetDiskInfo(disk, 'product')
738 capacity = self._GetDiskCapacity(device)
739 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700740 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700741 return disk_list
742
743 def WriteToSd(self, flash_dest, disk, uboot, payload):
744 if flash_dest:
Andrew Chew919858c2013-07-22 15:39:56 -0700745 # Set default values for sd.
746 if flash_dest['bus'] is None:
747 flash_dest['bus'] = 1
748 if flash_dest['dev'] is None:
749 flash_dest['dev'] = 0
750 raw_image = self._PrepareFlasher(uboot, payload, flash_dest)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700751 bl1, bl2, _ = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700752 spl_load_size = os.stat(raw_image).st_size
Simon Glass559b6612012-05-23 13:28:45 -0700753
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700754 bl2_handler = ExynosBl2(self._tools, self._out)
Vadim Bendebury0c961a72013-06-11 13:35:07 -0700755 bl2_file = bl2_handler.Configure(self._fdt, spl_load_size,
Vadim Bendebury8ae67892013-06-11 17:45:15 -0700756 bl2, 'flasher', True)
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700757 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2_file)
Simon Glass559b6612012-05-23 13:28:45 -0700758
Vadim Bendebury22de0492013-06-17 16:11:20 -0700759 # Pad BL2 out to the required size. Its size could be either 14K or 30K
760 # bytes, but the next object in the file needs to be aligned at an 8K
761 # boundary. The BL1 size is also known to be 8K bytes, so the total BL1
762 # + BL2 size needs to be aligned to 8K (0x2000) boundary.
763 aligned_size = (len(data) + 0x1fff) & ~0x1fff
764 pad_size = aligned_size - len(data)
765 data += '\0' * pad_size
766
Simon Glass559b6612012-05-23 13:28:45 -0700767 data += self._tools.ReadFile(raw_image)
768 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
769 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700770 self._out.Progress('Writing flasher to %s' % disk)
771 else:
772 image = payload
773 self._out.Progress('Writing image to %s' % disk)
774
775 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
776 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700777 self._out.Progress('Syncing')
778 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700779
780 def SendToSdCard(self, dest, flash_dest, uboot, payload):
781 """Write a flasher to an SD card.
782
783 Args:
784 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700785 ':.' selects the only available device, fails if more than one option
786 ':<device>' select deivce
787
788 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700789 ':.'
790 ':/dev/sdd'
791
792 flash_dest: Destination for flasher, or None to not create a flasher:
793 Valid options are spi, sdmmc.
794 uboot: Full path to u-boot.bin.
795 payload: Full path to payload.
796 """
797 disk = None
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700798
Vadim Bendebury223af572013-04-27 13:25:13 -0700799 # If no removable devices found - prompt user and wait for one to appear.
800 disks = self._ListUsbDisks()
801 try:
802 spinner = '|/-\\'
803 index = 0
804 while not disks:
805 self._out.ClearProgress()
806 self._out.Progress('No removable devices found, plug something in %s '
807 % spinner[index], trailer='')
808 index = (index + 1) % len(spinner)
809 disks = self._ListUsbDisks()
810 time.sleep(.2)
811 except KeyboardInterrupt:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700812 raise CmdError("No removable device found, interrupted")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700813
814 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700815 name = dest[1:]
816
817 # A '.' just means to use the only available disk.
818 if name == '.' and len(disks) == 1:
819 disk = disks[0][0]
820 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700821 # Use the device name.
822 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700823 disk = disk_info[0]
824
825 if disk:
826 self.WriteToSd(flash_dest, disk, uboot, payload)
827 else:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700828 msg = ["Please specify destination as '-w sd:<disk_description>'",]
829 msg.append(' - <disk_description> can be either . for the only disk,')
830 msg.append(' or the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700831 # List available disks as a convenience.
832 for disk in disks:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700833 msg.append(' %s - %s %.1f GB' % (
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700834 disk[0],
835 ' '.join(str(x) for x in disk[1:3]),
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700836 disk[3] / 10.0))
837 raise CmdError('\n'.join(msg))
Simon Glass0c2ba482012-03-22 21:57:51 -0700838
Vadim Bendebury19a77122013-01-24 17:38:00 -0800839 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700840 """Send an image to an attached EM100 device.
841
842 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
843 to do the SPI emulation, then write the image, then boot the board.
844 All going well, this is enough to get U-Boot running.
845
846 Args:
847 image_fname: Filename of image to send
848 """
849 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
850 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800851 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700852
853 # TODO(sjg@chromium.org): This is for link. We could make this
854 # configurable from the fdt.
855 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
856 self._out.Progress('Writing image to em100')
857 self._tools.Run('em100', args, sudo=True)
858
Simon Glass93673cf2013-04-26 17:55:55 -0700859 if self._servo_port is not None:
860 self._out.Progress('Resetting board via servo')
861 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
862 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
863 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700864
Simon Glass0c2ba482012-03-22 21:57:51 -0700865
Simon Glass27a9c142012-03-15 21:08:29 -0700866def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass60a40af2012-06-07 11:54:17 -0700867 bundle, update=True, verify=False, dest=None,
Andrew Chew919858c2013-07-22 15:39:56 -0700868 flasher_dest=None, kernel=None, bootstub=None,
869 servo='any', method='tegra'):
Simon Glasse0b61442012-03-13 15:29:51 -0700870 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700871
872 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700873 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700874
875 Args:
876 output: cros_output object to use.
877 tools: Tools object to use.
878 fdt: Fdt object to use as our device tree.
879 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700880 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700881 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700882 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800883 update: Use faster update algorithm rather then full device erase.
884 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700885 dest: Destination device to write firmware to (usb, sd).
Andrew Chew919858c2013-07-22 15:39:56 -0700886 flasher_dest: a string, destination device for flasher to program payload
887 into. This string has the form <type>:[bus]:[dev], where
888 bus and dev are optional (and default to device and target
889 specific defaults when absent).
Simon Glassde9c8072012-07-02 22:29:02 -0700890 kernel: Kernel file to write after U-Boot
Vadim Bendebury19a77122013-01-24 17:38:00 -0800891 bootstub: string, file name of the boot stub, if present
Simon Glass6a616c12012-09-24 18:13:46 -0700892 servo: Describes the servo unit to use: none=none; any=any; otherwise
893 port number of servo to use.
Simon Glass710dedc2011-08-09 14:08:52 -0700894 """
Vadim Bendebury2b719452013-02-12 17:00:06 -0800895 write = WriteFirmware(tools, fdt, output, bundle, update, verify)
Simon Glassacf4b3e2013-07-19 16:57:43 -0600896 fdt.PutInteger('/config', 'bootsecure', 0)
Simon Glass6a616c12012-09-24 18:13:46 -0700897 write.SelectServo(servo)
Andrew Chew919858c2013-07-22 15:39:56 -0700898 flash_dest = None
899 if flasher_dest:
900 # Parse flasher_dest and store into a dictionary.
901 flash_dest_list = flasher_dest.split(":")
902 flash_dest = {'type': flash_dest_list[0], 'bus': None, 'dev': None}
903 if len(flash_dest_list) > 1:
904 flash_dest['bus'] = flash_dest_list[1]
905 if len(flash_dest_list) > 2:
906 flash_dest['dev'] = flash_dest_list[2]
Simon Glassd65f65f2013-03-28 17:03:41 -0700907 write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
908 elif bootstub:
909 write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
Simon Glasse0b61442012-03-13 15:29:51 -0700910 if dest == 'usb':
Vadim Bendebury2b719452013-02-12 17:00:06 -0800911 try:
912 write.DutControl(['cpu_uart_capture:on',])
913 method = fdt.GetString('/chromeos-config', 'flash-method', method)
914 if method == 'tegra':
915 tools.CheckTool('tegrarcm')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800916 ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
917 image_fname, bootstub)
918 elif method == 'exynos':
919 tools.CheckTool('lsusb', 'usbutils')
920 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
921 ok = write.ExynosFlashImage(flash_dest, flasher,
922 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
923 kernel)
924 else:
925 raise CmdError("Unknown flash method '%s'" % method)
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800926
Vadim Bendebury2b719452013-02-12 17:00:06 -0800927 if not ok:
928 raise CmdError('Image upload failed - please check board connection')
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800929 output.Progress('Image uploaded, waiting for completion')
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800930
931 if flash_dest is not None and servo != 'none':
932 write.WaitForCompletion()
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800933 output.Progress('Done!')
934
Vadim Bendebury2b719452013-02-12 17:00:06 -0800935 finally:
936 write.DutControl(['cpu_uart_capture:off',])
Simon Glass9eb8c722012-06-07 13:34:31 -0700937 elif dest == 'em100':
938 # crosbug.com/31625
939 tools.CheckTool('em100')
Vadim Bendebury19a77122013-01-24 17:38:00 -0800940 write.Em100FlashImage(image_fname)
Simon Glass0c2ba482012-03-22 21:57:51 -0700941 elif dest.startswith('sd'):
942 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -0700943 else:
Simon Glasse0b61442012-03-13 15:29:51 -0700944 raise CmdError("Unknown destination device '%s'" % dest)