blob: 8624a6a7afa9c4f5b05b523d02a6e0c080c1285e [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 Glassc159e382013-08-05 19:42:04 -0600295 fdt.PutInteger('/config', 'bootsecure', 0)
296 fdt.PutInteger('/config', 'silent-console', 0)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700297 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700298
Simon Glass8bd05ec2012-03-22 11:09:04 -0700299 # Make sure that the checksum is not negative
300 checksum = binascii.crc32(payload_data) & 0xffffffff
301
Michael Prattc610dcf2013-07-17 15:38:53 -0700302 script, replace_start, replace_rw = self._GetFlashScript(len(payload_data),
303 flash_dest, checksum, ro_size)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700304 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800305 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700306 fdt_data = self._tools.ReadFile(fdt.fname)
307
308 # Work out where to place the payload in memory. This is a chicken-and-egg
309 # problem (although in case you haven't heard, it was the chicken that
310 # came first), so we resolve it by replacing the string after
311 # fdt.PutString has done its job.
312 #
313 # Correction: Technically, the egg came first. Whatever genetic mutation
314 # created the new species would have been present in the egg, but not the
315 # parent (since if it was in the parent, it would have been present in the
316 # parent when it was an egg).
317 #
318 # Question: ok so who laid the egg then?
319 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700320
321 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
322 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700323 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700324
Simon Glass2c4b3e52011-11-15 14:45:43 -0800325 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700326 new_str = '%08x' % load_address
Michael Prattc610dcf2013-07-17 15:38:53 -0700327 fdt_data = self._ReplaceAddr(fdt_data, replace_start, new_str)
328
329 if ro_size:
330 new_str_rw = '%08x' % (load_address[0] + ro_size)
331 fdt_data = self._ReplaceAddr(fdt_data, replace_rw, new_str_rw)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700332
333 # Now put it together.
334 data += fdt_data
335 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700336 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700337 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700338 self._tools.WriteFile(flasher, data)
339
340 # Tell the user about a few things.
341 self._tools.OutputSize('U-Boot', uboot)
342 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700343 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700344 self._tools.OutputSize('Flasher', flasher)
345 return flasher
346
Vadim Bendebury19a77122013-01-24 17:38:00 -0800347 def NvidiaFlashImage(self, flash_dest, uboot, bct, payload, bootstub):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700348 """Flash the image to SPI flash.
349
350 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000351 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700352
353 Args:
Andrew Chew919858c2013-07-22 15:39:56 -0700354 flash_dest: Destination for flasher, or None to not create a flasher.
355 This value is a dictionary of strings keyed by 'type', 'bus', and
356 'dev'.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700357 uboot: Full path to u-boot.bin.
358 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
359 payload: Full path to payload.
Simon Glass89ecf712012-06-07 12:20:15 -0700360 bootstub: Full path to bootstub, which is the payload without the
361 signing information (i.e. bootstub is u-boot.bin + the FDT)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700362
363 Returns:
364 True if ok, False if failed.
365 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800366 # Use a Regex to pull Boot type from BCT file.
367 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
368 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700369
370 # TODO(sjg): The boot type is currently selected by the bct, rather than
Andrew Chew919858c2013-07-22 15:39:56 -0700371 # flash_dest['type'] selecting which bct to use. This is a bit backwards.
372 # For now we go with the bct's idea.
373 flash_dest['type'] = filter(match.match, bct_dumped)
374 flash_dest['type'] = match.match(
375 flash_dest['type'][0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700376
Simon Glass89ecf712012-06-07 12:20:15 -0700377 if flash_dest:
Andrew Chew919858c2013-07-22 15:39:56 -0700378 image = self._PrepareFlasher(uboot, payload, flash_dest)
Simon Glasse1824db2012-07-11 17:38:40 +0200379 elif bootstub:
Simon Glass89ecf712012-06-07 12:20:15 -0700380 image = bootstub
Simon Glassa3f29ec2011-07-17 09:36:49 -0700381
Simon Glasse1824db2012-07-11 17:38:40 +0200382 else:
383 image = payload
384 # If we don't know the textbase, extract it from the payload.
385 if self.text_base == -1:
386 data = self._tools.ReadFile(payload)
387 # Skip the BCT which is the first 64KB
388 self.text_base = self._bundle.DecodeTextBase(data[0x10000:])
389
Simon Glass89ecf712012-06-07 12:20:15 -0700390 self._out.Notice('TEXT_BASE is %#x' % self.text_base)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700391 self._out.Progress('Uploading flasher image')
392 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700393 '--bct', bct,
Allen Martinb3aa2672012-03-23 15:55:25 +0000394 '--bootloader', image,
395 '--loadaddr', "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700396 ]
397
398 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
399 last_err = None
Vadim Bendebury19a77122013-01-24 17:38:00 -0800400 for _ in range(10):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700401 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700402 # TODO(sjg): Use Chromite library so we can monitor output
Allen Martinb3aa2672012-03-23 15:55:25 +0000403 self._tools.Run('tegrarcm', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700404 self._out.Notice('Flasher downloaded - please see serial output '
405 'for progress.')
406 return True
407
408 except CmdError as err:
409 if not self._out.stdout_is_tty:
410 return False
411
412 # Only show the error output once unless it changes.
413 err = str(err)
Simon Glass22190ff2012-07-11 14:52:26 +0200414 if not 'could not open USB device' in err:
Allen Martinb3aa2672012-03-23 15:55:25 +0000415 raise CmdError('tegrarcm failed: %s' % err)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700416
417 if err != last_err:
418 self._out.Notice(err)
419 last_err = err
420 self._out.Progress('Please connect USB A-A cable and do a '
421 'recovery-reset', True)
422 time.sleep(1)
423
424 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700425
Simon Glass27a9c142012-03-15 21:08:29 -0700426 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
427 """Wait until we see a device on the USB bus.
428
429 Args:
430 name: Board type name
431 vendor_id: USB vendor ID to look for
432 product_id: USB product ID to look for
433 timeout: Timeout to wait in seconds
434
435 Returns
436 True if the device was found, False if we timed out.
437 """
438 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass4968a472012-05-23 13:52:19 -0700439 start_time = time.time()
440 while time.time() - start_time < timeout:
Simon Glass27a9c142012-03-15 21:08:29 -0700441 try:
442 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
443 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700444 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700445 return True
446
Vadim Bendebury19a77122013-01-24 17:38:00 -0800447 except CmdError:
Simon Glass27a9c142012-03-15 21:08:29 -0700448 pass
449
Simon Glass3381a1a2012-03-22 11:13:19 -0700450 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700451
Vadim Bendebury2b719452013-02-12 17:00:06 -0800452 def DutControl(self, args):
Simon Glass6a616c12012-09-24 18:13:46 -0700453 """Run dut-control with supplied arguments.
454
Simon Glass2065a742013-02-09 13:39:26 -0800455 The correct servo will be used based on self._servo_port. If servo use is
456 disabled, this function does nothing.
Simon Glass6a616c12012-09-24 18:13:46 -0700457
458 Args:
459 args: List of arguments to dut-control.
460
Simon Glass2065a742013-02-09 13:39:26 -0800461 Returns:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800462 a string, stdout generated by running the command
Simon Glass6a616c12012-09-24 18:13:46 -0700463 """
464 if self._servo_port is None:
Simon Glass2065a742013-02-09 13:39:26 -0800465 return '' # User has requested not to use servo
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800466 if self._servo_port:
Simon Glass6a616c12012-09-24 18:13:46 -0700467 args.extend(['-p', '%s' % self._servo_port])
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800468 return self._tools.Run('dut-control', args)
Simon Glass6a616c12012-09-24 18:13:46 -0700469
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800470 def WaitForCompletion(self):
Vadim Bendebury2b719452013-02-12 17:00:06 -0800471 """Verify flash programming operation success.
472
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800473 The DUT is presumed to be programming flash with console capture mode on.
474 This function scans console output for the success or failure strings.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800475
476 Raises:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800477 CmdError if the following cases:
478 - none of the strings show up in the allotted time (2 minutes)
479 - console goes silent for more than 10 seconds
480 - one of the error messages seen in the stream
481 - misformatted output is seen in the stream
Vadim Bendebury2b719452013-02-12 17:00:06 -0800482 """
483
484 _SOFT_DEADLINE_LIMIT = 10
485 _HARD_DEADLINE_LIMIT = 120
486 string_leftover = ''
487 soft_deadline = time.time() + _SOFT_DEADLINE_LIMIT
488 hard_deadline = soft_deadline + _HARD_DEADLINE_LIMIT - _SOFT_DEADLINE_LIMIT
489
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800490 if self.verify:
491 done_line = self._WRITE_SUCCESS_MESSAGE
492 else:
493 done_line = self._SKIP_VERIFY_MESSAGE
494
Vadim Bendebury2b719452013-02-12 17:00:06 -0800495 while True:
496 now = time.time()
497 if now > hard_deadline:
498 raise CmdError('Target console flooded, programming failed')
499 if now > soft_deadline:
500 raise CmdError('Target console dead, programming failed')
501 stream = self.DutControl(['cpu_uart_stream',])
502 match = re.search("^cpu_uart_stream:'(.*)'\n", stream)
503 if not match:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800504 raise CmdError('Misformatted console output: \n%s\n' % stream)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800505
506 text = string_leftover + match.group(1)
507 strings = text.split('\\r')
508 string_leftover = strings.pop()
509 if strings:
510 soft_deadline = now + _SOFT_DEADLINE_LIMIT
511 for string in strings:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800512 if done_line in string:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800513 return True
514 if self._WRITE_FAILURE_MESSAGE in string:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800515 raise CmdError('Readback verification failed!')
516 if self._DOWNLOAD_FAILURE_MESSAGE in string:
517 raise CmdError('Download failed!')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800518
Simon Glass4c54a912013-02-18 16:56:29 -0800519 def _ExtractPayloadParts(self, payload, truncate_to_fdt):
Simon Glass3c5b35b2012-05-23 13:22:23 -0700520 """Extract the BL1, BL2 and U-Boot parts from a payload.
521
522 An exynos image consists of 3 parts: BL1, BL2 and U-Boot/FDT.
523
524 This pulls out the various parts, puts them into files and returns
525 these files.
526
527 Args:
528 payload: Full path to payload.
Simon Glass4c54a912013-02-18 16:56:29 -0800529 truncate_to_fdt: Truncate the U-Boot image at the start of its
530 embedded FDT
Simon Glass3c5b35b2012-05-23 13:22:23 -0700531
532 Returns:
Simon Glassa7e66e22013-07-23 07:21:16 -0600533 (bl1, bl2, image, uboot_offset) where:
Simon Glass3c5b35b2012-05-23 13:22:23 -0700534 bl1 is the filename of the extracted BL1
535 bl2 is the filename of the extracted BL2
536 image is the filename of the extracted U-Boot image
Simon Glassa7e66e22013-07-23 07:21:16 -0600537 uboot_offset is the offset of U-Boot in the image
Simon Glass3c5b35b2012-05-23 13:22:23 -0700538 """
539 # Pull out the parts from the payload
540 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
541 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
542 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
543 data = self._tools.ReadFile(payload)
544
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700545 try:
546 bl1_size = int(self._fdt.GetProps('/flash/pre-boot')['size'])
547 bl2_size = int(self._fdt.GetProps('/flash/spl')['size'])
548 uboot_offset = bl1_size + bl2_size
Simon Glass496c8302013-07-20 18:04:02 -0600549 except (CmdError, KeyError):
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700550 self._out.Warning('No component nodes in the device tree')
551 # The BL1 is always 8KB - extract that part into a new file
552 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
553 bl1_size = 0x2000
Simon Glass3c5b35b2012-05-23 13:22:23 -0700554
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700555 # Try to detect the BL2 size. We look for 0xea000014 or 0xea000013
556 # which is the 'B reset' instruction at the start of U-Boot. When
557 # U-Boot is LZO compressed, we look for a LZO magic instead.
558 start_data = [struct.pack('<L', 0xea000014),
559 struct.pack('<L', 0xea000013),
560 struct.pack('>B3s', 0x89, 'LZO')]
561 starts = [data.find(magic, bl1_size + 0x3800) for magic in start_data]
562 uboot_offset = None
563 for start in starts:
564 if start != -1 and (not uboot_offset or start < uboot_offset):
565 uboot_offset = start
566 if not uboot_offset:
567 raise ValueError('Could not locate start of U-Boot')
568 bl2_size = uboot_offset - bl1_size - 0x800 # 2KB gap after BL2
Simon Glass3c5b35b2012-05-23 13:22:23 -0700569
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700570 # Sanity check: At present we only allow 14KB and 30KB for SPL
571 allowed = [14, 30]
572 if (bl2_size >> 10) not in allowed:
573 raise ValueError('BL2 size is %dK - only %s supported' %
574 (bl2_size >> 10, ', '.join(
575 [str(size) for size in allowed])))
Simon Glasse86f3132013-01-08 16:10:43 -0800576 self._out.Notice('BL2 size is %dKB' % (bl2_size >> 10))
577
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700578 self._tools.WriteFile(bl1, data[:bl1_size])
579 self._tools.WriteFile(bl2, data[bl1_size:bl1_size + bl2_size])
Simon Glasse86f3132013-01-08 16:10:43 -0800580
Simon Glassbc0d8d42013-02-09 11:59:36 -0800581 # U-Boot itself starts at 24KB, after the gap. As a hack, truncate it
Simon Glass4c54a912013-02-18 16:56:29 -0800582 # to an assumed maximum size. As a secondary hack, locate the FDT
583 # and truncate U-Boot from that point. The correct FDT will be added
584 # when the image is written to the board.
Simon Glassbc0d8d42013-02-09 11:59:36 -0800585 # TODO(sjg@chromium.org): Get a proper flash map here so we know how
586 # large it is
Simon Glass4c54a912013-02-18 16:56:29 -0800587 uboot_data = data[uboot_offset:uboot_offset + 0xa0000]
588 if truncate_to_fdt:
589 fdt_magic = struct.pack('>L', 0xd00dfeed)
590 fdt_offset = uboot_data.rfind(fdt_magic)
591 uboot_data = uboot_data[:fdt_offset]
592
593 self._tools.WriteFile(image, uboot_data)
Simon Glassa7e66e22013-07-23 07:21:16 -0600594 return bl1, bl2, image, uboot_offset
Simon Glass3c5b35b2012-05-23 13:22:23 -0700595
Vadim Bendebury19a77122013-01-24 17:38:00 -0800596 def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
Simon Glassa7e66e22013-07-23 07:21:16 -0600597 kernel):
Simon Glass27a9c142012-03-15 21:08:29 -0700598 """Flash the image to SPI flash.
599
600 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000601 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glass27a9c142012-03-15 21:08:29 -0700602
603 Args:
Andrew Chew919858c2013-07-22 15:39:56 -0700604 flash_dest: Destination for flasher, or None to not create a flasher.
605 This is a dictionary of strings keyed by 'type', 'bus', and 'dev'.
606 Valid options for 'type' are spi, sdmmc.
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700607 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700608 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700609 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700610 payload: Full path to payload.
Simon Glassde9c8072012-07-02 22:29:02 -0700611 kernel: Kernel to send after the payload, or None.
Simon Glass27a9c142012-03-15 21:08:29 -0700612
613 Returns:
614 True if ok, False if failed.
Simon Glassb4c14af2013-07-04 11:56:33 +0900615
616 Raises:
617 CmdError if a supported Exynos model is not detected in the device tree.
Simon Glass27a9c142012-03-15 21:08:29 -0700618 """
Simon Glassa7e66e22013-07-23 07:21:16 -0600619 use_efs_memory = False
Simon Glassbc0d8d42013-02-09 11:59:36 -0800620 tools = self._tools
Simon Glassa7e66e22013-07-23 07:21:16 -0600621 payload_bl1, payload_bl2, payload_image, spl_load_offset = (
Simon Glass4c54a912013-02-18 16:56:29 -0800622 self._ExtractPayloadParts(payload, flash_dest is not None))
Simon Glassa7e66e22013-07-23 07:21:16 -0600623 bl2_handler = ExynosBl2(tools, self._out)
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700624 if flash_dest:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800625 # If we don't have some bits, get them from the image
626 if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
627 self._out.Warning('Extracting U-Boot from payload')
628 flash_uboot = payload_image
629 if not bl1 or not os.path.exists(tools.Filename(bl1)):
630 self._out.Warning('Extracting BL1 from payload')
631 bl1 = payload_bl1
632 if not bl2 or not os.path.exists(tools.Filename(bl2)):
633 self._out.Warning('Extracting BL2 from payload')
634 bl2 = payload_bl2
Michael Pratt24e7c162013-07-12 09:35:28 -0700635 else:
Simon Glassa7e66e22013-07-23 07:21:16 -0600636 # Update BL2 machine parameters, as the BL2 passed in may not be
637 # updated. Also make sure it doesn't use early-firmware-selection
638 # since our flasher needs to run from SDRAM.
Michael Pratt24e7c162013-07-12 09:35:28 -0700639 spl_load_size = os.stat(tools.Filename(bl2)).st_size
Simon Glassa7e66e22013-07-23 07:21:16 -0600640 bl2 = bl2_handler.Configure(self._fdt, spl_load_offset, spl_load_size,
641 bl2, 'flasher', loose_check=True,
642 use_efs_memory=False)
Andrew Chew919858c2013-07-22 15:39:56 -0700643 # Set default values for Exynos targets.
644 if flash_dest['bus'] is None:
645 flash_dest['bus'] = 1
646 if flash_dest['dev'] is None:
647 flash_dest['dev'] = 0
Michael Prattc610dcf2013-07-17 15:38:53 -0700648
649 # Try to determine RO section size
650 ro_size = None
651 if flash_dest['type'] == 'sdmmc':
652 try:
653 ro_size = self._fdt.GetFlashPartSize('wp', 'ro')
654 except (CmdError, ValueError):
655 self._out.Warning('Unable to detect RO section size')
656
657 image = self._PrepareFlasher(flash_uboot, payload, flash_dest, ro_size)
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700658 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800659 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700660
661 vendor_id = 0x04e8
662 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700663
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800664 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800665 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
666 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800667 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800668 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700669 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800670 if preserved_dut_hub_sel != required_dut_hub_sel:
671 # Need to set it to get the port properly powered up.
672 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Simon Glass93673cf2013-04-26 17:55:55 -0700673 if self._servo_port is not None:
674 self._out.Progress('Reseting board via servo')
675 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700676
Simon Glassde9c8072012-07-02 22:29:02 -0700677 # If we have a kernel to write, create a new image with that added.
678 if kernel:
679 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
680 data = self._tools.ReadFile(image)
681
682 # Pad the original payload out to the original length
683 data += '\0' * (os.stat(payload).st_size - len(data))
684 data += self._tools.ReadFile(kernel)
685 self._tools.WriteFile(dl_image, data)
686 else:
Simon Glassa7e66e22013-07-23 07:21:16 -0600687 # See which type of memory we should load U-Boot to
688 used_size = self._fdt.GetFlashPartUsed('ro', 'boot')
689 if self.use_efs and used_size:
690 node = self._fdt.GetFlashNode('ro', 'boot')
691 props = self._fdt.GetProp(node, 'type,efs', 'none')
692 if props != 'none' and props[0] == 'blob':
693 parts = props[1].split(',')
694 use_efs_memory = 'ro-boot' in parts
695
696 # Truncate the image to just the size actually used
697 if use_efs_memory:
698 dl_image = os.path.join(self._tools.outdir, 'image-used.bin')
699 data = self._tools.ReadFile(image)
700 self._tools.WriteFile(dl_image, data[:used_size])
701 self._out.Warning('Truncating to used size %#x' % used_size)
702 else:
703 dl_image = image
Simon Glassde9c8072012-07-02 22:29:02 -0700704
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700705 self._out.Progress('Uploading image')
Simon Glass81ed0792013-07-20 17:36:24 -0600706
707 # This list tells us the memory region to use, the offset into that
708 # region and the filename to upload.
709 upload_list = [
710 ['/iram', 'samsung,bl1-offset', bl1],
711 ['/iram', 'samsung,bl2-offset', bl2],
712 ['/memory', 'u-boot-offset', dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700713 ]
Simon Glassb4c14af2013-07-04 11:56:33 +0900714
Simon Glass3381a1a2012-03-22 11:13:19 -0700715 try:
Simon Glass81ed0792013-07-20 17:36:24 -0600716 for upto in range(len(upload_list)):
717 item = upload_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700718 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700719 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700720 raise CmdError('Could not find Exynos board on USB port')
Simon Glass81ed0792013-07-20 17:36:24 -0600721 raise CmdError("Stage '%s' did not complete" % item[1])
722 self._out.Notice(item[2])
Simon Glass3381a1a2012-03-22 11:13:19 -0700723
Simon Glass4968a472012-05-23 13:52:19 -0700724 if upto == 0:
725 # The IROM needs roughly 200ms here to be ready for USB download
726 time.sleep(.5)
727
Simon Glassa7e66e22013-07-23 07:21:16 -0600728 # Load U-Boot either to IRAM or SDRAM depending on EFS
729 if upto == 2:
730 addr = bl2_handler.GetUBootAddress(self._fdt, use_efs_memory)
731 else:
732 base = self._fdt.GetIntList(item[0], 'reg')[0]
733 offset = self._fdt.GetIntList('/config', item[1])[0]
734 addr = base + offset
Simon Glass81ed0792013-07-20 17:36:24 -0600735
736 self._out.Progress("Uploading stage '%s' to %x" % (item[1], addr))
737 args = ['-a', '%#x' % addr, '-f', item[2]]
Simon Glass79e3dd02012-08-28 20:08:50 -0700738 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700739
Simon Glass3381a1a2012-03-22 11:13:19 -0700740 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800741 # Make sure that the power button is released and dut_sel_hub state is
742 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700743 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800744 if preserved_dut_hub_sel != required_dut_hub_sel:
745 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800746 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700747
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800748 if flash_dest is None:
749 self._out.Notice('Image downloaded - please see serial output '
750 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700751 return True
752
Simon Glass0c2ba482012-03-22 21:57:51 -0700753 def _GetDiskInfo(self, disk, item):
754 """Returns information about a SCSI disk device.
755
756 Args:
757 disk: a block device name in sys/block, like '/sys/block/sdf'.
758 item: the item of disk information that is required.
759
760 Returns:
761 The information obtained, as a string, or '[Unknown]' if not found
762 """
763 dev_path = os.path.join(disk, 'device')
764
765 # Search upwards and through symlinks looking for the item.
766 while os.path.isdir(dev_path) and dev_path != '/sys':
767 fname = os.path.join(dev_path, item)
768 if os.path.exists(fname):
769 with open(fname, 'r') as fd:
770 return fd.readline().rstrip()
771
772 # Move up a level and follow any symlink.
773 new_path = os.path.join(dev_path, '..')
774 if os.path.islink(new_path):
775 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
776 dev_path = new_path
777 return '[Unknown]'
778
779 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700780 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700781
782 Args:
783 device: Device to check, like '/dev/sdf'.
784
785 Returns:
786 Capacity of device in GB, or 0 if not known.
787 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700788 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700789 args = ['-l', device]
790 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700791 for line in stdout.splitlines():
792 m = re_capacity.match(line)
793 if m:
794 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700795 return 0
796
797 def _ListUsbDisks(self):
798 """Return a list of available removable USB disks.
799
800 Returns:
801 List of USB devices, each element is itself a list containing:
802 device ('/dev/sdx')
803 manufacturer name
804 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700805 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700806 """
807 disk_list = []
808 for disk in glob.glob('/sys/block/sd*'):
809 with open(disk + '/removable', 'r') as fd:
810 if int(fd.readline()) == 1:
811 device = '/dev/%s' % disk.split('/')[-1]
812 manuf = self._GetDiskInfo(disk, 'manufacturer')
813 product = self._GetDiskInfo(disk, 'product')
814 capacity = self._GetDiskCapacity(device)
815 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700816 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700817 return disk_list
818
819 def WriteToSd(self, flash_dest, disk, uboot, payload):
820 if flash_dest:
Andrew Chew919858c2013-07-22 15:39:56 -0700821 # Set default values for sd.
822 if flash_dest['bus'] is None:
823 flash_dest['bus'] = 1
824 if flash_dest['dev'] is None:
825 flash_dest['dev'] = 0
826 raw_image = self._PrepareFlasher(uboot, payload, flash_dest)
Simon Glassa7e66e22013-07-23 07:21:16 -0600827 bl1, bl2, _, spl_load_offset = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700828 spl_load_size = os.stat(raw_image).st_size
Simon Glass559b6612012-05-23 13:28:45 -0700829
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700830 bl2_handler = ExynosBl2(self._tools, self._out)
Simon Glassa7e66e22013-07-23 07:21:16 -0600831 bl2_file = bl2_handler.Configure(self._fdt, spl_load_offset,
832 spl_load_size, bl2, 'flasher', True,
833 use_efs_memory=False)
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700834 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2_file)
Simon Glass559b6612012-05-23 13:28:45 -0700835
Vadim Bendebury22de0492013-06-17 16:11:20 -0700836 # Pad BL2 out to the required size. Its size could be either 14K or 30K
837 # bytes, but the next object in the file needs to be aligned at an 8K
838 # boundary. The BL1 size is also known to be 8K bytes, so the total BL1
839 # + BL2 size needs to be aligned to 8K (0x2000) boundary.
840 aligned_size = (len(data) + 0x1fff) & ~0x1fff
841 pad_size = aligned_size - len(data)
842 data += '\0' * pad_size
843
Simon Glass559b6612012-05-23 13:28:45 -0700844 data += self._tools.ReadFile(raw_image)
845 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
846 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700847 self._out.Progress('Writing flasher to %s' % disk)
848 else:
849 image = payload
850 self._out.Progress('Writing image to %s' % disk)
851
852 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
853 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700854 self._out.Progress('Syncing')
855 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700856
857 def SendToSdCard(self, dest, flash_dest, uboot, payload):
858 """Write a flasher to an SD card.
859
860 Args:
861 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700862 ':.' selects the only available device, fails if more than one option
863 ':<device>' select deivce
864
865 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700866 ':.'
867 ':/dev/sdd'
868
869 flash_dest: Destination for flasher, or None to not create a flasher:
870 Valid options are spi, sdmmc.
871 uboot: Full path to u-boot.bin.
872 payload: Full path to payload.
873 """
874 disk = None
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700875
Vadim Bendebury223af572013-04-27 13:25:13 -0700876 # If no removable devices found - prompt user and wait for one to appear.
877 disks = self._ListUsbDisks()
878 try:
879 spinner = '|/-\\'
880 index = 0
881 while not disks:
882 self._out.ClearProgress()
883 self._out.Progress('No removable devices found, plug something in %s '
884 % spinner[index], trailer='')
885 index = (index + 1) % len(spinner)
886 disks = self._ListUsbDisks()
887 time.sleep(.2)
888 except KeyboardInterrupt:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700889 raise CmdError("No removable device found, interrupted")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700890
891 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700892 name = dest[1:]
893
894 # A '.' just means to use the only available disk.
895 if name == '.' and len(disks) == 1:
896 disk = disks[0][0]
897 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700898 # Use the device name.
899 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700900 disk = disk_info[0]
901
902 if disk:
903 self.WriteToSd(flash_dest, disk, uboot, payload)
904 else:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700905 msg = ["Please specify destination as '-w sd:<disk_description>'",]
906 msg.append(' - <disk_description> can be either . for the only disk,')
907 msg.append(' or the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700908 # List available disks as a convenience.
909 for disk in disks:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700910 msg.append(' %s - %s %.1f GB' % (
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700911 disk[0],
912 ' '.join(str(x) for x in disk[1:3]),
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700913 disk[3] / 10.0))
914 raise CmdError('\n'.join(msg))
Simon Glass0c2ba482012-03-22 21:57:51 -0700915
Vadim Bendebury19a77122013-01-24 17:38:00 -0800916 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700917 """Send an image to an attached EM100 device.
918
919 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
920 to do the SPI emulation, then write the image, then boot the board.
921 All going well, this is enough to get U-Boot running.
922
923 Args:
924 image_fname: Filename of image to send
925 """
926 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
927 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800928 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700929
930 # TODO(sjg@chromium.org): This is for link. We could make this
931 # configurable from the fdt.
932 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
933 self._out.Progress('Writing image to em100')
934 self._tools.Run('em100', args, sudo=True)
935
Simon Glass93673cf2013-04-26 17:55:55 -0700936 if self._servo_port is not None:
937 self._out.Progress('Resetting board via servo')
938 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
939 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
940 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700941
Simon Glass0c2ba482012-03-22 21:57:51 -0700942
Simon Glass27a9c142012-03-15 21:08:29 -0700943def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass60a40af2012-06-07 11:54:17 -0700944 bundle, update=True, verify=False, dest=None,
Andrew Chew919858c2013-07-22 15:39:56 -0700945 flasher_dest=None, kernel=None, bootstub=None,
946 servo='any', method='tegra'):
Simon Glasse0b61442012-03-13 15:29:51 -0700947 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700948
949 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700950 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700951
952 Args:
953 output: cros_output object to use.
954 tools: Tools object to use.
955 fdt: Fdt object to use as our device tree.
956 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700957 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700958 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700959 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800960 update: Use faster update algorithm rather then full device erase.
961 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700962 dest: Destination device to write firmware to (usb, sd).
Andrew Chew919858c2013-07-22 15:39:56 -0700963 flasher_dest: a string, destination device for flasher to program payload
964 into. This string has the form <type>:[bus]:[dev], where
965 bus and dev are optional (and default to device and target
966 specific defaults when absent).
Simon Glassde9c8072012-07-02 22:29:02 -0700967 kernel: Kernel file to write after U-Boot
Vadim Bendebury19a77122013-01-24 17:38:00 -0800968 bootstub: string, file name of the boot stub, if present
Simon Glass6a616c12012-09-24 18:13:46 -0700969 servo: Describes the servo unit to use: none=none; any=any; otherwise
970 port number of servo to use.
Simon Glass710dedc2011-08-09 14:08:52 -0700971 """
Vadim Bendebury2b719452013-02-12 17:00:06 -0800972 write = WriteFirmware(tools, fdt, output, bundle, update, verify)
Simon Glass6a616c12012-09-24 18:13:46 -0700973 write.SelectServo(servo)
Andrew Chew919858c2013-07-22 15:39:56 -0700974 flash_dest = None
975 if flasher_dest:
976 # Parse flasher_dest and store into a dictionary.
977 flash_dest_list = flasher_dest.split(":")
978 flash_dest = {'type': flash_dest_list[0], 'bus': None, 'dev': None}
979 if len(flash_dest_list) > 1:
980 flash_dest['bus'] = flash_dest_list[1]
981 if len(flash_dest_list) > 2:
982 flash_dest['dev'] = flash_dest_list[2]
Simon Glassd65f65f2013-03-28 17:03:41 -0700983 write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
984 elif bootstub:
985 write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
Simon Glasse0b61442012-03-13 15:29:51 -0700986 if dest == 'usb':
Vadim Bendebury2b719452013-02-12 17:00:06 -0800987 try:
988 write.DutControl(['cpu_uart_capture:on',])
989 method = fdt.GetString('/chromeos-config', 'flash-method', method)
990 if method == 'tegra':
991 tools.CheckTool('tegrarcm')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800992 ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
993 image_fname, bootstub)
994 elif method == 'exynos':
995 tools.CheckTool('lsusb', 'usbutils')
996 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
997 ok = write.ExynosFlashImage(flash_dest, flasher,
998 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
999 kernel)
1000 else:
1001 raise CmdError("Unknown flash method '%s'" % method)
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -08001002
Vadim Bendebury2b719452013-02-12 17:00:06 -08001003 if not ok:
1004 raise CmdError('Image upload failed - please check board connection')
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -08001005 output.Progress('Image uploaded, waiting for completion')
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -08001006
1007 if flash_dest is not None and servo != 'none':
1008 write.WaitForCompletion()
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -08001009 output.Progress('Done!')
1010
Vadim Bendebury2b719452013-02-12 17:00:06 -08001011 finally:
1012 write.DutControl(['cpu_uart_capture:off',])
Simon Glass9eb8c722012-06-07 13:34:31 -07001013 elif dest == 'em100':
1014 # crosbug.com/31625
1015 tools.CheckTool('em100')
Vadim Bendebury19a77122013-01-24 17:38:00 -08001016 write.Em100FlashImage(image_fname)
Simon Glass0c2ba482012-03-22 21:57:51 -07001017 elif dest.startswith('sd'):
1018 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -07001019 else:
Simon Glasse0b61442012-03-13 15:29:51 -07001020 raise CmdError("Unknown destination device '%s'" % dest)