#!/bin/sh

#
# Utility for manipulating flags used for updating FW in u-boot.
# These flags needs to be preserved during the warm reboot and
# some of them need to be set/cleared in application (update, fail, ...).
# All flags are stored in the AO_RTI_STICKY_REG0 register.
#
# Following flags are available:
#      update - update FW from download partition
#        fail - set by u-boot, application is supposed to clear it
#  boot_count - the number of warm reboots, starting from 1
#
#
#  Copyright (C) 2012, StreamUnlimited Engineering GmbH, http://www.streamunlimited.com/
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation; either version 2 of
#  the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE.  See the
#  GNU General Public License for more details.
#

help () {
		echo -e \
"Utility for manipulating flags used for updating FW in u-boot.\n"\
"\n"\
"Usage:\n"\
"    sfuflags -f flag [-v value]\n"\
"\n"\
"      -f flag  flag to set/get value\n"\
"                   update: update flag, value range: 0 | 1 \n"\
"                     fail: update flag, value range: 0 | 1\n"\
"               boot_count: boot counter, value range: 0 - 255\n"\
"\n"\
"      -v value value to set.\n"\
"\n"\
"      -h       print this info\n"
}


DEVMEM=devmem2

which ${DEVMEM} 2> /dev/null > /dev/null

if [ $? -ne 0 ]; then
	echo "${DEVMEM} not found" >&2
	exit 2
fi

DFLAG=
DVALUE=

while getopts "f:v:h" opt; do
	case $opt in
	f)
		DFLAG=$OPTARG;;
	v)
		DVALUE=$OPTARG;;
	h)
		help
		exit 0
		;;
	\?)
		#echo "Invalid option -$OPTARG" >&2
		help
		exit 1
		;;
	esac
done

#echo DFLAG: \"$DFLAG\"
#echo DVALUE: \"$DVALUE\"

if [ -z "${DFLAG}" ]; then
	echo "Invalid arguments, the flag name was not specified." >&2
	help
	exit 1
fi

ADDRESS=
MIN=0
MAX=1
SHIFT=0
MASK=0

case ${DFLAG} in
	update) ADDRESS=0xff800130; MASK=0x1; SHIFT=0;;
	fail) ADDRESS=0xff800130; MASK=0x2; SHIFT=1;;
	boot_count) ADDRESS=0xff800130; MASK=0xff00; SHIFT=8; MIN=0; MAX=255;;
	*)
		echo "Invalid flag : ${DFLAG}" >&2
		exit 1
		;;
esac

if [ "${DVALUE}" ]; then
	# Write value
	dec_value=`printf "%d" ${DVALUE}`

	if [ -z "${dec_value}" ]; then
		echo "Invalid flag value: ${DVALUE}." >&2
		exit 1
	fi

	if [ ${dec_value:-0} -gt ${MAX:-0} -o ${dec_value:-255} -lt ${MIN} ]; then
		echo "Flag value out of range: ${DVALUE} (min: ${MIN}, max: ${MAX})." >&2
		exit 1
	fi

	value=`${DEVMEM} ${ADDRESS} w | sed -n 's/^.*: 0x//;3p'`
	value=$(( 0x${value} & ~${MASK} ))			# Clear
	value=$(( ${value} | (${dec_value} << ${SHIFT}) ))	# Set
	${DEVMEM} ${ADDRESS} w ${value} > /dev/null

	if [ $? -ne 0 ]; then
		echo "Failed to write flag value." >&2
		exit 3
	fi
else
	# Read value

	value=`${DEVMEM} ${ADDRESS} w | sed -n 's/^.*: 0x//;3p'`

	if [ $? -ne 0 -o -z "${value}" ]; then
		echo "Failed to read flag value." >&2
		exit 3
	fi

	value=$(( 0x${value} & ${MASK} ))
	value=$(( ${value} >> ${SHIFT} ))

	printf "%d\n" ${value}
fi

