1#!/bin/bash
2# Copyright 2020 Google LLC
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
17#################################################################
18# Prints CPLD version and save it in file /run/cpld0.version
19#
20#    CPLD version format: Major.Minor.Point.Subpoint
21#
22# Major/Minor: base vendor image version, encoded in register 0x0 of the CPLD
23# I2C bus.
24#    Major = higher 4 bits of register 0x00
25#    Minor = lower 4 bits of register 0x00
26#    Point/SubPoint: reserved as 0x0 for now
27#
28#   e.g. reg[0] = 0x25 -> ver 2.5.0.0
29#
30#################################################################
31
32CPLD_I2C_BUS_NUM=13
33CPLD_I2C_BUS_ADDR='0x21'
34CPLD_I2C_BASEVER_REG='0x00'
35VER_ENV_FILE='/run/cpld0.version'
36
37#################################################################
38# Parse the byte value from i2cget and sanity checks the hex format
39# Arguments:
40#   $1: i2c_bus_num
41#   $2: i2c_bus_addr
42#   $3: i2c_reg
43# Global:
44#   'byte_val' will be written with the numeric value from i2cget
45# Returns:
46#   0 if success, non-zero if failed to get the value or value is malformed
47#################################################################
48read_and_check_i2c_get() {
49  if ! (( $# == 3 )); then
50    echo "Usage: read_and_check_i2c_get i2c_bus_num i2c_bus_addr i2c_reg"
51    return 1
52  fi
53
54  local i2c_bus_num=$1
55  local i2c_bus_addr=$2
56  local i2c_reg=$3
57
58  local i2c_val_raw
59  i2c_val_raw=$(i2cget -y "${i2c_bus_num}" "${i2c_bus_addr}" "${i2c_reg}") || return
60
61  # Verify that it is of format 0x[hex][hex].
62  local HEXBYTE_RE='^0x[0-9A-Fa-f]{2}$'
63  if ! [[ ${i2c_val_raw} =~ ${HEXBYTE_RE} ]]; then
64    echo "i2cget $* outputs invalid value: ${i2c_val_raw}"
65    return 1
66  fi
67
68  ((byte_val = i2c_val_raw))
69  return 0
70}
71
72#################################################################
73# Prints CPLD version in Major.Minor.Point.Subpoint format.
74# Each dot separated field is decimal number with no leading zeros.
75# Arguments:
76#    None
77# Globals:
78#    Write parsed version into the following global variables:
79#      cpld_ver_major
80#      cpld_ver_minor
81#      cpld_point
82#      cpld_subpoint
83# Returns:
84#    0 if success, non-zero otherwise
85#################################################################
86parse_cpld_ver() {
87  # Stores the output of read_and_check_i2c_get
88  local byte_val
89
90  # Read a byte, assign higher 4 bits to cpld_ver_major and lower 4 bits to
91  # cpld_ver_minor.
92  # e.g. cpld_ver_raw = 0x09 => major_hex = 0, minor_hex = 9
93  read_and_check_i2c_get ${CPLD_I2C_BUS_NUM} ${CPLD_I2C_BUS_ADDR} ${CPLD_I2C_BASEVER_REG} ||
94    return
95  local cpld_ver
96  ((cpld_ver = byte_val))
97  ((cpld_ver_major = cpld_ver >> 4))
98  ((cpld_ver_minor = cpld_ver & 0xf))
99  ((cpld_point = 0))
100  ((cpld_subpoint = 0))
101
102  return 0
103}
104
105main() {
106  local cpld_ver_major
107  local cpld_ver_minor
108  local cpld_point
109  local cpld_subpoint
110
111  parse_cpld_ver || return
112
113  # Write CPLD version to file.
114  cpld_ver="${cpld_ver_major}.${cpld_ver_minor}.${cpld_point}.${cpld_subpoint}"
115  echo "CPLD version ${cpld_ver}"
116  echo "${cpld_ver}" > "${VER_ENV_FILE}"
117
118  return 0
119}
120
121# Exit without running main() if sourced
122if ! (return 0 2>/dev/null); then
123    main "$@"
124fi
125