#!/bin/bash
#
# Copyright 2018-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
. /usr/local/bin/openbmc-utils.sh
. /usr/local/bin/flashrom-utils.sh

pca9534_ee_sel=0x22
pca9534_spi_sel=0x26
output_reg=0x1
mode_reg=0x3
debug=0
m95m02_page_size=256
m95m02_page_count=1024
SPI_PIN_ARGS=(--cs BMC_SPI1_CS0 --clk BMC_SPI1_CLK \
              --mosi BMC_SPI1_MOSI --miso BMC_SPI1_MISO)
PIDFILE=/var/run/spi_util.pid

trap cleanup_spi INT TERM QUIT EXIT

check_duplicate_process() {
    exec 2> "$PIDFILE"
    flock -n 2 || (echo "Another process is running..." && exit 1)
    ret=$?
    if [ $ret -eq 1 ]; then
      exit 2
    fi
    pid=$$
    echo $pid 1>&200
}

remove_pid_file() {
    if [ -f $PIDFILE ]; then
        rm $PIDFILE
    fi
}

# $1: sysfs path, $2: value
set_sysfs_value() {
    local path=$1
    local val=$2
    local ret_val=-1
    local retry=3

    while [ "$((ret_val))" != "$((val))" ] && [ "$retry" -gt 0 ];
    do
        echo "$val" > "$path"
        usleep 100
        ret_val=$(head -n1 "$path" 2> /dev/null)
        retry=$((retry - 1))
    done
    if [ "$((ret_val))" != "$((val))" ]; then
        echo "Set sysfs value fail"
        echo "debug cmd: echo $val > $path, ret_val=$ret_val"
        exit 1
    fi
}

# $1: bus number, $2: device address, $3: register, $4: value
set_i2c_dev_value() {
    local bus=$1
    local addr=$2
    local reg=$3
    local val=$4
    local ret_val=-1
    local retry=3

    while [ "$((ret_val))" != "$((val))" ] && [ "$retry" -gt 0 ];
    do
        exec_and_print "i2cset -y $bus $addr $reg $val"
        usleep 100
        ret_val=$(i2cget -y "$bus" "$addr" "$reg" 2> /dev/null)
        retry=$((retry - 1))
    done
    if [ "$((ret_val))" != "$((val))" ]; then
        echo "Set I2C device value fail"
        echo "debug cmd: i2cset -y $bus $addr $reg $val, ret_val: $ret_val"
        exit 1
    fi
}

# $1: input file size $2: flash size $3: output file path
pad_ff() {
    out_file=$3
    pad_size=$(($2 - $1))
    dd if=/dev/zero bs="$pad_size" count=1 | tr "\000" "\377" >> "$out_file"
}

resize_file() {
    in_file=$1
    out_file=$2
    spi_no=$3
    storage_type=$4
    in_file_sz=$(stat -c%s "$in_file")
    storage_sz=0
    if [ "$storage_type" ] && [ "$storage_type" = "m95m02" ]; then
        storage_sz=$((m95m02_page_count * m95m02_page_size))
    else
        spi_dev=$(flash_device_name "$spi_no" 0)
        flash_sz=$(flash_get_size "$spi_dev")
        ret=$?
        if [ "$ret" -eq 0 ]; then
            storage_sz=$((flash_sz * 1024))
        else
            echo "Get flash size error: [$flash_sz]"
            exit 1
        fi
    fi

    if [ "$in_file_sz" -ne "$storage_sz" ]; then
        cp "$in_file" "$out_file"
        pad_ff "$in_file_sz" "$storage_sz" "$out_file"
    else
        ln -s "$(realpath "$in_file")" "$out_file"
    fi
}

dump_gpio_config() {
    if [ "$debug" = 0 ]; then
        return 0
    fi
    echo "Dump SPI configurations..."
    if [ "$1" = "SPI1" ]; then
        openbmc_gpio_util.py dump | grep SPI1
    else
        openbmc_gpio_util.py dump | grep SPI2
    fi
}

# currently only BCM5396 EEPROM
set_spi1_to_gpio() {
    devmem_set_bit "$(scu_addr 7C)" 12
    devmem_set_bit "$(scu_addr 7C)" 13
    devmem_set_bit "$(scu_addr 80)" 15
    gpio_set_direction BMC_SPI1_CLK out
    gpio_set_direction BMC_SPI1_CS0 out
    gpio_set_direction BMC_SPI1_MISO in
    gpio_set_direction BMC_SPI1_MOSI out
    dump_gpio_config SPI1
}

set_spi1_to_spi() {
    devmem_set_bit "$(scu_addr 70)" 12
    dump_gpio_config SPI1
}

# currently no use
set_spi2_to_spi_cs() {
    cs=$1
    if [ "$cs" = 0 ]; then
        # spi2 cs0
        devmem_set_bit "$(scu_addr 88)" 26
        devmem_set_bit "$(scu_addr 88)" 27
        devmem_set_bit "$(scu_addr 88)" 28
        devmem_set_bit "$(scu_addr 88)" 29
    else
        # spi2 cs1
        devmem_set_bit "$(scu_addr 8C)" 0
        devmem_set_bit "$(scu_addr 88)" 27
        devmem_set_bit "$(scu_addr 88)" 28
        devmem_set_bit "$(scu_addr 88)" 29
    fi
    dump_gpio_config SPI2
}

read_flash_to_file() {
    spi_no=$1
    file=$2
    spi_dev=$(flash_device_name "$spi_no" 0)

    modprobe -r spidev
    modprobe spidev
    type=$(flash_get_model "$spi_dev")
    flashrom -p linux_spi:dev=/dev/"$spi_dev" -r "$file" -c "$type"
    ret=$?
    if [ "$ret" -ne 0 ]; then
        echo "debug cmd: [flashrom -p linux_spi:dev=/dev/$spi_dev -r $file -c $type]"
        exit 1
    fi
}

write_flash_to_file() {
    spi_no=$1
    in_file=$2
    out_file="/tmp/${3}_spi${1}_tmp"
    spi_dev=$(flash_device_name "$spi_no" 0)

    modprobe -r spidev
    modprobe spidev
    resize_file "$in_file" "$out_file" "$spi_no"
    type=$(flash_get_model "$spi_dev")
    flashrom -p linux_spi:dev=/dev/"$spi_dev" -w "$out_file" -c "$type"
    ret=$?
    if [ "$ret" -ne 0 ]; then
        echo "debug cmd: [flashrom -p linux_spi:dev=/dev/$spi_dev -w $out_file -c $type]"
        exit 1
    fi
}

erase_flash() {
    spi_no=$1
    spi_dev=$(flash_device_name "$spi_no" 0)

    modprobe -r spidev
    modprobe spidev
    type=$(flash_get_model "$spi_dev")
    flashrom -p linux_spi:dev=/dev/"$spi_dev" -E -c "$type"
    ret=$?
    if [ "$ret" -ne 0 ]; then
        echo "debug cmd: [flashrom -p linux_spi:dev=/dev/$spi_dev -E -c $type]"
        exit 1
    fi
}

read_m95m02_to_file() {
    spi_no=$1
    file=$2
    eeprom_node="/sys/bus/spi/devices/spi${spi_no}.1/eeprom"
    modprobe -r at25
    modprobe at25
    dd if="$eeprom_node" of="$file" count="$m95m02_page_count" bs="$m95m02_page_size"
}

write_m95m02() {
    spi_no=$1
    file=$2
    out_file="/tmp/${3}_spi${1}_tmp"
    eeprom_node="/sys/bus/spi/devices/spi${spi_no}.1/eeprom"
    modprobe -r at25
    modprobe at25
    tr '\0' '\377' < /dev/zero | dd count="$m95m02_page_count" bs="$m95m02_page_size" of="$eeprom_node"
    resize_file "$file" "$out_file" "$spi_no" 'm95m02'
    dd of="$eeprom_node" if="$out_file" count="$m95m02_page_count" bs="$m95m02_page_size"
}

erase_m95m02() {
    spi_no=$1
    eeprom_node="/sys/bus/spi/devices/spi${spi_no}.1/eeprom"
    modprobe -r at25
    modprobe at25
    tr '\0' '\377' < /dev/zero | dd count="$m95m02_page_count" bs="$m95m02_page_size" of="$eeprom_node"
}

read_spi1_dev() {
    spi_no=1
    dev=$1
    file=$2
    case "$dev" in
        ## W25Q128 , W25Q128 , W25Q257
        "BACKUP_BIOS" | "IOB_FPGA_FLASH" | "TH3_FLASH")
            read_flash_to_file "$spi_no" "$file"
        ;;
        "BCM5396_EE")
            echo "Reading BCM5396 eeprom to $file..."
            at93cx6_util_py3.py "${SPI_PIN_ARGS[@]}" chip read --file "$file"
        ;;
    esac
}

write_spi1_dev() {
    spi_no=1
    dev=$1
    file=$2
    case "$dev" in
        ## W25Q128 , W25Q128 , W25Q257
        "BACKUP_BIOS" | "IOB_FPGA_FLASH" | "TH3_FLASH")
            write_flash_to_file "$spi_no" "$file" "$dev"
        ;;
        "BCM5396_EE")
            echo "Writing $file to BCM5396 eeprom..."
            at93cx6_util_py3.py "${SPI_PIN_ARGS[@]}" chip write --file "$file"
        ;;
    esac
}

erase_spi1_dev() {
    spi_no=1
    dev=$1
    file=$2
    case "$dev" in
        ## W25Q128 , W25Q128 , W25Q257
        "BACKUP_BIOS" | "IOB_FPGA_FLASH" | "TH3_FLASH")
            erase_flash "$spi_no"
        ;;
        "BCM5396_EE")
            echo "Erasing BCM5396 eeprom..."
            at93cx6_util_py3.py "${SPI_PIN_ARGS[@]}" chip erase
        ;;
    esac
}

set_smb_cpld_spi_1b() {
    if [ "$#" = 3 ]; then
        set_sysfs_value "$SMBCPLD_SYSFS_DIR"/spi_1_b0 "$3"
        set_sysfs_value "$SMBCPLD_SYSFS_DIR"/spi_1_b1 "$2"
        set_sysfs_value "$SMBCPLD_SYSFS_DIR"/spi_1_b2 "$1"
    else
        echo "Set SPI1 BIT FAILED"
    fi
}

config_spi1_pin_and_path() {
    dev=$1

    echo "Select SPI1 Device: $dev"
    case "$dev" in
        "BACKUP_BIOS")
            set_spi1_to_spi
            set_smb_cpld_spi_1b 0 1 1
            set_sysfs_value "$SCMCPLD_SYSFS_DIR"/iso_spi_en 0
            set_sysfs_value "$SCMCPLD_SYSFS_DIR"/com_spi_oe_n 0
            set_sysfs_value "$SCMCPLD_SYSFS_DIR"/com_spi_sel 1
        ;;
        "IOB_FPGA_FLASH")
            set_spi1_to_spi
            set_smb_cpld_spi_1b 0 0 0
            set_sysfs_value "$SMBCPLD_SYSFS_DIR"/fpga_spi_mux_sel 1
        ;;
        "TH3_FLASH")
            set_spi1_to_spi
            set_smb_cpld_spi_1b 0 0 1
            set_sysfs_value "$SMBCPLD_SYSFS_DIR"/th3_spi_mux_sel 1
        ;;
        "BCM5396_EE")
            set_spi1_to_gpio
            set_smb_cpld_spi_1b 0 1 0
            set_sysfs_value "$SMBCPLD_SYSFS_DIR"/cpld_bcm5396_mux_sel 1
            gpio_set_value BMC_BCM5396_MUX_SEL 1
        ;;
        *)
            echo "Please enter {IOB_FPGA_FLASH, TH3_FLASH, BCM5396_EE, BACKUP_BIOS}"
            exit 1
        ;;
    esac
    echo "Config SPI1 Done."
}

config_spi2_pin_and_path() {
    pim=$1
    dev=$2
    pim_no=${pim:3:3}
    bus=$(((pim_no-1)*8 + 85))
    echo "Select SPI2 Device: PIM$pim_no $dev"
    config_spi2_pim_path "$pim_no" "$dev"
    config_spi2_pim_dev_path "$bus" "$dev"
    echo "Config SPI2 Done."
}

set_smb_cpld_spi_2b() {
    if [ "$#" = 4 ]; then
        set_sysfs_value "$SMBCPLD_SYSFS_DIR"/spi_2_b0 "$4"
        set_sysfs_value "$SMBCPLD_SYSFS_DIR"/spi_2_b1 "$3"
        set_sysfs_value "$SMBCPLD_SYSFS_DIR"/spi_2_b2 "$2"
        set_sysfs_value "$SMBCPLD_SYSFS_DIR"/spi_2_b3 "$1"
    else
        echo "Set SPI2 BIT FAILED"
    fi
}

config_spi2_pim_path() {
    pim_no=$1
    local dev=$2
    dev=${dev:0:3}  # Detect PHY EEPROM to change CS1
    # Not PHY means CS0 FPGA, else CS1 PHY#_EE
    case "$pim_no" in
        "1")
            if [ "$dev" != "PHY" ]; then
                set_smb_cpld_spi_2b 0 0 0 0
            else
                set_smb_cpld_spi_2b 1 0 0 0
            fi
        ;;
        "2")
            if [ "$dev" != "PHY" ]; then
                set_smb_cpld_spi_2b 0 0 0 1
            else
                set_smb_cpld_spi_2b 1 0 0 1
            fi
        ;;
        "3")
            if [ "$dev" != "PHY" ]; then
                set_smb_cpld_spi_2b 0 0 1 0
            else
                set_smb_cpld_spi_2b 1 0 1 0
            fi
        ;;
        "4")
            if [ "$dev" != "PHY" ]; then
                set_smb_cpld_spi_2b 0 0 1 1
            else
                set_smb_cpld_spi_2b 1 0 1 1
            fi
        ;;
        "5")
            if [ "$dev" != "PHY" ]; then
                set_smb_cpld_spi_2b 0 1 0 0
            else
                set_smb_cpld_spi_2b 1 1 0 0
            fi
        ;;
        "6")
            if [ "$dev" != "PHY" ]; then
                set_smb_cpld_spi_2b 0 1 0 1
            else
                set_smb_cpld_spi_2b 1 1 0 1
            fi
        ;;
        "7")
            if [ "$dev" != "PHY" ]; then
                set_smb_cpld_spi_2b 0 1 1 0
            else
                set_smb_cpld_spi_2b 1 1 1 0
            fi
        ;;
        "8")
            if [ "$dev" != "PHY" ]; then
                set_smb_cpld_spi_2b 0 1 1 1
            else
                set_smb_cpld_spi_2b 1 1 1 1
            fi
        ;;
        *)
            exit 1
        ;;
    esac
}

exec_and_print() {
    if [ "$debug" = 1 ]; then
        echo "$1"
    fi
    $1
}

detect_pca9534() {
    bus=$1
    dev_addr=$2
    dev_no=${dev_addr:2:3}
    i2cdetect -y "$bus" "$dev_addr" "$dev_addr" | grep "$dev_no" > /dev/null
}

config_spi2_pim_dev_path() {
    bus=$1
    dev=$2

    # Configure output pin(0) to [0:2] 1111 1000 -> 0xf8
    spi_sel_output_bit=0xf8
    # Configure output pin(0) to [1:5] 1100 0001 -> 0xc1
    ee_sel_output_bit=0xc1

    detect_pca9534 "$bus" "$pca9534_spi_sel"
    spi_sel_ret=$?
    detect_pca9534 "$bus" "$pca9534_ee_sel"
    ee_sel_ret=$?
    if [ "$spi_sel_ret" != 0 ]; then
        echo "Cannot detect I2C device bus[$bus] addr[$pca9534_spi_sel]"
        exit 1
    elif [ "$ee_sel_ret" != 0 ]; then
        echo "Cannot detect I2C device bus[$bus] addr[$pca9534_ee_sel]"
        exit 1
    fi

    i2c_ret=$(i2cget -y "$bus" "$pca9534_spi_sel" "$mode_reg")
    if [ "$i2c_ret" = "" ]; then
        echo "Cannot read bus:$bus addr:$pca9534_spi_sel"
        exit 1
    fi
    # Current value and with 0xf8
    config_val=$(printf "0x%x" $((spi_sel_output_bit & "$i2c_ret")))
    set_i2c_dev_value "$bus" "$pca9534_spi_sel" "$mode_reg" "$config_val"

    i2c_ret=$(i2cget -y "$bus" "$pca9534_ee_sel" "$mode_reg")
    if [ "$i2c_ret" = "" ]; then
        echo "Cannot read bus:$bus addr:$pca9534_ee_sel"
        exit 1
    fi
    config_val=$(printf "0x%x" $((ee_sel_output_bit & "$i2c_ret")))
    set_i2c_dev_value "$bus" "$pca9534_ee_sel" "$mode_reg" "$config_val"

    read_spi_sel_val=$(i2cget -y "$bus" "$pca9534_spi_sel" "$output_reg")
    read_spi_sel_val=$((read_spi_sel_val | 0x7))

    read_spi_ee_val=$(i2cget -y "$bus" "$pca9534_ee_sel" "$output_reg")
    read_spi_ee_val=$((read_spi_ee_val | 0x3e))

    case "$dev" in
        "PHY1_EE")
            set_spi2_to_spi_cs 1
            write_val=$(printf "0x%x" $((read_spi_sel_val & 0xf8)))
            set_i2c_dev_value "$bus" "$pca9534_spi_sel" "$output_reg" "$write_val"
            write_val=$(printf "0x%x" $((read_spi_ee_val & 0xfb)))
            set_i2c_dev_value "$bus" "$pca9534_ee_sel" "$output_reg" "$write_val"
        ;;
        "PHY2_EE")
            set_spi2_to_spi_cs 1
            write_val=$(printf "0x%x" $((read_spi_sel_val & 0xf9)))
            set_i2c_dev_value "$bus" "$pca9534_spi_sel" "$output_reg" "$write_val"
            write_val=$(printf "0x%x" $((read_spi_ee_val & 0xf7)))
            set_i2c_dev_value "$bus" "$pca9534_ee_sel" "$output_reg" "$write_val"
        ;;
        "PHY3_EE")
            set_spi2_to_spi_cs 1
            write_val=$(printf "0x%x" $((read_spi_sel_val & 0xfa)))
            set_i2c_dev_value "$bus" "$pca9534_spi_sel" "$output_reg" "$write_val"
            write_val=$(printf "0x%x" $((read_spi_ee_val & 0xef)))
            set_i2c_dev_value "$bus" "$pca9534_ee_sel" "$output_reg" "$write_val"
        ;;
        "PHY4_EE")
            set_spi2_to_spi_cs 1
            write_val=$(printf "0x%x" $((read_spi_sel_val & 0xfb)))
            set_i2c_dev_value "$bus" "$pca9534_spi_sel" "$output_reg" "$write_val"
            write_val=$(printf "0x%x" $((read_spi_ee_val & 0xdf)))
            set_i2c_dev_value "$bus" "$pca9534_ee_sel" "$output_reg" "$write_val"
        ;;
        "DOM_FPGA_FLASH")
            set_spi2_to_spi_cs 0
            write_val=$(printf "0x%x" $((read_spi_sel_val & 0xfc)))
            set_i2c_dev_value "$bus" "$pca9534_spi_sel" "$output_reg" "$write_val"
            write_val=$(printf "0x%x" $((read_spi_ee_val & 0xfd)))
            set_i2c_dev_value "$bus" "$pca9534_ee_sel" "$output_reg" "$write_val"
        ;;
        *)
            echo "Please enter with {PHY#_EE, DOM_FPGA_FLASH}"
            exit 1
        ;;
    esac
}

read_spi2_dev() {
    spi_no=2
    dev=$1
    file=$2

    case "$dev" in
        "PHY"[1-4]"_EE")
            # M95M02 EEPROM
            echo "Reading PHY eeprom to $file..."
            read_m95m02_to_file "$spi_no" "$file"
        ;;
        "DOM_FPGA_FLASH")
            # W25Q32
            read_flash_to_file "$spi_no" "$file"
        ;;
        *)
            echo "SPI2 without this device [$dev]"
        ;;
    esac
}

write_spi2_dev() {
    spi_no=2
    dev=$1
    case "$dev" in
        "PHY"[1-4]"_EE")
            # M95M02 EEPROM
            echo "Writing $file to PHY eeprom..."
            write_m95m02 "$spi_no" "$file" "$dev"
        ;;
        "DOM_FPGA_FLASH")
            # W25Q32
            write_flash_to_file "$spi_no" "$file" "$dev"
        ;;
        *)
            echo "SPI2 without this device [$dev]"
        ;;
    esac
}

erase_spi2_dev() {
    spi_no=2
    dev=$1
    case "$dev" in
        "PHY"[1-4]"_EE")
            # M95M02 EEPROM
            echo "Erasing PHY eeprom..."
            erase_m95m02 "$spi_no"
        ;;
        "DOM_FPGA_FLASH")
            # W25Q32
            erase_flash "$spi_no"
        ;;
        *)
            echo "SPI2 without this device [$dev]"
        ;;
    esac
}

operate_spi1_dev() {
    op=$1
    dev=$2
    file=$3
    ## Operate devices ##
    case "$op" in
        "read")
                read_spi1_dev "$dev" "$file"
        ;;
        "write")
                write_spi1_dev "$dev" "$file"
        ;;
        "erase")
                erase_spi1_dev "$dev"
        ;;
        *)
            echo "Operation $op is not defined."
        ;;
    esac
}

operate_spi2_dev() {
    op=$1
    dev=$2
    file=$3
	## Operate devices ##
    case "$op" in
        "read")
                read_spi2_dev "$dev" "$file"
        ;;
        "write")
                write_spi2_dev "$dev" "$file"
        ;;
        "erase")
                erase_spi2_dev "$dev"
        ;;
        *)
            echo "Operation $op is not defined."
        ;;
    esac
}

cleanup_spi() {
    if [ "$?" -eq 2 ]; then
        exit 1
    fi

    set_sysfs_value "$SMBCPLD_SYSFS_DIR"/fpga_spi_mux_sel 0
    set_sysfs_value "$SMBCPLD_SYSFS_DIR"/th3_spi_mux_sel 0
    set_sysfs_value "$SMBCPLD_SYSFS_DIR"/cpld_bcm5396_mux_sel 0
    set_sysfs_value "$SCMCPLD_SYSFS_DIR"/com_spi_sel 0

    for i in {1..8}
    do
        bus=$(((i-1)*8 + 85))
        detect_pca9534 "$bus" "$pca9534_ee_sel"
        ret=$?
        if [ "$ret" = 0 ]; then
            read_spi_ee_val=$(i2cget -y "$bus" "$pca9534_ee_sel" "$output_reg")
            write_ee_val=$((read_spi_ee_val | 0x3e))
            set_i2c_dev_value "$bus" "$pca9534_ee_sel" "$output_reg" "$write_ee_val"
        fi
    done
    rm -rf /tmp/*_spi*_tmp
    remove_pid_file "$SPI_INF"
}

ui() {
    op=$1
    spi=$2

    # SPI 1.0 speed
    devmem 0x1e630010 32 0x407
    # SPI 2.0 speed
    devmem 0x1e631010 32 0x407
    # SPI 2.1 speed
    devmem 0x1e631014 32 0x2007
	## Open the path to device ##
    case "$spi" in
        "spi1")
            dev=$3
            file=$4
            config_spi1_pin_and_path "$dev"
            operate_spi1_dev "$op" "$dev" "$file"
        ;;
        "spi2")
            pim=$3
            dev=$4
            file=$5
            config_spi2_pin_and_path "$pim" "$dev"
            operate_spi2_dev "$op" "$dev" "$file"
        ;;
        *)
            echo "No such SPI bus."
            exit 1
        ;;
    esac
}

usage() {
    program=$(basename "$0")
    echo "Usage:"
    echo "$program <op> spi1 <spi1 device> <file>"
    echo "$program <op> spi2 <pim#> <spi2 device> <file>"
    echo "  <op>          : read, write, erase"
    echo "  <spi1 device> : IOB_FPGA_FLASH, TH3_FLASH, BCM5396_EE, BACKUP_BIOS"
    echo "  <pim#>        : PIM1, PIM2, PIM3, PIM4, PIM5, PIM6, PIM7, PIM8"
    echo "  <spi2 device> : PHY1_EE, PHY2_EE, PH3_EE, PHY4_EE, DOM_FPGA_FLASH"
    echo ""
    echo "Examples:"
    echo "  $program write spi1 IOB_FPGA_FLASH iob.bit"
    echo "  $program read spi2 PIM1 PHY1_EE image.bin"
    echo "  $program erase spi2 PIM1 DOM_FPGA_FLASH"
    echo ""
}

check_parameter() {
    program=$(basename "$0")
    op=$1
    spi=$2
    case "$op" in
        "read" | "write" | "erase")
            ;;
        *)
            return 1
            ;;
    esac
    if [ "$spi" ] && [ "$spi" = "spi1" ]; then
        dev=$3
        file=$4
        ## Check device
        case "$dev" in
            "IOB_FPGA_FLASH" | "TH3_FLASH" | "BCM5396_EE" | "BACKUP_BIOS")
                ## Check operation
                case "$op" in
                    "read" | "write")
                        if [ "$#" -ne 4 ]; then
                            return 1
                        fi
                        ;;
                    "erase")
                        if [ "$#" -ne 3 ]; then
                            return 1
                        fi
                        ;;
                esac
                ;;
            *)
                return 1
                ;;
        esac
    elif [ "$spi" ] && [ "$spi" = "spi2" ]; then
        pim=$3
        dev=$4
        file=$5
        ## Check device
        case ${pim} in
            "PIM"[1-8])
                case "$dev" in
                    "PHY"[1-4]"_EE" | "DOM_FPGA_FLASH")
                        ## Check operation
                        case "$op" in
                            "read" | "write")
                                if [ "$#" -ne 5 ]; then
                                    return 1
                                fi
                                ;;
                            "erase")
                                if [ "$#" -ne 4 ]; then
                                    return 1
                                fi
                                ;;
                        esac
                        ;;
                    *)
                        return 1
                        ;;
                esac
                ;;
            *)
                return 1
                ;;
        esac
    else
        return 1
    fi

    return 0
}

check_duplicate_process
check_parameter "$@"
is_par_ok=$?

if [ "$is_par_ok" -eq 0 ]; then
    ui "$@"
else
    usage
    exit 2
fi


#!/bin/sh
#
# Copyright 2018-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

usage() {
    echo "$0 <connect | disconnect>"
}

. /usr/local/bin/openbmc-utils.sh

if [ $# -ne 1 ]; then
    usage
    exit 1
fi

if [ "$1" == "connect" ]; then
    VALUE=1
elif [ "$1" == "disconnect" ]; then
    VALUE=0
else
    usage
    exit 1
fi

# GPIOS5 (32) controls if uS console connects to UART5 or not.
# To enable GPIOS5, SCU8C[5] must be 0
devmem_clear_bit $(scu_addr 8C) 5

gpio_set_value BMC_UART_SEL5 "$VALUE"


#!/bin/bash
#
# Copyright 2018-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

. /usr/local/bin/openbmc-utils.sh

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

prog="$0"
board_rev=$(wedge_board_rev)

PWR_USRV_RST_SYSFS="${SCMCPLD_SYSFS_DIR}/iso_com_rst_n"
PWR_L_CYCLE_SYSFS="${LEFT_PDBCPLD_SYSFS_DIR}/power_cycle_go"
PWR_R_CYCLE_SYSFS="${RIGHT_PDBCPLD_SYSFS_DIR}/power_cycle_go"
PWR_L_TIMER_BASE_1S_SYSFS="${LEFT_PDBCPLD_SYSFS_DIR}/timer_base_1s"
PWR_R_TIMER_BASE_1S_SYSFS="${RIGHT_PDBCPLD_SYSFS_DIR}/timer_base_1s"
PWR_L_TIMER_BASE_10S_SYSFS="${LEFT_PDBCPLD_SYSFS_DIR}/timer_base_10s"
PWR_R_TIMER_BASE_10S_SYSFS="${RIGHT_PDBCPLD_SYSFS_DIR}/timer_base_10s"
PWR_L_TIMER_COUNTER_SETTING_SYSFS="${LEFT_PDBCPLD_SYSFS_DIR}/timer_counter_setting"
PWR_R_TIMER_COUNTER_SETTING_SYSFS="${RIGHT_PDBCPLD_SYSFS_DIR}/timer_counter_setting"
PWR_L_TIMER_COUNTER_SETTING_UPDATE_SYSFS="${LEFT_PDBCPLD_SYSFS_DIR}/timer_counter_setting_update"
PWR_R_TIMER_COUNTER_SETTING_UPDATE_SYSFS="${RIGHT_PDBCPLD_SYSFS_DIR}/timer_counter_setting_update"
SCM_CPLD_BUS=16
PIM_CPLD_BUS=(84 92 100 108 116 124 132 140)
CPLD_ADDR=0x10
CPLD_RESET_CMD=0xd9

usage() {
    echo "Usage: $prog <command> [command options]"
    echo
    echo "Commands:"
    echo "  status: Get the current microserver power status"
    echo
    echo "  on: Power on microserver if not powered on already"
    echo "    options:"
    echo "      -f: Re-do power on sequence no matter if microserver has "
    echo "          been powered on or not."
    echo
    echo "  off: Power off microserver ungracefully"
    echo
    echo "  reset: Power reset microserver ungracefully"
    echo "    options:"
    echo "      -s: Power reset whole minipack system ungracefully"
    echo "      -s -t [1-2550]: Setting boot up time."
    echo "            From 1 to 249 the step is 1 second."
    echo "            From 250 to 2550 the step is 10 seconds"
    echo "            and don't care ones-digits."
    echo
    echo "  pimreset: Power-cycle one or all PIM(s)"
    echo "    options:"
    echo "      -a  : Reset all PIMs or "
    echo "      -2 , -3 , ... , -9 : Reset a single PIM (2, 3 ... 9) "
    echo
}

main_power_status() {
    return 0
}

do_status() {
    echo -n "Microserver power is "
    return_code=0

    if wedge_is_us_on; then
        echo "on"
    else
        echo "off"
        return_code=1
    fi

    return $return_code
}

do_on_com_e() {
    echo 1 > $PWR_USRV_SYSFS
    return $?
}

do_on_main_pwr() {
    # minipack com-e main power is controlled by SCMCPLD
    return 0
}

do_on() {
    local force opt ret
    force=0
    while getopts "f" opt; do
        case $opt in
            f)
                force=1
                ;;
            *)
                usage
                exit -1
                ;;
        esac
    done
    echo -n "Power on microserver ..."
    if [ $force -eq 0 ]; then
        # need to check if uS is on or not
        if wedge_is_us_on; then
            echo " Already on. Skip!"
            return 1
        fi
    fi

    # power on sequence
    do_on_com_e
    ret=$?
    if [ $ret -eq 0 ]; then
        echo " Done"
	logger "Successfully power on micro-server"
    else
        echo " Failed"
        logger "Failed to power on micro-server"
    fi
    return $ret
}

do_off_com_e() {
    echo 0 > $PWR_USRV_SYSFS
    return $?
}

do_off() {
    local ret
    echo -n "Power off microserver ..."
    do_off_com_e
    ret=$?
    if [ $ret -eq 0 ]; then
        echo " Done"
    else
        echo " Failed"
    fi
    return $ret
}

do_config_reset_timer() {
    # Check numeric
    wake_t=$1
    echo $wake_t | egrep -q '^[0-9]+$'
    ret=$?
    if [ $ret -ne 0 ]; then
        usage
        exit -1
    else
        if [ $wake_t -ge 1 -a $wake_t -lt 250 ];then
            echo 1 > $PWR_L_TIMER_BASE_1S_SYSFS
            echo 1 > $PWR_R_TIMER_BASE_1S_SYSFS
            echo 0 > $PWR_L_TIMER_BASE_10S_SYSFS
            echo 0 > $PWR_R_TIMER_BASE_10S_SYSFS
            logger "Waiting $wake_t seconds for the system boot up"
            echo "Waiting $wake_t seconds for the system boot up"
        elif [ $wake_t -ge 250 -a $wake_t -le 2550 ];then
            echo 0 > $PWR_L_TIMER_BASE_1S_SYSFS
            echo 0 > $PWR_R_TIMER_BASE_1S_SYSFS
            echo 1 > $PWR_L_TIMER_BASE_10S_SYSFS
            echo 1 > $PWR_R_TIMER_BASE_10S_SYSFS
            wake_t=$((wake_t/10))
            logger "Waiting $(($wake_t * 10)) seconds for the system boot up"
            echo "Waiting $(($wake_t * 10)) seconds for the system boot up"
        else
            usage
            exit -1
        fi
        echo $wake_t > $PWR_L_TIMER_COUNTER_SETTING_SYSFS
        echo $wake_t > $PWR_R_TIMER_COUNTER_SETTING_SYSFS
        echo 1 > $PWR_L_TIMER_COUNTER_SETTING_UPDATE_SYSFS
        echo 1 > $PWR_R_TIMER_COUNTER_SETTING_UPDATE_SYSFS
        echo 0 > $PWR_L_TIMER_COUNTER_SETTING_UPDATE_SYSFS
        echo 0 > $PWR_R_TIMER_COUNTER_SETTING_UPDATE_SYSFS
    fi
}

do_reset() {
    local system timer wake_t opt pulse_us
    system=0
    timer=0
    wake_t=0
    while getopts "st:" opt; do
        case $opt in
            s)
                system=1
                ;;
            t)
                timer=1
                wake_t=$OPTARG
                ;;
            *)
                usage
                exit -1
                ;;
        esac
    done

    if [ $system -eq 1 ]; then
        logger -p user.crit "Power reset the whole system ..."
        if [ $board_rev -eq 4 ]; then
            logger "EVTA is not supported, running a workaround instead"
            echo "EVTA is not supported, running a workaround instead"

            #
            # Sync cached writes to persistent storage before chassis
            # power cycle.
            #
            sync

            i2cset -f -y 1 0x3a 0x12 0
        else
            if [ $timer -eq 1 ]; then
                do_config_reset_timer $wake_t
            fi
            echo  "Power reset the whole system ..."

            #
            # Sync cached writes to persistent storage before chassis
            # power cycle.
            #
            sync

            echo 1 > $PWR_L_CYCLE_SYSFS
            sleep 1
            echo 1 > $PWR_R_CYCLE_SYSFS
            sleep 3
            # Control should not reach here, but if it failed to reset
            # the system through PSU, then run a workaround to reset
            # most of the system instead (if not all)
            logger "Failed to reset the system. Running a workaround"
            echo "Failed to reset the system. Running a workaround"
            i2cset -f -y 1 0x3a 0x12 0
        fi
    else
        if ! wedge_is_us_on; then
            echo "Power resetting microserver that is powered off has no effect."
            echo "Use '$prog on' to power the microserver on"
            return -1
        fi
        echo -n "Power reset microserver ..."
        echo 0 > $PWR_USRV_RST_SYSFS
        sleep 1
        echo 1 > $PWR_USRV_RST_SYSFS
        logger "Successfully power reset micro-server"
    fi
    echo " Done"
    return 0
}

toggle_pim_reset() {
    retval=0
    pim=$1
    for slot in 2 3 4 5 6 7 8 9; do
      if [ $pim -eq 0 ] || [ $slot -eq $pim ]; then
        index=$(expr $slot - 2)
         # We don't have PIM CPLD driver for now,
         # so we will use raw i2c access for the time being
         echo Power-cycling PIM in slot $slot
         i2cset -f -y ${PIM_CPLD_BUS[$index]} $CPLD_ADDR $CPLD_RESET_CMD
         result=$?
         if [ $result -ne 0 ]; then
           retval=$result
         fi
      fi
    done
    return $retval
}

do_pimreset() {
    local pim opt retval rc
    retval=0
    pim=-1
    while getopts "23456789a" opt; do
        case $opt in
            a)
                pim=0
                ;;
            2)
                pim=2
                ;;
            3)
                pim=3
                ;;
            4)
                pim=4
                ;;
            5)
                pim=5
                ;;
            6)
                pim=6
                ;;
            7)
                pim=7
                ;;
            8)
                pim=8
                ;;
            9)
                pim=9
                ;;
            *)
                usage
                exit -1
                ;;
        esac
    done
    if [ $pim -eq -1 ]; then
      usage
      exit -1
    fi

    toggle_pim_reset $pim
    retval=$?

    return $retval
}

if [ $# -lt 1 ]; then
    usage
    exit -1
fi

command="$1"
shift

case "$command" in
    status)
        do_status $@
        ;;
    on)
        do_on $@
        ;;
    off)
        do_off $@
        ;;
    reset)
        do_reset $@
        ;;
    pimreset)
        do_pimreset $@
        exit $?
        ;;
    *)
        usage
        exit -1
        ;;
esac

exit $?


#!/bin/bash
#
# Copyright 2015-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

# Get output from bic-util
bic_output=`bic-util scm --read_mac`

# Check if the read was successful and output matches with our format
match=`echo $bic_output| grep -e 'MAC address: [0-9a-f][0-9a-f]:'|wc -l`
if [ "$match" == "1" ]; then
    # Mac address: xx:xx:xx:xx:xx:xx
    echo $bic_output| cut -d ' ' -f 3
    exit 0
else
    echo "Cannot find out the microserver MAC" 1>&2
    exit -1
fi


#!/bin/bash
#
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA

#shellcheck disable=SC1091,SC2034
# Do not change this line to openbmc-utils.sh, or it will generate a source loop.
. /usr/local/bin/i2c-utils.sh

MCBCPLD_SYSFS_DIR=$(i2c_device_sysfs_abspath 12-0060)

PWR_FORCE_OFF="${MCBCPLD_SYSFS_DIR}/pwr_force_off"
PWR_COME_EN="${MCBCPLD_SYSFS_DIR}/pwr_come_en"
PWR_COME_CYCLE_N="${MCBCPLD_SYSFS_DIR}/pwr_come_cycle_n"

TIMER_BASE_10S="${MCBCPLD_SYSFS_DIR}/timer_base_10s"
TIMER_BASE_1S="${MCBCPLD_SYSFS_DIR}/timer_base_1s"
TIMER_BASE_100MS="${MCBCPLD_SYSFS_DIR}/timer_base_100ms"
TIMER_BASE_10MS="${MCBCPLD_SYSFS_DIR}/timer_base_10ms"
TIMER_COUNTER_SETTING="${MCBCPLD_SYSFS_DIR}/timer_counter_setting"
TIMER_COUNTER_SETTING_UPDATE="${MCBCPLD_SYSFS_DIR}/timer_counter_setting_update"
POWER_CYCLE_GO="${MCBCPLD_SYSFS_DIR}/power_cycle_go"

BOARD_ID="${MCBCPLD_SYSFS_DIR}/board_id"
VERSION_ID="${MCBCPLD_SYSFS_DIR}/version_id"

wedge_board_type() {
    echo 'MONTBLANC'
}

# read hardware revision from MCB CPLD register
wedge_board_rev() {
    board_id=$(head -n 1 < "$BOARD_ID" 2> /dev/null)
    version_id=$(head -n 1 < "$VERSION_ID" 2> /dev/null)

    case "$((board_id))" in
        1)
            echo "Board type: Minipack3 Switching System"
            ;;
        *)
            echo "Board type: unknown value [$board_id]"
            ;;
    esac

    case "$((version_id))" in
        0)
            echo "Revision: EVT-1"
            ;;
        *)
            echo "Revision: unknown value [$version_id]"
            ;;
    esac

    return 0
}

userver_power_is_on() {
    val1=$(head -n 1 < "$PWR_FORCE_OFF" 2> /dev/null)
    val2=$(head -n 1 < "$PWR_COME_EN" 2> /dev/null)

    if [ $((val1)) -eq $((0x1)) ] && [ $((val2)) -eq $((0x1)) ] ; then
        return 0            # powered on
    else
        return 1
    fi
}

userver_power_on() {
    echo 1 > "$PWR_FORCE_OFF"
    echo 1 > "$PWR_COME_EN"
    return 0
}

userver_power_off() {
    echo 0 > "$PWR_FORCE_OFF"
    return 0
}

userver_reset() {
    # write 0 to trigger CPLD power cycling COMe
    # then this bit will auto set to 1 after Power cycle finish
    echo 0 > "$PWR_COME_CYCLE_N"

    timeout=10 #timeout 10 second
    while [ $((timeout)) -ge 0 ]; do
        val=$(head -n 1 < "$PWR_COME_CYCLE_N" 2> /dev/null)
        if [ $((val)) -eq 1 ]; then
            # reset successful
            return 0
        fi
        sleep 1
        timeout=$((timeout-1))
    done
    # reset fail
    echo " userver reset failed."
    return 1
}

chassis_power_cycle() {
    # TIME_COUTER will be calculated
    # based on register TIMER_BASE (10S,1S,100MS,10MS)
    #
    # eg. TIMER_BASE set as 100MS
    #     TIMER_COUNTER_SETTING set as 50
    #     timer is 50 x 100ms = 5 sec.

    echo 0 > "$TIMER_BASE_10S"
    echo 0 > "$TIMER_BASE_1S"
    echo 1 > "$TIMER_BASE_100MS"
    echo 0 > "$TIMER_BASE_10MS"

    echo 50 > "$TIMER_COUNTER_SETTING"

    echo 1 > "$TIMER_COUNTER_SETTING_UPDATE"
    echo 1 > "$POWER_CYCLE_GO"

    return 0
}

bmc_mac_addr() {
    weutil_output=$(weutil -e chassis_eeprom | grep 'Local MAC:' | cut -d ' ' -f 3)

    if [ -n "$weutil_output" ]; then
        # Mac address: xx:xx:xx:xx:xx:xx
        echo "$weutil_output"
        return 0
    else
        echo "Cannot find out the BMC MAC" 1>&2
        return 1
    fi
}

userver_mac_addr() {
    weutil_output=$(weutil -e scm_eeprom | grep 'Local MAC:' | cut -d ' ' -f 3)

    if [ -n "$weutil_output" ]; then
        # Mac address: xx:xx:xx:xx:xx:xx
        echo "$weutil_output"
        return 0
    else
        echo "Cannot find out the microserver MAC" 1>&2
        return 1
    fi
}


#!/bin/sh
#
# Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
# shellcheck disable=SC1091,SC3046
. /usr/local/bin/openbmc-utils.sh

prog="$0"
CPLD_TYPE="$2"
UPDATE_IMG="$4"

chip_ver=$(aspeed_g6_chip_ver | cut -c 2)

DLL_AST_JTAG_PATH=/usr/lib/libcpldupdate_dll_ast_jtag.so

usage() {
    echo "Usage: $prog -s <CPLD_TYPE> -f <img_file> <hw|sw>"
    echo
    echo "CPLD_TYPE: ( COME )"
    echo
    echo "img_file: Image file for lattice CPLD"
    echo "  VME file for software mode"
    echo "  JED file for hardware mode"
    echo "  JBC file for Intel PFR FPGA update software mode"
    echo "  HEX file for i2c mode"
    echo "options:"
    echo "  hw: Program the CPLD using JTAG hardware mode"
    echo "  sw: Program the CPLD using JTAG software mode"
    echo
    echo
}

if [ $# -lt 5 ]; then
    usage
    exit 1
fi

#  Multiplex diagram
#                         SEL_0
#       from HEADER  >>> |0\  |
#                        |  >C| >> SCM CPLD
#              |  /0| >> |1/  |
#  BMC SPI1 >> |C<  |
#              |  \1| >>>  COMe CPLD
#               SEL_1

enable_scm_jtag_chain(){
    gpiocli -s MUX_JTAG_SEL_0 set-value 1
    gpiocli -s MUX_JTAG_SEL_1 set-value 0
}

enable_come_jtag_chain(){
    gpiocli -s MUX_JTAG_SEL_0 set-value 0
    gpiocli -s MUX_JTAG_SEL_1 set-value 1
}

disable_jtag_chain(){
    gpiocli -s MUX_JTAG_SEL_0 set-value 0
    gpiocli -s MUX_JTAG_SEL_1 set-value 0
}

cpld_update_sw_mode(){
    n=1
    while [ "${n}" -le 5 ]; do
        echo "Program $CPLD_TYPE $n times"
        if [ "$CPLD_TYPE" = "COME" ];then
            expect=0
            jbi -aPROGRAM -ddo_real_time_isp=1 -W "${UPDATE_IMG}"
        else
            # ispvm success return code is 1
            expect=1
            ispvm -f 1000 dll $DLL_AST_JTAG_PATH "${UPDATE_IMG}"
        fi

        result=$?
        if [ $result -eq $expect ]; then
                break
        fi
        n=$((n + 1))
    done
}

cpld_update_hw_mode(){
    if [ $((chip_ver)) -ge 3 ];then
        cpldprog -p "${UPDATE_IMG}"
    else
        echo "Only AST262x A3 chip can support HW Mode !!!"
        exit 1
    fi
    result=$?
}

trap 'rm -rf /tmp/cpld_update && disable_jtag_chain' INT TERM QUIT EXIT

echo 1 > /tmp/cpld_update

expect=0

if [ -e "$UPDATE_IMG" ];then
    if [ "$CPLD_TYPE" = "SCM" ];then
        #enable_scm_jtag_chain
        echo "SCM CPLD didn't support yet"
        exit 1
    elif [ "$CPLD_TYPE" = "COME" ];then
        enable_come_jtag_chain
    else
        echo 'argument '"$CPLD_TYPE"' is wrong'
        exit 1
    fi
else
    echo 'argument '"$UPDATE_IMG"' not exist'
    exit 1
fi

case $5 in
    hw)
        cpld_update_hw_mode
        ;;
    sw)
        cpld_update_sw_mode
        ;;
    *)
        # default: sw mode
        cpld_update_sw_mode
        ;;
esac

disable_jtag_chain

# 0 is returned upon upgrade success
if [ $((result)) -eq $((expect)) ]; then
    echo "Upgrade successful."
    exit 0
fi


#!/bin/sh

cmd="ipmb-util 0x5 0x2c 0xb8 0xc8 0x57 0x01 0x00 0x01 0x00 0x00"

val=$($cmd)
ret=$?

if [ $((ret)) -ne 0 ]; then
    echo "command failed : $cmd"
    echo "  return value : $ret"
    exit 1
fi

# ref : Capture3 Intel ME Intel NM IPMI Interface
#       Intelz Intelligent Power Node Manager 3.0 External Interface Specification Using IPMI
#  NetFn 0x2E cmd 0xC8
# example response : 57 01 00 1E 00 0D 00 27 00 1E 00 FF FF FF FF EF 39 01 00 50
# [1:3]   - MFG ID
# [4:5]   - Current value
# [6:7]   - Minimum value
# [8:9]   - Maximum value
# [10:11] - Average value
# [12:15] - Timestamp
# [16:19]
# [20]    Domain Id | Policy

cur_power="0x$(echo "$val" | cut -d' ' -f5)$(echo "$val" | cut -d' ' -f4)"
min_power="0x$(echo "$val" | cut -d' ' -f7)$(echo "$val" | cut -d' ' -f6)"
max_power="0x$(echo "$val" | cut -d' ' -f9)$(echo "$val" | cut -d' ' -f8)"
avr_power="0x$(echo "$val" | cut -d' ' -f11)$(echo "$val" | cut -d' ' -f10)"

printf "INA230 Current power : %d Watts\n" "$cur_power"
printf "INA230 Minimum power : %d Watts\n" "$min_power"
printf "INA230 Maximum power : %d Watts\n" "$max_power"
printf "INA230 Average power : %d Watts\n" "$avr_power"


#!/bin/bash
#
# Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

### BEGIN INIT INFO
# Provides:          gpio-setup
# Required-Start:
# Required-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description:  Set up GPIO pins as appropriate
### END INIT INFO

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

# arg: NAME PIN DIR [DEFAULT VALUE]
setup_gpio() {
    NAME="$1"
    PIN="$2"
    DIR="$3"

    gpio_export_by_name "${ASPEED_GPIO}" "$PIN" "$NAME"
    if [ "$DIR" = "out" ]; then
        gpio_set_direction "$NAME" out
        if [ $# -ge 4 ]; then
            VALUE="$4"
            gpio_set_value "$NAME" "$VALUE"
        else
            echo "ERROR: setup-gpio $NAME output default value not defined" > /dev/kmsg
        fi
    elif [ "$DIR" = "in" ]; then
        gpio_set_direction "$NAME" in
    else
        echo "ERROR: setup-gpio $NAME invalid direction [$DIR] not (in,out)" > /dev/kmsg
    fi
}

# To debug jumper
setup_gpio BMC_DEBUG_JUMPER1                GPIOG5 in
setup_gpio BMC_DEBUG_JUMPER2                GPIOB1 in
setup_gpio BMC_DEBUG_JUMPER3                GPIOB2 in
# OCP Debug Card present event, high active
setup_gpio DEBUG_PRSNT                      GPIOG2 in

# Indicate the PCH power good on the Netlake. From COME D83
setup_gpio PWRGD_PCH_PWROK                  GPIOF4 in
# Reserved for power button event input, also pass through to BMC Pin40
setup_gpio PWR_BTN_L                        GPIOP4 in
# Reserved for reset button event input, also pass through to BMC Pin76
setup_gpio RST_BTN_L                        GPIOP2 in

# BMC Power Good, output to CPLD
setup_gpio BMC_PWRGD_R                      GPIOV4 out 1
# BMC ready event to COME (COME A85)
setup_gpio FM_BMC_READY_R_L                 GPIOP0 out 0
# Reserved for Power button event output, which pass through from BMC Pin160
setup_gpio BMC_PTH_PWR_BTN_L                GPIOP5 out 1
# Reserved for reset button event output, which pass through from BMC Pin121
setup_gpio BMC_PTH_RST_BTN_L                GPIOP3 out 1

setup_gpio BMC_I2C1_EN                      GPIOG0 out 0
setup_gpio BMC_I2C2_EN                      GPIOF1 out 0
# JTAG MUX
setup_gpio MUX_JTAG_SEL_0                   GPIOF0 out 0
setup_gpio MUX_JTAG_SEL_1                   GPIOF5 out 0
# Mux select signal for BMC to program IOB flash (SPI)
setup_gpio IOB_FLASH_SEL                    GPIOG4 out 0
# SPI Mux select to COME (B89) and PROT module
setup_gpio SPI_MUX_SEL                      GPIOQ6 out 0

# BMC CPU_RST#
setup_gpio BMC_CPU_RST                      GPION2 in
# To SCM CPLD, reserved.
setup_gpio BMC_GPIO126_USB2APWREN           GPION4 in
# CPU power good event indicates to BMC
setup_gpio COME_ISO_PWRGD_CPU_LVC3          GPIOO2 in
# CATERR/MSMI event from SOC
setup_gpio FM_CPU_MSMI_CATERR_LVT3_BUF_N    GPIOM3 in
# Non-maskable Interrupt to BMC, from COMe B95
setup_gpio ISO_FM_BMC_NMI_L                 GPIOO3 in
# Reserve for BMC to enable Netlake power, to COMe A93
setup_gpio ISO_FM_BMC_ONCTL_L               GPIOG6 out 0
# COMe FPGA CRC error event indication, from COMe C69
setup_gpio ISO_FPGA_CRC_ERROR               GPIOQ0 in
# Netlake FPGA asset it to inform BMC for PCIe hot plug (From COME A16)
setup_gpio ISO_SMB_FPGA_VPP_ALERT_L         GPIOG3 in


#!/bin/bash
#
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA

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

# FRU EEPROM
i2c_device_add 3 0x56 24c64    # SCM FRU EEPROM#2
i2c_device_add 6 0x53 24c64    # FCB_B EEPROM
i2c_device_add 8 0x51 24c64    # BMC EEPROM

# FPGA / CPLD
i2c_device_add 12 0x60 mcbcpld

# CPU IPMI
ulimit -q 1024000
i2c_device_add 5 0x1010 slave-mqueue  # mqueue for ipmi from COMe CPU


#!/bin/sh
#
# Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#
#shellcheck disable=SC1091
#shellcheck disable=SC2086
. /usr/local/bin/openbmc-utils.sh

ret=0
trap cleanup_spi INT TERM QUIT EXIT

PIDFILE="/var/run/spi_util.pid"
check_duplicate_process()
{
    exec 2>$PIDFILE
    flock -n 2 || (echo "Another process is running" && exit 1)
    ret=$?
    if [ $ret -eq 1 ]; then
      exit 1
    fi
    pid=$$
    echo $pid 1>&200
}

remove_pid_file()
{
    if [ -f $PIDFILE ]; then
        rm $PIDFILE
    fi
}

SPI1_DRIVER="1e630000.spi"
ASPEED_SMC_PATH="/sys/bus/platform/drivers/spi-aspeed-smc/"

mtd_driver_unbind_spi1() {
    [ -e ${ASPEED_SMC_PATH}${SPI1_DRIVER} ] && echo ${SPI1_DRIVER} > ${ASPEED_SMC_PATH}unbind
}

mtd_driver_rebind_spi1() {
    # Sometime kernel may complain "vmap allocation for size 268439552 failed: use vmalloc=<size> to increase size"
    # until now the root cause is not clear, still need more investigation
    mtd_driver_unbind_spi1
    echo ${SPI1_DRIVER} > ${ASPEED_SMC_PATH}bind

    # add more delay to make sure the driver has probe done.
    sleep 1;

    SPI1_MTD_PATH=$(realpath /run/devmap/spi-devices/spi1-flash)
    if [ ! -e "$SPI1_MTD_PATH" ]; then
        echo "cannot find SPI1 MTD path [$SPI1_MTD_PATH]"
        exit 1
    fi
    SPI1_MTD_INDEX=$(echo "$SPI1_MTD_PATH" | sed 's_/dev/mtd__g')
}

read_spi1_dev(){
    dev=$1
    file=$2
    echo "Reading ${dev} to $file..."
    flashrom -p linux_mtd:dev=$SPI1_MTD_INDEX -r "$file"
}

write_spi1_dev(){
    dev=$1
    file=$2
    echo "Writing $file to ${dev}..."

    tmpfile="/tmp/temp_image"
    flashsize=$(flashrom -p linux_mtd:dev=$SPI1_MTD_INDEX | grep -i kB | xargs echo | cut -d '(' -f 2 | cut -d ' ' -f 0)
    targetsize=$((flashsize * 1024))

    case ${dev} in
        "COME_BIOS"|"PROT"|"IOB_FPGA")
        # store to the temp-file
        cp "$file" "$tmpfile"
        ;;
    esac

    #extend the temp-file
    filesize=$(stat -c%s $tmpfile)
    echo $filesize
    add_size=$((targetsize - filesize))
    echo $add_size
    dd if=/dev/zero bs="$add_size" count=1 | tr "\000" "\377" >> "$tmpfile"

    echo flashrom -p linux_mtd:dev=$SPI1_MTD_INDEX -w "$tmpfile"

    flashrom -p linux_mtd:dev=$SPI1_MTD_INDEX -w "$tmpfile"

    case ${dev} in
        "IOB_FPGA")
            # TODO: add reset signal component after programed
        ;;
        "COME_BIOS")
            # no need action, let user run command to reset COMe [wedge_power.sh reset]
        ;;
        "PROT")
            # TODO: need confirm, this path use only for debuging
        ;;
    esac
}

erase_spi1_dev(){
    flashrom -p linux_mtd:dev=$SPI1_MTD_INDEX -E
}

config_spi1_pin_and_path(){
    dev=$1

    # enable i2c buff BMC able to access
    #  i2c-0  for COME CPLD  (0x1f)
    #  i2c-1  for SCM CPLD   (0x35)
    gpiocli -s BMC_I2C1_EN set-value 1
    gpiocli -s BMC_I2C2_EN set-value 1
    case ${dev} in
        "IOB_FPGA")
            # SCM CPLD: BMC_SPI1
            #                    to (X) IOB_FPGA   0
            #                       ( ) COME_BIOS  1
            #                       ( ) PRoT       2
            i2cset -f -y 1 0x35 0x34 0x0

            # BMC GPIO: IOB_FLASH
            #                    to ( ) IOB_FPGA 0
            #                       (X) BMC_SPI1 1
            gpiocli -s IOB_FLASH_SEL set-value 1
        ;;
        "COME_BIOS")
            # SCM CPLD: BMC_SPI1
            #                    to ( ) IOB_FPGA   0
            #                       (X) COME_BIOS  1
            #                       ( ) PRoT       2
            i2cset -f -y 1 0x35 0x34 0x1

            # BMC GPIO: BIOS_FLASH
            #                    to ( ) NetLake CPU 0
            #                       (X) BMC_SPI1    1
            gpiocli -s SPI_MUX_SEL set-value 1

            # COME CPLD: BIOS_FLASH_CS0
            #                    to ( ) BMC_SPI1_CS1 0x7
            #                       (X) BMC_SPI1_CS0 0x5
            #                       ( ) SPI_PCH_CS0 0x4
            #                       ( ) SPI_PCH_CS1 0x6
            i2cset -f -y 0 0x1f 0xa 0x5
        ;;
        "PROT")
            # TODO: need confirm, this path use only for debuging
            # SCM CPLD: set BMC_SPI1
            #                    to ( ) IOB_FPGA   0
            #                       (X) COME_BIOS  1
            #                       ( ) PRoT       2
            i2cset -f -y 1 0x35 0x34 0x2
        ;;
    esac
    mtd_driver_rebind_spi1
}

cleanup_spi(){
    if [ $ret -eq 1 ]; then
        exit 1
    fi

    # select muxing FLASH to normal mode
    # BMC GPIO: IOB_FLASH
    #                    to (X) IOB_FPGA    0
    #                       ( ) BMC_SPI1    1
    gpiocli -s IOB_FLASH_SEL set-value 0
    # BMC GPIO: BIOS_FLASH
    #                    to (X) NetLake CPU 0
    #                       ( ) BMC_SPI1    1
    gpiocli -s SPI_MUX_SEL set-value 0

    rm -rf /tmp/*_spi*_tmp
    remove_pid_file
}

operate_spi1_dev(){
    op=$1
    dev=$2
    file=$3
    ## Operate devices ##
    case ${op} in
        "read")
                read_spi1_dev "$dev" "$file"
        ;;
        "write")
                if [ ! -f "$file" ]; then
                    echo "$file not exist!!!"
                    exit 1
                fi
                write_spi1_dev "$dev" "$file"
        ;;
        "erase")
                erase_spi1_dev "$dev"
        ;;
        *)
            echo "Operation $op is not defined."
        ;;
    esac
    mtd_driver_unbind_spi1
}

ui(){
    . /usr/local/bin/openbmc-utils.sh
    op=$1
    spi=$2

    ## Open the path to device ##
    case ${spi} in
        "spi1")
            dev=$3
            file=$4
            config_spi1_pin_and_path "$dev"
            operate_spi1_dev "$op" "$dev" "$file"
        ;;
        *)
            echo "No such SPI bus."
            return 1
        ;;
    esac
}

usage(){
    program=$(basename "$0")
    echo "Usage:"
    echo "  $program <op> <spi> <spi device> <file>"
    echo "    <op>          : read, write, erase"
    echo "    <spi>         : spi1"
    echo "    <spi1 device> : IOB_FPGA, COME_BIOS"
    echo ""
    echo "Examples:"
    echo "  $program write spi1 IOB_FPGA iofpga.bit"
    echo ""
}

check_parameter(){
    program=$(basename "$0")
    op=$1
    spi=$2

    # check operations.
    case ${op} in
        "read" | "write" | "erase")
            ;;
        *)
            return 1
            ;;
    esac

    case ${spi} in
        # check spi 1 device and parameters.
        "spi1")
            dev=$3
            file=$4
            case ${dev} in
                "IOB_FPGA"|"COME_BIOS")
                    case ${op} in
                        "read" | "write")
                            if [ $# -ne 4 ]; then
                                return 1
                            fi
                            ;;
                        "erase")
                            if [ $# -ne 3 ]; then
                                return 1
                            fi
                            ;;
                    esac
                    ;;
                "PROT")
                    echo "PRoT upgrade not support yet"
                    return 1
                    ;;
                *)
                    return 1
                    ;;
            esac
            ;;

        # check device and parameters fail.
        *)
            return 1
            ;;
    esac

    return 0
}

# check_duplicate_process - to check if there is the duplicate spi util process, will return fail and stop execute command.
check_duplicate_process

# check_parameter - to check command parameters
check_parameter "$@"
is_par_ok=$?

if [ $is_par_ok -eq 0 ]; then
    ui "$@"
    exit 0
else
    usage
    exit 1
fi


#!/bin/bash
#
# Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

# Read AST2620 register SCU014 [23:16] to retrieve the board hardware revision.

SCU014_REG=0x1e6e2014
HW_REV_BIT=16
BOARD_REV=$(($(($(devmem "${SCU014_REG}") >> "${HW_REV_BIT}")) & 0xff))
echo "ASPEED Chip Revision: A${BOARD_REV}"


#!/bin/bash
#
# Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

# shellcheck disable=SC1091
# read the Hardware revision from MCB CPLD register
. /usr/local/bin/openbmc-utils.sh

wedge_board_rev


#!/bin/bash
#
# Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

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

printf "%-1s | %-3s | %-30s\n" "v" "dir" "GPIONAME"
for i in /tmp/gpionames/*
do
   gpio="$(basename "$i")"
   val="$(gpio_get_value "$gpio")"
   direction="$(gpio_get_direction "$gpio")"
   printf "%-1s | %-3s | %-30s\n" "$val" "$direction" "$gpio"
done


#!/bin/bash
#
# Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

# This utility prints the meta information for specified boot flash
# mtd partition
START_OFFSET_KB=960
LEN_KB=64

usage() {
    echo "Usage $0 [flash0|flash1]"
}

case "$1" in
    flash0)
        mtd="$(grep flash0 /proc/mtd | awk '{print $1}' | tr -d ':')"
        ;;
    flash1)
        mtd="$(grep flash1 /proc/mtd | awk '{print $1}' | tr -d ':')"
        ;;
    *)
        usage
        exit 1
        ;;
esac

dd if=/dev/"$mtd" of=/tmp/."$1"_meta bs=1K skip="$START_OFFSET_KB" count="$LEN_KB"
strings /tmp/."$1"_meta


#!/bin/sh
#
# Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

OOB_MDIO_BUS=2
OOB_PHY_ADDR=0x12

mode=$1
port=$2
reg_addr=$3

usage() {
    echo "OOB MDIO Utility to access Marvell 88E6321 OOB Switch"
    echo "Usage:"
    echo "$0 read <port> <reg_addr> "
    echo "$0 write <port> <reg_addr> <data>"
}

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

if [ "$mode" = "write" ]; then
    if [ $# -ne 4 ]; then
        usage
        exit 1;
    fi
    ctrl_cmd=$(( 0x9000 | (0x1 << 10) | ( (0x10 + port) << 5) | reg_addr ))
    data=$3
    mdio-util -m "$OOB_MDIO_BUS" -p "$OOB_PHY_ADDR" -w 0x1 -d "$data"
    mdio-util -m "$OOB_MDIO_BUS" -p "$OOB_PHY_ADDR" -w 0x0 -d "$ctrl_cmd"
elif [ "$mode" = "read" ]; then
    if [ $# -ne 3 ]; then
        usage
        exit 1;
    fi
    ctrl_cmd=$(( 0x9000 | (0x2 << 10) | ( (0x10 + port) << 5) | reg_addr ))
    ctrl_cmd=$(printf "0x%08X" "$ctrl_cmd")
    mdio-util -m "$OOB_MDIO_BUS" -p "$OOB_PHY_ADDR" -w 0x0 -d "$ctrl_cmd"
    mdio-util -m "$OOB_MDIO_BUS" -p "$OOB_PHY_ADDR" -r 0x1
else
    usage
    exit 1;
fi


#!/bin/bash
#
# Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

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

trap handle_signal INT TERM QUIT

# mdio prints in the format
# "Write to PHY 0x12.0x0, value is 0x9a00"
# "Read from PHY 0x12.0x1, value is 0x4e09"
MDIO_READ_PATTERN_DETECT="^Read .* value is 0x[a-fA-F0-9]*$"
MDIO_READ_PATTERN_EXTRACT="^Read .* value is (0x[a-fA-F0-9]*)$"

# Global variable to stack tabs for formatting
tab=""

usage() {
    echo "Read 88E6321 (oob switch) port status registers"
    echo ""
    echo "# To dump all port status"
    echo "oob-status.sh"
    echo "# To dump port status for ports in 0, 1, 2, 3, 4, 5, 6"
    echo "oob-status.sh [Port(s)]"
    echo "# To print only link status"
    echo "oob-status.sh link_status [Port(s)]"
    echo "# To print only link speed"
    echo "oob-status.sh link_speed [Port(s)]"
    echo ""
    echo "Example:"
    echo ""
    echo "oob-status.sh link_status 0 3"
    echo "Link Status:"
    echo "	Port 0: Link Up"
    echo "	Port 3: Link Up"

}

handle_signal() {
    echo "Exiting because of signal" >&2
    exit 1
}

check_sts_args() {
    # Convert arguments to port numbers
    local port
    ret="$*"
    if [ $# -lt 1 ]; then
       # No arguments: do all ports
       ret="0 1 2 3 4 5 6"
    else
        for port in "$@"; do
            if [ "$port" -lt 0 ] || [ "$port" -gt 6 ]; then
                echo "Invalid port $port"
                exit 1
            fi
        done
    fi
    echo "$ret"
}

do_read_lnksts() {
    local result ports port val
    ports="$*"

    printf "%sLink status:\n" "$tab"
    tab="	$tab"

    for port in $ports; do
        port=${port^^}
        result=$(oob-mdio-util.sh read "$port" 0x0 \
            | grep -e "$MDIO_READ_PATTERN_DETECT" \
            | sed -E "s/$MDIO_READ_PATTERN_EXTRACT/\1/")
        val=$(( (result >> 11) & 0x1 ))
        case "$val" in
            0)
                link_state="Link Down"
                ;;
            1)
                link_state="Link Up  "
                ;;
        esac
        printf "%sPort: %s - %s\n" "$tab" "$port" "$link_state"
    done
    tab=${tab:1}
}

do_read_spdsts() {
    local result ports port val
    ports="$*"

    printf "%sLink speed:\n" "$tab"
    tab="	$tab"

    for port in $ports; do
        port=${port^^}
        result=$(oob-mdio-util.sh read "$port" 0x0 \
            | grep -e "$MDIO_READ_PATTERN_DETECT" \
            | sed -E "s/$MDIO_READ_PATTERN_EXTRACT/\1/")
        val=$(( (result >> 10) & 0x1 ))
        case "$val" in
            0)
                duplex="half-duplex"
                ;;
            1)
                duplex="full-duplex"
                ;;
        esac

        val=$(( (result >> 8) & 0x3 ))
        case "$val" in
            0)
                speed="10   Mb/s"
                ;;
            1)
                speed="100  Mb/s"
                ;;
            2)
                speed="1000 Mb/s"
                ;;
        esac
        printf "%sPort: %s - %s %s \n" "$tab" "$port" "$speed" "$duplex"
    done
    tab=${tab:1}
}

read_lnksts() {
    ports=$(check_sts_args "$@")
    do_read_lnksts "$ports"
}

read_spdsts() {
    ports=$(check_sts_args "$@")
    do_read_spdsts "$ports"
}

read_status() {
    ports=$(check_sts_args "$@")
    printf "%sStatus:\n" "$tab"
    tab="	$tab"
    do_read_lnksts "$ports"
    do_read_spdsts "$ports"
    tab=${tab:1}
}

# Only allow one instance of script to run at a time.
script=$(realpath "$0")
exec 100< "$script"
flock -n 100 || { echo "ERROR: $0 already running" && exit 1; }

command="$1"

case "$command" in
    link_status)
        shift
        read_lnksts "$@"
        ;;
    link_speed)
        shift
        read_spdsts "$@"
        ;;
    "--help")
        usage
        exit 1
        ;;
    *)
        read_status "$@"
        ;;
esac


#!/bin/bash

logger "Update eth0 IPv6 link local address after NC-SI MAC address configured"

# shellcheck disable=SC2086
mac_to_ll() {
  IFS=':'; set $1; unset IFS
  echo "fe80::$(printf %x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6" | \
    sed -E 's/:0+/:/g; s/:{3,}/::/; s/:$/:0/'
}

exp_ll=""
ll=""

for _ in {1..30}; do
  # wait getting address from NC-SI
  if [ "$(cat /sys/class/net/eth0/addr_assign_type)" = "3" ]; then
    exp_ll=$(mac_to_ll "$(cat /sys/class/net/eth0/address)")
    rc_exp_ll=$?
    ll=$(ip -6 addr show dev eth0 scope link | sed -e's/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d')
    rc_ll=$?

    if [ "$ll" = "$exp_ll" ]; then
      break;
    fi
    # re-generate link-local address
    ip -6 addr flush dev eth0 scope link
    echo 1 > /proc/sys/net/ipv6/conf/eth0/addr_gen_mode
    echo 0 > /proc/sys/net/ipv6/conf/eth0/addr_gen_mode
    break;
  fi
  sleep 1
done

if [ "$ll" != "$exp_ll" ]; then
  for i in {1..100}; do
    usleep 10000
    ll=$(ip -6 addr show dev eth0 scope link | sed -e's/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d')
    if [ "$ll" = "$exp_ll" ]; then
      break;
    elif [ "$ll" != "$exp_ll" ] && [ "$i" -eq 100 ]; then
      logger "Failed to set address from MAC"
    else
      continue;
    fi
  done
fi

logger "Restart eth0 after MAC and Linklock addr update"
ifdown eth0
sleep 1
ifup eth0 &


#!/bin/sh
#
# Copyright 2015-present Facebook. All Rights Reserved.
#
### BEGIN INIT INFO
# Provides:          setup-front-paneld
# Required-Start:
# Required-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description: Start front panel control daemon
### END INIT INFO

echo -n "Setup Front Panel Daemon..."
runsv /etc/sv/front-paneld > /dev/null 2>&1 &
echo "done."


#!/bin/bash
#
# Copyright 2015-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

### BEGIN INIT INFO
# Provides:          setup-fan
# Required-Start:    board-id
# Required-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description: Set fan speed
### END INIT INFO

echo -n "Setup fan speed... "
/usr/local/bin/fan-util --set 100
echo "Setup fan speed done."


#!/bin/sh
#
# Copyright 2015-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

### BEGIN INIT INFO
# Provides:          setup-sensord
# Required-Start:
# Required-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description: Setup sensor monitoring
### END INIT INFO

echo -n "Setup gpio monitoring for netlakeMTP... "

runsv /etc/sv/gpiod > /dev/null 2>&1 &

echo "done."


#!/bin/sh
# first byte: ME i2c-address is 0x10, second byte: 0x10 as BMC's slave address when get response
echo slave-mqueue 0x1010 > /sys/bus/i2c/devices/i2c-1/new_device
exec /usr/local/bin/ipmbd 1 1


#! /bin/sh
#
# Copyright 2015-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

### BEGIN INIT INFO
# Provides:          ipmbd
# Required-Start:
# Required-Stop:
# Default-Start:     S
# Default-Stop:      0 6
# Short-Description: Provides ipmb message tx/rx service
#
### END INIT INFO

echo -n "Starting IPMB Rx/Tx Daemon.."
sleep 10
ulimit -q 1024000

runsv /etc/sv/ipmbd_1 > /dev/null 2>&1 &

echo "Done."


#!/bin/sh

# PLATFORM MAY CHOOSE TO OVERRIDE THIS FILE
echo -n "Starting mTerm console server..."
runsv /etc/sv/mTerm > /dev/null 2>&1 &
echo "done."


#!/bin/sh
#
# Copyright 2015-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

### BEGIN INIT INFO
# Provides:          setup-ncsid
# Required-Start:
# Required-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description: Setup sensor monitoring
### END INIT INFO

echo -n "Setup ncsid for BMC "

./usr/local/bin/fruid-util nic > /dev/null
if [ $? == 0 ]; then
runsv /etc/sv/ncsid > /dev/null 2>&1 &
fi

echo "done."


#!/bin/sh
. /usr/local/fbpackages/utils/ast-functions
KV_STORE=/mnt/data/kv_store

#get power on reset config
power_on_reset_conf="$KV_STORE/server_power_on_reset_cfg"
last_power_state_conf="$KV_STORE/server_last_power_state"

# control the system power based on $power_on_reset_conf
power_on_reset_cfg_val=$(cat $power_on_reset_conf)
last_power_state_val=$(cat $last_power_state_conf)

if [ "$(is_bmc_power_on_reset)" -eq 1 ]; then
    if [ "$power_on_reset_cfg_val" = "on" ]; then
      /usr/local/bin/power-util server on
    elif [ "$power_on_reset_cfg_val" = "lps" ] && [ "$last_power_state_val" = "on" ]; then
      /usr/local/bin/power-util server on
    fi
fi
echo "Done"


#!/bin/sh
#
# Copyright 2014-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

addr=$(/usr/bin/mac-util --get)

if ! [ "$addr" = "ff:ff:ff:ff:ff:ff" ]
then
  ifconfig eth1 hw ether "$addr"
fi

dhclient eth1 > /dev/null 2>&1 &


#!/bin/bash
#
# Copyright 2014-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

MAX_RETRY=5
NTP_CMD=/usr/sbin/ntpq

##### sync time from NTP server
retry=0
while [ $retry -lt "$MAX_RETRY" ]
do
  if ! $NTP_CMD -p | grep '^\*' > /dev/null ; then
    retry=$((retry+1))
    sleep 1
  else
    logger -s -p user.crit -t sync-date "Syncing up BMC time from NTP"
    exit 0
  fi
done
logger -s -p user.info -t sync-date "Syncing up BMC time from NTP failed because NTP server not exist"

echo Syncing up BMC time with server...

# Use standard IPMI command 'get-sel-time' to read RTC time
time=$(/usr/local/bin/me-util 0x28 0x48)
ret=$?
if [ $ret = "0" ] ; then
  date -s @$((16#$(echo "$time" | awk '{print $4$3$2$1}')))
  ret=$?
  if [ $ret = "0" ]; then
      logger -s -p user.crit -t sync-date "Syncing up BMC time from Host(ME)"
      exit 0
  fi
fi

##### sync time from default time
logger -s -p user.crit -t sync-date "Syncing up BMC time from Default(OpenBMC build time)"


#!/bin/sh

#TODO: Add functions as shell's lib in /usr/local/fbpackages/utils/ast-functions#
echo "Setup sensor monitoring for NETLAKEMTP... "

FRUS="server bmc pdb fio nic"

exec /usr/local/bin/sensord $FRUS


#!/bin/sh
#
# Copyright 2020-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

### BEGIN INIT INFO
# Provides:          setup-sensord
# Required-Start:
# Required-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description: Setup sensor monitoring
### END INIT INFO

echo "Setup sensor monitoring for NETLAKEMTP... "

runsv /etc/sv/sensord > /dev/null 2>&1 &
#enable the register of VIN sampling of ADM1278
echo "done."


#!/bin/bash

# Copyright 2022-present Facebook. All Rights Reserved.

#
# Protect against multiple power requests
#
BOARD_UTILS_TIMEOUT=20
# Worst case in FPGA design is 10 seconds for power to drain before power on
# again. Add some buffer for time variation, errors, and serializing
# simultaneous requests.
if [[ "${FLOCKER}" != "$0" ]]; then
    exec env FLOCKER="$0" flock -w "$BOARD_UTILS_TIMEOUT" "$0" "$0" "$@"
fi

wedge_board_type() {
    echo 'SANDIA'
}

SEQ_STR="sequenced"
ON_STR="powered on"

wait_for_sequencing() {
    PSEQ=/sys/bus/platform/devices/pseq
    TIMEOUT=12
    COUNT=0
    if [ -e ${PSEQ} ]; then
        while grep -q "${SEQ_STR}" ${PSEQ}/power_state;
        do
            if [ ${COUNT} -ge ${TIMEOUT} ]; then
                #Error: Time out
                return 1
            fi
            sleep 1
            COUNT=$(( COUNT + 1 ))
        done
    fi

    return 0
}

userver_power_is_on() {
    PSEQ=/sys/bus/platform/devices/pseq
    if [ -e ${PSEQ} ]; then
        if grep -q "${ON_STR}" ${PSEQ}/power_state; then
            return 0 #powered on
        fi
    else
        i2cset -f -y 2 0x21 0x90
        i2cset -f -y 2 0x22 0x40
        i2cset -f -y 2 0x23 0x01
        i2cset -f -y 2 0x24 0x00
        i2cset -f -y 2 0x20 0x01
        power_state=$(i2cget -f -y 2 0x26)
        power_state=$((power_state >> 1))
        power_state=$((power_state & 0x03))
        if [ $power_state -eq 2 ]; then
            return 0 #powered on
        fi
    fi

    return 1 # not powered on
}

userver_power_on() {
    if ! wait_for_sequencing; then
        return 1
    fi

    # Safe to perform power operation
    MSD=/sys/bus/platform/devices/msd
    for ((i=0; i<20; i++)); do
        if [ -w ${MSD} ]; then
            echo 0 > ${MSD}/cfg7
            echo power-on > ${MSD}/control
            break
        else
            # Write 0x00000000 at Cyclonus 0x0000103c
            if ! i2cset -f -y 2 0x21 0x3c &> /dev/null; then
                sleep 10
                continue
            fi
            i2cset -f -y 2 0x22 0x10
            i2cset -f -y 2 0x23 0x00
            i2cset -f -y 2 0x24 0x00
            i2cset -f -y 2 0x25 0x00
            i2cset -f -y 2 0x26 0x00
            i2cset -f -y 2 0x27 0x00
            i2cset -f -y 2 0x28 0x00
            i2cset -f -y 2 0x20 0x00

	    # Trigger rising edge of bit 5 at Cyclonus 0x0000103c
            i2cset -f -y 2 0x25 0x20
            i2cset -f -y 2 0x20 0x00
            break
        fi
    done

    if wait_for_sequencing; then
        return 0
    else
        return 1
    fi
}

userver_power_off() {
    if ! wait_for_sequencing; then
        return 1
    fi

    # Safe to perform power operation
    MSD=/sys/bus/platform/devices/msd
    XIL=/sys/bus/platform/devices/xil
    if [ -w ${MSD} ]; then
        echo 0 > ${MSD}/cfg7
        echo power-off > ${MSD}/control
        if [ -w ${XIL} ]; then
            # Reset SMB power
            echo 0 > ${XIL}/cfg7
            echo 0x400 > ${XIL}/cfg7
        else
            #Error: XIL driver not loaded
            return 1
        fi
    else
        # Write 0x00000000 at Cyclonus 0x0000103c
        i2cset -f -y 2 0x21 0x3c
        i2cset -f -y 2 0x22 0x10
        i2cset -f -y 2 0x23 0x00
        i2cset -f -y 2 0x24 0x00
        i2cset -f -y 2 0x25 0x00
        i2cset -f -y 2 0x26 0x00
        i2cset -f -y 2 0x27 0x00
        i2cset -f -y 2 0x28 0x00
        i2cset -f -y 2 0x20 0x00

        # Trigger rising edge of bit 3 at Cyclonus 0x0000103c
        i2cset -f -y 2 0x25 0x08
        i2cset -f -y 2 0x20 0x00
    fi

    if wait_for_sequencing; then
        return 0
    else
        return 1
    fi
}

userver_reset() {
    if ! wait_for_sequencing; then
        return 1
    fi

    MSD=/sys/bus/platform/devices/msd
    XIL=/sys/bus/platform/devices/xil
    if [ -w ${MSD} ]; then
        echo 0 > ${MSD}/cfg7
        echo cold-reset > ${MSD}/control
        if [ -w ${XIL} ]; then
            # Reset SMB power
            echo 0 > ${XIL}/cfg7
            echo 0x400 > ${XIL}/cfg7
        else
            #Error: XIL driver not loaded
            return 1
        fi
    else
        # Write 0x00000000 at Cyclonus 0x0000103c
        i2cset -f -y 2 0x21 0x3c
        i2cset -f -y 2 0x22 0x10
        i2cset -f -y 2 0x23 0x00
        i2cset -f -y 2 0x24 0x00
        i2cset -f -y 2 0x25 0x00
        i2cset -f -y 2 0x26 0x00
        i2cset -f -y 2 0x27 0x00
        i2cset -f -y 2 0x28 0x00
        i2cset -f -y 2 0x20 0x00

        # Trigger rising edge of bit 6 at Cyclonus 0x0000103c
        i2cset -f -y 2 0x25 0x40
        i2cset -f -y 2 0x20 0x00
    fi

    if wait_for_sequencing; then
        return 0
    else
        return 1
    fi
}

chassis_power_cycle() {
    if ! wait_for_sequencing; then
        return 1
    fi

    MSD=/sys/bus/platform/devices/msd
    if [ -w ${MSD} ]; then
        echo 0 > ${MSD}/cfg7
        echo 0x400 > ${MSD}/cfg7
    else
        # Write 0x00000000 at Cyclonus 0x0000103c
        i2cset -f -y 2 0x21 0x3c
        i2cset -f -y 2 0x22 0x10
        i2cset -f -y 2 0x23 0x00
        i2cset -f -y 2 0x24 0x00
        i2cset -f -y 2 0x25 0x00
        i2cset -f -y 2 0x26 0x00
        i2cset -f -y 2 0x27 0x00
        i2cset -f -y 2 0x28 0x00
        i2cset -f -y 2 0x20 0x00

        # Trigger rising edge of bit 10 at Cyclonus 0x0000103c
        i2cset -f -y 2 0x26 0x04
        i2cset -f -y 2 0x20 0x00
    fi

    # Power sequncers take 10 seconds to complete.
    if wait_for_sequencing; then
        return 0
    else
        return 1
    fi
}

bmc_mac_addr() {
    mac=00:00:00:00:00:00

    hexdump -ve '1/1 "%.2x"' "$SYSFS_I2C_DEVICES"/8-0054/eeprom > /tmp/eeprom_data

    ((i = 0))
    while [[ $i -lt 512 ]]; do
        var=$( dd skip=$i count=4 if=/tmp/eeprom_data bs=1 2> /dev/null )
        if [ "$var" = "cf06" ];then
            ((i = i + 4))
            mac1=$( dd skip=$i count=2 if=/tmp/eeprom_data bs=1 2> /dev/null)
            ((i = i + 2))
            mac2=$( dd skip=$i count=2 if=/tmp/eeprom_data bs=1 2> /dev/null)
            ((i = i + 2))
            mac3=$( dd skip=$i count=2 if=/tmp/eeprom_data bs=1 2> /dev/null)
            ((i = i + 2))
            mac4=$( dd skip=$i count=2 if=/tmp/eeprom_data bs=1 2> /dev/null)
            ((i = i + 2))
            mac5=$( dd skip=$i count=2 if=/tmp/eeprom_data bs=1 2> /dev/null)
            ((i = i + 2))
            mac6=$( dd skip=$i count=2 if=/tmp/eeprom_data bs=1 2> /dev/null)

            mac=$mac1:$mac2:$mac3:$mac4:$mac5:$mac6
            break
        fi
        ((i = i + 1))
    done

    rm /tmp/eeprom_data
    echo "$mac"
}

userver_mac_addr() {
    weutil --json | jq -r '."Extended MAC Base"'
}


#!/bin/bash
#
# Copyright 2022-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
#shellcheck disable=SC1091
source /usr/local/bin/openbmc-utils.sh

#
# Will need to move some devices to dts later.
#
i2c_device_add 8 0x50 24c04
i2c_device_add 8 0x54 24c64

# Setup Chassis/PDB IDPROM
setup_chassis_idprom() {
    idp_path=$(i2cdetect -l | grep SCM_IDPROM)
    if [ -n "${idp_path}" ]; then
        bus=$(echo "${idp_path}" | tr "-" " " | awk '{print $2}')
        i2c_device_add "${bus}" 0xa0d0 24c64 #Chassis IDPROM
    fi
}

setup_chassis_idprom


#!/bin/sh
exec /usr/local/bin/ipmbd 11 3


#! /bin/bash
#
# Copyright 2015-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

### BEGIN INIT INFO
# Provides:          ipmbd
# Required-Start:
# Required-Stop:
# Default-Start:     S
# Default-Stop:      0 6
# Short-Description: Provides ipmb message tx/rx service
#
### END INIT INFO

. /usr/local/fbpackages/utils/plat-functions

echo -n "Starting IPMB Rx/Tx Daemon.."

ulimit -q 2048000

echo slave-mqueue 0x1010 > /sys/bus/i2c/devices/i2c-1/new_device
runsv /etc/sv/ipmbd_1 > /dev/null 2>&1 &

echo slave-mqueue 0x1010 > /sys/bus/i2c/devices/i2c-2/new_device
runsv /etc/sv/ipmbd_2 > /dev/null 2>&1 &

echo slave-mqueue 0x1010 > /sys/bus/i2c/devices/i2c-11/new_device
runsv /etc/sv/ipmbd_11 > /dev/null 2>&1 &

sys_sku_id=$(get_sys_sku)
if [ "$sys_sku_id" = "$SKU_SINGLE_COMPUTE" ]; then
  echo slave-mqueue 0x1010 > /sys/bus/i2c/devices/i2c-6/new_device
  runsv /etc/sv/ipmbd_6 > /dev/null 2>&1 &

  echo slave-mqueue 0x1010 > /sys/bus/i2c/devices/i2c-7/new_device
  runsv /etc/sv/ipmbd_7 > /dev/null 2>&1 &

  echo slave-mqueue 0x1010 > /sys/bus/i2c/devices/i2c-8/new_device
  runsv /etc/sv/ipmbd_8 > /dev/null 2>&1 &

  echo slave-mqueue 0x1010 > /sys/bus/i2c/devices/i2c-9/new_device
  runsv /etc/sv/ipmbd_9 > /dev/null 2>&1 &
fi

echo "Done."


#!/bin/sh
#
# Copyright 2018-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

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

echo Probe Ex-GPIO device
i2c_device_add 1 0x21 pca9555 #SCB Expender


#!/bin/bash
#
# Copyright 2020-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

### BEGIN INIT INFO
# Provides:          gpio-setup
# Required-Start:
# Required-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description:  Set up GPIO pins as appropriate
### END INIT INFO

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

# FM_BMC_PWRBTN_OUT_N
gpio_export_by_name  "${ASPEED_GPIO}" GPIOP0 FM_BMC_PWRBTN_OUT_N
gpio_set_value FM_BMC_PWRBTN_OUT_N 1

# GPIOP1
# set GPIOP1 output high to prevent GPIOP0 from being affected
# if GPIOP1 is set to input, GPIOP0 only 1.7V when set to output high
gpio_export_by_name  "${ASPEED_GPIO}" GPIOP1 GPIOP1
gpio_set_value GPIOP1 1

# FM_BMC_RSTBTN_OUT_N
gpio_export_by_name  "${ASPEED_GPIO}" GPIOP3 FM_BMC_RSTBTN_OUT_N
gpio_set_value FM_BMC_RSTBTN_OUT_N 1

# SYS_SKU_ID0_R
gpio_export_by_name  "${ASPEED_GPIO}" GPIOC4 SYS_SKU_ID0_R

# SYS_SKU_ID1_R
gpio_export_by_name  "${ASPEED_GPIO}" GPIOX2 SYS_SKU_ID1_R

# MB_P12V_HS_EN_N
gpio_export_by_name  "${ASPEED_GPIO}" GPIOC5 MB_P12V_HS_EN_N
gpio_set_value MB_P12V_HS_EN_N 0

# FM_BIC_DEBUG_SW_N_R
gpio_export_by_name  "${ASPEED_GPIO}" GPIOD2 FM_BIC_DEBUG_SW_N_R
gpio_set_value FM_BIC_DEBUG_SW_N_R 0

# PWRGD_CPUPWRGD_LVC1
gpio_export_by_name  "${ASPEED_GPIO}" GPIOR6 PWRGD_CPUPWRGD_LVC1

# BIC_EXTRST
gpio_export_by_name  "${ASPEED_GPIO}" GPIOS6 BIC_EXTRST
gpio_set_value BIC_EXTRST 1

# BIC_FWSPICK
gpio_export_by_name  "${ASPEED_GPIO}" GPIOD0 BIC_FWSPICK
gpio_set_value BIC_FWSPICK 0

# BIC_SRST
gpio_export_by_name  "${ASPEED_GPIO}" GPIOD1 BIC_SRST
gpio_set_value BIC_SRST 1

#SCB IO-Expender
gpio_export_by_offset 1-0021 0 BMC_UART_SEL0
gpio_set  BMC_UART_SEL0  0
gpio_export_by_offset 1-0021 1 BMC_UART_SEL1
gpio_set  BMC_UART_SEL1  0
gpio_export_by_offset 1-0021 2 BMC_UART_SEL2
gpio_set  BMC_UART_SEL2  0
gpio_export_by_offset 1-0021 3 BMC_UART_SEL3
gpio_set  BMC_UART_SEL3  0
gpio_export_by_offset 1-0021 4 BMC_UART_SEL4
gpio_export_by_offset 1-0021 5 BMC_UART_MUX_SEL_N
gpio_set  BMC_UART_MUX_SEL_N  0
gpio_export_by_offset 1-0021 6 FM_PWRGD_SCB_R_PWRGD_BUF
gpio_export_by_offset 1-0021 7 FP_PWR_LED_BMC
gpio_export_by_offset 1-0021 8 FP_STS_LED_BMC
gpio_export_by_offset 1-0021 9 BMC_FP_LED_MUX_SEL_N
gpio_export_by_offset 1-0021 10 PWR_BTN_QS_N_BMC
gpio_export_by_offset 1-0021 11 RST_BTN_QS_N_BMC
gpio_export_by_offset 1-0021 12 DC_SCM_FW_RDY_R_N

# FM_BMC_READY_PLD_R
gpio_export_by_name  "${ASPEED_GPIO}" GPIOV5 FM_BMC_READY_PLD_R
gpio_set_value FM_BMC_READY_PLD_R 0


#!/bin/sh
#
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA

### BEGIN INIT INFO
# Provides:          setup-por
# Required-Start:
# Required-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description: Power on Server
### END INIT INFO

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

DEF_PWR_ON=1
TO_PWR_ON=

check_por_config() {
  TO_PWR_ON=0

  if POR=$(kv get "server_por_cfg" persistent); then
    echo "server_por_cfg = $POR"
    if [ "$POR" = "lps" ]; then
      if LS=$(kv get "pwr_server_last_state" persistent); then
        if [ "$LS" = "on" ]; then
          TO_PWR_ON=1;
        fi
      else
        TO_PWR_ON=$DEF_PWR_ON
      fi
    elif [ "$POR" = "on" ]; then
      TO_PWR_ON=1;
    fi
  else
    echo "cannot get server_por_cfg"
    TO_PWR_ON=$DEF_PWR_ON
  fi
}

mb_server_power_on() {
  if [ "$(is_bmc_por)" -eq 1 ]; then
    check_por_config
    if [ $TO_PWR_ON -eq 1 ]; then
      /usr/local/bin/power-util mb on
    fi
  fi
}

mb_server_power_on


#!/bin/sh
#
# Copyright 2021-present Facebook. All Rights Reserved.
#
# This program file 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; version 2 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

MAX_RETRY=15
NTP_CMD=/usr/sbin/ntpq
ME_CMD=/usr/local/bin/me-util
SEL_TIME_RESPONSE_LEN=12
SYNC_TIME_OK=0

NETFN_STORAGE_REQ="0x28" #after shift left 2 bits
CMD_GET_SEL_TIME="0x48"

##### sync time from NTP server
retry=0
while [ $retry -lt "$MAX_RETRY" ]
do
  if ! $NTP_CMD -p | grep '^\*' > /dev/null ; then
    retry=$((retry+1))
    sleep 1
  else
    logger -s -p user.info -t sync-date "Syncing up BMC time from NTP"
    exit 0
  fi
done

##### sync time from Host

retry=0
while [ $retry -lt "$MAX_RETRY" ]
do
  output=$("$ME_CMD" mb "$NETFN_STORAGE_REQ" "$CMD_GET_SEL_TIME")

  # sync BMC time only when ME returns correct response length
  if [ ${#output} = "$SEL_TIME_RESPONSE_LEN" ] ; then
    time_hex0=$(echo "$output" | cut -d' ' -f1 | sed 's/^0*//') # get byte0
    time_hex1=$(echo "$output" | cut -d' ' -f2 | sed 's/^0*//') # get byte1
    time_hex2=$(echo "$output" | cut -d' ' -f3 | sed 's/^0*//') # get byte2
    time_hex3=$(echo "$output" | cut -d' ' -f4 | sed 's/^0*//') # get byte3

    # change hexadecimal to decimal
    time_dec=$((0x$time_hex3 << 24 | 0x$time_hex2 << 16 | 0x$time_hex1 << 8 | 0x$time_hex0))

    # change decimal number to date formate
    date -s @$time_dec +"%Y.%m.%d-%H:%M:%S"
    ret=$?
    if [ $ret = "$SYNC_TIME_OK" ]; then
      logger -s -p user.info -t sync-date "Syncing up BMC time from Host(ME)"
      exit 0
    else
      # get invalid SEL time
      logger -s -p user.info -t sync-date "Syncing up BMC time from Host(ME) failed because get invalid SEL time: $output"
      retry=$((retry+1))
    fi
  else
    retry=$((retry+1))
  fi
done
logger -s -p user.info -t sync-date "Syncing up BMC time from Host(ME) failed because get SEL time from ME failed"

##### sync time from default time
logger -s -p user.info -t sync-date "Syncing up BMC time from Default(OpenBMC build time)"