blob: 4f2af1d56959d8e7d5071fc13c7058b710fa3955 [file] [log] [blame]
Simon Glassa3f29ec2011-07-17 09:36:49 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Simon Glass8bd05ec2012-03-22 11:09:04 -07005import binascii
Simon Glass3381a1a2012-03-22 11:13:19 -07006import glob
Simon Glassa3f29ec2011-07-17 09:36:49 -07007import os
8import re
Simon Glasse86f3132013-01-08 16:10:43 -08009import struct
Simon Glassa3f29ec2011-07-17 09:36:49 -070010import time
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -070011
12from exynos import ExynosBl2
Simon Glassa3f29ec2011-07-17 09:36:49 -070013from tools import CmdError
14
15def RoundUp(value, boundary):
16 """Align a value to the next power of 2 boundary.
17
18 Args:
19 value: The value to align.
20 boundary: The boundary value, e.g. 4096. Must be a power of 2.
21
22 Returns:
23 The rounded-up value.
24 """
25 return (value + boundary - 1) & ~(boundary - 1)
26
27
28class WriteFirmware:
29 """Write firmware to a Tegra 2 board using USB A-A cable.
30
31 This class handles re-reflashing a board with new firmware using the Tegra's
32 built-in boot ROM feature. This works by putting the chip into a special mode
33 where it ignores any available firmware and instead reads it from a connected
34 host machine over USB.
35
36 In our case we use that feature to send U-Boot along with a suitable payload
37 and instructions to flash it to SPI flash. The payload is itself normally a
38 full Chrome OS image consisting of U-Boot, some keys and verification
39 information, images and a map of the flash memory.
Simon Glass6a616c12012-09-24 18:13:46 -070040
41 Private attributes:
42 _servo_port: Port number to use to talk to servo with dut-control.
43 Special values are:
44 None: servo is not available.
45 0: any servo will do.
46
Simon Glassa3f29ec2011-07-17 09:36:49 -070047 """
Vadim Bendebury2b719452013-02-12 17:00:06 -080048
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080049 _DOWNLOAD_FAILURE_MESSAGE = '** Load checksum error: check download tool **'
50 _SKIP_VERIFY_MESSAGE = 'Skipping verify'
Vadim Bendebury2b719452013-02-12 17:00:06 -080051 _WRITE_FAILURE_MESSAGE = '** Readback checksum error, programming failed!! **'
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080052 _WRITE_SUCCESS_MESSAGE = 'Image Programmed Successfully'
Vadim Bendebury2b719452013-02-12 17:00:06 -080053
54 def __init__(self, tools, fdt, output, bundle, update, verify):
Simon Glassa3f29ec2011-07-17 09:36:49 -070055 """Set up a new WriteFirmware object.
56
57 Args:
58 tools: A tools library for us to use.
59 fdt: An fdt which gives us some info that we need.
60 output: An output object to use for printing progress and messages.
Simon Glass0191a882012-05-23 13:15:06 -070061 bundle: A BundleFirmware object which created the image.
Vadim Bendebury2b719452013-02-12 17:00:06 -080062 update: Use faster update algorithm rather then full device erase.
63 verify: Verify the write by doing a readback and CRC.
Simon Glassa3f29ec2011-07-17 09:36:49 -070064 """
65 self._tools = tools
66 self._fdt = fdt
67 self._out = output
Simon Glass0191a882012-05-23 13:15:06 -070068 self._bundle = bundle
Vadim Bendebury19a77122013-01-24 17:38:00 -080069 self.text_base = self._fdt.GetInt('/chromeos-config', 'textbase', -1)
Simon Glassa3f29ec2011-07-17 09:36:49 -070070
Simon Glass5b5fd642011-08-17 12:24:01 -070071 # For speed, use the 'update' algorithm and don't verify
Vadim Bendebury2b719452013-02-12 17:00:06 -080072 self.update = update
73 self.verify = verify
Simon Glass5b5fd642011-08-17 12:24:01 -070074
Simon Glass6a616c12012-09-24 18:13:46 -070075 # Use default servo port
76 self._servo_port = 0
77
Simon Glassa7e66e22013-07-23 07:21:16 -060078 # By default, no early firmware selection.
79 self.use_efs = False
80
Simon Glass6a616c12012-09-24 18:13:46 -070081 def SelectServo(self, servo):
82 """Select the servo to use for writing firmware.
83
84 Args:
85 servo: String containing description of servo to use:
86 'none' : Don't use servo, generate an error on any attempt.
87 'any' : Use any available servo.
88 '<port>': Use servo with that port number.
89 """
90 if servo == 'none':
91 self._servo_port = None
92 elif servo == 'any':
93 self._servo_port = 0
94 else:
95 self._servo_port = int(servo)
96 self._out.Notice('Servo port %s' % str(self._servo_port))
97
Michael Prattc610dcf2013-07-17 15:38:53 -070098 def _GetFlashScript(self, payload_size, flash_dest, checksum, ro_size=None):
Simon Glassa3f29ec2011-07-17 09:36:49 -070099 """Get the U-Boot boot command needed to flash U-Boot.
100
101 We leave a marker in the string for the load address of the image,
102 since this depends on the size of this script. This can be replaced by
103 the caller provided that the marker length is unchanged.
104
105 Args:
106 payload_size: Size of payload in bytes.
Andrew Chew919858c2013-07-22 15:39:56 -0700107 flash_dest: A dictionary of strings keyed by 'type' (nand, sdmmc,
108 or spi), 'bus', and 'dev'.
Simon Glass8bd05ec2012-03-22 11:09:04 -0700109 checksum: The checksum of the payload (an integer)
Michael Prattc610dcf2013-07-17 15:38:53 -0700110 ro_size: Size of read-only partition. If set, split MMC image between
111 partition 1 (ro) and partition 2 (rw).
Simon Glassa3f29ec2011-07-17 09:36:49 -0700112
113 Returns:
114 A tuple containing:
115 The script, as a string ready to use as a U-Boot boot command, with an
116 embedded marker for the load address.
117 The marker string, which the caller should replace with the correct
118 load address as 8 hex digits, without changing its length.
Michael Prattc610dcf2013-07-17 15:38:53 -0700119 The marker RW string, which the caller should replace with the correct
120 load address for the RW section as 8 hex digits, without changing
121 its length. This is only required if ro_size is set.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700122 """
123 replace_me = 'zsHEXYla'
Michael Prattc610dcf2013-07-17 15:38:53 -0700124 replace_me_rw = 'zsHEXYrw'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800125 page_size = 4096
Andrew Chew919858c2013-07-22 15:39:56 -0700126 boot_type = flash_dest['type']
Simon Glass0dcbecb2012-03-22 21:38:55 -0700127 if boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800128 page_size = 512
Vadim Bendebury2b719452013-02-12 17:00:06 -0800129 update = self.update and boot_type == 'spi'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800130
Simon Glassa3f29ec2011-07-17 09:36:49 -0700131 cmds = [
132 'setenv address 0x%s' % replace_me,
133 'setenv firmware_size %#x' % payload_size,
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800134 'setenv length %#x' % RoundUp(payload_size, page_size),
135 'setenv blocks %#x' % (RoundUp(payload_size, page_size) / page_size),
Simon Glass5b51b472013-03-28 13:06:05 -0700136 'setenv _crc "crc32 -v ${address} ${firmware_size} %08x"' %
Simon Glass8bd05ec2012-03-22 11:09:04 -0700137 checksum,
Simon Glass5b5fd642011-08-17 12:24:01 -0700138 'setenv _clear "echo Clearing RAM; mw.b ${address} 0 ${length}"',
Doug Anderson37ae2292011-09-15 17:41:57 -0700139 ]
Michael Prattc610dcf2013-07-17 15:38:53 -0700140
141 if ro_size:
142 rw_size = payload_size - ro_size
143
144 cmds.extend([
145 'setenv address_ro ${address}',
146 'setenv address_rw 0x%s' % replace_me_rw,
147 'setenv blocks_ro %#x' % (RoundUp(ro_size, page_size) / page_size),
148 'setenv blocks_rw %#x' % (RoundUp(rw_size, page_size) / page_size),
149 ])
150
Simon Glass0dcbecb2012-03-22 21:38:55 -0700151 if boot_type == 'nand':
Doug Anderson37ae2292011-09-15 17:41:57 -0700152 cmds.extend([
153 'setenv _init "echo Init NAND; nand info"',
154 'setenv _erase "echo Erase NAND; nand erase 0 ${length}"',
155 'setenv _write "echo Write NAND; nand write ${address} 0 ${length}"',
156 'setenv _read "echo Read NAND; nand read ${address} 0 ${length}"',
157 ])
Simon Glass0dcbecb2012-03-22 21:38:55 -0700158 elif boot_type == 'sdmmc':
Michael Pratt54aaeed2013-07-12 13:42:47 -0700159 # In U-Boot, strings in double quotes have variables expanded to actual
160 # values. For reasons unclear, this expansion splits the single quoted
161 # argument into separate arguements for each word, which on exynos
162 # boards causes the command to exceed the maximum configured argument
163 # count. Passing the string in single quotes prevents this expansion,
164 # allowing variables to be expanded when run is called.
165 # crbug.com/260294
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800166 cmds.extend([
Michael Pratt54aaeed2013-07-12 13:42:47 -0700167 'setenv _init "echo Init EMMC; mmc rescan"',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800168 'setenv _erase "echo Erase EMMC; "',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800169 ])
Michael Prattc610dcf2013-07-17 15:38:53 -0700170 if ro_size:
171 # Write RO section to partition 1, RW to partition 2
172 cmds.extend([
173 "setenv _write 'echo Write EMMC;" \
174 " mmc open 0 1;" \
175 " mmc write ${address_ro} 0 ${blocks_ro};" \
176 " mmc close 0 1;" \
177 " mmc open 0 2;" \
178 " mmc write ${address_rw} 0 ${blocks_rw};" \
179 " mmc close 0 2'",
180 "setenv _read 'echo Read EMMC;" \
181 " mmc open 0 1;" \
182 " mmc read ${address_ro} 0 ${blocks_ro};" \
183 " mmc close 0 1;" \
184 " mmc open 0 2;" \
185 " mmc read ${address_rw} 0 ${blocks_rw};" \
186 " mmc close 0 2'",
187 ])
188 else:
189 cmds.extend([
190 "setenv _write 'echo Write EMMC;" \
191 " mmc open 0 1;" \
192 " mmc write ${address} 0 ${blocks};" \
193 " mmc close 0 1'",
194 "setenv _read 'echo Read EMMC;" \
195 " mmc open 0 1;" \
196 " mmc read ${address} 0 ${blocks};" \
197 " mmc close 0 1'",
198 ])
Doug Anderson37ae2292011-09-15 17:41:57 -0700199 else:
Andrew Chew919858c2013-07-22 15:39:56 -0700200 if flash_dest['bus'] is None:
201 flash_dest['bus'] = '0'
202 if flash_dest['dev'] is None:
203 flash_dest['dev'] = '0'
Doug Anderson37ae2292011-09-15 17:41:57 -0700204 cmds.extend([
Andrew Chew919858c2013-07-22 15:39:56 -0700205 'setenv _init "echo Init SPI; sf probe %s:%s"' %
206 (flash_dest['bus'], flash_dest['dev']),
Doug Anderson37ae2292011-09-15 17:41:57 -0700207 'setenv _erase "echo Erase SPI; sf erase 0 ${length}"',
208 'setenv _write "echo Write SPI; sf write ${address} 0 ${length}"',
209 'setenv _read "echo Read SPI; sf read ${address} 0 ${length}"',
210 'setenv _update "echo Update SPI; sf update ${address} 0 ${length}"',
211 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700212
Doug Anderson37ae2292011-09-15 17:41:57 -0700213 cmds.extend([
Simon Glassa3f29ec2011-07-17 09:36:49 -0700214 'echo Firmware loaded to ${address}, size ${firmware_size}, '
215 'length ${length}',
Simon Glass8bd05ec2012-03-22 11:09:04 -0700216 'if run _crc; then',
Simon Glassa3f29ec2011-07-17 09:36:49 -0700217 'run _init',
Doug Anderson37ae2292011-09-15 17:41:57 -0700218 ])
Simon Glass5b5fd642011-08-17 12:24:01 -0700219 if update:
220 cmds += ['time run _update']
221 else:
222 cmds += ['run _erase', 'run _write']
Vadim Bendebury2b719452013-02-12 17:00:06 -0800223 if self.verify:
Simon Glass5b5fd642011-08-17 12:24:01 -0700224 cmds += [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700225 'run _clear',
226 'run _read',
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800227 'if run _crc; then',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800228 'echo "%s"' % self._WRITE_SUCCESS_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800229 'else',
230 'echo',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800231 'echo "%s"' % self._WRITE_FAILURE_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800232 'echo',
233 'fi',
Simon Glass5b5fd642011-08-17 12:24:01 -0700234 ]
235 else:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800236 cmds += ['echo %s' % self._SKIP_VERIFY_MESSAGE]
Simon Glass8bd05ec2012-03-22 11:09:04 -0700237 cmds.extend([
238 'else',
239 'echo',
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800240 'echo "%s"' % self._DOWNLOAD_FAILURE_MESSAGE,
Simon Glass8bd05ec2012-03-22 11:09:04 -0700241 'fi',
242 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700243 script = '; '.join(cmds)
Michael Prattc610dcf2013-07-17 15:38:53 -0700244 return script, replace_me, replace_me_rw
Simon Glassa3f29ec2011-07-17 09:36:49 -0700245
Michael Prattc610dcf2013-07-17 15:38:53 -0700246 def _ReplaceAddr(self, data, replace_me, replacement):
247 """Replace address in FDT
248
249 Detect and replace a placeholder address in the FDT.
250
251 Args:
252 data: FDT data to do replacement on
253 replace_me: String currently in FDT to replace
254 replacement: Replacement string
255
256 Returns:
257 Updated data with replacement
258 """
259 if len(replace_me) is not len(replacement):
260 raise ValueError("Internal error: replacement string '%s' length does "
261 "not match new string '%s'" % (replace_me, replacement))
262
263 matches = len(re.findall(replace_me, data))
264 if matches != 1:
265 raise ValueError("Internal error: replacement string '%s' already "
266 "exists in the fdt (%d matches)" % (replace_me, matches))
267
268 return re.sub(replace_me, replacement, data)
269
270 def _PrepareFlasher(self, uboot, payload, flash_dest, ro_size=None):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700271 """Get a flasher ready for sending to the board.
272
273 The flasher is an executable image consisting of:
274
275 - U-Boot (u-boot.bin);
276 - a special FDT to tell it what to do in the form of a run command;
277 - (we could add some empty space here, in case U-Boot is not built to
278 be relocatable);
279 - the payload (which is a full flash image, or signed U-Boot + fdt).
280
281 Args:
282 uboot: Full path to u-boot.bin.
283 payload: Full path to payload.
Andrew Chew919858c2013-07-22 15:39:56 -0700284 flash_dest: A dictionary of strings keyed by 'type' (nand, sdmmc,
285 or spi), 'bus', and 'dev'.
Michael Prattc610dcf2013-07-17 15:38:53 -0700286 boot_type: the src for bootdevice (nand, sdmmc, or spi)
287 ro_size: Size of read-only partition on emmc. If set, indicates that
288 the image should be split, with half written to partition 1, and
289 half written to partition 2.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700290
291 Returns:
Simon Glass290a1802011-07-17 13:54:32 -0700292 Filename of the flasher binary created.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700293 """
Simon Glass951a2db2011-07-17 15:58:58 -0700294 fdt = self._fdt.Copy(os.path.join(self._tools.outdir, 'flasher.dtb'))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700295 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700296
Simon Glass8bd05ec2012-03-22 11:09:04 -0700297 # Make sure that the checksum is not negative
298 checksum = binascii.crc32(payload_data) & 0xffffffff
299
Michael Prattc610dcf2013-07-17 15:38:53 -0700300 script, replace_start, replace_rw = self._GetFlashScript(len(payload_data),
301 flash_dest, checksum, ro_size)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700302 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800303 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700304 fdt_data = self._tools.ReadFile(fdt.fname)
305
306 # Work out where to place the payload in memory. This is a chicken-and-egg
307 # problem (although in case you haven't heard, it was the chicken that
308 # came first), so we resolve it by replacing the string after
309 # fdt.PutString has done its job.
310 #
311 # Correction: Technically, the egg came first. Whatever genetic mutation
312 # created the new species would have been present in the egg, but not the
313 # parent (since if it was in the parent, it would have been present in the
314 # parent when it was an egg).
315 #
316 # Question: ok so who laid the egg then?
317 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700318
319 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
320 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700321 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700322
Simon Glass2c4b3e52011-11-15 14:45:43 -0800323 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700324 new_str = '%08x' % load_address
Michael Prattc610dcf2013-07-17 15:38:53 -0700325 fdt_data = self._ReplaceAddr(fdt_data, replace_start, new_str)
326
327 if ro_size:
328 new_str_rw = '%08x' % (load_address[0] + ro_size)
329 fdt_data = self._ReplaceAddr(fdt_data, replace_rw, new_str_rw)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700330
331 # Now put it together.
332 data += fdt_data
333 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700334 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700335 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700336 self._tools.WriteFile(flasher, data)
337
338 # Tell the user about a few things.
339 self._tools.OutputSize('U-Boot', uboot)
340 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700341 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700342 self._tools.OutputSize('Flasher', flasher)
343 return flasher
344
Vadim Bendebury19a77122013-01-24 17:38:00 -0800345 def NvidiaFlashImage(self, flash_dest, uboot, bct, payload, bootstub):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700346 """Flash the image to SPI flash.
347
348 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000349 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700350
351 Args:
Andrew Chew919858c2013-07-22 15:39:56 -0700352 flash_dest: Destination for flasher, or None to not create a flasher.
353 This value is a dictionary of strings keyed by 'type', 'bus', and
354 'dev'.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700355 uboot: Full path to u-boot.bin.
356 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
357 payload: Full path to payload.
Simon Glass89ecf712012-06-07 12:20:15 -0700358 bootstub: Full path to bootstub, which is the payload without the
359 signing information (i.e. bootstub is u-boot.bin + the FDT)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700360
361 Returns:
362 True if ok, False if failed.
363 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800364 # Use a Regex to pull Boot type from BCT file.
365 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
366 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700367
368 # TODO(sjg): The boot type is currently selected by the bct, rather than
Andrew Chew919858c2013-07-22 15:39:56 -0700369 # flash_dest['type'] selecting which bct to use. This is a bit backwards.
370 # For now we go with the bct's idea.
371 flash_dest['type'] = filter(match.match, bct_dumped)
372 flash_dest['type'] = match.match(
373 flash_dest['type'][0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700374
Simon Glass89ecf712012-06-07 12:20:15 -0700375 if flash_dest:
Andrew Chew919858c2013-07-22 15:39:56 -0700376 image = self._PrepareFlasher(uboot, payload, flash_dest)
Simon Glasse1824db2012-07-11 17:38:40 +0200377 elif bootstub:
Simon Glass89ecf712012-06-07 12:20:15 -0700378 image = bootstub
Simon Glassa3f29ec2011-07-17 09:36:49 -0700379
Simon Glasse1824db2012-07-11 17:38:40 +0200380 else:
381 image = payload
382 # If we don't know the textbase, extract it from the payload.
383 if self.text_base == -1:
384 data = self._tools.ReadFile(payload)
385 # Skip the BCT which is the first 64KB
386 self.text_base = self._bundle.DecodeTextBase(data[0x10000:])
387
Simon Glass89ecf712012-06-07 12:20:15 -0700388 self._out.Notice('TEXT_BASE is %#x' % self.text_base)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700389 self._out.Progress('Uploading flasher image')
390 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700391 '--bct', bct,
Allen Martinb3aa2672012-03-23 15:55:25 +0000392 '--bootloader', image,
393 '--loadaddr', "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700394 ]
395
396 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
397 last_err = None
Vadim Bendebury19a77122013-01-24 17:38:00 -0800398 for _ in range(10):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700399 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700400 # TODO(sjg): Use Chromite library so we can monitor output
Allen Martinb3aa2672012-03-23 15:55:25 +0000401 self._tools.Run('tegrarcm', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700402 self._out.Notice('Flasher downloaded - please see serial output '
403 'for progress.')
404 return True
405
406 except CmdError as err:
407 if not self._out.stdout_is_tty:
408 return False
409
410 # Only show the error output once unless it changes.
411 err = str(err)
Simon Glass22190ff2012-07-11 14:52:26 +0200412 if not 'could not open USB device' in err:
Allen Martinb3aa2672012-03-23 15:55:25 +0000413 raise CmdError('tegrarcm failed: %s' % err)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700414
415 if err != last_err:
416 self._out.Notice(err)
417 last_err = err
418 self._out.Progress('Please connect USB A-A cable and do a '
419 'recovery-reset', True)
420 time.sleep(1)
421
422 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700423
Simon Glass27a9c142012-03-15 21:08:29 -0700424 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
425 """Wait until we see a device on the USB bus.
426
427 Args:
428 name: Board type name
429 vendor_id: USB vendor ID to look for
430 product_id: USB product ID to look for
431 timeout: Timeout to wait in seconds
432
433 Returns
434 True if the device was found, False if we timed out.
435 """
436 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass4968a472012-05-23 13:52:19 -0700437 start_time = time.time()
438 while time.time() - start_time < timeout:
Simon Glass27a9c142012-03-15 21:08:29 -0700439 try:
440 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
441 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700442 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700443 return True
444
Vadim Bendebury19a77122013-01-24 17:38:00 -0800445 except CmdError:
Simon Glass27a9c142012-03-15 21:08:29 -0700446 pass
447
Simon Glass3381a1a2012-03-22 11:13:19 -0700448 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700449
Vadim Bendebury2b719452013-02-12 17:00:06 -0800450 def DutControl(self, args):
Simon Glass6a616c12012-09-24 18:13:46 -0700451 """Run dut-control with supplied arguments.
452
Simon Glass2065a742013-02-09 13:39:26 -0800453 The correct servo will be used based on self._servo_port. If servo use is
454 disabled, this function does nothing.
Simon Glass6a616c12012-09-24 18:13:46 -0700455
456 Args:
457 args: List of arguments to dut-control.
458
Simon Glass2065a742013-02-09 13:39:26 -0800459 Returns:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800460 a string, stdout generated by running the command
Simon Glass6a616c12012-09-24 18:13:46 -0700461 """
462 if self._servo_port is None:
Simon Glass2065a742013-02-09 13:39:26 -0800463 return '' # User has requested not to use servo
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800464 if self._servo_port:
Simon Glass6a616c12012-09-24 18:13:46 -0700465 args.extend(['-p', '%s' % self._servo_port])
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800466 return self._tools.Run('dut-control', args)
Simon Glass6a616c12012-09-24 18:13:46 -0700467
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800468 def WaitForCompletion(self):
Vadim Bendebury2b719452013-02-12 17:00:06 -0800469 """Verify flash programming operation success.
470
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800471 The DUT is presumed to be programming flash with console capture mode on.
472 This function scans console output for the success or failure strings.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800473
474 Raises:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800475 CmdError if the following cases:
476 - none of the strings show up in the allotted time (2 minutes)
477 - console goes silent for more than 10 seconds
478 - one of the error messages seen in the stream
479 - misformatted output is seen in the stream
Vadim Bendebury2b719452013-02-12 17:00:06 -0800480 """
481
482 _SOFT_DEADLINE_LIMIT = 10
483 _HARD_DEADLINE_LIMIT = 120
484 string_leftover = ''
485 soft_deadline = time.time() + _SOFT_DEADLINE_LIMIT
486 hard_deadline = soft_deadline + _HARD_DEADLINE_LIMIT - _SOFT_DEADLINE_LIMIT
487
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800488 if self.verify:
489 done_line = self._WRITE_SUCCESS_MESSAGE
490 else:
491 done_line = self._SKIP_VERIFY_MESSAGE
492
Vadim Bendebury2b719452013-02-12 17:00:06 -0800493 while True:
494 now = time.time()
495 if now > hard_deadline:
496 raise CmdError('Target console flooded, programming failed')
497 if now > soft_deadline:
498 raise CmdError('Target console dead, programming failed')
499 stream = self.DutControl(['cpu_uart_stream',])
500 match = re.search("^cpu_uart_stream:'(.*)'\n", stream)
501 if not match:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800502 raise CmdError('Misformatted console output: \n%s\n' % stream)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800503
504 text = string_leftover + match.group(1)
505 strings = text.split('\\r')
506 string_leftover = strings.pop()
507 if strings:
508 soft_deadline = now + _SOFT_DEADLINE_LIMIT
509 for string in strings:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800510 if done_line in string:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800511 return True
512 if self._WRITE_FAILURE_MESSAGE in string:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800513 raise CmdError('Readback verification failed!')
514 if self._DOWNLOAD_FAILURE_MESSAGE in string:
515 raise CmdError('Download failed!')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800516
Simon Glass4c54a912013-02-18 16:56:29 -0800517 def _ExtractPayloadParts(self, payload, truncate_to_fdt):
Simon Glass3c5b35b2012-05-23 13:22:23 -0700518 """Extract the BL1, BL2 and U-Boot parts from a payload.
519
520 An exynos image consists of 3 parts: BL1, BL2 and U-Boot/FDT.
521
522 This pulls out the various parts, puts them into files and returns
523 these files.
524
525 Args:
526 payload: Full path to payload.
Simon Glass4c54a912013-02-18 16:56:29 -0800527 truncate_to_fdt: Truncate the U-Boot image at the start of its
528 embedded FDT
Simon Glass3c5b35b2012-05-23 13:22:23 -0700529
530 Returns:
Simon Glassa7e66e22013-07-23 07:21:16 -0600531 (bl1, bl2, image, uboot_offset) where:
Simon Glass3c5b35b2012-05-23 13:22:23 -0700532 bl1 is the filename of the extracted BL1
533 bl2 is the filename of the extracted BL2
534 image is the filename of the extracted U-Boot image
Simon Glassa7e66e22013-07-23 07:21:16 -0600535 uboot_offset is the offset of U-Boot in the image
Simon Glass3c5b35b2012-05-23 13:22:23 -0700536 """
537 # Pull out the parts from the payload
538 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
539 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
540 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
541 data = self._tools.ReadFile(payload)
542
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700543 try:
544 bl1_size = int(self._fdt.GetProps('/flash/pre-boot')['size'])
545 bl2_size = int(self._fdt.GetProps('/flash/spl')['size'])
546 uboot_offset = bl1_size + bl2_size
Simon Glass496c8302013-07-20 18:04:02 -0600547 except (CmdError, KeyError):
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700548 self._out.Warning('No component nodes in the device tree')
549 # The BL1 is always 8KB - extract that part into a new file
550 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
551 bl1_size = 0x2000
Simon Glass3c5b35b2012-05-23 13:22:23 -0700552
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700553 # Try to detect the BL2 size. We look for 0xea000014 or 0xea000013
554 # which is the 'B reset' instruction at the start of U-Boot. When
555 # U-Boot is LZO compressed, we look for a LZO magic instead.
556 start_data = [struct.pack('<L', 0xea000014),
557 struct.pack('<L', 0xea000013),
558 struct.pack('>B3s', 0x89, 'LZO')]
559 starts = [data.find(magic, bl1_size + 0x3800) for magic in start_data]
560 uboot_offset = None
561 for start in starts:
562 if start != -1 and (not uboot_offset or start < uboot_offset):
563 uboot_offset = start
564 if not uboot_offset:
565 raise ValueError('Could not locate start of U-Boot')
566 bl2_size = uboot_offset - bl1_size - 0x800 # 2KB gap after BL2
Simon Glass3c5b35b2012-05-23 13:22:23 -0700567
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700568 # Sanity check: At present we only allow 14KB and 30KB for SPL
569 allowed = [14, 30]
570 if (bl2_size >> 10) not in allowed:
571 raise ValueError('BL2 size is %dK - only %s supported' %
572 (bl2_size >> 10, ', '.join(
573 [str(size) for size in allowed])))
Simon Glasse86f3132013-01-08 16:10:43 -0800574 self._out.Notice('BL2 size is %dKB' % (bl2_size >> 10))
575
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700576 self._tools.WriteFile(bl1, data[:bl1_size])
577 self._tools.WriteFile(bl2, data[bl1_size:bl1_size + bl2_size])
Simon Glasse86f3132013-01-08 16:10:43 -0800578
Simon Glassbc0d8d42013-02-09 11:59:36 -0800579 # U-Boot itself starts at 24KB, after the gap. As a hack, truncate it
Simon Glass4c54a912013-02-18 16:56:29 -0800580 # to an assumed maximum size. As a secondary hack, locate the FDT
581 # and truncate U-Boot from that point. The correct FDT will be added
582 # when the image is written to the board.
Simon Glassbc0d8d42013-02-09 11:59:36 -0800583 # TODO(sjg@chromium.org): Get a proper flash map here so we know how
584 # large it is
Simon Glass4c54a912013-02-18 16:56:29 -0800585 uboot_data = data[uboot_offset:uboot_offset + 0xa0000]
586 if truncate_to_fdt:
587 fdt_magic = struct.pack('>L', 0xd00dfeed)
588 fdt_offset = uboot_data.rfind(fdt_magic)
589 uboot_data = uboot_data[:fdt_offset]
590
591 self._tools.WriteFile(image, uboot_data)
Simon Glassa7e66e22013-07-23 07:21:16 -0600592 return bl1, bl2, image, uboot_offset
Simon Glass3c5b35b2012-05-23 13:22:23 -0700593
Vadim Bendebury19a77122013-01-24 17:38:00 -0800594 def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
Simon Glassa7e66e22013-07-23 07:21:16 -0600595 kernel):
Simon Glass27a9c142012-03-15 21:08:29 -0700596 """Flash the image to SPI flash.
597
598 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000599 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glass27a9c142012-03-15 21:08:29 -0700600
601 Args:
Andrew Chew919858c2013-07-22 15:39:56 -0700602 flash_dest: Destination for flasher, or None to not create a flasher.
603 This is a dictionary of strings keyed by 'type', 'bus', and 'dev'.
604 Valid options for 'type' are spi, sdmmc.
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700605 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700606 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700607 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700608 payload: Full path to payload.
Simon Glassde9c8072012-07-02 22:29:02 -0700609 kernel: Kernel to send after the payload, or None.
Simon Glass27a9c142012-03-15 21:08:29 -0700610
611 Returns:
612 True if ok, False if failed.
Simon Glassb4c14af2013-07-04 11:56:33 +0900613
614 Raises:
615 CmdError if a supported Exynos model is not detected in the device tree.
Simon Glass27a9c142012-03-15 21:08:29 -0700616 """
Simon Glassa7e66e22013-07-23 07:21:16 -0600617 use_efs_memory = False
Simon Glassbc0d8d42013-02-09 11:59:36 -0800618 tools = self._tools
Simon Glassa7e66e22013-07-23 07:21:16 -0600619 payload_bl1, payload_bl2, payload_image, spl_load_offset = (
Simon Glass4c54a912013-02-18 16:56:29 -0800620 self._ExtractPayloadParts(payload, flash_dest is not None))
Simon Glassa7e66e22013-07-23 07:21:16 -0600621 bl2_handler = ExynosBl2(tools, self._out)
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700622 if flash_dest:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800623 # If we don't have some bits, get them from the image
624 if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
625 self._out.Warning('Extracting U-Boot from payload')
626 flash_uboot = payload_image
627 if not bl1 or not os.path.exists(tools.Filename(bl1)):
628 self._out.Warning('Extracting BL1 from payload')
629 bl1 = payload_bl1
630 if not bl2 or not os.path.exists(tools.Filename(bl2)):
631 self._out.Warning('Extracting BL2 from payload')
632 bl2 = payload_bl2
Michael Pratt24e7c162013-07-12 09:35:28 -0700633 else:
Simon Glassa7e66e22013-07-23 07:21:16 -0600634 # Update BL2 machine parameters, as the BL2 passed in may not be
635 # updated. Also make sure it doesn't use early-firmware-selection
636 # since our flasher needs to run from SDRAM.
Michael Pratt24e7c162013-07-12 09:35:28 -0700637 spl_load_size = os.stat(tools.Filename(bl2)).st_size
Simon Glassa7e66e22013-07-23 07:21:16 -0600638 bl2 = bl2_handler.Configure(self._fdt, spl_load_offset, spl_load_size,
639 bl2, 'flasher', loose_check=True,
640 use_efs_memory=False)
Andrew Chew919858c2013-07-22 15:39:56 -0700641 # Set default values for Exynos targets.
642 if flash_dest['bus'] is None:
643 flash_dest['bus'] = 1
644 if flash_dest['dev'] is None:
645 flash_dest['dev'] = 0
Michael Prattc610dcf2013-07-17 15:38:53 -0700646
647 # Try to determine RO section size
648 ro_size = None
649 if flash_dest['type'] == 'sdmmc':
650 try:
651 ro_size = self._fdt.GetFlashPartSize('wp', 'ro')
652 except (CmdError, ValueError):
653 self._out.Warning('Unable to detect RO section size')
654
655 image = self._PrepareFlasher(flash_uboot, payload, flash_dest, ro_size)
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700656 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800657 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700658
659 vendor_id = 0x04e8
660 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700661
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800662 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800663 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
664 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800665 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800666 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700667 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800668 if preserved_dut_hub_sel != required_dut_hub_sel:
669 # Need to set it to get the port properly powered up.
670 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Simon Glass93673cf2013-04-26 17:55:55 -0700671 if self._servo_port is not None:
672 self._out.Progress('Reseting board via servo')
673 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700674
Simon Glassde9c8072012-07-02 22:29:02 -0700675 # If we have a kernel to write, create a new image with that added.
676 if kernel:
677 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
678 data = self._tools.ReadFile(image)
679
680 # Pad the original payload out to the original length
681 data += '\0' * (os.stat(payload).st_size - len(data))
682 data += self._tools.ReadFile(kernel)
683 self._tools.WriteFile(dl_image, data)
684 else:
Simon Glassa7e66e22013-07-23 07:21:16 -0600685 # See which type of memory we should load U-Boot to
686 used_size = self._fdt.GetFlashPartUsed('ro', 'boot')
687 if self.use_efs and used_size:
688 node = self._fdt.GetFlashNode('ro', 'boot')
689 props = self._fdt.GetProp(node, 'type,efs', 'none')
690 if props != 'none' and props[0] == 'blob':
691 parts = props[1].split(',')
692 use_efs_memory = 'ro-boot' in parts
693
694 # Truncate the image to just the size actually used
695 if use_efs_memory:
696 dl_image = os.path.join(self._tools.outdir, 'image-used.bin')
697 data = self._tools.ReadFile(image)
698 self._tools.WriteFile(dl_image, data[:used_size])
699 self._out.Warning('Truncating to used size %#x' % used_size)
700 else:
701 dl_image = image
Simon Glassde9c8072012-07-02 22:29:02 -0700702
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700703 self._out.Progress('Uploading image')
Simon Glass81ed0792013-07-20 17:36:24 -0600704
705 # This list tells us the memory region to use, the offset into that
706 # region and the filename to upload.
707 upload_list = [
708 ['/iram', 'samsung,bl1-offset', bl1],
709 ['/iram', 'samsung,bl2-offset', bl2],
710 ['/memory', 'u-boot-offset', dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700711 ]
Simon Glassb4c14af2013-07-04 11:56:33 +0900712
Simon Glass3381a1a2012-03-22 11:13:19 -0700713 try:
Simon Glass81ed0792013-07-20 17:36:24 -0600714 for upto in range(len(upload_list)):
715 item = upload_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700716 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700717 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700718 raise CmdError('Could not find Exynos board on USB port')
Simon Glass81ed0792013-07-20 17:36:24 -0600719 raise CmdError("Stage '%s' did not complete" % item[1])
720 self._out.Notice(item[2])
Simon Glass3381a1a2012-03-22 11:13:19 -0700721
Simon Glass4968a472012-05-23 13:52:19 -0700722 if upto == 0:
723 # The IROM needs roughly 200ms here to be ready for USB download
724 time.sleep(.5)
725
Simon Glassa7e66e22013-07-23 07:21:16 -0600726 # Load U-Boot either to IRAM or SDRAM depending on EFS
727 if upto == 2:
728 addr = bl2_handler.GetUBootAddress(self._fdt, use_efs_memory)
729 else:
730 base = self._fdt.GetIntList(item[0], 'reg')[0]
731 offset = self._fdt.GetIntList('/config', item[1])[0]
732 addr = base + offset
Simon Glass81ed0792013-07-20 17:36:24 -0600733
734 self._out.Progress("Uploading stage '%s' to %x" % (item[1], addr))
735 args = ['-a', '%#x' % addr, '-f', item[2]]
Simon Glass79e3dd02012-08-28 20:08:50 -0700736 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700737
Simon Glass3381a1a2012-03-22 11:13:19 -0700738 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800739 # Make sure that the power button is released and dut_sel_hub state is
740 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700741 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800742 if preserved_dut_hub_sel != required_dut_hub_sel:
743 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800744 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700745
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800746 if flash_dest is None:
747 self._out.Notice('Image downloaded - please see serial output '
748 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700749 return True
750
Simon Glass0c2ba482012-03-22 21:57:51 -0700751 def _GetDiskInfo(self, disk, item):
752 """Returns information about a SCSI disk device.
753
754 Args:
755 disk: a block device name in sys/block, like '/sys/block/sdf'.
756 item: the item of disk information that is required.
757
758 Returns:
759 The information obtained, as a string, or '[Unknown]' if not found
760 """
761 dev_path = os.path.join(disk, 'device')
762
763 # Search upwards and through symlinks looking for the item.
764 while os.path.isdir(dev_path) and dev_path != '/sys':
765 fname = os.path.join(dev_path, item)
766 if os.path.exists(fname):
767 with open(fname, 'r') as fd:
768 return fd.readline().rstrip()
769
770 # Move up a level and follow any symlink.
771 new_path = os.path.join(dev_path, '..')
772 if os.path.islink(new_path):
773 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
774 dev_path = new_path
775 return '[Unknown]'
776
777 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700778 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700779
780 Args:
781 device: Device to check, like '/dev/sdf'.
782
783 Returns:
784 Capacity of device in GB, or 0 if not known.
785 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700786 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700787 args = ['-l', device]
788 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700789 for line in stdout.splitlines():
790 m = re_capacity.match(line)
791 if m:
792 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700793 return 0
794
795 def _ListUsbDisks(self):
796 """Return a list of available removable USB disks.
797
798 Returns:
799 List of USB devices, each element is itself a list containing:
800 device ('/dev/sdx')
801 manufacturer name
802 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700803 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700804 """
805 disk_list = []
806 for disk in glob.glob('/sys/block/sd*'):
807 with open(disk + '/removable', 'r') as fd:
808 if int(fd.readline()) == 1:
809 device = '/dev/%s' % disk.split('/')[-1]
810 manuf = self._GetDiskInfo(disk, 'manufacturer')
811 product = self._GetDiskInfo(disk, 'product')
812 capacity = self._GetDiskCapacity(device)
813 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700814 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700815 return disk_list
816
817 def WriteToSd(self, flash_dest, disk, uboot, payload):
818 if flash_dest:
Andrew Chew919858c2013-07-22 15:39:56 -0700819 # Set default values for sd.
820 if flash_dest['bus'] is None:
821 flash_dest['bus'] = 1
822 if flash_dest['dev'] is None:
823 flash_dest['dev'] = 0
824 raw_image = self._PrepareFlasher(uboot, payload, flash_dest)
Simon Glassa7e66e22013-07-23 07:21:16 -0600825 bl1, bl2, _, spl_load_offset = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700826 spl_load_size = os.stat(raw_image).st_size
Simon Glass559b6612012-05-23 13:28:45 -0700827
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700828 bl2_handler = ExynosBl2(self._tools, self._out)
Simon Glassa7e66e22013-07-23 07:21:16 -0600829 bl2_file = bl2_handler.Configure(self._fdt, spl_load_offset,
830 spl_load_size, bl2, 'flasher', True,
831 use_efs_memory=False)
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700832 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2_file)
Simon Glass559b6612012-05-23 13:28:45 -0700833
Vadim Bendebury22de0492013-06-17 16:11:20 -0700834 # Pad BL2 out to the required size. Its size could be either 14K or 30K
835 # bytes, but the next object in the file needs to be aligned at an 8K
836 # boundary. The BL1 size is also known to be 8K bytes, so the total BL1
837 # + BL2 size needs to be aligned to 8K (0x2000) boundary.
838 aligned_size = (len(data) + 0x1fff) & ~0x1fff
839 pad_size = aligned_size - len(data)
840 data += '\0' * pad_size
841
Simon Glass559b6612012-05-23 13:28:45 -0700842 data += self._tools.ReadFile(raw_image)
843 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
844 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700845 self._out.Progress('Writing flasher to %s' % disk)
846 else:
847 image = payload
848 self._out.Progress('Writing image to %s' % disk)
849
850 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
851 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700852 self._out.Progress('Syncing')
853 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700854
855 def SendToSdCard(self, dest, flash_dest, uboot, payload):
856 """Write a flasher to an SD card.
857
858 Args:
859 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700860 ':.' selects the only available device, fails if more than one option
861 ':<device>' select deivce
862
863 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700864 ':.'
865 ':/dev/sdd'
866
867 flash_dest: Destination for flasher, or None to not create a flasher:
868 Valid options are spi, sdmmc.
869 uboot: Full path to u-boot.bin.
870 payload: Full path to payload.
871 """
872 disk = None
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700873
Vadim Bendebury223af572013-04-27 13:25:13 -0700874 # If no removable devices found - prompt user and wait for one to appear.
875 disks = self._ListUsbDisks()
876 try:
877 spinner = '|/-\\'
878 index = 0
879 while not disks:
880 self._out.ClearProgress()
881 self._out.Progress('No removable devices found, plug something in %s '
882 % spinner[index], trailer='')
883 index = (index + 1) % len(spinner)
884 disks = self._ListUsbDisks()
885 time.sleep(.2)
886 except KeyboardInterrupt:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700887 raise CmdError("No removable device found, interrupted")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700888
889 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700890 name = dest[1:]
891
892 # A '.' just means to use the only available disk.
893 if name == '.' and len(disks) == 1:
894 disk = disks[0][0]
895 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700896 # Use the device name.
897 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700898 disk = disk_info[0]
899
900 if disk:
901 self.WriteToSd(flash_dest, disk, uboot, payload)
902 else:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700903 msg = ["Please specify destination as '-w sd:<disk_description>'",]
904 msg.append(' - <disk_description> can be either . for the only disk,')
905 msg.append(' or the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700906 # List available disks as a convenience.
907 for disk in disks:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700908 msg.append(' %s - %s %.1f GB' % (
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700909 disk[0],
910 ' '.join(str(x) for x in disk[1:3]),
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700911 disk[3] / 10.0))
912 raise CmdError('\n'.join(msg))
Simon Glass0c2ba482012-03-22 21:57:51 -0700913
Vadim Bendebury19a77122013-01-24 17:38:00 -0800914 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700915 """Send an image to an attached EM100 device.
916
917 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
918 to do the SPI emulation, then write the image, then boot the board.
919 All going well, this is enough to get U-Boot running.
920
921 Args:
922 image_fname: Filename of image to send
923 """
924 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
925 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800926 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700927
928 # TODO(sjg@chromium.org): This is for link. We could make this
929 # configurable from the fdt.
930 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
931 self._out.Progress('Writing image to em100')
932 self._tools.Run('em100', args, sudo=True)
933
Simon Glass93673cf2013-04-26 17:55:55 -0700934 if self._servo_port is not None:
935 self._out.Progress('Resetting board via servo')
936 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
937 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
938 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700939
Simon Glass0c2ba482012-03-22 21:57:51 -0700940
Simon Glass27a9c142012-03-15 21:08:29 -0700941def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass60a40af2012-06-07 11:54:17 -0700942 bundle, update=True, verify=False, dest=None,
Andrew Chew919858c2013-07-22 15:39:56 -0700943 flasher_dest=None, kernel=None, bootstub=None,
944 servo='any', method='tegra'):
Simon Glasse0b61442012-03-13 15:29:51 -0700945 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700946
947 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700948 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700949
950 Args:
951 output: cros_output object to use.
952 tools: Tools object to use.
953 fdt: Fdt object to use as our device tree.
954 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700955 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700956 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700957 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800958 update: Use faster update algorithm rather then full device erase.
959 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700960 dest: Destination device to write firmware to (usb, sd).
Andrew Chew919858c2013-07-22 15:39:56 -0700961 flasher_dest: a string, destination device for flasher to program payload
962 into. This string has the form <type>:[bus]:[dev], where
963 bus and dev are optional (and default to device and target
964 specific defaults when absent).
Simon Glassde9c8072012-07-02 22:29:02 -0700965 kernel: Kernel file to write after U-Boot
Vadim Bendebury19a77122013-01-24 17:38:00 -0800966 bootstub: string, file name of the boot stub, if present
Simon Glass6a616c12012-09-24 18:13:46 -0700967 servo: Describes the servo unit to use: none=none; any=any; otherwise
968 port number of servo to use.
Simon Glass710dedc2011-08-09 14:08:52 -0700969 """
Vadim Bendebury2b719452013-02-12 17:00:06 -0800970 write = WriteFirmware(tools, fdt, output, bundle, update, verify)
Simon Glassacf4b3e2013-07-19 16:57:43 -0600971 fdt.PutInteger('/config', 'bootsecure', 0)
Simon Glass6a616c12012-09-24 18:13:46 -0700972 write.SelectServo(servo)
Andrew Chew919858c2013-07-22 15:39:56 -0700973 flash_dest = None
974 if flasher_dest:
975 # Parse flasher_dest and store into a dictionary.
976 flash_dest_list = flasher_dest.split(":")
977 flash_dest = {'type': flash_dest_list[0], 'bus': None, 'dev': None}
978 if len(flash_dest_list) > 1:
979 flash_dest['bus'] = flash_dest_list[1]
980 if len(flash_dest_list) > 2:
981 flash_dest['dev'] = flash_dest_list[2]
Simon Glassd65f65f2013-03-28 17:03:41 -0700982 write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
983 elif bootstub:
984 write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
Simon Glasse0b61442012-03-13 15:29:51 -0700985 if dest == 'usb':
Vadim Bendebury2b719452013-02-12 17:00:06 -0800986 try:
987 write.DutControl(['cpu_uart_capture:on',])
988 method = fdt.GetString('/chromeos-config', 'flash-method', method)
989 if method == 'tegra':
990 tools.CheckTool('tegrarcm')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800991 ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
992 image_fname, bootstub)
993 elif method == 'exynos':
994 tools.CheckTool('lsusb', 'usbutils')
995 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
996 ok = write.ExynosFlashImage(flash_dest, flasher,
997 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
998 kernel)
999 else:
1000 raise CmdError("Unknown flash method '%s'" % method)
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -08001001
Vadim Bendebury2b719452013-02-12 17:00:06 -08001002 if not ok:
1003 raise CmdError('Image upload failed - please check board connection')
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -08001004 output.Progress('Image uploaded, waiting for completion')
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -08001005
1006 if flash_dest is not None and servo != 'none':
1007 write.WaitForCompletion()
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -08001008 output.Progress('Done!')
1009
Vadim Bendebury2b719452013-02-12 17:00:06 -08001010 finally:
1011 write.DutControl(['cpu_uart_capture:off',])
Simon Glass9eb8c722012-06-07 13:34:31 -07001012 elif dest == 'em100':
1013 # crosbug.com/31625
1014 tools.CheckTool('em100')
Vadim Bendebury19a77122013-01-24 17:38:00 -08001015 write.Em100FlashImage(image_fname)
Simon Glass0c2ba482012-03-22 21:57:51 -07001016 elif dest.startswith('sd'):
1017 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -07001018 else:
Simon Glasse0b61442012-03-13 15:29:51 -07001019 raise CmdError("Unknown destination device '%s'" % dest)