blob: 3946f53052fc2b14f8078e50aceff2b5328c707e [file] [log] [blame]
Simon Glassa3f29ec2011-07-17 09:36:49 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Simon Glass8bd05ec2012-03-22 11:09:04 -07005import binascii
Simon Glass3381a1a2012-03-22 11:13:19 -07006import glob
Simon Glassa3f29ec2011-07-17 09:36:49 -07007import os
8import re
Simon Glasse86f3132013-01-08 16:10:43 -08009import struct
Simon Glassa3f29ec2011-07-17 09:36:49 -070010import time
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -070011
12from exynos import ExynosBl2
Simon Glassa3f29ec2011-07-17 09:36:49 -070013from tools import CmdError
14
15def RoundUp(value, boundary):
16 """Align a value to the next power of 2 boundary.
17
18 Args:
19 value: The value to align.
20 boundary: The boundary value, e.g. 4096. Must be a power of 2.
21
22 Returns:
23 The rounded-up value.
24 """
25 return (value + boundary - 1) & ~(boundary - 1)
26
27
28class WriteFirmware:
29 """Write firmware to a Tegra 2 board using USB A-A cable.
30
31 This class handles re-reflashing a board with new firmware using the Tegra's
32 built-in boot ROM feature. This works by putting the chip into a special mode
33 where it ignores any available firmware and instead reads it from a connected
34 host machine over USB.
35
36 In our case we use that feature to send U-Boot along with a suitable payload
37 and instructions to flash it to SPI flash. The payload is itself normally a
38 full Chrome OS image consisting of U-Boot, some keys and verification
39 information, images and a map of the flash memory.
Simon Glass6a616c12012-09-24 18:13:46 -070040
41 Private attributes:
42 _servo_port: Port number to use to talk to servo with dut-control.
43 Special values are:
44 None: servo is not available.
45 0: any servo will do.
46
Simon Glassa3f29ec2011-07-17 09:36:49 -070047 """
Vadim Bendebury2b719452013-02-12 17:00:06 -080048
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080049 _DOWNLOAD_FAILURE_MESSAGE = '** Load checksum error: check download tool **'
50 _SKIP_VERIFY_MESSAGE = 'Skipping verify'
Vadim Bendebury2b719452013-02-12 17:00:06 -080051 _WRITE_FAILURE_MESSAGE = '** Readback checksum error, programming failed!! **'
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080052 _WRITE_SUCCESS_MESSAGE = 'Image Programmed Successfully'
Vadim Bendebury2b719452013-02-12 17:00:06 -080053
54 def __init__(self, tools, fdt, output, bundle, update, verify):
Simon Glassa3f29ec2011-07-17 09:36:49 -070055 """Set up a new WriteFirmware object.
56
57 Args:
58 tools: A tools library for us to use.
59 fdt: An fdt which gives us some info that we need.
60 output: An output object to use for printing progress and messages.
Simon Glass0191a882012-05-23 13:15:06 -070061 bundle: A BundleFirmware object which created the image.
Vadim Bendebury2b719452013-02-12 17:00:06 -080062 update: Use faster update algorithm rather then full device erase.
63 verify: Verify the write by doing a readback and CRC.
Simon Glassa3f29ec2011-07-17 09:36:49 -070064 """
65 self._tools = tools
66 self._fdt = fdt
67 self._out = output
Simon Glass0191a882012-05-23 13:15:06 -070068 self._bundle = bundle
Vadim Bendebury19a77122013-01-24 17:38:00 -080069 self.text_base = self._fdt.GetInt('/chromeos-config', 'textbase', -1)
Simon Glassa3f29ec2011-07-17 09:36:49 -070070
Simon Glass5b5fd642011-08-17 12:24:01 -070071 # For speed, use the 'update' algorithm and don't verify
Vadim Bendebury2b719452013-02-12 17:00:06 -080072 self.update = update
73 self.verify = verify
Simon Glass5b5fd642011-08-17 12:24:01 -070074
Simon Glass6a616c12012-09-24 18:13:46 -070075 # Use default servo port
76 self._servo_port = 0
77
78 def SelectServo(self, servo):
79 """Select the servo to use for writing firmware.
80
81 Args:
82 servo: String containing description of servo to use:
83 'none' : Don't use servo, generate an error on any attempt.
84 'any' : Use any available servo.
85 '<port>': Use servo with that port number.
86 """
87 if servo == 'none':
88 self._servo_port = None
89 elif servo == 'any':
90 self._servo_port = 0
91 else:
92 self._servo_port = int(servo)
93 self._out.Notice('Servo port %s' % str(self._servo_port))
94
Michael Prattc610dcf2013-07-17 15:38:53 -070095 def _GetFlashScript(self, payload_size, flash_dest, checksum, ro_size=None):
Simon Glassa3f29ec2011-07-17 09:36:49 -070096 """Get the U-Boot boot command needed to flash U-Boot.
97
98 We leave a marker in the string for the load address of the image,
99 since this depends on the size of this script. This can be replaced by
100 the caller provided that the marker length is unchanged.
101
102 Args:
103 payload_size: Size of payload in bytes.
Andrew Chew919858c2013-07-22 15:39:56 -0700104 flash_dest: A dictionary of strings keyed by 'type' (nand, sdmmc,
105 or spi), 'bus', and 'dev'.
Simon Glass8bd05ec2012-03-22 11:09:04 -0700106 checksum: The checksum of the payload (an integer)
Michael Prattc610dcf2013-07-17 15:38:53 -0700107 ro_size: Size of read-only partition. If set, split MMC image between
108 partition 1 (ro) and partition 2 (rw).
Simon Glassa3f29ec2011-07-17 09:36:49 -0700109
110 Returns:
111 A tuple containing:
112 The script, as a string ready to use as a U-Boot boot command, with an
113 embedded marker for the load address.
114 The marker string, which the caller should replace with the correct
115 load address as 8 hex digits, without changing its length.
Michael Prattc610dcf2013-07-17 15:38:53 -0700116 The marker RW string, which the caller should replace with the correct
117 load address for the RW section as 8 hex digits, without changing
118 its length. This is only required if ro_size is set.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700119 """
120 replace_me = 'zsHEXYla'
Michael Prattc610dcf2013-07-17 15:38:53 -0700121 replace_me_rw = 'zsHEXYrw'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800122 page_size = 4096
Andrew Chew919858c2013-07-22 15:39:56 -0700123 boot_type = flash_dest['type']
Simon Glass0dcbecb2012-03-22 21:38:55 -0700124 if boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800125 page_size = 512
Vadim Bendebury2b719452013-02-12 17:00:06 -0800126 update = self.update and boot_type == 'spi'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800127
Simon Glassa3f29ec2011-07-17 09:36:49 -0700128 cmds = [
129 'setenv address 0x%s' % replace_me,
130 'setenv firmware_size %#x' % payload_size,
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800131 'setenv length %#x' % RoundUp(payload_size, page_size),
132 'setenv blocks %#x' % (RoundUp(payload_size, page_size) / page_size),
Simon Glass5b51b472013-03-28 13:06:05 -0700133 'setenv _crc "crc32 -v ${address} ${firmware_size} %08x"' %
Simon Glass8bd05ec2012-03-22 11:09:04 -0700134 checksum,
Simon Glass5b5fd642011-08-17 12:24:01 -0700135 'setenv _clear "echo Clearing RAM; mw.b ${address} 0 ${length}"',
Doug Anderson37ae2292011-09-15 17:41:57 -0700136 ]
Michael Prattc610dcf2013-07-17 15:38:53 -0700137
138 if ro_size:
139 rw_size = payload_size - ro_size
140
141 cmds.extend([
142 'setenv address_ro ${address}',
143 'setenv address_rw 0x%s' % replace_me_rw,
144 'setenv blocks_ro %#x' % (RoundUp(ro_size, page_size) / page_size),
145 'setenv blocks_rw %#x' % (RoundUp(rw_size, page_size) / page_size),
146 ])
147
Simon Glass0dcbecb2012-03-22 21:38:55 -0700148 if boot_type == 'nand':
Doug Anderson37ae2292011-09-15 17:41:57 -0700149 cmds.extend([
150 'setenv _init "echo Init NAND; nand info"',
151 'setenv _erase "echo Erase NAND; nand erase 0 ${length}"',
152 'setenv _write "echo Write NAND; nand write ${address} 0 ${length}"',
153 'setenv _read "echo Read NAND; nand read ${address} 0 ${length}"',
154 ])
Simon Glass0dcbecb2012-03-22 21:38:55 -0700155 elif boot_type == 'sdmmc':
Michael Pratt54aaeed2013-07-12 13:42:47 -0700156 # In U-Boot, strings in double quotes have variables expanded to actual
157 # values. For reasons unclear, this expansion splits the single quoted
158 # argument into separate arguements for each word, which on exynos
159 # boards causes the command to exceed the maximum configured argument
160 # count. Passing the string in single quotes prevents this expansion,
161 # allowing variables to be expanded when run is called.
162 # crbug.com/260294
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800163 cmds.extend([
Michael Pratt54aaeed2013-07-12 13:42:47 -0700164 'setenv _init "echo Init EMMC; mmc rescan"',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800165 'setenv _erase "echo Erase EMMC; "',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800166 ])
Michael Prattc610dcf2013-07-17 15:38:53 -0700167 if ro_size:
168 # Write RO section to partition 1, RW to partition 2
169 cmds.extend([
170 "setenv _write 'echo Write EMMC;" \
171 " mmc open 0 1;" \
172 " mmc write ${address_ro} 0 ${blocks_ro};" \
173 " mmc close 0 1;" \
174 " mmc open 0 2;" \
175 " mmc write ${address_rw} 0 ${blocks_rw};" \
176 " mmc close 0 2'",
177 "setenv _read 'echo Read EMMC;" \
178 " mmc open 0 1;" \
179 " mmc read ${address_ro} 0 ${blocks_ro};" \
180 " mmc close 0 1;" \
181 " mmc open 0 2;" \
182 " mmc read ${address_rw} 0 ${blocks_rw};" \
183 " mmc close 0 2'",
184 ])
185 else:
186 cmds.extend([
187 "setenv _write 'echo Write EMMC;" \
188 " mmc open 0 1;" \
189 " mmc write ${address} 0 ${blocks};" \
190 " mmc close 0 1'",
191 "setenv _read 'echo Read EMMC;" \
192 " mmc open 0 1;" \
193 " mmc read ${address} 0 ${blocks};" \
194 " mmc close 0 1'",
195 ])
Doug Anderson37ae2292011-09-15 17:41:57 -0700196 else:
Andrew Chew919858c2013-07-22 15:39:56 -0700197 if flash_dest['bus'] is None:
198 flash_dest['bus'] = '0'
199 if flash_dest['dev'] is None:
200 flash_dest['dev'] = '0'
Doug Anderson37ae2292011-09-15 17:41:57 -0700201 cmds.extend([
Andrew Chew919858c2013-07-22 15:39:56 -0700202 'setenv _init "echo Init SPI; sf probe %s:%s"' %
203 (flash_dest['bus'], flash_dest['dev']),
Doug Anderson37ae2292011-09-15 17:41:57 -0700204 'setenv _erase "echo Erase SPI; sf erase 0 ${length}"',
205 'setenv _write "echo Write SPI; sf write ${address} 0 ${length}"',
206 'setenv _read "echo Read SPI; sf read ${address} 0 ${length}"',
207 'setenv _update "echo Update SPI; sf update ${address} 0 ${length}"',
208 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700209
Doug Anderson37ae2292011-09-15 17:41:57 -0700210 cmds.extend([
Simon Glassa3f29ec2011-07-17 09:36:49 -0700211 'echo Firmware loaded to ${address}, size ${firmware_size}, '
212 'length ${length}',
Simon Glass8bd05ec2012-03-22 11:09:04 -0700213 'if run _crc; then',
Simon Glassa3f29ec2011-07-17 09:36:49 -0700214 'run _init',
Doug Anderson37ae2292011-09-15 17:41:57 -0700215 ])
Simon Glass5b5fd642011-08-17 12:24:01 -0700216 if update:
217 cmds += ['time run _update']
218 else:
219 cmds += ['run _erase', 'run _write']
Vadim Bendebury2b719452013-02-12 17:00:06 -0800220 if self.verify:
Simon Glass5b5fd642011-08-17 12:24:01 -0700221 cmds += [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700222 'run _clear',
223 'run _read',
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800224 'if run _crc; then',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800225 'echo "%s"' % self._WRITE_SUCCESS_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800226 'else',
227 'echo',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800228 'echo "%s"' % self._WRITE_FAILURE_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800229 'echo',
230 'fi',
Simon Glass5b5fd642011-08-17 12:24:01 -0700231 ]
232 else:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800233 cmds += ['echo %s' % self._SKIP_VERIFY_MESSAGE]
Simon Glass8bd05ec2012-03-22 11:09:04 -0700234 cmds.extend([
235 'else',
236 'echo',
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800237 'echo "%s"' % self._DOWNLOAD_FAILURE_MESSAGE,
Simon Glass8bd05ec2012-03-22 11:09:04 -0700238 'fi',
239 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700240 script = '; '.join(cmds)
Michael Prattc610dcf2013-07-17 15:38:53 -0700241 return script, replace_me, replace_me_rw
Simon Glassa3f29ec2011-07-17 09:36:49 -0700242
Michael Prattc610dcf2013-07-17 15:38:53 -0700243 def _ReplaceAddr(self, data, replace_me, replacement):
244 """Replace address in FDT
245
246 Detect and replace a placeholder address in the FDT.
247
248 Args:
249 data: FDT data to do replacement on
250 replace_me: String currently in FDT to replace
251 replacement: Replacement string
252
253 Returns:
254 Updated data with replacement
255 """
256 if len(replace_me) is not len(replacement):
257 raise ValueError("Internal error: replacement string '%s' length does "
258 "not match new string '%s'" % (replace_me, replacement))
259
260 matches = len(re.findall(replace_me, data))
261 if matches != 1:
262 raise ValueError("Internal error: replacement string '%s' already "
263 "exists in the fdt (%d matches)" % (replace_me, matches))
264
265 return re.sub(replace_me, replacement, data)
266
267 def _PrepareFlasher(self, uboot, payload, flash_dest, ro_size=None):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700268 """Get a flasher ready for sending to the board.
269
270 The flasher is an executable image consisting of:
271
272 - U-Boot (u-boot.bin);
273 - a special FDT to tell it what to do in the form of a run command;
274 - (we could add some empty space here, in case U-Boot is not built to
275 be relocatable);
276 - the payload (which is a full flash image, or signed U-Boot + fdt).
277
278 Args:
279 uboot: Full path to u-boot.bin.
280 payload: Full path to payload.
Andrew Chew919858c2013-07-22 15:39:56 -0700281 flash_dest: A dictionary of strings keyed by 'type' (nand, sdmmc,
282 or spi), 'bus', and 'dev'.
Michael Prattc610dcf2013-07-17 15:38:53 -0700283 boot_type: the src for bootdevice (nand, sdmmc, or spi)
284 ro_size: Size of read-only partition on emmc. If set, indicates that
285 the image should be split, with half written to partition 1, and
286 half written to partition 2.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700287
288 Returns:
Simon Glass290a1802011-07-17 13:54:32 -0700289 Filename of the flasher binary created.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700290 """
Simon Glass951a2db2011-07-17 15:58:58 -0700291 fdt = self._fdt.Copy(os.path.join(self._tools.outdir, 'flasher.dtb'))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700292 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700293
Simon Glass8bd05ec2012-03-22 11:09:04 -0700294 # Make sure that the checksum is not negative
295 checksum = binascii.crc32(payload_data) & 0xffffffff
296
Michael Prattc610dcf2013-07-17 15:38:53 -0700297 script, replace_start, replace_rw = self._GetFlashScript(len(payload_data),
298 flash_dest, checksum, ro_size)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700299 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800300 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700301 fdt_data = self._tools.ReadFile(fdt.fname)
302
303 # Work out where to place the payload in memory. This is a chicken-and-egg
304 # problem (although in case you haven't heard, it was the chicken that
305 # came first), so we resolve it by replacing the string after
306 # fdt.PutString has done its job.
307 #
308 # Correction: Technically, the egg came first. Whatever genetic mutation
309 # created the new species would have been present in the egg, but not the
310 # parent (since if it was in the parent, it would have been present in the
311 # parent when it was an egg).
312 #
313 # Question: ok so who laid the egg then?
314 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700315
316 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
317 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700318 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700319
Simon Glass2c4b3e52011-11-15 14:45:43 -0800320 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700321 new_str = '%08x' % load_address
Michael Prattc610dcf2013-07-17 15:38:53 -0700322 fdt_data = self._ReplaceAddr(fdt_data, replace_start, new_str)
323
324 if ro_size:
325 new_str_rw = '%08x' % (load_address[0] + ro_size)
326 fdt_data = self._ReplaceAddr(fdt_data, replace_rw, new_str_rw)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700327
328 # Now put it together.
329 data += fdt_data
330 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700331 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700332 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700333 self._tools.WriteFile(flasher, data)
334
335 # Tell the user about a few things.
336 self._tools.OutputSize('U-Boot', uboot)
337 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700338 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700339 self._tools.OutputSize('Flasher', flasher)
340 return flasher
341
Vadim Bendebury19a77122013-01-24 17:38:00 -0800342 def NvidiaFlashImage(self, flash_dest, uboot, bct, payload, bootstub):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700343 """Flash the image to SPI flash.
344
345 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000346 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700347
348 Args:
Andrew Chew919858c2013-07-22 15:39:56 -0700349 flash_dest: Destination for flasher, or None to not create a flasher.
350 This value is a dictionary of strings keyed by 'type', 'bus', and
351 'dev'.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700352 uboot: Full path to u-boot.bin.
353 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
354 payload: Full path to payload.
Simon Glass89ecf712012-06-07 12:20:15 -0700355 bootstub: Full path to bootstub, which is the payload without the
356 signing information (i.e. bootstub is u-boot.bin + the FDT)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700357
358 Returns:
359 True if ok, False if failed.
360 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800361 # Use a Regex to pull Boot type from BCT file.
362 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
363 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700364
365 # TODO(sjg): The boot type is currently selected by the bct, rather than
Andrew Chew919858c2013-07-22 15:39:56 -0700366 # flash_dest['type'] selecting which bct to use. This is a bit backwards.
367 # For now we go with the bct's idea.
368 flash_dest['type'] = filter(match.match, bct_dumped)
369 flash_dest['type'] = match.match(
370 flash_dest['type'][0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700371
Simon Glass89ecf712012-06-07 12:20:15 -0700372 if flash_dest:
Andrew Chew919858c2013-07-22 15:39:56 -0700373 image = self._PrepareFlasher(uboot, payload, flash_dest)
Simon Glasse1824db2012-07-11 17:38:40 +0200374 elif bootstub:
Simon Glass89ecf712012-06-07 12:20:15 -0700375 image = bootstub
Simon Glassa3f29ec2011-07-17 09:36:49 -0700376
Simon Glasse1824db2012-07-11 17:38:40 +0200377 else:
378 image = payload
379 # If we don't know the textbase, extract it from the payload.
380 if self.text_base == -1:
381 data = self._tools.ReadFile(payload)
382 # Skip the BCT which is the first 64KB
383 self.text_base = self._bundle.DecodeTextBase(data[0x10000:])
384
Simon Glass89ecf712012-06-07 12:20:15 -0700385 self._out.Notice('TEXT_BASE is %#x' % self.text_base)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700386 self._out.Progress('Uploading flasher image')
387 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700388 '--bct', bct,
Allen Martinb3aa2672012-03-23 15:55:25 +0000389 '--bootloader', image,
390 '--loadaddr', "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700391 ]
392
393 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
394 last_err = None
Vadim Bendebury19a77122013-01-24 17:38:00 -0800395 for _ in range(10):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700396 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700397 # TODO(sjg): Use Chromite library so we can monitor output
Allen Martinb3aa2672012-03-23 15:55:25 +0000398 self._tools.Run('tegrarcm', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700399 self._out.Notice('Flasher downloaded - please see serial output '
400 'for progress.')
401 return True
402
403 except CmdError as err:
404 if not self._out.stdout_is_tty:
405 return False
406
407 # Only show the error output once unless it changes.
408 err = str(err)
Simon Glass22190ff2012-07-11 14:52:26 +0200409 if not 'could not open USB device' in err:
Allen Martinb3aa2672012-03-23 15:55:25 +0000410 raise CmdError('tegrarcm failed: %s' % err)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700411
412 if err != last_err:
413 self._out.Notice(err)
414 last_err = err
415 self._out.Progress('Please connect USB A-A cable and do a '
416 'recovery-reset', True)
417 time.sleep(1)
418
419 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700420
Simon Glass27a9c142012-03-15 21:08:29 -0700421 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
422 """Wait until we see a device on the USB bus.
423
424 Args:
425 name: Board type name
426 vendor_id: USB vendor ID to look for
427 product_id: USB product ID to look for
428 timeout: Timeout to wait in seconds
429
430 Returns
431 True if the device was found, False if we timed out.
432 """
433 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass4968a472012-05-23 13:52:19 -0700434 start_time = time.time()
435 while time.time() - start_time < timeout:
Simon Glass27a9c142012-03-15 21:08:29 -0700436 try:
437 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
438 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700439 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700440 return True
441
Vadim Bendebury19a77122013-01-24 17:38:00 -0800442 except CmdError:
Simon Glass27a9c142012-03-15 21:08:29 -0700443 pass
444
Simon Glass3381a1a2012-03-22 11:13:19 -0700445 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700446
Vadim Bendebury2b719452013-02-12 17:00:06 -0800447 def DutControl(self, args):
Simon Glass6a616c12012-09-24 18:13:46 -0700448 """Run dut-control with supplied arguments.
449
Simon Glass2065a742013-02-09 13:39:26 -0800450 The correct servo will be used based on self._servo_port. If servo use is
451 disabled, this function does nothing.
Simon Glass6a616c12012-09-24 18:13:46 -0700452
453 Args:
454 args: List of arguments to dut-control.
455
Simon Glass2065a742013-02-09 13:39:26 -0800456 Returns:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800457 a string, stdout generated by running the command
Simon Glass6a616c12012-09-24 18:13:46 -0700458 """
459 if self._servo_port is None:
Simon Glass2065a742013-02-09 13:39:26 -0800460 return '' # User has requested not to use servo
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800461 if self._servo_port:
Simon Glass6a616c12012-09-24 18:13:46 -0700462 args.extend(['-p', '%s' % self._servo_port])
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800463 return self._tools.Run('dut-control', args)
Simon Glass6a616c12012-09-24 18:13:46 -0700464
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800465 def WaitForCompletion(self):
Vadim Bendebury2b719452013-02-12 17:00:06 -0800466 """Verify flash programming operation success.
467
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800468 The DUT is presumed to be programming flash with console capture mode on.
469 This function scans console output for the success or failure strings.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800470
471 Raises:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800472 CmdError if the following cases:
473 - none of the strings show up in the allotted time (2 minutes)
474 - console goes silent for more than 10 seconds
475 - one of the error messages seen in the stream
476 - misformatted output is seen in the stream
Vadim Bendebury2b719452013-02-12 17:00:06 -0800477 """
478
479 _SOFT_DEADLINE_LIMIT = 10
480 _HARD_DEADLINE_LIMIT = 120
481 string_leftover = ''
482 soft_deadline = time.time() + _SOFT_DEADLINE_LIMIT
483 hard_deadline = soft_deadline + _HARD_DEADLINE_LIMIT - _SOFT_DEADLINE_LIMIT
484
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800485 if self.verify:
486 done_line = self._WRITE_SUCCESS_MESSAGE
487 else:
488 done_line = self._SKIP_VERIFY_MESSAGE
489
Vadim Bendebury2b719452013-02-12 17:00:06 -0800490 while True:
491 now = time.time()
492 if now > hard_deadline:
493 raise CmdError('Target console flooded, programming failed')
494 if now > soft_deadline:
495 raise CmdError('Target console dead, programming failed')
496 stream = self.DutControl(['cpu_uart_stream',])
497 match = re.search("^cpu_uart_stream:'(.*)'\n", stream)
498 if not match:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800499 raise CmdError('Misformatted console output: \n%s\n' % stream)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800500
501 text = string_leftover + match.group(1)
502 strings = text.split('\\r')
503 string_leftover = strings.pop()
504 if strings:
505 soft_deadline = now + _SOFT_DEADLINE_LIMIT
506 for string in strings:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800507 if done_line in string:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800508 return True
509 if self._WRITE_FAILURE_MESSAGE in string:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800510 raise CmdError('Readback verification failed!')
511 if self._DOWNLOAD_FAILURE_MESSAGE in string:
512 raise CmdError('Download failed!')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800513
Simon Glass4c54a912013-02-18 16:56:29 -0800514 def _ExtractPayloadParts(self, payload, truncate_to_fdt):
Simon Glass3c5b35b2012-05-23 13:22:23 -0700515 """Extract the BL1, BL2 and U-Boot parts from a payload.
516
517 An exynos image consists of 3 parts: BL1, BL2 and U-Boot/FDT.
518
519 This pulls out the various parts, puts them into files and returns
520 these files.
521
522 Args:
523 payload: Full path to payload.
Simon Glass4c54a912013-02-18 16:56:29 -0800524 truncate_to_fdt: Truncate the U-Boot image at the start of its
525 embedded FDT
Simon Glass3c5b35b2012-05-23 13:22:23 -0700526
527 Returns:
528 (bl1, bl2, image) where:
529 bl1 is the filename of the extracted BL1
530 bl2 is the filename of the extracted BL2
531 image is the filename of the extracted U-Boot image
532 """
533 # Pull out the parts from the payload
534 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
535 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
536 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
537 data = self._tools.ReadFile(payload)
538
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700539 try:
540 bl1_size = int(self._fdt.GetProps('/flash/pre-boot')['size'])
541 bl2_size = int(self._fdt.GetProps('/flash/spl')['size'])
542 uboot_offset = bl1_size + bl2_size
Simon Glass496c8302013-07-20 18:04:02 -0600543 except (CmdError, KeyError):
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700544 self._out.Warning('No component nodes in the device tree')
545 # The BL1 is always 8KB - extract that part into a new file
546 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
547 bl1_size = 0x2000
Simon Glass3c5b35b2012-05-23 13:22:23 -0700548
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700549 # Try to detect the BL2 size. We look for 0xea000014 or 0xea000013
550 # which is the 'B reset' instruction at the start of U-Boot. When
551 # U-Boot is LZO compressed, we look for a LZO magic instead.
552 start_data = [struct.pack('<L', 0xea000014),
553 struct.pack('<L', 0xea000013),
554 struct.pack('>B3s', 0x89, 'LZO')]
555 starts = [data.find(magic, bl1_size + 0x3800) for magic in start_data]
556 uboot_offset = None
557 for start in starts:
558 if start != -1 and (not uboot_offset or start < uboot_offset):
559 uboot_offset = start
560 if not uboot_offset:
561 raise ValueError('Could not locate start of U-Boot')
562 bl2_size = uboot_offset - bl1_size - 0x800 # 2KB gap after BL2
Simon Glass3c5b35b2012-05-23 13:22:23 -0700563
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700564 # Sanity check: At present we only allow 14KB and 30KB for SPL
565 allowed = [14, 30]
566 if (bl2_size >> 10) not in allowed:
567 raise ValueError('BL2 size is %dK - only %s supported' %
568 (bl2_size >> 10, ', '.join(
569 [str(size) for size in allowed])))
Simon Glasse86f3132013-01-08 16:10:43 -0800570 self._out.Notice('BL2 size is %dKB' % (bl2_size >> 10))
571
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700572 self._tools.WriteFile(bl1, data[:bl1_size])
573 self._tools.WriteFile(bl2, data[bl1_size:bl1_size + bl2_size])
Simon Glasse86f3132013-01-08 16:10:43 -0800574
Simon Glassbc0d8d42013-02-09 11:59:36 -0800575 # U-Boot itself starts at 24KB, after the gap. As a hack, truncate it
Simon Glass4c54a912013-02-18 16:56:29 -0800576 # to an assumed maximum size. As a secondary hack, locate the FDT
577 # and truncate U-Boot from that point. The correct FDT will be added
578 # when the image is written to the board.
Simon Glassbc0d8d42013-02-09 11:59:36 -0800579 # TODO(sjg@chromium.org): Get a proper flash map here so we know how
580 # large it is
Simon Glass4c54a912013-02-18 16:56:29 -0800581 uboot_data = data[uboot_offset:uboot_offset + 0xa0000]
582 if truncate_to_fdt:
583 fdt_magic = struct.pack('>L', 0xd00dfeed)
584 fdt_offset = uboot_data.rfind(fdt_magic)
585 uboot_data = uboot_data[:fdt_offset]
586
587 self._tools.WriteFile(image, uboot_data)
Simon Glass3c5b35b2012-05-23 13:22:23 -0700588 return bl1, bl2, image
589
Vadim Bendebury19a77122013-01-24 17:38:00 -0800590 def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
Simon Glassde9c8072012-07-02 22:29:02 -0700591 kernel):
Simon Glass27a9c142012-03-15 21:08:29 -0700592 """Flash the image to SPI flash.
593
594 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000595 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glass27a9c142012-03-15 21:08:29 -0700596
597 Args:
Andrew Chew919858c2013-07-22 15:39:56 -0700598 flash_dest: Destination for flasher, or None to not create a flasher.
599 This is a dictionary of strings keyed by 'type', 'bus', and 'dev'.
600 Valid options for 'type' are spi, sdmmc.
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700601 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700602 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700603 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700604 payload: Full path to payload.
Simon Glassde9c8072012-07-02 22:29:02 -0700605 kernel: Kernel to send after the payload, or None.
Simon Glass27a9c142012-03-15 21:08:29 -0700606
607 Returns:
608 True if ok, False if failed.
Simon Glassb4c14af2013-07-04 11:56:33 +0900609
610 Raises:
611 CmdError if a supported Exynos model is not detected in the device tree.
Simon Glass27a9c142012-03-15 21:08:29 -0700612 """
Simon Glassbc0d8d42013-02-09 11:59:36 -0800613 tools = self._tools
614 payload_bl1, payload_bl2, payload_image = (
Simon Glass4c54a912013-02-18 16:56:29 -0800615 self._ExtractPayloadParts(payload, flash_dest is not None))
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700616 if flash_dest:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800617 # If we don't have some bits, get them from the image
618 if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
619 self._out.Warning('Extracting U-Boot from payload')
620 flash_uboot = payload_image
621 if not bl1 or not os.path.exists(tools.Filename(bl1)):
622 self._out.Warning('Extracting BL1 from payload')
623 bl1 = payload_bl1
624 if not bl2 or not os.path.exists(tools.Filename(bl2)):
625 self._out.Warning('Extracting BL2 from payload')
626 bl2 = payload_bl2
Michael Pratt24e7c162013-07-12 09:35:28 -0700627 else:
628 # Update BL2 machine parameters, as
629 # the BL2 passed in may not be updated
630 spl_load_size = os.stat(tools.Filename(bl2)).st_size
631 bl2_handler = ExynosBl2(tools, self._out)
632 bl2 = bl2_handler.Configure(self._fdt, spl_load_size,
633 bl2, 'flasher', True)
Andrew Chew919858c2013-07-22 15:39:56 -0700634 # Set default values for Exynos targets.
635 if flash_dest['bus'] is None:
636 flash_dest['bus'] = 1
637 if flash_dest['dev'] is None:
638 flash_dest['dev'] = 0
Michael Prattc610dcf2013-07-17 15:38:53 -0700639
640 # Try to determine RO section size
641 ro_size = None
642 if flash_dest['type'] == 'sdmmc':
643 try:
644 ro_size = self._fdt.GetFlashPartSize('wp', 'ro')
645 except (CmdError, ValueError):
646 self._out.Warning('Unable to detect RO section size')
647
648 image = self._PrepareFlasher(flash_uboot, payload, flash_dest, ro_size)
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700649 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800650 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700651
652 vendor_id = 0x04e8
653 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700654
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800655 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800656 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
657 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800658 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800659 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700660 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800661 if preserved_dut_hub_sel != required_dut_hub_sel:
662 # Need to set it to get the port properly powered up.
663 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Simon Glass93673cf2013-04-26 17:55:55 -0700664 if self._servo_port is not None:
665 self._out.Progress('Reseting board via servo')
666 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700667
Simon Glassde9c8072012-07-02 22:29:02 -0700668 # If we have a kernel to write, create a new image with that added.
669 if kernel:
670 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
671 data = self._tools.ReadFile(image)
672
673 # Pad the original payload out to the original length
674 data += '\0' * (os.stat(payload).st_size - len(data))
675 data += self._tools.ReadFile(kernel)
676 self._tools.WriteFile(dl_image, data)
677 else:
678 dl_image = image
679
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700680 self._out.Progress('Uploading image')
Simon Glass81ed0792013-07-20 17:36:24 -0600681
682 # This list tells us the memory region to use, the offset into that
683 # region and the filename to upload.
684 upload_list = [
685 ['/iram', 'samsung,bl1-offset', bl1],
686 ['/iram', 'samsung,bl2-offset', bl2],
687 ['/memory', 'u-boot-offset', dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700688 ]
Simon Glassb4c14af2013-07-04 11:56:33 +0900689
Simon Glass3381a1a2012-03-22 11:13:19 -0700690 try:
Simon Glass81ed0792013-07-20 17:36:24 -0600691 for upto in range(len(upload_list)):
692 item = upload_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700693 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700694 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700695 raise CmdError('Could not find Exynos board on USB port')
Simon Glass81ed0792013-07-20 17:36:24 -0600696 raise CmdError("Stage '%s' did not complete" % item[1])
697 self._out.Notice(item[2])
Simon Glass3381a1a2012-03-22 11:13:19 -0700698
Simon Glass4968a472012-05-23 13:52:19 -0700699 if upto == 0:
700 # The IROM needs roughly 200ms here to be ready for USB download
701 time.sleep(.5)
702
Simon Glass81ed0792013-07-20 17:36:24 -0600703 base = self._fdt.GetIntList(item[0], 'reg')[0]
704 offset = self._fdt.GetIntList('/config', item[1])[0]
705 addr = base + offset
706
707 self._out.Progress("Uploading stage '%s' to %x" % (item[1], addr))
708 args = ['-a', '%#x' % addr, '-f', item[2]]
Simon Glass79e3dd02012-08-28 20:08:50 -0700709 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700710
Simon Glass3381a1a2012-03-22 11:13:19 -0700711 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800712 # Make sure that the power button is released and dut_sel_hub state is
713 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700714 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800715 if preserved_dut_hub_sel != required_dut_hub_sel:
716 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800717 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700718
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800719 if flash_dest is None:
720 self._out.Notice('Image downloaded - please see serial output '
721 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700722 return True
723
Simon Glass0c2ba482012-03-22 21:57:51 -0700724 def _GetDiskInfo(self, disk, item):
725 """Returns information about a SCSI disk device.
726
727 Args:
728 disk: a block device name in sys/block, like '/sys/block/sdf'.
729 item: the item of disk information that is required.
730
731 Returns:
732 The information obtained, as a string, or '[Unknown]' if not found
733 """
734 dev_path = os.path.join(disk, 'device')
735
736 # Search upwards and through symlinks looking for the item.
737 while os.path.isdir(dev_path) and dev_path != '/sys':
738 fname = os.path.join(dev_path, item)
739 if os.path.exists(fname):
740 with open(fname, 'r') as fd:
741 return fd.readline().rstrip()
742
743 # Move up a level and follow any symlink.
744 new_path = os.path.join(dev_path, '..')
745 if os.path.islink(new_path):
746 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
747 dev_path = new_path
748 return '[Unknown]'
749
750 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700751 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700752
753 Args:
754 device: Device to check, like '/dev/sdf'.
755
756 Returns:
757 Capacity of device in GB, or 0 if not known.
758 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700759 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700760 args = ['-l', device]
761 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700762 for line in stdout.splitlines():
763 m = re_capacity.match(line)
764 if m:
765 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700766 return 0
767
768 def _ListUsbDisks(self):
769 """Return a list of available removable USB disks.
770
771 Returns:
772 List of USB devices, each element is itself a list containing:
773 device ('/dev/sdx')
774 manufacturer name
775 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700776 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700777 """
778 disk_list = []
779 for disk in glob.glob('/sys/block/sd*'):
780 with open(disk + '/removable', 'r') as fd:
781 if int(fd.readline()) == 1:
782 device = '/dev/%s' % disk.split('/')[-1]
783 manuf = self._GetDiskInfo(disk, 'manufacturer')
784 product = self._GetDiskInfo(disk, 'product')
785 capacity = self._GetDiskCapacity(device)
786 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700787 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700788 return disk_list
789
790 def WriteToSd(self, flash_dest, disk, uboot, payload):
791 if flash_dest:
Andrew Chew919858c2013-07-22 15:39:56 -0700792 # Set default values for sd.
793 if flash_dest['bus'] is None:
794 flash_dest['bus'] = 1
795 if flash_dest['dev'] is None:
796 flash_dest['dev'] = 0
797 raw_image = self._PrepareFlasher(uboot, payload, flash_dest)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700798 bl1, bl2, _ = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700799 spl_load_size = os.stat(raw_image).st_size
Simon Glass559b6612012-05-23 13:28:45 -0700800
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700801 bl2_handler = ExynosBl2(self._tools, self._out)
Vadim Bendebury0c961a72013-06-11 13:35:07 -0700802 bl2_file = bl2_handler.Configure(self._fdt, spl_load_size,
Vadim Bendebury8ae67892013-06-11 17:45:15 -0700803 bl2, 'flasher', True)
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700804 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2_file)
Simon Glass559b6612012-05-23 13:28:45 -0700805
Vadim Bendebury22de0492013-06-17 16:11:20 -0700806 # Pad BL2 out to the required size. Its size could be either 14K or 30K
807 # bytes, but the next object in the file needs to be aligned at an 8K
808 # boundary. The BL1 size is also known to be 8K bytes, so the total BL1
809 # + BL2 size needs to be aligned to 8K (0x2000) boundary.
810 aligned_size = (len(data) + 0x1fff) & ~0x1fff
811 pad_size = aligned_size - len(data)
812 data += '\0' * pad_size
813
Simon Glass559b6612012-05-23 13:28:45 -0700814 data += self._tools.ReadFile(raw_image)
815 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
816 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700817 self._out.Progress('Writing flasher to %s' % disk)
818 else:
819 image = payload
820 self._out.Progress('Writing image to %s' % disk)
821
822 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
823 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700824 self._out.Progress('Syncing')
825 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700826
827 def SendToSdCard(self, dest, flash_dest, uboot, payload):
828 """Write a flasher to an SD card.
829
830 Args:
831 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700832 ':.' selects the only available device, fails if more than one option
833 ':<device>' select deivce
834
835 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700836 ':.'
837 ':/dev/sdd'
838
839 flash_dest: Destination for flasher, or None to not create a flasher:
840 Valid options are spi, sdmmc.
841 uboot: Full path to u-boot.bin.
842 payload: Full path to payload.
843 """
844 disk = None
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700845
Vadim Bendebury223af572013-04-27 13:25:13 -0700846 # If no removable devices found - prompt user and wait for one to appear.
847 disks = self._ListUsbDisks()
848 try:
849 spinner = '|/-\\'
850 index = 0
851 while not disks:
852 self._out.ClearProgress()
853 self._out.Progress('No removable devices found, plug something in %s '
854 % spinner[index], trailer='')
855 index = (index + 1) % len(spinner)
856 disks = self._ListUsbDisks()
857 time.sleep(.2)
858 except KeyboardInterrupt:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700859 raise CmdError("No removable device found, interrupted")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700860
861 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700862 name = dest[1:]
863
864 # A '.' just means to use the only available disk.
865 if name == '.' and len(disks) == 1:
866 disk = disks[0][0]
867 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700868 # Use the device name.
869 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700870 disk = disk_info[0]
871
872 if disk:
873 self.WriteToSd(flash_dest, disk, uboot, payload)
874 else:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700875 msg = ["Please specify destination as '-w sd:<disk_description>'",]
876 msg.append(' - <disk_description> can be either . for the only disk,')
877 msg.append(' or the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700878 # List available disks as a convenience.
879 for disk in disks:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700880 msg.append(' %s - %s %.1f GB' % (
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700881 disk[0],
882 ' '.join(str(x) for x in disk[1:3]),
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700883 disk[3] / 10.0))
884 raise CmdError('\n'.join(msg))
Simon Glass0c2ba482012-03-22 21:57:51 -0700885
Vadim Bendebury19a77122013-01-24 17:38:00 -0800886 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700887 """Send an image to an attached EM100 device.
888
889 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
890 to do the SPI emulation, then write the image, then boot the board.
891 All going well, this is enough to get U-Boot running.
892
893 Args:
894 image_fname: Filename of image to send
895 """
896 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
897 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800898 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700899
900 # TODO(sjg@chromium.org): This is for link. We could make this
901 # configurable from the fdt.
902 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
903 self._out.Progress('Writing image to em100')
904 self._tools.Run('em100', args, sudo=True)
905
Simon Glass93673cf2013-04-26 17:55:55 -0700906 if self._servo_port is not None:
907 self._out.Progress('Resetting board via servo')
908 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
909 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
910 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700911
Simon Glass0c2ba482012-03-22 21:57:51 -0700912
Simon Glass27a9c142012-03-15 21:08:29 -0700913def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass60a40af2012-06-07 11:54:17 -0700914 bundle, update=True, verify=False, dest=None,
Andrew Chew919858c2013-07-22 15:39:56 -0700915 flasher_dest=None, kernel=None, bootstub=None,
916 servo='any', method='tegra'):
Simon Glasse0b61442012-03-13 15:29:51 -0700917 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700918
919 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700920 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700921
922 Args:
923 output: cros_output object to use.
924 tools: Tools object to use.
925 fdt: Fdt object to use as our device tree.
926 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700927 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700928 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700929 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800930 update: Use faster update algorithm rather then full device erase.
931 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700932 dest: Destination device to write firmware to (usb, sd).
Andrew Chew919858c2013-07-22 15:39:56 -0700933 flasher_dest: a string, destination device for flasher to program payload
934 into. This string has the form <type>:[bus]:[dev], where
935 bus and dev are optional (and default to device and target
936 specific defaults when absent).
Simon Glassde9c8072012-07-02 22:29:02 -0700937 kernel: Kernel file to write after U-Boot
Vadim Bendebury19a77122013-01-24 17:38:00 -0800938 bootstub: string, file name of the boot stub, if present
Simon Glass6a616c12012-09-24 18:13:46 -0700939 servo: Describes the servo unit to use: none=none; any=any; otherwise
940 port number of servo to use.
Simon Glass710dedc2011-08-09 14:08:52 -0700941 """
Vadim Bendebury2b719452013-02-12 17:00:06 -0800942 write = WriteFirmware(tools, fdt, output, bundle, update, verify)
Simon Glassacf4b3e2013-07-19 16:57:43 -0600943 fdt.PutInteger('/config', 'bootsecure', 0)
Simon Glass6a616c12012-09-24 18:13:46 -0700944 write.SelectServo(servo)
Andrew Chew919858c2013-07-22 15:39:56 -0700945 flash_dest = None
946 if flasher_dest:
947 # Parse flasher_dest and store into a dictionary.
948 flash_dest_list = flasher_dest.split(":")
949 flash_dest = {'type': flash_dest_list[0], 'bus': None, 'dev': None}
950 if len(flash_dest_list) > 1:
951 flash_dest['bus'] = flash_dest_list[1]
952 if len(flash_dest_list) > 2:
953 flash_dest['dev'] = flash_dest_list[2]
Simon Glassd65f65f2013-03-28 17:03:41 -0700954 write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
955 elif bootstub:
956 write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
Simon Glasse0b61442012-03-13 15:29:51 -0700957 if dest == 'usb':
Vadim Bendebury2b719452013-02-12 17:00:06 -0800958 try:
959 write.DutControl(['cpu_uart_capture:on',])
960 method = fdt.GetString('/chromeos-config', 'flash-method', method)
961 if method == 'tegra':
962 tools.CheckTool('tegrarcm')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800963 ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
964 image_fname, bootstub)
965 elif method == 'exynos':
966 tools.CheckTool('lsusb', 'usbutils')
967 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
968 ok = write.ExynosFlashImage(flash_dest, flasher,
969 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
970 kernel)
971 else:
972 raise CmdError("Unknown flash method '%s'" % method)
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800973
Vadim Bendebury2b719452013-02-12 17:00:06 -0800974 if not ok:
975 raise CmdError('Image upload failed - please check board connection')
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800976 output.Progress('Image uploaded, waiting for completion')
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800977
978 if flash_dest is not None and servo != 'none':
979 write.WaitForCompletion()
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800980 output.Progress('Done!')
981
Vadim Bendebury2b719452013-02-12 17:00:06 -0800982 finally:
983 write.DutControl(['cpu_uart_capture:off',])
Simon Glass9eb8c722012-06-07 13:34:31 -0700984 elif dest == 'em100':
985 # crosbug.com/31625
986 tools.CheckTool('em100')
Vadim Bendebury19a77122013-01-24 17:38:00 -0800987 write.Em100FlashImage(image_fname)
Simon Glass0c2ba482012-03-22 21:57:51 -0700988 elif dest.startswith('sd'):
989 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -0700990 else:
Simon Glasse0b61442012-03-13 15:29:51 -0700991 raise CmdError("Unknown destination device '%s'" % dest)