summaryrefslogtreecommitdiff
path: root/util/flash_ec
blob: 47d6318afff9cec0494cac2d4ac14bd4d3acc250 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
#!/bin/bash

# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

SCRIPT="$(readlink -f "$0")"
SCRIPT_DIR="$(dirname "$SCRIPT")"

EC_DIR="$(readlink -f "${SCRIPT_DIR}/..")"
if [[ "$(basename "${EC_DIR}")" != "ec" ]]; then
	EC_DIR=
fi

# Loads script libraries.
. "/usr/share/misc/shflags" || exit 1

# Redirects tput to stderr, and drop any error messages.
tput2() {
	tput "$@" 1>&2 2>/dev/null || true
}

error() {
	tput2 bold && tput2 setaf 1
	echo "ERROR: $*" >&2
	tput2 sgr0
}


info() {
	tput2 bold && tput2 setaf 2
	echo "INFO: $*" >&2
	tput2 sgr0
}

warn() {
	tput2 bold && tput2 setaf 3
	echo "WARNING: $*" >&2
	tput2 sgr0
}

die() {
	[ -z "$*" ] || error "$@"
	exit 1
}

# Note: Link is a special case and is not included here.
BOARDS_LM4=(
	auron
	falco
	peppy
	rambi
	samus
	squawks
)

BOARDS_LM4_USB=(
	samus
)

BOARDS_STM32=(
	big
	blaze
	discovery
	firefly
	fruitpie
	jerry
	kitty
	mighty
	minimuffin
	nyan
	pinky
	pit
	plankton
	ryu
	ryu_sh
	ryu_p1
	samus_pd
	snow
	speedy
	spring
	zinger
)

BOARDS_PRIVATE_SPI_PP3300=(
	glower
)

BOARDS_STM32_PROG_EN=(
	plankton
)

BOARDS_STM32_DFU=(
	dingdong
	hoho
	twinkie
)

BOARDS_NPCX=(
	npcx_evb
)

# Flags
DEFINE_string board "${DEFAULT_BOARD}" \
	"The board to run debugger on."
DEFINE_string image "" \
	"Full pathname of the EC firmware image to flash."
DEFINE_string offset "0" \
	"Offset where to program the image from."
DEFINE_integer port 9999 \
	"Port to communicate to servo on."
DEFINE_boolean ro "${FLAGS_FALSE}" \
	"Write only the read-only partition"
DEFINE_boolean unprotect "${FLAGS_FALSE}" \
	"Clear the protect flag."
DEFINE_boolean usb "${FLAGS_FALSE}" \
	"Use case-closed debugging over USB type-C."

# Parse command line
FLAGS_HELP="usage: $0 [flags]"
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
if [[ $# -gt 0 ]]; then
	die "invalid arguments: \"$*\""
fi

set -e

SERVO_TYPE=servo

in_array() {
	local n=$#
	local value=${!n}

	for (( i=1; i<$#; i++ )) do
		if [ "${!i}" == "${value}" ]; then
			return 0
		fi
	done
	return 1
}

# reset the EC
toad_ec_hard_reset() {
	if dut_control cold_reset 2>/dev/null ; then
		dut_control cold_reset:on
		dut_control cold_reset:off
	else
		info "you probably need to hard-reset your EC manually"
	fi
}

servo_ec_hard_reset() {
	dut_control cold_reset:on
	dut_control cold_reset:off
}

servo_usbpd_hard_reset() {
	dut_control usbpd_reset:on sleep:0.5 usbpd_reset:off
}

servo_sh_hard_reset() {
	dut_control sh_reset:on
	dut_control sh_reset:off
}

ec_reset() {
	eval ${SERVO_TYPE}_${MCU}_hard_reset
}

# force the EC to boot in serial monitor mode
toad_ec_boot0() {
	dut_control boot_mode:yes
}

servo_ec_boot0() {
	dut_control spi1_vref:pp3300
}

servo_usbpd_boot0() {
	dut_control usbpd_boot_mode:on
}

servo_sh_boot0() {
	dut_control sh_boot_mode:on
}

ec_enable_boot0() {
	# Enable programming GPIOs
	if $(in_array "${BOARDS_STM32_PROG_EN[@]}" "${BOARD}"); then
		dut_control prog_en:yes
	fi
	eval ${SERVO_TYPE}_${MCU}_boot0
}

# Put back the servo and the system in a clean state at exit
cleanup() {
	if [ -n "${save}" ]; then
		info "Restoring servo settings..."
		servo_restore "$save"
	fi

	ec_reset
}
trap cleanup EXIT

BOARD=${FLAGS_board}
BOARD_ROOT=/build/${BOARD}

# Possible default EC images
if $(in_array "${BOARDS_PRIVATE_SPI_PP3300[@]}" "${BOARD}"); then
	EC_FILE=ec.spi.bin
elif [ "${FLAGS_ro}" = ${FLAGS_TRUE} ] ; then
	EC_FILE=ec.RO.flat
else
	EC_FILE=ec.bin
fi

EMERGE_BUILD=${BOARD_ROOT}/firmware/${EC_FILE}

LOCAL_BUILD=
if [[ -n "${EC_DIR}" ]]; then
	LOCAL_BUILD="${EC_DIR}/build/${BOARD}/${EC_FILE}"
fi

# Find the EC image to use
function ec_image() {
	# No image specified on the command line, try default ones
	if [[ -n "${FLAGS_image}" ]] ; then
		if [ -f "${FLAGS_image}" ] || \
		   [ "${FLAGS_image}" == "-" ]; then
			echo "${FLAGS_image}"
			return
		fi
		die "Invalid image path : ${FLAGS_image}"
	else
		if [ -f "${LOCAL_BUILD}" ]; then
			echo "${LOCAL_BUILD}"
			return
		fi
		if [ -f "${EMERGE_BUILD}" ]; then
			echo "${EMERGE_BUILD}"
			return
		fi
	fi
	die "no EC image found : build one or specify one."
}

DUT_CONTROL_CMD="dut-control --port=${FLAGS_port}"

# Find the EC UART on the servo v2
function ec_uart() {
	SERVOD_FAIL="Cannot communicate with servo. is servod running ?"
	($DUT_CONTROL_CMD ${MCU}_uart_pty || \
	    die "${SERVOD_FAIL}") | cut -d: -f2
}

# Servo variables management
case "${BOARD}" in
	ryu_sh ) MCU="sh" ;;
	samus_pd ) MCU="usbpd" ;;
	dingdong|hoho|twinkie ) DUT_CONTROL_CMD="true" ; MCU="ec" ;;
	*) MCU="ec" ;;
esac

servo_VARS="${MCU}_uart_en ${MCU}_uart_parity \
${MCU}_uart_baudrate jtag_buf_on_flex_en jtag_buf_en spi1_vref"
if [[ "${MCU}" == "usbpd" ]] ; then
	servo_VARS+=" usbpd_boot_mode"
	if $(in_array "${BOARDS_STM32_PROG_EN[@]}" "${BOARD}"); then
		servo_VARS+=" prog_en"
	fi
fi
if $(in_array "${BOARDS_PRIVATE_SPI_PP3300[@]}" "${BOARD}"); then
	servo_VARS+=" spi1_buf_en spi1_buf_on_flex_en spi_hold"
fi
toad_VARS="${MCU}_uart_parity \
${MCU}_uart_baudrate boot_mode"

function dut_control() {
	$DUT_CONTROL_CMD "$@" >/dev/null
}

function servo_save() {
	SERVO_VARS_NAME=${SERVO_TYPE}_VARS
	$DUT_CONTROL_CMD ${!SERVO_VARS_NAME}
}

function servo_restore() {
	echo "$1" | while read line
	do
		dut_control "$line"
	done
}

function free_pty() {
	local pids

	pids=$(lsof -F p 2>/dev/null -- $1 | cut -d'p' -f2)
	if [ "${pids}" == "" ]; then
		return
	fi

	# Try to kill nicely at first...
	kill ${pids}
	info "You'll need to re-launch console on $1"

	# Wait up to 3 seconds for them to die...
	for i in $(seq 30); do
		pids=$(lsof -F p 2>/dev/null -- $1 | cut -d'p' -f2)
		if [ "${pids}" == "" ]; then
			return
		fi
		sleep .1
	done

	# Forcibly kill
	kill -9 ${pids}
}

# Board specific flashing scripts

# helper function for setting up servo v2/3 with openocd paths
function setup_openocd() {
	if [[ -z "${EC_DIR}" ]]; then
	    # check if we're on beaglebone
	    if [[ -e "/usr/bin/lib" ]]; then
		OCD_CFG="servo_v3.cfg"
		OCD_PATH="/usr/bin/lib"
	    else
		die "Cannot locate openocd configs"
	    fi
	else
	    if [ "${FLAGS_usb}" = ${FLAGS_TRUE} ] ; then
		OCD_CFG="${BOARD}.cfg"
	    else
		OCD_CFG="servo_v2.cfg"
	    fi
	fi
}

function flash_stm32() {
	TOOL_PATH="${EC_DIR}/build/${BOARD}/util:$PATH"
	STM32MON=$(PATH="${TOOL_PATH}" which stm32mon)
	if [ ! -x "$STM32MON" ]; then
		die "no stm32mon util found."
	fi

	if [ "${FLAGS_unprotect}" = ${FLAGS_TRUE} ] ; then
		# Unprotect exists, but isn't needed because erasing pstate is
		# implicit in writing the entire image
		die "--unprotect not supported for this board."
	fi

	info "Using serial flasher : ${STM32MON}"
	free_pty ${EC_UART}

	if [ "${SERVO_TYPE}" = "servo" ] ; then
		dut_control ${MCU}_uart_en:on
	fi
	dut_control ${MCU}_uart_parity:even
	dut_control ${MCU}_uart_baudrate:115200
	# Force the EC to boot in serial monitor mode
	ec_enable_boot0
	# Reset the EC
	ec_reset
	# Unprotect flash, erase, and write
	${STM32MON} -d ${EC_UART} -U -u -e -w "${IMG}"
}

function flash_stm32_dfu() {
	DFU_DEVICE=0483:df11
	ADDR=0x08000000
	DFU_UTIL='dfu-util'
	which $DFU_UTIL &> /dev/null || die \
		"no dfu-util util found.  Did you 'sudo emerge dfu-util'"

	info "Using dfu flasher : ${DFU_UTIL}"

	dev_cnt=$(lsusb -d $DFU_DEVICE | wc -l)
	if [ $dev_cnt -eq 0 ] ; then
		die "unable to locate dfu device at $DFU_DEVICE"
	elif [ $dev_cnt -ne 1 ] ; then
		die "too many dfu devices (${dev_cnt}). Disconnect all but one."
	fi

	SIZE=$(wc -c ${IMG} | cut -d' ' -f1)
	# Remove read protection
	sudo $DFU_UTIL -a 0 -s ${ADDR}:${SIZE}:force:unprotect -D "${IMG}"
	# Wait for mass-erase and reboot after unprotection
	sleep 1
	# Actual image flashing
	sudo $DFU_UTIL -a 0 -s ${ADDR}:${SIZE} -D "${IMG}"
}

function flash_link() {
	OCD_PATH="${EC_DIR}/chip/lm4/openocd"
	setup_openocd

	OCD_CMDS="init; flash_lm4 ${IMG} ${FLAGS_offset};"
	if [ "${FLAGS_unprotect}" = ${FLAGS_TRUE} ] ; then
		info "Clearing write protect flag."
		OCD_CMDS="${OCD_CMDS} unprotect_link;"
	fi
	OCD_CMDS="${OCD_CMDS} shutdown;"

	dut_control jtag_buf_on_flex_en:on
	dut_control jtag_buf_en:on

	sudo openocd -s "${OCD_PATH}" -f "${OCD_CFG}" -c "${OCD_CMDS}" || \
	die "Failed to program ${IMG}"
}

function flash_lm4() {
	OCD_PATH="${EC_DIR}/chip/lm4/openocd"
	setup_openocd

	OCD_CMDS="init; flash_lm4 ${IMG} ${FLAGS_offset};"
	if [ "${FLAGS_unprotect}" = ${FLAGS_TRUE} ] ; then
		# Unprotect exists, but isn't needed because erasing pstate is
		# implicit in writing the entire image
		die "--unprotect not supported for this board."
	fi
	OCD_CMDS="${OCD_CMDS} shutdown;"

	dut_control jtag_buf_on_flex_en:on
	dut_control jtag_buf_en:on

	sudo openocd -s "${OCD_PATH}" -f "${OCD_CFG}" -c "${OCD_CMDS}" || \
	die "Failed to program ${IMG}"
}

function flash_npcx() {
	OCD_PATH="${EC_DIR}/chip/npcx/openocd"
	setup_openocd

	if [ "${FLAGS_unprotect}" = ${FLAGS_TRUE} ] ; then
		# Unprotect exists, but isn't needed because erasing pstate is
		# implicit in writing the entire image
		die "--unprotect not supported for this board."
	fi

	dut_control jtag_buf_on_flex_en:on
	dut_control jtag_buf_en:on

	if [ "${FLAGS_ro}" = ${FLAGS_TRUE} ] ; then
		# Program RO region only
		OCD_CMDS="init; flash_npcx_ro ${FLAGS_offset}; shutdown;"
		sudo openocd -s "${OCD_PATH}" -f "${OCD_CFG}" -c "${OCD_CMDS}" || \
		die "Failed to program ${IMG}"
	else
		# Program all EC regions
		OCD_CMDS="init; flash_npcx_evb ${FLAGS_offset}; shutdown;"
		sudo openocd -s "${OCD_PATH}" -f "${OCD_CFG}" -c "${OCD_CMDS}" || \
		die "Failed to program ${IMG}"
	fi
}

function flash_private_spi_pp3300() {
	dut_control cold_reset:on spi1_vref:pp3300
	dut_control spi1_buf_en:on spi1_buf_on_flex_en:on spi_hold:off
	sudo flashrom -p ft2232_spi:type=servo-v2,port=B -w "${IMG}"
}

if dut_control boot_mode 2>/dev/null ; then
	if [[ "${MCU}" != "ec" ]] ; then
		die "Toad cable can't support non-ec UARTs"
	fi
	SERVO_TYPE=toad
	info "Using a dedicated debug cable"
fi

IMG="$(ec_image)"
info "Using ${MCU} image : ${IMG}"

EC_UART="$(ec_uart)"
info "${MCU} UART pty : ${EC_UART}"

save="$(servo_save)"

if ([ "${FLAGS_usb}" = ${FLAGS_TRUE} ] && \
      ! $(in_array "${BOARDS_LM4_USB[@]}" "${BOARD}")); then
	die "--usb not supported for this board."
fi

if $(in_array "${BOARDS_LM4[@]}" "${BOARD}"); then
	flash_lm4
elif $(in_array "${BOARDS_STM32[@]}" "${BOARD}"); then
	flash_stm32
elif $(in_array "${BOARDS_STM32_DFU[@]}" "${BOARD}"); then
	flash_stm32_dfu
elif [ "${BOARD}" == "link" ]; then
	flash_link
elif $(in_array "${BOARDS_NPCX[@]}" "${BOARD}"); then
	flash_npcx
elif $(in_array "${BOARDS_PRIVATE_SPI_PP3300[@]}" "${BOARD}"); then
	flash_private_spi_pp3300
else
	die "board ${BOARD} not supported"
fi

info "Flashing done."