meta-quanta: gbs: check CPLD version

Read CPLD version by i2c bus and dump to file

Tested:
Check /run/cpld0.version file

Signed-off-by: George Hung <george.hung@quantatw.com>
Change-Id: I4b72d35dad7233dd08105fbfc6edfa04034720d2
diff --git a/meta-gbs/recipes-gbs/cpld-ver-check/files/cpld-version.service b/meta-gbs/recipes-gbs/cpld-ver-check/files/cpld-version.service
new file mode 100644
index 0000000..87f42ae
--- /dev/null
+++ b/meta-gbs/recipes-gbs/cpld-ver-check/files/cpld-version.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Report CPLD Version
+
+[Service]
+RemainAfterExit=yes
+Type=oneshot
+ExecStart=/usr/bin/cpld_version.sh
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-gbs/recipes-gbs/cpld-ver-check/files/cpld_version.sh b/meta-gbs/recipes-gbs/cpld-ver-check/files/cpld_version.sh
new file mode 100644
index 0000000..c69949c
--- /dev/null
+++ b/meta-gbs/recipes-gbs/cpld-ver-check/files/cpld_version.sh
@@ -0,0 +1,124 @@
+#!/bin/bash
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+#################################################################
+# Prints CPLD version and save it in file /run/cpld0.version
+#
+#    CPLD version format: Major.Minor.Point.Subpoint
+#
+# Major/Minor: base vendor image version, encoded in register 0x0 of the CPLD
+# I2C bus.
+#    Major = higher 4 bits of register 0x00
+#    Minor = lower 4 bits of register 0x00
+#    Point/SubPoint: reserved as 0x0 for now
+#
+#   e.g. reg[0] = 0x25 -> ver 2.5.0.0
+#
+#################################################################
+
+CPLD_I2C_BUS_NUM=13
+CPLD_I2C_BUS_ADDR='0x21'
+CPLD_I2C_BASEVER_REG='0x00'
+VER_ENV_FILE='/run/cpld0.version'
+
+#################################################################
+# Parse the byte value from i2cget and sanity checks the hex format
+# Arguments:
+#   $1: i2c_bus_num
+#   $2: i2c_bus_addr
+#   $3: i2c_reg
+# Global:
+#   'byte_val' will be written with the numeric value from i2cget
+# Returns:
+#   0 if success, non-zero if failed to get the value or value is malformed
+#################################################################
+read_and_check_i2c_get() {
+  if ! (( $# == 3 )); then
+    echo "Usage: read_and_check_i2c_get i2c_bus_num i2c_bus_addr i2c_reg"
+    return 1
+  fi
+
+  local i2c_bus_num=$1
+  local i2c_bus_addr=$2
+  local i2c_reg=$3
+
+  local i2c_val_raw
+  i2c_val_raw=$(i2cget -y "${i2c_bus_num}" "${i2c_bus_addr}" "${i2c_reg}") || return
+
+  # Verify that it is of format 0x[hex][hex].
+  local HEXBYTE_RE='^0x[0-9A-Fa-f]{2}$'
+  if ! [[ ${i2c_val_raw} =~ ${HEXBYTE_RE} ]]; then
+    echo "i2cget $* outputs invalid value: ${i2c_val_raw}"
+    return 1
+  fi
+
+  ((byte_val = i2c_val_raw))
+  return 0
+}
+
+#################################################################
+# Prints CPLD version in Major.Minor.Point.Subpoint format.
+# Each dot separated field is decimal number with no leading zeros.
+# Arguments:
+#    None
+# Globals:
+#    Write parsed version into the following global variables:
+#      cpld_ver_major
+#      cpld_ver_minor
+#      cpld_point
+#      cpld_subpoint
+# Returns:
+#    0 if success, non-zero otherwise
+#################################################################
+parse_cpld_ver() {
+  # Stores the output of read_and_check_i2c_get
+  local byte_val
+
+  # Read a byte, assign higher 4 bits to cpld_ver_major and lower 4 bits to
+  # cpld_ver_minor.
+  # e.g. cpld_ver_raw = 0x09 => major_hex = 0, minor_hex = 9
+  read_and_check_i2c_get ${CPLD_I2C_BUS_NUM} ${CPLD_I2C_BUS_ADDR} ${CPLD_I2C_BASEVER_REG} ||
+    return
+  local cpld_ver
+  ((cpld_ver = byte_val))
+  ((cpld_ver_major = cpld_ver >> 4))
+  ((cpld_ver_minor = cpld_ver & 0xf))
+  ((cpld_point = 0))
+  ((cpld_subpoint = 0))
+
+  return 0
+}
+
+main() {
+  local cpld_ver_major
+  local cpld_ver_minor
+  local cpld_point
+  local cpld_subpoint
+
+  parse_cpld_ver || return
+
+  # Write CPLD version to file.
+  cpld_ver="${cpld_ver_major}.${cpld_ver_minor}.${cpld_point}.${cpld_subpoint}"
+  echo "CPLD version ${cpld_ver}"
+  echo "${cpld_ver}" > "${VER_ENV_FILE}"
+
+  return 0
+}
+
+# Exit without running main() if sourced
+return 0 2>/dev/null
+
+main "$@"
diff --git a/meta-gbs/recipes-gbs/cpld-ver-check/gbs-cpld-ver-check.bb b/meta-gbs/recipes-gbs/cpld-ver-check/gbs-cpld-ver-check.bb
new file mode 100644
index 0000000..afe91fc
--- /dev/null
+++ b/meta-gbs/recipes-gbs/cpld-ver-check/gbs-cpld-ver-check.bb
@@ -0,0 +1,25 @@
+DESCRIPTION = "Report CPLD Version"
+PR = "r1"
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
+
+inherit systemd
+
+SRC_URI = " file://cpld_version.sh \
+            file://cpld-version.service \
+          "
+
+S = "${WORKDIR}"
+
+DEPENDS = "systemd"
+RDEPENDS_${PN} = "bash"
+
+SYSTEMD_SERVICE_${PN} = "cpld-version.service"
+
+do_install() {
+    install -d ${D}${bindir}
+    install -m 0755 ${S}/cpld_version.sh ${D}${bindir}/
+
+    install -d ${D}${systemd_system_unitdir}
+    install -m 0644 ${S}/cpld-version.service ${D}${systemd_system_unitdir}
+}