[NEUS7920-477] wlbt: Load optional Common HCF (configurable)
authorIvan Priest <i.priest@samsung.com>
Thu, 22 Nov 2018 13:56:11 +0000 (13:56 +0000)
committerKim Gunho <gunho.kim@samsung.com>
Fri, 28 Jun 2019 14:46:09 +0000 (23:46 +0900)
Load HCF files for Common configuration, and pass to Common FW
via the mxconf structure.

Change-Id: I08727d5f2c4c9d5d0c70c8db025cee092b7920fe
SCSC-Bug-Id: SSB-46627
Signed-off-by: Garry Rank <g.rank@samsung.com>
drivers/misc/samsung/scsc/Kconfig
drivers/misc/samsung/scsc/Makefile
drivers/misc/samsung/scsc/mxconf.h
drivers/misc/samsung/scsc/mxfwconfig.c [new file with mode: 0644]
drivers/misc/samsung/scsc/mxfwconfig.h [new file with mode: 0644]
drivers/misc/samsung/scsc/mxman.c
drivers/misc/samsung/scsc/scsc_logring_main.c
drivers/misc/samsung/scsc/scsc_mx_impl.c
drivers/misc/samsung/scsc/scsc_mx_impl.h
include/scsc/scsc_logring.h

index 3b30cb008c8516757d632326e2acfa8e5add35a3..4e7e3f8f84c83878b98dbf0122e98233895046fe 100644 (file)
@@ -162,3 +162,10 @@ config SCSC_LOG_COLLECTION
        ---help---
          Enable LOG collection to collect Chunks (host and FW) and generate a SBL file
 
+config SCSC_COMMON_HCF
+       bool "Enable Common HCF loader"
+       depends on SCSC_CORE
+       default n
+       ---help---
+         Enable Common HCF loader
+
index a5fdb79ba5ee761c88dca5e3783add543356fc47..920c71a71bbbdc35c80a24d5c9918207cc68b335 100644 (file)
@@ -87,8 +87,9 @@ scsc_mx-$(CONFIG_SCSC_CORE_CM) += \
        mifstream.o \
        mxmgmt_transport.o \
        gdb_transport.o \
-       mx140_file.o \
-       scsc_lerna.o
+       scsc_lerna.o \
+       mxfwconfig.o \
+       mx140_file.o
 
 # Maxwell logger
 scsc_mx-$(CONFIG_SCSC_MXLOGGER) += mxlogger.o
index d263bb1b4a02b17fad060f87eddd8c2d3832b326..1a566dbc2ea39021022d5ffe957edc03a65fd7d7 100644 (file)
@@ -48,7 +48,7 @@
  *  mismatches.
  */
 #define MXCONF_VERSION_MAJOR 0
-#define MXCONF_VERSION_MINOR 3 /* For FM status */
+#define MXCONF_VERSION_MINOR 4 /* For Common HCF override */
 
 /* Types */
 
@@ -107,6 +107,16 @@ struct mxlogconf
        struct mxstreamconf stream_conf;
 } __MXPACKED;
 
+
+/**
+ * Maxwell Infrastructure Configuration Override (HCF block)
+ */
+struct mxmibref {
+       uint32_t offset;
+       uint32_t size;
+} __MXPACKED;
+
+
 /**
  * Maxwell Infrastructure Configuration
  */
@@ -158,6 +168,13 @@ struct mxconf {
 #define MXCONF_FLAGS_FM_ON     (BIT(0))        /* FM already on */
        uint32_t flags;
 
+       /* FROM MINOR_4 */
+
+       /**
+        * Common HCF offset
+        */
+       struct mxmibref fwconfig;
+
 } __MXPACKED;
 
 #endif /* MXCONF_H__ */
diff --git a/drivers/misc/samsung/scsc/mxfwconfig.c b/drivers/misc/samsung/scsc/mxfwconfig.c
new file mode 100644 (file)
index 0000000..fa6ec7d
--- /dev/null
@@ -0,0 +1,224 @@
+/*****************************************************************************
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ ****************************************************************************/
+
+#include <scsc/scsc_mx.h>
+#include <scsc/scsc_logring.h>
+
+#include "mxfwconfig.h"
+#include "miframman.h"
+#include "scsc_mx_impl.h"
+#include "mxconf.h"
+
+#ifdef CONFIG_SCSC_LOG_COLLECTION
+#include <scsc/scsc_log_collector.h>
+#endif
+
+#define MXFWCONFIG_CFG_SUBDIR  "common"
+#define MXFWCONFIG_CFG_FILE_HW "common.hcf"
+#define MXFWCONFIG_CFG_FILE_SW "common_sw.hcf"
+
+static void mxfwconfig_get_dram_ref(struct scsc_mx *mx, struct mxmibref *cfg_ref);
+
+/* Load config into non-shared DRAM */
+static int mxfwconfig_load_cfg(struct scsc_mx *mx, struct mxfwconfig *cfg, const char *filename)
+{
+       int r = 0;
+       u32 i;
+
+       if (cfg->configs >= SCSC_MX_MAX_COMMON_CFG) {
+               SCSC_TAG_ERR(MX_CFG, "Too many common config files (%u)\n", cfg->configs);
+               return -E2BIG;
+       }
+
+       i = cfg->configs++; /* Claim next config slot */
+
+       /* Load config file from file system into DRAM */
+       r = mx140_file_request_conf(mx, &cfg->config[i].fw, MXFWCONFIG_CFG_SUBDIR, filename);
+       if (r)
+               return r;
+
+       /* Initial size of file */
+       cfg->config[i].cfg_len = cfg->config[i].fw->size;
+       cfg->config[i].cfg_data = cfg->config[i].fw->data;
+
+       /* Validate file in DRAM */
+       if (cfg->config[i].cfg_len >= MX_COMMON_HCF_HDR_SIZE && /* Room for header */
+               /*(cfg->config[i].cfg[6] & 0xF0) == 0x10 && */  /* Curator subsystem */
+               cfg->config[i].cfg_data[7] == 1) {              /* First file format */
+               int j;
+
+               cfg->config[i].cfg_hash = 0;
+
+               /* Calculate hash */
+               for (j = 0; j < MX_COMMON_HASH_SIZE_BYTES; j++) {
+                       cfg->config[i].cfg_hash =
+                               (cfg->config[i].cfg_hash << 8) | cfg->config[i].cfg_data[j + MX_COMMON_HASH_OFFSET];
+               }
+
+               SCSC_TAG_INFO(MX_CFG, "CFG hash: 0x%.04x\n", cfg->config[i].cfg_hash);
+
+               /* All good - consume header and continue */
+               cfg->config[i].cfg_len -= MX_COMMON_HCF_HDR_SIZE;
+               cfg->config[i].cfg_data += MX_COMMON_HCF_HDR_SIZE;
+       } else {
+               SCSC_TAG_ERR(MX_CFG, "Invalid HCF header size %zu\n", cfg->config[i].cfg_len);
+
+               /* Caller must call mxfwconfig_unload_cfg() to release the buffer */
+               return -EINVAL;
+       }
+
+       /* Running shtotal payload */
+       cfg->shtotal += cfg->config[i].cfg_len;
+
+       SCSC_TAG_INFO(MX_CFG, "Loaded common config %s, size %zu, payload size %zu, shared dram total %zu\n",
+               filename, cfg->config[i].fw->size, cfg->config[i].cfg_len, cfg->shtotal);
+
+       return r;
+}
+
+/* Unload config from non-shared DRAM */
+static int mxfwconfig_unload_cfg(struct scsc_mx *mx, struct mxfwconfig *cfg, u32 index)
+{
+       if (index >= SCSC_MX_MAX_COMMON_CFG) {
+               SCSC_TAG_ERR(MX_CFG, "Out of range index (%u)\n", index);
+               return -E2BIG;
+       }
+
+       if (cfg->config[index].fw) {
+               SCSC_TAG_DBG3(MX_CFG, "Unload common config %u\n", index);
+
+               mx140_file_release_conf(mx, cfg->config[index].fw);
+
+               cfg->config[index].fw = NULL;
+               cfg->config[index].cfg_data = NULL;
+               cfg->config[index].cfg_len = 0;
+       }
+
+       return 0;
+}
+
+/*
+ * Load Common config files
+ */
+int mxfwconfig_load(struct scsc_mx *mx, struct mxmibref *cfg_ref)
+{
+       struct mxfwconfig *cfg = scsc_mx_get_mxfwconfig(mx);
+       struct miframman *miframman = scsc_mx_get_ramman(mx);
+       int r;
+       u32 i;
+       u8 *dest;
+
+       /* HW file is optional */
+       r = mxfwconfig_load_cfg(mx, cfg, MXFWCONFIG_CFG_FILE_HW);
+       if (r)
+               goto done;
+
+       /* SW file is optional, but not without HW file */
+       r = mxfwconfig_load_cfg(mx, cfg, MXFWCONFIG_CFG_FILE_SW);
+       if (r == -EINVAL) {
+               /* If SW file is corrupt, abandon both HW and SW */
+               goto done;
+       }
+
+       /* Allocate shared DRAM */
+       cfg->shdram = miframman_alloc(miframman, cfg->shtotal, 4, MIFRAMMAN_OWNER_COMMON);
+       if (!cfg->shdram) {
+               SCSC_TAG_ERR(MX_CFG, "MIF alloc failed for %zu octets\n", cfg->shtotal);
+               r = -ENOMEM;
+               goto done;
+       }
+
+       /* Copy files into shared DRAM */
+       for (i = 0, dest = (u8 *)cfg->shdram;
+            i < cfg->configs;
+            i++) {
+               /* Add to shared DRAM block */
+               memcpy(dest, cfg->config[i].cfg_data, cfg->config[i].cfg_len);
+               dest += cfg->config[i].cfg_len;
+       }
+
+done:
+       /* Release the files from non-shared DRAM */
+       for (i = 0; i < cfg->configs; i++)
+               mxfwconfig_unload_cfg(mx, cfg, i);
+
+       /* Configs abandoned on error */
+       if (r)
+               cfg->configs = 0;
+
+       /* Pass offset of common HCF data.
+        * FW must ignore if zero length, so set up even if we loaded nothing.
+        */
+       mxfwconfig_get_dram_ref(mx, cfg_ref);
+
+       return r;
+}
+
+/*
+ * Unload Common config data
+ */
+void mxfwconfig_unload(struct scsc_mx *mx)
+{
+       struct mxfwconfig *cfg = scsc_mx_get_mxfwconfig(mx);
+       struct miframman *miframman = scsc_mx_get_ramman(mx);
+
+       /* Free config block in shared DRAM */
+       if (cfg->shdram) {
+               SCSC_TAG_INFO(MX_CFG, "Free common config %zu bytes shared DRAM\n", cfg->shtotal);
+
+               miframman_free(miframman, cfg->shdram);
+
+               cfg->configs = 0;
+               cfg->shtotal = 0;
+               cfg->shdram = NULL;
+       }
+}
+
+/*
+ * Get ref (offset) of config block in shared DRAM
+ */
+static void mxfwconfig_get_dram_ref(struct scsc_mx *mx, struct mxmibref *cfg_ref)
+{
+       struct mxfwconfig *mxfwconfig = scsc_mx_get_mxfwconfig(mx);
+       struct scsc_mif_abs *mif = scsc_mx_get_mif_abs(mx);
+
+       if (!mxfwconfig->shdram) {
+               cfg_ref->offset = (scsc_mifram_ref)0;
+               cfg_ref->size = 0;
+       } else {
+               mif->get_mifram_ref(mif, mxfwconfig->shdram, &cfg_ref->offset);
+               cfg_ref->size = mxfwconfig->shtotal;
+       }
+
+       SCSC_TAG_INFO(MX_CFG, "cfg_ref: 0x%x, size %u\n", cfg_ref->offset, cfg_ref->size);
+}
+
+/*
+ * Init config file module
+ */
+int mxfwconfig_init(struct scsc_mx *mx)
+{
+       struct mxfwconfig *cfg = scsc_mx_get_mxfwconfig(mx);
+
+       cfg->configs = 0;
+       cfg->shtotal = 0;
+       cfg->shdram = NULL;
+
+       return 0;
+}
+
+/*
+ * Exit config file module
+ */
+void mxfwconfig_deinit(struct scsc_mx *mx)
+{
+       struct mxfwconfig *cfg = scsc_mx_get_mxfwconfig(mx);
+
+       /* Leaked memory? */
+       WARN_ON(cfg->configs > 0);
+       WARN_ON(cfg->shdram);
+}
+
diff --git a/drivers/misc/samsung/scsc/mxfwconfig.h b/drivers/misc/samsung/scsc/mxfwconfig.h
new file mode 100644 (file)
index 0000000..f24d44c
--- /dev/null
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ ****************************************************************************/
+
+#ifndef __MXFWCONFIG_H
+#define __MXFWCONFIG_H
+
+#define SCSC_MX_MAX_COMMON_CFG         2
+#define MX_COMMON_HCF_HDR_SIZE         8
+#define MX_COMMON_HASH_SIZE_BYTES      2 /* Hash will be contained in a uint32 */
+#define MX_COMMON_HASH_OFFSET          4
+
+struct mxfwconfig {
+       u32             configs;        /* Number of files */
+       void            *shdram;        /* Combined payload in shared DRAM */
+       size_t          shtotal;        /* Size of combined payload in shared DRAM */
+
+       struct {
+               const struct firmware   *fw;            /* File image in DRAM */
+               const u8                *cfg_data;      /* Payload in DRAM */
+               size_t                  cfg_len;        /* Length of payload */
+               u32                     cfg_hash;       /* ID hash */
+       } config[SCSC_MX_MAX_COMMON_CFG];
+};
+
+struct mxmibref;
+
+int mxfwconfig_init(struct scsc_mx *mx);
+void mxfwconfig_deinit(struct scsc_mx *mx);
+int mxfwconfig_load(struct scsc_mx *mx, struct mxmibref *cfg_ref);
+void mxfwconfig_unload(struct scsc_mx *mx);
+
+#endif // __MXFWCONFIG_H
index b58197828ae1cc6888ba7202b8e2fbd1fb2a3dba..fe645ef68eb39c871b106a427fcab4fa80addd8e 100755 (executable)
@@ -34,6 +34,7 @@
 #ifdef CONFIG_SCSC_QOS
 #include "mifqos.h"
 #endif
+#include "mxfwconfig.h"
 #include <scsc/kic/slsi_kic_lib.h>
 #include <scsc/scsc_release.h>
 #include <scsc/scsc_mx.h>
@@ -841,13 +842,12 @@ static int transports_init(struct mxman *mxman)
        mxconf->version.minor = MXCONF_VERSION_MINOR;
 
        /* Pass pre-existing FM status to FW */
-#if (MXCONF_VERSION_MINOR >= 3)
        mxconf->flags = 0;
 #ifdef CONFIG_SCSC_FM
        mxconf->flags |= is_fm_on ? MXCONF_FLAGS_FM_ON : 0;
 #endif
        SCSC_TAG_INFO(MXMAN, "mxconf flags 0x%08x\n", mxconf->flags);
-#endif
+
        /* serialise mxmgmt transport */
        mxmgmt_transport_config_serialise(scsc_mx_get_mxmgmt_transport(mx), &mxconf->mx_trans_conf);
        /* serialise Cortex-R4 gdb transport */
@@ -866,6 +866,13 @@ static int transports_init(struct mxman *mxman)
                       *scsc_mx_get_mxlog_transport(mx)->mif_stream.buffer.write_index
                      );
 
+       /* Need to initialise fwconfig or else random data can make firmware data abort. */
+       mxconf->fwconfig.offset = 0;
+       mxconf->fwconfig.size = 0;
+#ifdef CONFIG_SCSC_COMMON_HCF
+       /* Load Common Config HCF */
+       mxfwconfig_load(mxman->mx, &mxconf->fwconfig);
+#endif
        return 0;
 }
 
@@ -1117,6 +1124,7 @@ static int mxman_start(struct mxman *mxman)
        miframabox_init(scsc_mx_get_aboxram(mxman->mx), start_mifram_heap2 + length_mifram_heap2);
        mifmboxman_init(scsc_mx_get_mboxman(mxman->mx));
        mifintrbit_init(scsc_mx_get_intrbit(mxman->mx), mif);
+       mxfwconfig_init(mxman->mx);
 
        /* Initialise transports */
        r = transports_init(mxman);
@@ -1896,6 +1904,7 @@ static void mxman_stop(struct mxman *mxman)
 
        panicmon_deinit(scsc_mx_get_panicmon(mxman->mx));
        transports_release(mxman);
+       mxfwconfig_unload(mxman->mx);
 
        mxlog_release(scsc_mx_get_mxlog(mxman->mx));
        /* unregister channel handler */
@@ -1904,6 +1913,7 @@ static void mxman_stop(struct mxman *mxman)
        fw_crc_wq_stop(mxman);
 
        /* Unitialise components (they may perform some checks - e.g. all memory freed) */
+       mxfwconfig_deinit(mxman->mx);
        mifintrbit_deinit(scsc_mx_get_intrbit(mxman->mx));
        miframman_deinit(scsc_mx_get_ramman(mxman->mx));
        miframman_deinit(scsc_mx_get_ramman2(mxman->mx));
index 194e043805a456b8390a9bb1b357123ca2986799..9b623c4529f3523481fb453f801a6a0814671d1c 100644 (file)
@@ -222,6 +222,7 @@ ADD_DEBUG_MODULE_PARAM(kic_common, SCSC_FULL_DEBUG, KIC_COMMON);
 ADD_DEBUG_MODULE_PARAM(wlbtd, SCSC_FULL_DEBUG, WLBTD);
 ADD_DEBUG_MODULE_PARAM(wlog, SCSC_DEBUG, WLOG);
 ADD_DEBUG_MODULE_PARAM(lerna, SCSC_FULL_DEBUG, LERNA);
+ADD_DEBUG_MODULE_PARAM(mxcfg, SCSC_FULL_DEBUG, MX_CFG);
 #ifdef CONFIG_SCSC_DEBUG_COMPATIBILITY
 ADD_DEBUG_MODULE_PARAM(init_deinit,  SCSC_FULL_DEBUG, SLSI_INIT_DEINIT);
 ADD_DEBUG_MODULE_PARAM(netdev,  SCSC_DBG4, SLSI_NETDEV);
@@ -296,6 +297,7 @@ int *scsc_droplevels[] = {
        &scsc_droplevel_wlbtd,
        &scsc_droplevel_wlog,
        &scsc_droplevel_lerna,
+       &scsc_droplevel_mxcfg,
 #ifdef CONFIG_SCSC_DEBUG_COMPATIBILITY
        &scsc_droplevel_init_deinit,
        &scsc_droplevel_netdev,
index cfd339bdd5561cf5c2702ecdcbf612b31a51c343..dd6cf22a7a2be90fd40a73858dc71b0cd00bc6b1 100644 (file)
 #include "suspendmon.h"
 
 #include "scsc/api/bt_audio.h"
+#include "mxfwconfig.h"
 #ifdef CONFIG_SCSC_WLBTD
 #include "scsc_wlbtd.h"
 #endif
+
 struct scsc_mx {
        struct scsc_mif_abs     *mif_abs;
        struct mifintrbit       intr;
@@ -58,6 +60,7 @@ struct scsc_mx {
        struct panicmon         panicmon;
        struct mxlog_transport  mxlog_transport;
        struct suspendmon       suspendmon;
+       struct mxfwconfig       mxfwconfig;
 };
 
 
@@ -204,3 +207,9 @@ struct suspendmon *scsc_mx_get_suspendmon(struct scsc_mx *mx)
 {
        return &mx->suspendmon;
 }
+
+struct mxfwconfig *scsc_mx_get_mxfwconfig(struct scsc_mx *mx)
+{
+       return &mx->mxfwconfig;
+}
+
index 479e5743c8bd12226f321af0120a68e50b35edb8..d7b1e13a1374a2783626baae85a36c3d0c3a71bf 100644 (file)
@@ -19,6 +19,7 @@ struct mxman;
 struct srvman;
 struct mxmgmt_transport;
 struct mxproc;
+struct mxfwconfig;
 
 struct scsc_mx          *scsc_mx_create(struct scsc_mif_abs *mif);
 void scsc_mx_destroy(struct scsc_mx *mx);
@@ -47,6 +48,8 @@ struct mxlog_transport  *scsc_mx_get_mxlog_transport(struct scsc_mx *mx);
 struct mxlogger         *scsc_mx_get_mxlogger(struct scsc_mx *mx);
 struct panicmon         *scsc_mx_get_panicmon(struct scsc_mx *mx);
 struct suspendmon      *scsc_mx_get_suspendmon(struct scsc_mx *mx);
+struct mxfwconfig      *scsc_mx_get_mxfwconfig(struct scsc_mx *mx);
+
 int mx140_file_download_fw(struct scsc_mx *mx, void *dest, size_t dest_size, u32 *fw_image_size);
 int mx140_request_file(struct scsc_mx *mx, char *path, const struct firmware **firmp);
 int mx140_release_file(struct scsc_mx *mx, const struct firmware *firmp);
index 0f3274e63df722b28888fd58ca03d7cb3bc575d8..707fc46055fc4d3cff835ae89c116300bc7a6846 100644 (file)
@@ -62,6 +62,7 @@ enum scsc_logring_tags {
        WLBTD,
        WLOG,
        LERNA,
+       MX_CFG,
 #ifdef CONFIG_SCSC_DEBUG_COMPATIBILITY
        SLSI_INIT_DEINIT,
        SLSI_NETDEV,