new file mode 100644
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "version.h"
+#include "fw/msg_tx.h"
+#include "debug.h"
+#include "chip.h"
+#include "utils/utils.h"
+
+/*
+ * Don't move this define to a different file, and
+ * don't change the default version.
+ */
+#define HP_VERSION "8.0.0.0.0.0"
+
+static int cl_version_request(struct cl_hw *cl_hw)
+{
+ struct mm_version_cfm *cfm = NULL;
+ struct cl_version_db *vd = &cl_hw->version_db;
+ int ret = 0;
+
+ ret = cl_msg_tx_version(cl_hw);
+ if (ret)
+ return ret;
+
+ cfm = (struct mm_version_cfm *)cl_hw->msg_cfm_params[MM_VERSION_CFM];
+ if (!cfm)
+ return -ENOMSG;
+
+ vd->last_update = jiffies;
+ vd->dsp = le32_to_cpu(cfm->versions.dsp);
+ vd->rfic_sw = le32_to_cpu(cfm->versions.rfic_sw);
+ vd->rfic_hw = le32_to_cpu(cfm->versions.rfic_hw);
+ vd->agcram = le32_to_cpu(cfm->versions.agcram);
+
+ cl_hw->rf_crystal_mhz = cfm->rf_crystal_mhz;
+
+ strncpy(vd->fw, cfm->versions.fw, sizeof(vd->fw));
+ vd->fw[sizeof(vd->fw) - 1] = '\0';
+
+ strncpy(vd->drv, HP_VERSION, sizeof(vd->drv));
+ vd->drv[sizeof(vd->drv) - 1] = '\0';
+
+ cl_msg_tx_free_cfm_params(cl_hw, MM_VERSION_CFM);
+
+ return ret;
+}
+
+int cl_version_read(struct cl_hw *cl_hw, bool reply)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ struct cl_version_db *vd = &cl_hw->version_db;
+ int ret = 0;
+ struct cl_agc_profile *agc_profile1 = &cl_hw->phy_data_info.data->agc_params.profile1;
+ struct cl_agc_profile *agc_profile2 = &cl_hw->phy_data_info.data->agc_params.profile2;
+ char *buf = NULL;
+ ssize_t bufsz;
+ int len = 0;
+ u32 version_agcram, major, minor, internal;
+
+ /* Request data if existing is not actual */
+ if (!vd->last_update && (ret = cl_version_request(cl_hw)))
+ return ret;
+
+ /* PHY components specifics */
+ cl_snprintf(&buf, &len, &bufsz, "DRV VERSION: %s\n", vd->drv);
+ cl_snprintf(&buf, &len, &bufsz, "FW VERSION: %s\n", vd->fw);
+ cl_snprintf(&buf, &len, &bufsz, "DSP VERSION: 0x%-.8X\n", vd->dsp);
+ cl_snprintf(&buf, &len, &bufsz, "RFIC SW VERSION: %u\n", vd->rfic_sw);
+ cl_snprintf(&buf, &len, &bufsz, "RFIC HW VERSION: 0x%X\n", vd->rfic_hw);
+
+ version_agcram = vd->agcram;
+ major = (version_agcram >> 16) & 0xffff;
+ minor = (version_agcram >> 8) & 0xff;
+ internal = version_agcram & 0xff;
+ cl_snprintf(&buf, &len, &bufsz,
+ "AGC RAM VERSION: B.%x.%x.%x\n",
+ major, minor, internal);
+
+ cl_agc_params_print_profile(&buf, &len, &bufsz, agc_profile1,
+ "AGC PARAMS PROFILE:");
+ cl_agc_params_print_profile(&buf, &len, &bufsz, agc_profile2,
+ "AGC PARAMS PROFILE (Elastic):");
+ cl_snprintf(&buf, &len, &bufsz, "TX POWER VERSION: %u\n", cl_hw->tx_power_version);
+
+ if (IS_PHY_OLYMPUS(chip))
+ cl_snprintf(&buf, &len, &bufsz, "RFIC TYPE: OLYMPUS\n");
+ else
+ cl_snprintf(&buf, &len, &bufsz, "RFIC TYPE: ATHOS\n");
+
+ cl_snprintf(&buf, &len, &bufsz, "RF CRYSTAL: %uMHz\n",
+ cl_hw->rf_crystal_mhz);
+
+ if (reply)
+ ret = cl_vendor_reply(cl_hw, buf, len);
+ else
+ pr_debug("%s\n", buf);
+
+ kfree(buf);
+
+ return ret;
+}
+
+int cl_version_update(struct cl_hw *cl_hw)
+{
+ int ret = 0;
+
+ /* Force logic to update versions */
+ cl_hw->version_db.last_update = 0;
+
+ ret = cl_version_read(cl_hw, false);
+
+ /* Share version info */
+ if (ret == 0)
+ cl_version_sync_wiphy(cl_hw, cl_hw->hw->wiphy);
+
+ return ret;
+}
+
+void cl_version_sync_wiphy(struct cl_hw *cl_hw, struct wiphy *wiphy)
+{
+ strncpy(wiphy->fw_version, cl_hw->version_db.fw, sizeof(wiphy->fw_version));
+ wiphy->fw_version[sizeof(wiphy->fw_version) - 1] = '\0';
+}
+
+int cl_version_cli(struct cl_hw *cl_hw)
+{
+ return cl_version_read(cl_hw, true);
+}