Skip to content

Commit

Permalink
ELBERT: Update fpga_util.sh (#68)
Browse files Browse the repository at this point in the history
Summary:
ELBERT: Update fpga_util.sh to support all programmable fpga images
- Latest fpga_util script
- Also peutil script is added here to avoid merge conflict in makefile

This includes:
- SCM FPGA (JTAG)
- SMB FPGA (JTAG)
- SMB CPLD (JTAG)
- FAN FPGA (JTAG)
- PIM SPI Image (SPI)
- TH4 QSPI Image (SPI)

For SPI programming, we only program the first 1MB of 32 MB device.  The images are only around ~350KB at the moment so this speeds things ups. The utility will zero fill the image to 1MB and program this.
Note: This requires flashrom1.2 to detech and talk to the devices used on Elbert PIM/TH4_QSPI

Testing:
Successfully upgraded all programmables using:
fpga_util.sh scm program <file>
fpga_util.sh smb program <file>
fpga_util.sh smb_cpld program <file>
fpga_util.sh fan program <file>
fpga_util.sh pim program <file>
fpga_util.sh th4_qspi program <file>

Pull Request resolved: facebookexternal/openbmc.arista#68

Reviewed By: mikechoifb

fbshipit-source-id: fef7a0c304
  • Loading branch information
joancaneus authored and facebook-github-bot committed Aug 26, 2020
1 parent 8a6f952 commit 2b6871f
Show file tree
Hide file tree
Showing 4 changed files with 328 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
00000000:000fffff primary
00100000:01ffffff unused
310 changes: 280 additions & 30 deletions meta-facebook/meta-elbert/recipes-utils/openbmc-utils/files/fpga_util.sh
Original file line number Diff line number Diff line change
@@ -1,82 +1,332 @@
#!/bin/sh

# shellcheck disable=SC1091
# shellcheck disable=SC2012
. /usr/local/bin/openbmc-utils.sh

CPLD_JTAG_SEL_L="CPLD_JTAG_SEL_L"
JTAG_EN="${SUPCPLD_SYSFS_DIR}/jtag_en"
JTAG_SEL="${SUPCPLD_SYSFS_DIR}/jtag_sel"
JTAG_TRST_L="JTAG_TRST_L"
JTAG_EN="${SCMCPLD_SYSFS_DIR}/jtag_en"
PROGRAM_SEL="${SCMCPLD_SYSFS_DIR}/program_sel"
SPI_CTRL="${SMBCPLD_SYSFS_DIR}/spi_ctrl"
SPI_PIM_SEL="${SMBCPLD_SYSFS_DIR}/spi_pim_en"
SPI_TH4_QSPI_SEL="${SMBCPLD_SYSFS_DIR}/spi_th4_qspi_en"
JTAG_CTRL="${SMBCPLD_SYSFS_DIR}/jtag_ctrl"
SMB_SPIDEV="spidev1.1"

# ELBERTTODO SCD, LC, FAN support
SCM_PROGRAM=false
SMB_PROGRAM=false

trap disconnect_program_paths INT TERM QUIT EXIT

usage() {
program=$(basename "$0")
echo "Usage:"
echo "$program <fpga> <action> <fpga file>"
echo " <fpga> : sup, scd, lc1, lc2, ..., lc8, fan"
echo " <fpga> : scm, smb, smb_cpld, fan, pim, th4_qspi"
echo " <action> : program, verify"
exit 1
}

disconnect_jtag() {
disconnect_program_paths() {
# Return values to defaults
gpio_set_value $CPLD_JTAG_SEL_L 1
gpio_set_value $JTAG_TRST_L 0
if [ "$SCM_PROGRAM" = false ]; then
echo 0 > "$JTAG_EN"
echo 1 > "$PROGRAM_SEL"
fi
if [ "$SMB_PROGRAM" = false ]; then
echo 0 > "$SPI_CTRL"
echo 0 > "$JTAG_CTRL"
fi
}

connect_scm_jtag() {
gpio_set_value $CPLD_JTAG_SEL_L 0
gpio_set_value $JTAG_TRST_L 1
echo 0 > "$JTAG_EN"
echo 0 > "$JTAG_SEL"
}

disconnect_program_paths() {
disconnect_jtag
connect_smb_jtag() {
gpio_set_value $CPLD_JTAG_SEL_L 1
gpio_set_value $JTAG_TRST_L 1
echo 1 > "$JTAG_EN"
echo 1 > "$PROGRAM_SEL"
}

connect_sup_jtag() {
gpio_set_value $CPLD_JTAG_SEL_L 0
echo 0 > "$JTAG_EN"
connect_smb_cpld_jtag() {
gpio_set_value $CPLD_JTAG_SEL_L 1
gpio_set_value $JTAG_TRST_L 1
echo 1 > "$JTAG_EN"
echo 0 > "$PROGRAM_SEL"
echo 0 > "$SPI_CTRL"
echo 0x2 > "$JTAG_CTRL"
}

connect_fan_jtag() {
gpio_set_value $CPLD_JTAG_SEL_L 1
gpio_set_value $JTAG_TRST_L 1
echo 1 > "$JTAG_EN"
echo 0 > "$PROGRAM_SEL"
echo 0 > "$SPI_CTRL"
echo 0x1 > "$JTAG_CTRL"
}

connect_pim_flash() {
gpio_set_value $CPLD_JTAG_SEL_L 1
echo 0 > "$PROGRAM_SEL"
echo 1 > "$SPI_PIM_SEL"
devmem_set_bit 0x1e6e2438 8 # SPI1CS1 Function enable

for i in $(seq 1 5); do
msg="$(flashrom -p linux_spi:dev=/dev/"$SMB_SPIDEV" -c "MT25QL256" 2>/dev/null)"
if echo "$msg" | grep -q "Found Micron flash chip"; then
echo "Detected PIM Flash device."
return 0;
else
echo "Attempt ${i} to detect pim flash failed..."
fi
done

echo "Failed to detect PIM Flash device with flashrom"
echo "$msg"
exit 1
}

connect_th4_qspi_flash() {
gpio_set_value $CPLD_JTAG_SEL_L 1
echo 0 > "$PROGRAM_SEL"
echo 1 > "$SPI_TH4_QSPI_SEL"
devmem_set_bit 0x1e6e2438 8 # SPI1CS1 Function enable

for i in $(seq 1 5); do
msg="$(flashrom -p linux_spi:dev=/dev/"$SMB_SPIDEV" -c "MT25QU256" 2>/dev/null)"
if echo "$msg" | grep -q "Found Micron flash chip"; then
echo "Detected TH4 QSPI Flash device."
return 0;
else
echo "Attempt ${i} to detect TH4 QSPI flash failed..."
fi
done

echo "Failed to detect TH4 QSPI Flash device with flashrom"
echo "$msg"
exit 1
}

do_sup() {
do_scm() {
# verify the fpga file
if ! grep "DESIGN.*ird" "$2" > /dev/null; then
echo "$2 is not a vaild SUP FPGA file"
echo "$2 is not a valid SCM FPGA file"
exit 1
fi
connect_sup_jtag
jam -l/usr/lib/libcpldupdate_dll_ast_jtag.so -v -a"${1^^}" "$2"
SCM_PROGRAM=true
connect_scm_jtag
jam -l/usr/lib/libcpldupdate_dll_ioctl.so -v -a"${1^^}" "$2" \
--ioctl IOCBITBANG
}

do_scd() {
echo "SCD CPLD upgrade is not supported"
exit 1
do_smb() {
# verify the fpga file
if ! grep "DESIGN.*onda" "$2" > /dev/null; then
echo "$2 is not a valid SMB FPGA file"
exit 1
fi
SMB_PROGRAM=true
connect_smb_jtag
jam -l/usr/lib/libcpldupdate_dll_ioctl.so -v -a"${1^^}" "$2" \
--ioctl IOCBITBANG
}

do_smb_cpld() {
# verify the fpga file
if ! grep "DESIGN.*ide" "$2" > /dev/null; then
echo "$2 is not a valid SMB CPLD file"
exit 1
fi
connect_smb_cpld_jtag
jam -l/usr/lib/libcpldupdate_dll_ioctl.so -v -a"${1^^}" "$2" \
--ioctl IOCBITBANG
}

do_fan() {
echo "Fan CPLD upgrade is not supported"
exit 1
# verify the fpga file
if ! grep "DESIGN.*ckels" "$2" > /dev/null; then
echo "$2 is not a valid FAN FPGA file"
exit 1
fi
connect_fan_jtag
jam -l/usr/lib/libcpldupdate_dll_ioctl.so -v -a"${1^^}" "$2" \
--ioctl IOCBITBANG
}

program_spi_image() {
ORIGINAL_IMAGE="$1" # Image path
CHIP_TYPE="$2" # Chip type

case "${3^^}" in # optional - defaults to primary partition
*)
PARTITION="primary"
SKIP_MB=0
;;
esac

# We need to 32 MB binary, we will zero fill if needed.
# We will only program/verify the specified image partition
EEPROM_SIZE="33554432" # 32 MB
IMAGE_SIZE="$(ls -l "$ORIGINAL_IMAGE" | awk '{print $5}')"
TEMP_IMAGE="/tmp/pim_image_32mb.bin"

if [ "$IMAGE_SIZE" -gt "$EEPROM_SIZE" ] ; then
echo "$IMAGE size $IMAGE_SIZE is greater than eeprom capacity $EEPROM_SIZE"
exit 1
fi

fill=$((EEPROM_SIZE - IMAGE_SIZE))
if [ "$fill" = 0 ] ; then
echo "$ORIGINAL_IMAGE already 32MB, no need to resize..."
flashrom -p linux_spi:dev=/dev/"$SMB_SPIDEV" -c "$CHIP_TYPE" -N \
--layout /etc/elbert_pim.layout --image "$PARTITION" -w "$ORIGINAL_IMAGE"
else
bs=1048576 # 1MB blocks

echo "$ORIGINAL_IMAGE size $IMAGE_SIZE < $EEPROM_SIZE (32MB)"
echo "Resizing $ORIGINAL_IMAGE by $fill bytes to $TEMP_IMAGE"

# Let's make a copy of the program image and zero-fill it to 32MB
# Prepend/append zero bytes accordingly
{
dd if=/dev/zero bs=$bs count="$SKIP_MB"
dd if="$ORIGINAL_IMAGE"
} 2>/dev/null > "$TEMP_IMAGE"
# cp "$ORIGINAL_IMAGE" "$TEMP_IMAGE"

div=$((fill/bs)) # Number of 1MB blocks to write
div=$((div - SKIP_MB))
rem=$((fill%bs)) # Remaining
{
dd if=/dev/zero bs=$bs count=$div
dd if=/dev/zero bs=$rem count=1
} 2>/dev/null >> "$TEMP_IMAGE"

TEMP_IMAGE_SIZE="$(ls -l "$TEMP_IMAGE" | awk '{print $5}')"
if [ "$TEMP_IMAGE_SIZE" -ne "$EEPROM_SIZE" ] ; then
echo "Failed to resize $ORIGINAL_IMAGE to 32MB... exiting."
exit 1
fi
# Program the 32MB pim image
flashrom -p linux_spi:dev=/dev/"$SMB_SPIDEV" -c "$CHIP_TYPE" -N \
--layout /etc/elbert_pim.layout --image "$PARTITION" -w "$TEMP_IMAGE"
rm "$TEMP_IMAGE"
fi
}

read_spi_partition_image() {
DEST="$1" # READ Image output path
TEMP="/tmp/tmp_pim_image" # Temporary path for 32MB read
CHIP_TYPE="$2" # Chip type

case "${3^^}" in # Selects primary by default
*)
PARTITION="primary"
SKIP_MB=0
;;
esac
flashrom -p linux_spi:dev=/dev/"$SMB_SPIDEV" -c "$CHIP_TYPE" \
--layout /etc/elbert_pim.layout --image "$PARTITION" -r "$TEMP"
dd if="$TEMP" of="$DEST" bs=1M count=1 skip="$SKIP_MB"
rm "$TEMP"
}

strip_pim_header() {
ORIG_IMAGE="$1"
NEW_IMAGE="$2"
POS=$(head -c4096 "$ORIG_IMAGE" | hexdump -v -e '/1 "%u\n"' | \
(grep -n -e '^0$' || echo 0) | head -n1 | cut -d':' -f1)
if [ "$POS" -gt 0 ]
then
if ! dd if="$ORIG_IMAGE" bs=1 count="$POS" 2> /dev/null | grep _REVISION \
> /dev/null
then
# No REVISION header found
POS=0
fi
fi

if [ "$POS" -gt 0 ]
then
dd if="$ORIG_IMAGE" of="$NEW_IMAGE" bs="$POS" skip=1 2> /dev/null
else
cp "$ORIG_IMAGE" "$NEW_IMAGE"
fi
}

do_linecard() {
echo "LC CPLD Upgrade is not supported"
exit 1
do_pim() {
case "${1^^}" in
PROGRAM)
# Image with header stripped
BIN_IMAGE="/tmp/stripped_pim_image"
connect_pim_flash
strip_pim_header "$2" "$BIN_IMAGE"
program_spi_image "$BIN_IMAGE" "MT25QL256" "$3"
rm "$BIN_IMAGE"
;;
READ)
connect_pim_flash
if [ -z "$3" ]; then
flashrom -p linux_spi:dev=/dev/"$SMB_SPIDEV" -c MT25QL256 -r "$2"
else
read_spi_partition_image "$2" "MT25QL256" "$3"
fi
;;
*)
echo "PIM only supports program/read action. Exiting..."
exit 1
;;
esac
}

if [ $# -ne 3 ]; then
do_th4_qspi() {
case "${1^^}" in
PROGRAM)
connect_th4_qspi_flash
program_spi_image "$2" "MT25QU256"
;;
READ)
connect_th4_qspi_flash
flashrom -p linux_spi:dev=/dev/"$SMB_SPIDEV" -c "MT25QU256" -r "$2"
;;
*)
echo "TH4 QSPI only supports program/read action. Exiting..."
exit 1
;;
esac
}

if [ $# -lt 3 ]; then
usage
fi

case "$1" in
scd) shift 1
do_scd "$@"
smb) shift 1
do_smb "$@"
;;
sup) shift 1
do_sup "$@"
smb_cpld) shift 1
do_smb_cpld "$@"
;;
lc*) shift 1
do_linecard "$@"
scm) shift 1
do_scm "$@"
;;
pim) shift 1
do_pim "$@"
;;
fan) shift 1
do_fan "$@"
;;
th4_qspi) shift 1
do_th4_qspi "$@"
;;
*)
usage
;;
Expand Down

0 comments on commit 2b6871f

Please sign in to comment.