1#! /bin/bash
2#
3# CompuLab CM-FX6 module boot loader update utility
4#
5# Copyright (C) 2013-2015 CompuLab, Ltd.
6# Author: Igor Grinberg <grinberg@compulab.co.il>
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17
18UPDATER_VERSION="2.3"
19UPDATER_VERSION_DATE="Oct 18 2015"
20UPDATER_BANNER="CompuLab CM-FX6 (Utilite) boot loader update utility ${UPDATER_VERSION} (${UPDATER_VERSION_DATE})"
21
22NORMAL="\033[0m"
23WARN="\033[33;1m"
24BAD="\033[31;1m"
25BOLD="\033[1m"
26GOOD="\033[32;1m"
27
28function good_msg() {
29	local msg_string=$1
30	msg_string="${msg_string:-...}"
31	echo -e "${GOOD}>>${NORMAL}${BOLD} ${msg_string} ${NORMAL}"
32}
33
34function bad_msg() {
35	local msg_string=$1
36	msg_string="${msg_string:-...}"
37	echo -e "${BAD}!!${NORMAL}${BOLD} ${msg_string} ${NORMAL}"
38}
39
40function warn_msg() {
41	local msg_string=$1
42	msg_string="${msg_string:-...}"
43	echo -e "${WARN}**${NORMAL}${BOLD} ${msg_string} ${NORMAL}"
44}
45
46function DD() {
47	dd $* &> /dev/null & pid=$!
48
49	while [ -e /proc/$pid ] ; do
50		echo -n "."
51		sleep 1
52	done
53
54	echo ""
55	wait $pid
56	return $?
57}
58
59function confirm() {
60	good_msg "$1"
61
62	select yn in "Yes" "No"; do
63		case $yn in
64			"Yes")
65				return 0;
66				;;
67			"No")
68				return 1;
69				;;
70			*)
71				case ${REPLY,,} in
72					"y"|"yes")
73						return 0;
74						;;
75					"n"|"no"|"abort")
76						return 1;
77						;;
78				esac
79		esac
80	done
81
82	return 1;
83}
84
85EEPROM_DEV="/sys/bus/i2c/devices/2-0050/eeprom"
86MTD_DEV="mtd0"
87MTD_DEV_FILE="/dev/${MTD_DEV}"
88CPU_NAME=""
89DRAM_NAME=""
90BOOTLOADER_FILE="cm-fx6-firmware"
91
92function find_bootloader_file() {
93	read -p "Please input firmware file path (or press ENTER to use \"cm-fx6-firmware\"): " filepath
94	if [[ -n $filepath ]]; then
95		BOOTLOADER_FILE=`eval "echo $filepath"`
96	fi
97
98	good_msg "Looking for boot loader image file: $BOOTLOADER_FILE"
99	if [ ! -s $BOOTLOADER_FILE ]; then
100		bad_msg "Can't find boot loader image file for the board"
101		return 1;
102	fi
103
104	good_msg "...Found"
105	return 0;
106}
107
108function check_spi_flash() {
109	good_msg "Looking for SPI flash: $MTD_DEV"
110
111	grep -qE "$MTD_DEV: [0-f]+ [0-f]+ \"uboot\"" /proc/mtd
112	if [ $? -ne 0 ]; then
113		bad_msg "Can't find $MTD_DEV device, is the SPI flash support enabled in kernel?"
114		return 1;
115	fi
116
117	if [ ! -c $MTD_DEV_FILE ]; then
118		bad_msg "Can't find $MTD_DEV device special file: $MTD_DEV_FILE"
119		return 1;
120	fi
121
122	good_msg "...Found"
123	return 0;
124}
125
126function get_uboot_version() {
127	local file="$1"
128	grep -oaE "U-Boot [0-9]+\.[0-9]+.* \(... +[0-9]+ [0-9]+ - [0-9]+:[0-9]+:[0-9]+.*\)" "$file"
129}
130
131function check_bootloader_versions() {
132	local flash_version=`echo \`get_uboot_version $MTD_DEV_FILE\``
133	local file_version=`echo \`get_uboot_version $BOOTLOADER_FILE\``
134	local file_size=`du -hL $BOOTLOADER_FILE | cut -f1`
135
136	good_msg "Current U-Boot version in SPI flash:\t$flash_version"
137	good_msg "New U-Boot version in file:\t\t$file_version ($file_size)"
138
139	confirm "Proceed with the update?" && return 0;
140
141	return 1;
142}
143
144function check_utility() {
145	local util_name="$1"
146	local utility=`which "$util_name"`
147
148	if [[ -z "$utility" || ! -x $utility ]]; then
149		bad_msg "Can't find $util_name utility! Please install $util_name before proceding!"
150		return 1;
151	fi
152
153	return 0;
154}
155
156function check_utilities() {
157	good_msg "Checking for utilities..."
158
159	check_utility "diff"		|| return 1;
160	check_utility "grep"		|| return 1;
161	check_utility "sed"		|| return 1;
162	check_utility "hexdump"		|| return 1;
163	check_utility "dd"		|| return 1;
164	check_utility "flash_erase"	|| return 1;
165
166	good_msg "...Done"
167	return 0;
168}
169
170function erase_spi_flash() {
171	good_msg "Erasing SPI flash..."
172
173	flash_erase $MTD_DEV_FILE 0 0
174	if [ $? -ne 0 ]; then
175		bad_msg "Failed erasing SPI flash!"
176		bad_msg "If you reboot, your system might not boot anymore!"
177		bad_msg "Please, try re-installing mtd-utils package and retry!"
178		return 1;
179	fi
180
181	good_msg "...Done"
182	return 0;
183}
184
185function write_bootloader() {
186	good_msg "Writing boot loader to the SPI flash..."
187
188	DD if=$BOOTLOADER_FILE of=$MTD_DEV_FILE
189	if [ $? -ne 0 ]; then
190		bad_msg "Failed writing boot loader to the SPI flash!"
191		bad_msg "If you reboot, your system might not boot anymore!"
192		bad_msg "Please, try re-installing mtd-utils package and retry!"
193		return 1;
194	fi
195
196	good_msg "...Done"
197	return 0;
198}
199
200function check_bootloader() {
201	good_msg "Checking boot loader in the SPI flash..."
202
203	local test_file="${BOOTLOADER_FILE}.test"
204	local size=$((`du -L $BOOTLOADER_FILE | cut -f1`*1024))
205
206	DD if=$MTD_DEV_FILE of=$test_file bs=$size count=1
207
208	diff $BOOTLOADER_FILE $test_file > /dev/null
209	if [ $? -ne 0 ]; then
210		bad_msg "Boot loader check failed! Please retry the update procedure!"
211		return 1;
212	fi
213
214	rm -f $test_file
215
216	good_msg "...Done"
217	return 0;
218}
219
220function check_board() {
221	good_msg "Checking that board is CM-FX6 (Utilite)..."
222	local module=`hexdump -C $EEPROM_DEV | grep 00000080 | sed 's/.*|\(CM-FX6\).*/\1/g'`
223	if [ "$module" == "CM-FX6" ]; then
224		good_msg "...Done"
225		return 0;
226	fi;
227
228	bad_msg "This board is not a CM-FX6 (Utilite)!"
229	return 1;
230}
231
232function error_exit() {
233	bad_msg "Boot loader update failed!"
234	exit $1;
235}
236
237function env_set() {
238	local var=$1
239	local value=$2
240
241	fw_setenv $var "$value"
242
243	local match=`fw_printenv $var | grep -e "^$var=$value\$" | wc -l`
244	[ $match -eq 1 ] && return 0;
245
246	return 1;
247}
248
249function reset_environment() {
250	warn_msg "Resetting U-Boot environment will override any changes made to the environment!"
251	confirm "Reset U-Boot environment (recommended)?"
252	if [ $? -eq 1 ]; then
253		good_msg "U-boot environment will not be reset."
254		return 0;
255	fi
256
257	check_utility "fw_setenv" && check_utility "fw_printenv"
258	if [[ $? -ne 0 ]]; then
259		bad_msg "Cannot reset environment."
260		return 1;
261	fi
262
263	local bootcmd_new="env default -a && saveenv; reset"
264	env_set bootcmd "$bootcmd_new" && env_set bootdelay 0
265	if [[ $? -eq 0 ]]; then
266		good_msg "U-boot environment will be reset on restart."
267		return 0;
268	fi
269
270	bad_msg "U-Boot environment reset failed!"
271	return 1;
272}
273
274#main()
275echo -e "\n${UPDATER_BANNER}\n"
276
277check_utilities			|| error_exit 4;
278check_board			|| error_exit 3;
279find_bootloader_file		|| error_exit 1;
280check_spi_flash			|| error_exit 2;
281check_bootloader_versions	|| exit 0;
282
283warn_msg "Do not power off or reset your computer!!!"
284
285erase_spi_flash			|| error_exit 5;
286write_bootloader		|| error_exit 6;
287check_bootloader		|| error_exit 7;
288
289good_msg "Boot loader update succeeded!\n"
290
291reset_environment		|| exit 0;
292
293good_msg "Done!\n"
294