# Copyright (c) 2015 The Linux Foundation. All rights reserved.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

USE_REFRESH=

# make sure we got the tools we need during the fw upgrade process
platform_add_ramfs_ioe_tools()
{
	install_bin /usr/sbin/fw_printenv /usr/sbin/fw_setenv
	install_bin /bin/busybox /usr/bin/cut /usr/bin/sed
	install_bin /usr/bin/md5sum
	install_bin /usr/sbin/nandwrite
	install_file /etc/fw_env.config
}
append sysupgrade_pre_upgrade platform_add_ramfs_ioe_tools

# determine size of the main firmware partition
platform_get_firmware_size() {
	local dev size erasesize name
	while read dev size erasesize name; do
		name=${name#'"'}; name=${name%'"'}
		case "$name" in
			firmware)
				printf "%d" "0x$size"
				break
			;;
		esac
	done < /proc/mtd
}

get_filesize() {
	wc -c "$1" | while read image_size _n ; do echo $image_size ; break; done
}

# This function read the MTD mapping in /proc/mtd and output
# its offset in flash
# @1) (OUTPUT) variable to store the offset to
# @2) partition name
# @3) NAND flash
get_mtdpart_offset() {
	local varname=$1
	local partname=$2
	local offset=0
	local mtdsize=0

	# Iterate over every line in mtd until the partition name matches
	local line
	while read line && echo ${line} | grep -vq ".*\"${partname}\""; do
		# If the line doesn't start with mtd* (like first line)
		# we just skip it
		echo ${line} | grep -q "^mtd.*" || continue
		echo ${line} | grep -q "rootfs_data" && continue
		echo ${line} | grep -q "firmware" && continue
		echo ${line} | grep -q "fw-2" && continue
		# Here we extract the size info and add it to the previous offset
		mtdsize=$(echo ${line}|cut -f2 -d' ')
		offset=$(printf '%x' $((0x${offset} + 0x${mtdsize})))
	done < /proc/mtd

	eval "${varname}=${offset}"
}

platform_check_image_ioe() {
	local image_size=$( get_filesize "$1" )
	local firmware_size=$( platform_get_firmware_size )

	[ $image_size -ge $firmware_size ] &&
	{
		echo "upgrade image is too big (${image_size}b > ${firmware_size}b)"
		return 1
	}

	return 0
}

ioe_update_uboot_env() {
	local file="$1"
	local nand=$2
        # NOR0 size - 16MB hex (dual NOR)
        local nor0_size=1000000
        # NOR0 size - 512kB hex (NAND flash)
        local nor0_size_nand=80000

	local kernel_addr
	local bootargs bootcmd

	# Perform sanity checks to make sure we've got all the tools we need
	[ -x /usr/sbin/fw_printenv -a -x /usr/sbin/fw_setenv -a \
	  -x /bin/grep -a -x /usr/bin/cut -a -x /usr/bin/md5sum ] || {
		v "Error: missing tools to perform FW upgrade"
		return 1
	}
	[ -f /etc/fw_env.config ] || {
		v "/etc/fw_env.config does not exist"
		return 1
	}

	get_mtdpart_offset kernel_addr "k-2"

	local bootcmd_old=$(fw_printenv -n bootcmd)
	local bootargs_old=$(fw_printenv -n bootargs)

	local ubi=$(fw_printenv -n bootargs |grep ubi)
	[ -n "$ubi" ] && {
		mtdx=$(cat /proc/mtd |grep "r-2" |cut -f1 -d ":")
		r_n=$(echo $mtdx |cut -f2 -d "d")

		while read line; do
			echo $line | grep -q "rootfs" || continue
			mtdx=$(echo $line |cut -f1 -d ":")
			rootfs_n=$(echo $mtdx |cut -f2 -d "d")
			break
		done < /proc/mtd
	}

	v "Updating cus-531 u-boot-env..."
	bootargs=$(fw_printenv -n bootargs | sed \
		-e 's/(kernel)/(tmp-k-1)/' \
		-e 's/(rootfs)/(tmp-r-1)/' \
		-e 's/(vendor)/(tmp-v-1)/' \
		-e 's/(firmware)/(tmp-fw-1)/' \
		\
		-e 's/(k-2)/(kernel)/' \
		-e 's/(r-2)/(rootfs)/' \
		-e 's/(v-2)/(vendor)/' \
		-e 's/(fw-2)/(firmware)/' \
		\
		-e 's/(tmp-k-1)/(k-2)/' \
		-e 's/(tmp-r-1)/(r-2)/' \
		-e 's/(tmp-v-1)/(v-2)/' \
		-e 's/(tmp-fw-1)/(fw-2)/' \
	)

	_kernel_addr=$(printf '%d' 0x${kernel_addr})
	_nor0_size=$(printf '%d' 0x${nor0_size})

	if [ -n "$nand" ]; then
		# Kernel and rootfs for NAND flash are on second SPI partition
		v "NAND flash detected"
		kernel_addr=$(printf '%x' $((0x${kernel_addr} - 0x${nor0_size_nand})))
		bootcmd="nboot 0x81000000 0 0x${kernel_addr}; run fail"
		[ -n "$ubi" ] && bootargs=$(echo ${bootargs} | sed -e 's/ubi.mtd='"${rootfs_n}"'/ubi.mtd='"${r_n}"'/')
	elif [ $_kernel_addr -lt $_nor0_size ]; then
		bootcmd="bootm 0x9f${kernel_addr}; run fail"
	else
		v "32M NOR flash detected"
		kernel_addr=$(printf '%x' $((0x${kernel_addr} - 0x${nor0_size})))
		bootcmd="flselect 1; bootm 0x9f${kernel_addr}; run fail"
	fi

	fw_setenv -s - << EOF
	swap_root set bootargs_tmp \${bootargs}; set bootargs \${bootargs_old}; set bootargs_old \${bootargs_tmp}
	swap_kernel set bootcmd_tmp \${bootcmd}; set bootcmd \${bootcmd_old}; set bootcmd_old \${bootcmd_tmp}
	fail run swap_root; run swap_kernel; save; reset
	bootargs ${bootargs}
	bootcmd ${bootcmd}
	bootargs_old ${bootargs_old}
	bootcmd_old ${bootcmd_old}
EOF
	v "done"
}

platform_do_upgrade_ioe() {
	local file=$1
	local name=$2
	local fw="firmware"
	local valid_env=$(fw_printenv | grep "bootcmd=bootp")

	[ -n "$valid_env" ] && {
		v "ERROR, invalid u-boot-env, sysupgrade failed"
		return
	}

	dual=$(cat /proc/mtd | grep fw-2)
	[ -n "$dual" ] && fw="fw-2"

	sync

	nand=$(echo $name | grep "nand");
	if [ -n "$nand" ]; then
		mtd_fw=$(cat /proc/mtd |grep $fw |cut -f1 -d ":")
		mtd_dev="/dev/$mtd_fw"

		mtd erase $mtd_dev
		dd if=$file bs=2048 | nandwrite -p $mtd_dev -
	else
		get_image "$1" | mtd -j "$CONF_TAR" write - $fw
	fi

	[ -n "$dual" ] && ioe_update_uboot_env "$file" "$nand"
}

