1210 lines
39 KiB
C
Executable file
1210 lines
39 KiB
C
Executable file
/****************************************************************************
|
|
*
|
|
* Copyright (c) 2014 - 2021 Samsung Electronics Co., Ltd. All rights reserved
|
|
*
|
|
****************************************************************************/
|
|
#include <scsc/scsc_logring.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/firmware.h>
|
|
#include "mxman_res.h"
|
|
#include "scsc_mx_impl.h"
|
|
#include "mxman.h"
|
|
#include "whdr.h"
|
|
#include "fwhdr_if.h"
|
|
#include "bhdr.h"
|
|
#include "fhdr.h"
|
|
#include "fw_obj_index.h"
|
|
#include "pmuhdr.h"
|
|
#include <scsc/kic/slsi_kic_lib.h>
|
|
#include <scsc/scsc_release.h>
|
|
#include <scsc/scsc_mx.h>
|
|
|
|
#define MBOX2_MAGIC_NUMBER 0xbcdeedcb
|
|
#define MBOX_INDEX_0 0
|
|
#define MBOX_INDEX_1 1
|
|
#define MBOX_INDEX_2 2
|
|
#define MBOX_INDEX_3 3
|
|
#ifdef CONFIG_SOC_EXYNOS7570
|
|
#define MBOX_INDEX_4 4
|
|
#define MBOX_INDEX_5 5
|
|
#define MBOX_INDEX_6 6
|
|
#define MBOX_INDEX_7 7
|
|
#endif
|
|
|
|
#if IS_ENABLED(CONFIG_SCSC_MEMLOG)
|
|
#include <soc/samsung/memlogger.h>
|
|
#endif
|
|
|
|
/* MIF resources - USES */
|
|
#include "mifmboxman.h"
|
|
#include "miframman.h"
|
|
#include "mifpmuman.h"
|
|
#include "mxfwconfig.h"
|
|
#include "mxlog_transport.h"
|
|
#include "mxlog.h"
|
|
#include "gdb_transport.h"
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
#include "mxlogger.h"
|
|
#endif
|
|
#ifdef CONFIG_SCSC_SMAPPER
|
|
#include "mifsmapper.h"
|
|
#endif
|
|
#ifdef CONFIG_SCSC_QOS
|
|
#include "mifqos.h"
|
|
#endif
|
|
#ifdef CONFIG_SCSC_LAST_PANIC_IN_DRAM
|
|
#include "scsc_log_in_dram.h"
|
|
#endif
|
|
|
|
/* This values should be defined in the DTS.. so we may need to
|
|
* provision some calls to platform driver */
|
|
#define MX_DRAM_SIZE_SECTION_1 (8 * 1024 * 1024)
|
|
#define MX_DRAM_SIZE_SECTION_2 (8 * 1024 * 1024)
|
|
|
|
static uint firmware_startup_flags;
|
|
module_param(firmware_startup_flags, uint, S_IRUGO | S_IWUSR);
|
|
MODULE_PARM_DESC(firmware_startup_flags,
|
|
"0 = Proceed as normal (default); Bit 0 = 1 - spin at start of CRT0; Other bits reserved = 0");
|
|
|
|
static bool allow_unidentified_firmware;
|
|
module_param(allow_unidentified_firmware, bool, S_IRUGO | S_IWUSR);
|
|
MODULE_PARM_DESC(allow_unidentified_firmware, "Allow unidentified firmware");
|
|
|
|
static bool skip_header;
|
|
module_param(skip_header, bool, S_IRUGO | S_IWUSR);
|
|
MODULE_PARM_DESC(skip_header, "Skip header, assuming unidentified firmware");
|
|
|
|
int mxman_res_mem_map(struct mxman *mxman, void **start_dram, size_t *size_dram)
|
|
{
|
|
struct scsc_mif_abs *mif;
|
|
|
|
mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
|
|
*start_dram = mif->map(mif, size_dram);
|
|
|
|
if (!*start_dram) {
|
|
SCSC_TAG_ERR(MXMAN, "Error allocating dram\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mxman_res_mem_unmap(struct mxman *mxman, void *start_dram)
|
|
{
|
|
struct scsc_mif_abs *mif;
|
|
mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
|
|
mif->unmap(mif, start_dram);
|
|
|
|
mxlog_unload_log_strings(scsc_mx_get_mxlog(mxman->mx));
|
|
mxlog_unload_log_strings(scsc_mx_get_mxlog_wpan(mxman->mx));
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_SCSC_MEMLOG)
|
|
struct memlog_obj *mxman_res_get_memlog_obj(struct scsc_mif_abs *mif, const char *desc_name, size_t len)
|
|
{
|
|
struct device *dev = mif->get_mif_device(mif);
|
|
struct memlog *desc = memlog_get_desc(desc_name);
|
|
struct memlog_obj *obj = NULL;
|
|
const char *obj_name = "drm-mem";
|
|
|
|
if (!desc) {
|
|
int val = memlog_register(desc_name, dev, &desc);
|
|
|
|
if (val) {
|
|
SCSC_TAG_ERR(MXMAN, "Error registering %s to memlog\n", desc_name);
|
|
return NULL;
|
|
}
|
|
|
|
obj = memlog_alloc_direct(desc, len, NULL, obj_name);
|
|
if (!obj) {
|
|
/* Alloc fail - null fallback */
|
|
SCSC_TAG_INFO(MXMAN, "obj alloc failed!!\n");
|
|
}
|
|
} else {
|
|
/* Object exists, return the pointer */
|
|
obj = memlog_get_obj_by_name(desc, obj_name);
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
static void mxman_res_set_memlog_version(struct scsc_mif_abs *mif)
|
|
{
|
|
struct memlog *desc = memlog_get_desc("WB_LOG");
|
|
struct memlog_obj *scsc_memlog_version_info_obj;
|
|
|
|
struct scsc_memlog_version_info {
|
|
char fw_version[128];
|
|
char host_version[64];
|
|
char fapi_version[64];
|
|
} * memlog_version_info;
|
|
|
|
if (desc) {
|
|
//const char *fapi_version = "ma:14.1, mlme:14.6, debug:13.3, test:14.0";
|
|
|
|
scsc_memlog_version_info_obj = memlog_get_obj_by_name(desc, "str-mem");
|
|
if (!scsc_memlog_version_info_obj) {
|
|
scsc_memlog_version_info_obj =
|
|
memlog_alloc_array(desc, 1, sizeof(struct scsc_memlog_version_info), NULL, "str-mem",
|
|
"scsc_memlog_version_info", 0);
|
|
|
|
if (!scsc_memlog_version_info_obj) {
|
|
/* Alloc fail */
|
|
return;
|
|
}
|
|
}
|
|
|
|
memlog_version_info = (struct scsc_memlog_version_info *)scsc_memlog_version_info_obj->vaddr;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
int mxman_res_mappings_logger_init(struct mxman *mxman, void *start_dram)
|
|
{
|
|
void *start_dram_section2;
|
|
int ret = 0;
|
|
#if IS_ENABLED(CONFIG_SCSC_MEMLOG)
|
|
const char *desc_name = "WB_LOG";
|
|
struct memlog_obj *obj;
|
|
struct device *dev;
|
|
struct scsc_mif_abs *mif;
|
|
|
|
mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
|
|
SCSC_TAG_INFO(MXMAN, "Using memlogger for mxlogger\n");
|
|
dev = mif->get_mif_device(mif);
|
|
obj = mxman_res_get_memlog_obj(mif, desc_name, MX_DRAM_SIZE_SECTION_LOG);
|
|
if (!obj) {
|
|
SCSC_TAG_ERR(MXMAN, "memlog error\n");
|
|
return -ENOMEM;
|
|
}
|
|
mxman_res_set_memlog_version(mif);
|
|
/* assing memory regions for memory mappings */
|
|
mif->set_mem_region2(mif, obj->vaddr, MX_DRAM_SIZE_SECTION_LOG);
|
|
mif->set_memlog_paddr(mif, obj->paddr);
|
|
start_dram_section2 = (char *)obj->vaddr;
|
|
#else
|
|
struct scsc_mif_abs *mif;
|
|
//scsc_mifram_ref mifram_ref;
|
|
|
|
mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
start_dram_section2 = (char *)start_dram + MX_DRAM_SIZE_SECTION_1;
|
|
#endif
|
|
/* Second partition allocator */
|
|
/* Initialize allocator for mem region for logging WLAN */
|
|
ret = miframman_init(scsc_mx_get_ramman2(mxman->mx), start_dram_section2, MX_DRAM_SIZE_SECTION_WLAN,
|
|
start_dram_section2);
|
|
if (ret) {
|
|
SCSC_TAG_INFO(MXMAN, "miframman_init failed with %d\n", ret);
|
|
return ret;
|
|
}
|
|
/* Initialize allocator for mem region for logging WPAN */
|
|
start_dram_section2 = (char *)start_dram_section2 + MX_DRAM_SIZE_SECTION_WLAN;
|
|
ret = miframman_init(scsc_mx_get_ramman2_wpan(mxman->mx), start_dram_section2, MX_DRAM_SIZE_SECTION_WPAN,
|
|
start_dram_section2);
|
|
if (ret) {
|
|
SCSC_TAG_INFO(MXMAN, "miframman_init failed with %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
mxlogger_init(mxman->mx, scsc_mx_get_mxlogger(mxman->mx), MX_DRAM_SIZE_SECTION_LOG);
|
|
return 0;
|
|
}
|
|
int mxman_res_mappings_logger_deinit(struct mxman *mxman)
|
|
{
|
|
miframman_deinit(scsc_mx_get_ramman_wpan(mxman->mx));
|
|
miframman_deinit(scsc_mx_get_ramman2_wpan(mxman->mx));
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int mxman_res_mappings_allocator_init(struct mxman *mxman, void *start_dram)
|
|
{
|
|
void *start_mifram_heap;
|
|
u32 length_mifram_heap;
|
|
struct fwhdr_if *whdr_if = mxman->fw_wlan;
|
|
struct fwhdr_if *bhdr_if = mxman->fw_wpan;
|
|
u32 wlan_rt = 0, wpan_rt = 0, wpan_off = 0;
|
|
int ret = 0;
|
|
|
|
/* mxconf should be appended after RT FWs */
|
|
wlan_rt = whdr_if->get_fw_rt_len(whdr_if) + sizeof(struct mxconf);
|
|
if (bhdr_if) {
|
|
wpan_rt = bhdr_if->get_fw_rt_len(bhdr_if) + sizeof(struct mxconf);
|
|
wpan_off = bhdr_if->get_fw_offset(bhdr_if);
|
|
} else {
|
|
/* Force MAX memory to WLAN as BT is not present */
|
|
wpan_rt = 0;
|
|
wpan_off = MX_DRAM_SIZE_SECTION_1;
|
|
}
|
|
|
|
SCSC_TAG_INFO(MXMAN, "Creating wlan/wpan memory regions. WLAN rt 0x%x WPAN rt 0x%x WPAN offset 0x%x\n", wlan_rt,
|
|
wpan_rt, wpan_off);
|
|
|
|
if (wlan_rt > wpan_off) {
|
|
SCSC_TAG_ERR(MXMAN, "WLAN FW Rt will overlay WPAN FW region\n");
|
|
return -EIO;
|
|
}
|
|
|
|
if ((wpan_off + wpan_rt) > MX_DRAM_SIZE_SECTION_1) {
|
|
SCSC_TAG_ERR(MXMAN, "WPAN FW region beyond total MX_DRAM_SIZE_SECTION_1 0x%x\n", MX_DRAM_SIZE_SECTION_1);
|
|
return -EIO;
|
|
}
|
|
|
|
/* wlan partition allocator */
|
|
start_mifram_heap = (void *)((uintptr_t)start_dram + wlan_rt);
|
|
length_mifram_heap = wpan_off - wlan_rt;
|
|
ret = miframman_init(scsc_mx_get_ramman(mxman->mx), start_mifram_heap, length_mifram_heap, start_dram);
|
|
if (ret) {
|
|
SCSC_TAG_INFO(MXMAN, "miframman_init failed with %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Set here the mxconf address */
|
|
mxman->mxconf = (struct mxconf *)((uintptr_t)start_dram + whdr_if->get_fw_rt_len(whdr_if));
|
|
SCSC_TAG_INFO(MXMAN, "WLAN start 0x%x heap 0x%x heap length 0x%x\n", (uintptr_t)start_dram,
|
|
(uintptr_t)start_mifram_heap, length_mifram_heap);
|
|
|
|
/* WPAN partition allocator */
|
|
if (bhdr_if) {
|
|
start_mifram_heap = (void *)((uintptr_t)start_dram + wpan_rt + wpan_off);
|
|
length_mifram_heap = (MX_DRAM_SIZE_SECTION_1 - wpan_off) - wpan_rt;
|
|
miframman_init(scsc_mx_get_ramman_wpan(mxman->mx), start_mifram_heap, length_mifram_heap,
|
|
(void *)((uintptr_t)start_dram + wpan_off));
|
|
SCSC_TAG_INFO(MXMAN, "WPAN start 0x%x heap 0x%x heap length 0x%x\n", ((uintptr_t)start_dram + wpan_off),
|
|
(uintptr_t)start_mifram_heap, length_mifram_heap);
|
|
|
|
/* Set here the mxconf_wpan address */
|
|
mxman->mxconf_wpan = (struct mxconf *)((uintptr_t)start_dram + bhdr_if->get_fw_rt_len(bhdr_if) + wpan_off);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int mxman_res_mappings_allocator_deinit(struct mxman *mxman)
|
|
{
|
|
miframman_deinit(scsc_mx_get_ramman(mxman->mx));
|
|
miframman_deinit(scsc_mx_get_ramman2(mxman->mx));
|
|
return 0;
|
|
}
|
|
|
|
int mxman_res_fw_init_get_fhdr_strings(const void *fw)
|
|
{
|
|
uint32_t len;
|
|
const void *val;
|
|
|
|
val = fhdr_lookup_tag(fw, FHDR_TAG_META_BRANCH, &len);
|
|
if (val == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "fhdr_lookup_tag FHDR_TAG_META_BRANCH missing\n");
|
|
} else {
|
|
SCSC_TAG_INFO(MXMAN, "FHDR_TAG_META_BRANCH: %.*s\n", len, val);
|
|
}
|
|
|
|
val = fhdr_lookup_tag(fw, FHDR_TAG_META_BUILD_IDENTIFIER, &len);
|
|
if (val == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "fhdr_lookup_tag FHDR_TAG_META_BUILD_IDENTIFIER missing\n");
|
|
} else {
|
|
SCSC_TAG_INFO(MXMAN, "FHDR_TAG_META_BUILD_IDENTIFIER: %.*s\n", len, val);
|
|
}
|
|
|
|
val = fhdr_lookup_tag(fw, FHDR_TAG_META_FW_COMMON_HASH, &len);
|
|
if (val == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "fhdr_lookup_tag FHDR_TAG_META_FW_COMMON_HASH missing\n");
|
|
} else {
|
|
SCSC_TAG_INFO(MXMAN, "FHDR_TAG_META_FW_COMMON_HASH: %.*s\n", len, val);
|
|
}
|
|
|
|
val = fhdr_lookup_tag(fw, FHDR_TAG_META_FW_WLAN_HASH, &len);
|
|
if (val == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "fhdr_lookup_tag FHDR_TAG_META_FW_WLAN_HASH missing\n");
|
|
} else {
|
|
SCSC_TAG_INFO(MXMAN, "FHDR_TAG_META_FW_WLAN_HASH: %.*s\n", len, val);
|
|
}
|
|
|
|
val = fhdr_lookup_tag(fw, FHDR_TAG_META_FW_BT_HASH, &len);
|
|
if (val == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "fhdr_lookup_tag FHDR_TAG_META_FW_BT_HASH missing\n");
|
|
} else {
|
|
SCSC_TAG_INFO(MXMAN, "FHDR_TAG_META_FW_BT_HASH: %.*s\n", len, val);
|
|
}
|
|
|
|
val = fhdr_lookup_tag(fw, FHDR_TAG_META_FW_PMU_HASH, &len);
|
|
if (val == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "fhdr_lookup_tag FHDR_TAG_META_FW_PMU_HASH missing\n");
|
|
} else {
|
|
SCSC_TAG_INFO(MXMAN, "FHDR_TAG_META_FW_PMU_HASH: %.*s\n", len, val);
|
|
}
|
|
|
|
val = fhdr_lookup_tag(fw, FHDR_TAG_META_HARDWARE_HASH, &len);
|
|
if (val == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "fhdr_lookup_tag FHDR_TAG_META_HARDWARE_HASH missing\n");
|
|
} else {
|
|
SCSC_TAG_INFO(MXMAN, "FHDR_TAG_META_HARDWARE_HASH: %.*s\n", len, val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mxman_res_fw_init(struct mxman *mxman, struct fwhdr_if **fw_wlan, struct fwhdr_if **fw_wpan, void *start_dram,
|
|
size_t size_dram)
|
|
{
|
|
int r;
|
|
char *build_id;
|
|
char *ttid;
|
|
u32 fw_image_size;
|
|
char *fw = start_dram;
|
|
const struct firmware *firm;
|
|
struct fwhdr_if *bhdr_if;
|
|
struct fwhdr_if *whdr_if;
|
|
struct scsc_mif_abs *mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
uint32_t wlan_length;
|
|
uint32_t wlan_fw_runtime_size_val;
|
|
const void *wlan_fw;
|
|
uint32_t bt_length;
|
|
const void *bt_fw;
|
|
uint32_t log_strings_length;
|
|
const void *log_strings;
|
|
uint32_t pmu_length;
|
|
struct pmu_firmware_header *pmu;
|
|
uint32_t bt_fw_runtime_size_val;
|
|
uint32_t bt_fw_offset_val;
|
|
|
|
whdr_if = whdr_create();
|
|
if (!whdr_if) {
|
|
SCSC_TAG_ERR(MXMAN, "fwhdr_create() failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
bhdr_if = bhdr_create();
|
|
if (!bhdr_if) {
|
|
SCSC_TAG_ERR(MXMAN, "bwhdr_create() failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
*fw_wlan = whdr_if;
|
|
*fw_wpan = bhdr_if;
|
|
|
|
r = mx140_file_get_fw(mxman->mx, &firm);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "mx140_file_get_fw() failed (%d)\n", r);
|
|
return r;
|
|
}
|
|
SCSC_TAG_INFO(MXMAN, "mx140_file_get_fw success,size %zu\n", firm->size);
|
|
|
|
/* Print FW header strings */
|
|
mxman_res_fw_init_get_fhdr_strings(firm->data);
|
|
|
|
fw_image_size = firm->size;
|
|
/* We need to read the FHDR_TAG_WLAN_FW tag */
|
|
wlan_fw = fhdr_lookup_tag(firm->data, FHDR_TAG_WLAN_FW, &wlan_length);
|
|
if (wlan_fw == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "fhdr_lookup_tag FHDR_TAG_WLAN_FW failed\n");
|
|
mx140_release_file(mxman->mx, firm);
|
|
return -EINVAL;
|
|
}
|
|
|
|
r = whdr_if->init(whdr_if, (char *)wlan_fw, wlan_length, skip_header);
|
|
if (r) {
|
|
/* Check if we allow unidentified fw*/
|
|
if (allow_unidentified_firmware && !whdr_if->get_parsed_ok(whdr_if)) {
|
|
SCSC_TAG_INFO(MXMAN, "Unidentified firmware override\n");
|
|
whdr_if->set_entry_point(whdr_if, 0);
|
|
whdr_if->set_fw_rt_len(whdr_if, MX_FW_RUNTIME_LENGTH);
|
|
} else {
|
|
SCSC_TAG_ERR(MXMAN, "fwhdr_init() failed\n");
|
|
mx140_release_file(mxman->mx, firm);
|
|
return r;
|
|
}
|
|
}
|
|
wlan_fw_runtime_size_val = whdr_if->get_fw_rt_len(whdr_if);
|
|
|
|
/* Get BT image */
|
|
bt_fw = fhdr_lookup_tag(firm->data, FHDR_TAG_BT_FW, &bt_length);
|
|
SCSC_TAG_INFO(MXMAN, "BT %p\n", bt_fw);
|
|
if (bt_fw == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "fhdr_lookup_tag FHDR_TAG_BT_FW failed. Try to read WLAN\n");
|
|
bhdr_destroy(bhdr_if);
|
|
*fw_wpan = bhdr_if = NULL;
|
|
mxman->wpan_present = false;
|
|
goto cont_no_bt;
|
|
}
|
|
|
|
r = bhdr_if->init(bhdr_if, (char *)bt_fw, bt_length, skip_header);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "bwhdr_init() failed\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
mxman->wpan_present = true;
|
|
bt_fw_offset_val = bhdr_if->get_fw_offset(bhdr_if);
|
|
bt_fw_runtime_size_val = bhdr_if->get_fw_rt_len(bhdr_if);
|
|
|
|
/* Do size check before copying to DRAM */
|
|
if ((bt_fw_runtime_size_val + wlan_fw_runtime_size_val) > size_dram) {
|
|
SCSC_TAG_ERR(MXMAN, "firmware image too big for buffer (%zu > %u)", size_dram,
|
|
bt_fw_runtime_size_val + wlan_fw_runtime_size_val);
|
|
mx140_release_file(mxman->mx, firm);
|
|
return -EINVAL;
|
|
}
|
|
mif->remap_set(mif, (uintptr_t)bt_fw_offset_val, SCSC_MIF_ABS_TARGET_WPAN);
|
|
|
|
cont_no_bt:
|
|
whdr_if->copy_fw(whdr_if, (char *)wlan_fw, wlan_length, start_dram);
|
|
if (bhdr_if)
|
|
bhdr_if->copy_fw(bhdr_if, (char *)bt_fw, bt_length, start_dram);
|
|
|
|
/* set remaper address */
|
|
mif->remap_set(mif, (uintptr_t)0x00000000, SCSC_MIF_ABS_TARGET_WLAN);
|
|
|
|
/* Get log-string.bin */
|
|
log_strings = fhdr_lookup_tag(firm->data, FHDR_TAG_WLAN_STRINGS, &log_strings_length);
|
|
if (log_strings == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "fhdr_lookup_tag FHDR_TAG_WLAN_STRINGS failed\n");
|
|
} else {
|
|
SCSC_TAG_INFO(MXMAN, "Loading WLAN log-strings %d\n", log_strings_length);
|
|
mxlog_load_log_strings(scsc_mx_get_mxlog(mxman->mx), log_strings, log_strings_length);
|
|
}
|
|
|
|
log_strings = fhdr_lookup_tag(firm->data, FHDR_TAG_BT_STRINGS, &log_strings_length);
|
|
if (log_strings == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "fhdr_lookup_tag FHDR_TAG_BT_STRINGS failed\n");
|
|
} else {
|
|
SCSC_TAG_INFO(MXMAN, "Loading BT log-strings %d\n", log_strings_length);
|
|
mxlog_load_log_strings(scsc_mx_get_mxlog_wpan(mxman->mx), log_strings, log_strings_length);
|
|
}
|
|
|
|
SCSC_TAG_ERR(MXMAN, "Search PMU in FWHR blob\n");
|
|
pmu = (struct pmu_firmware_header *)fhdr_lookup_tag(firm->data, FHDR_TAG_PMU_FW, &pmu_length);
|
|
if (pmu)
|
|
goto found;
|
|
|
|
SCSC_TAG_ERR(MXMAN, "Search PMU in WLAN blob\n");
|
|
#if defined(CONFIG_SOC_S5E8825)
|
|
pmu = (struct pmu_firmware_header *)fw_obj_index_lookup_tag(wlan_fw, PMU_8051_INIT, &pmu_length);
|
|
#else
|
|
pmu = (struct pmu_firmware_header *)fw_obj_index_lookup_tag(wlan_fw, PMU_CM0_INIT, &pmu_length);
|
|
#endif
|
|
if (pmu == NULL) {
|
|
SCSC_TAG_ERR(MXMAN, "PMU not found in WLAN blob or FWHRD\n");
|
|
goto not_found;
|
|
}
|
|
found:
|
|
SCSC_TAG_INFO(MXMAN, "Loading PMU fw %u\n", pmu_length);
|
|
SCSC_TAG_INFO(MXMAN, "PMU hdr_version %u size %u\n", pmu->hdr_version, pmu->hdr_size);
|
|
SCSC_TAG_INFO(MXMAN, "PMU fw_offset %u fw_size %u\n", pmu->fw_offset, pmu->fw_size);
|
|
SCSC_TAG_INFO(MXMAN, "PMU fw_patch version 0x%x\n", pmu->fw_patch_ver);
|
|
/* Load the FW extracted in PMU image and copy to platform driver */
|
|
mifpmuman_load_fw(scsc_mx_get_mifpmuman(mxman->mx), (int *)((uintptr_t)pmu + pmu->fw_offset), pmu->fw_size);
|
|
|
|
not_found:
|
|
SCSC_TAG_INFO(MXMAN, "Releasing firm file\n");
|
|
mx140_release_file(mxman->mx, firm);
|
|
|
|
mxman->fw = fw;
|
|
mxman->fw_image_size = fw_image_size;
|
|
if (whdr_if->get_check_crc(whdr_if)) {
|
|
/* do CRC on the entire image */
|
|
r = whdr_if->do_fw_crc32_checks(whdr_if, true);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "do_fw_crc32_checks() failed\n");
|
|
return r;
|
|
}
|
|
whdr_if->crc_wq_start(whdr_if);
|
|
}
|
|
|
|
if (whdr_if->get_parsed_ok(whdr_if)) {
|
|
build_id = whdr_if->get_build_id(whdr_if);
|
|
if (build_id) {
|
|
struct slsi_kic_service_info kic_info;
|
|
|
|
(void)snprintf(mxman->fw_build_id, sizeof(mxman->fw_build_id), "%s", build_id);
|
|
SCSC_TAG_INFO(MXMAN, "Firmware BUILD_ID: %s\n", mxman->fw_build_id);
|
|
|
|
(void)snprintf(kic_info.ver_str, min(sizeof(mxman->fw_build_id), sizeof(kic_info.ver_str)),
|
|
"%s", mxman->fw_build_id);
|
|
kic_info.fw_api_major = whdr_if->get_fwapi_major(whdr_if);
|
|
kic_info.fw_api_minor = whdr_if->get_fwapi_minor(whdr_if);
|
|
kic_info.release_product = SCSC_RELEASE_PRODUCT;
|
|
kic_info.host_release_iteration = SCSC_RELEASE_ITERATION;
|
|
kic_info.host_release_candidate = SCSC_RELEASE_CANDIDATE;
|
|
|
|
slsi_kic_service_information(slsi_kic_technology_type_common, &kic_info);
|
|
} else
|
|
SCSC_TAG_ERR(MXMAN, "Failed to get Firmware BUILD_ID\n");
|
|
|
|
ttid = whdr_if->get_ttid(whdr_if);
|
|
if (ttid) {
|
|
(void)snprintf(mxman->fw_ttid, sizeof(mxman->fw_ttid), "%s", ttid);
|
|
SCSC_TAG_INFO(MXMAN, "Firmware ttid: %s\n", mxman->fw_ttid);
|
|
}
|
|
}
|
|
|
|
SCSC_TAG_DEBUG(MXMAN, "firmware_entry_point=0x%x fw_runtime_length=%d\n", whdr_if->get_entry_point(whdr_if),
|
|
whdr_if->get_fw_rt_len(whdr_if));
|
|
|
|
return 0;
|
|
}
|
|
#ifdef CONFIG_SOC_S5E8825
|
|
int mxman_res_pmu_init(struct mxman *mxman, mifpmuisr_handler handler)
|
|
#else
|
|
int mxman_res_pmu_init(struct mxman *mxman)
|
|
#endif
|
|
{
|
|
struct scsc_mif_abs *mif;
|
|
mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
|
|
#ifdef CONFIG_SOC_S5E8825
|
|
mifpmuman_init(scsc_mx_get_mifpmuman(mxman->mx), mif, handler, mxman);
|
|
#else
|
|
mifpmuman_init(scsc_mx_get_mifpmuman(mxman->mx), mif, NULL, NULL);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mxman_res_pmu_deinit(struct mxman *mxman)
|
|
{
|
|
mifpmuman_deinit(scsc_mx_get_mifpmuman(mxman->mx));
|
|
return 0;
|
|
}
|
|
|
|
int mxman_res_pmu_boot(struct mxman *mxman, enum scsc_subsystem sub)
|
|
{
|
|
int r;
|
|
#ifdef CONFIG_SOC_S5E8825
|
|
/* This should be a blocking call, mifpmu should do the waitqueue */
|
|
r = mifpmuman_start_subsystem(scsc_mx_get_mifpmuman(mxman->mx), sub);
|
|
if (r)
|
|
SCSC_TAG_INFO(MXMAN, "PMU error\n");
|
|
return r;
|
|
#else
|
|
enum pmu_msg msg;
|
|
|
|
switch (sub) {
|
|
case SCSC_SUBSYSTEM_WLAN:
|
|
SCSC_TAG_INFO(MXMAN, "Booting WLAN subsystem\n");
|
|
msg = PMU_AP_MB_MSG_START_WLAN;
|
|
break;
|
|
case SCSC_SUBSYSTEM_WPAN:
|
|
SCSC_TAG_INFO(MXMAN, "Booting WPAN subsystem\n");
|
|
msg = PMU_AP_MB_MSG_START_WPAN;
|
|
break;
|
|
default:
|
|
SCSC_TAG_ERR(MXMAN, "Subsystem %d not found\n", sub);
|
|
return -EIO;
|
|
}
|
|
|
|
/* This should be a blocking call, mifpmu should do the waitqueue */
|
|
r = mifpmuman_send_msg(scsc_mx_get_mifpmuman(mxman->mx), msg);
|
|
if (r) {
|
|
SCSC_TAG_INFO(MXMAN, "PMU error\n");
|
|
return r;
|
|
}
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_SOC_S5E8825
|
|
int mxman_res_pmu_reset(struct mxman *mxman, enum scsc_subsystem sub)
|
|
{
|
|
int r;
|
|
|
|
/* This should be a blocking call, mifpmu should do the waitqueue */
|
|
r = mifpmuman_stop_subsystem(scsc_mx_get_mifpmuman(mxman->mx), sub);
|
|
if (r)
|
|
SCSC_TAG_INFO(MXMAN, "PMU error\n");
|
|
return r;
|
|
}
|
|
#else
|
|
int mxman_res_pmu_reset(struct mxman *mxman, enum scsc_subsystem sub)
|
|
{
|
|
enum pmu_msg msg;
|
|
int r;
|
|
|
|
switch (sub) {
|
|
case SCSC_SUBSYSTEM_WLAN:
|
|
SCSC_TAG_INFO(MXMAN, "Stopping WLAN subsystem\n");
|
|
msg = PMU_AP_MB_MSG_RESET_WLAN;
|
|
break;
|
|
case SCSC_SUBSYSTEM_WPAN:
|
|
SCSC_TAG_INFO(MXMAN, "Stopping WPAN subsystem\n");
|
|
msg = PMU_AP_MB_MSG_RESET_WPAN;
|
|
break;
|
|
default:
|
|
SCSC_TAG_ERR(MXMAN, "Subsystem %d not found\n", sub);
|
|
return -EIO;
|
|
}
|
|
|
|
/* This should be a blocking call, mifpmu should do the waitqueue */
|
|
r = mifpmuman_send_msg(scsc_mx_get_mifpmuman(mxman->mx), msg);
|
|
if (r) {
|
|
SCSC_TAG_INFO(MXMAN, "PMU error\n");
|
|
return r;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_SOC_S5E8825
|
|
int mxman_res_pmu_monitor(struct mxman *mxman, enum scsc_subsystem sub)
|
|
{
|
|
int r;
|
|
|
|
/* This should be a blocking call, mifpmu should do the waitqueue */
|
|
r = mifpmuman_force_monitor_mode_subsystem(scsc_mx_get_mifpmuman(mxman->mx), sub);
|
|
if (r)
|
|
SCSC_TAG_INFO(MXMAN, "PMU error\n");
|
|
return r;
|
|
}
|
|
#endif
|
|
|
|
static int mxman_res_transports_deinit_wlan(struct mxman *mxman)
|
|
{
|
|
mxlog_transport_release(scsc_mx_get_mxlog_transport(mxman->mx));
|
|
mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mxman->mx));
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_wlan(mxman->mx));
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_fxm_1(mxman->mx));
|
|
#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_fxm_2(mxman->mx));
|
|
#endif
|
|
if (mxman->data_mxconf){
|
|
miframman_free(scsc_mx_get_ramman(mxman->mx), mxman->data_mxconf);
|
|
mxman->data_mxconf = NULL;
|
|
}
|
|
|
|
mxlog_release(scsc_mx_get_mxlog(mxman->mx));
|
|
/* unregister channel handler */
|
|
mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mxman->mx),
|
|
MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, NULL, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int mxman_res_transports_deinit_wpan(struct mxman *mxman)
|
|
{
|
|
mxlog_transport_release(scsc_mx_get_mxlog_transport_wpan(mxman->mx));
|
|
mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport_wpan(mxman->mx));
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_wpan(mxman->mx));
|
|
if (mxman->data_mxconf_wpan){
|
|
miframman_free(scsc_mx_get_ramman_wpan(mxman->mx), mxman->data_mxconf_wpan);
|
|
mxman->data_mxconf_wpan = NULL;
|
|
}
|
|
|
|
mxlog_release(scsc_mx_get_mxlog_wpan(mxman->mx));
|
|
/* unregister channel handler */
|
|
mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport_wpan(mxman->mx),
|
|
MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, NULL, NULL);
|
|
return 0;
|
|
}
|
|
|
|
int mxman_res_deinit_subsystem(struct mxman *mxman, enum scsc_subsystem sub)
|
|
{
|
|
SCSC_TAG_INFO(MXMAN, "Deinit %s subsystem\n", sub ? "WPAN" : "WLAN");
|
|
|
|
switch (sub) {
|
|
case SCSC_SUBSYSTEM_WLAN:
|
|
mxfwconfig_unload(mxman->mx);
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
mxlogger_stop_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WLAN);
|
|
mxlogger_deinit_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WLAN);
|
|
#endif
|
|
mxman_res_transports_deinit_wlan(mxman);
|
|
/* Deinit WLAN MIF interrupt */
|
|
mifintrbit_deinit(scsc_mx_get_intrbit(mxman->mx), SCSC_MIF_ABS_TARGET_WLAN);
|
|
mifmboxman_deinit(scsc_mx_get_mboxman(mxman->mx));
|
|
break;
|
|
case SCSC_SUBSYSTEM_WPAN:
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
mxlogger_stop_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WPAN);
|
|
mxlogger_deinit_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WPAN);
|
|
#endif
|
|
mxman_res_transports_deinit_wpan(mxman);
|
|
/* Deinit WLAN MIF interrupt */
|
|
mifintrbit_deinit(scsc_mx_get_intrbit_wpan(mxman->mx), SCSC_MIF_ABS_TARGET_WPAN);
|
|
mifmboxman_deinit(scsc_mx_get_mboxman_wpan(mxman->mx));
|
|
break;
|
|
default:
|
|
SCSC_TAG_ERR(MXMAN, "Subsystem %d not found\n", sub);
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if !IS_ENABLED(CONFIG_SCSC_PCIE_PAEAN_X86) && !IS_ENABLED(CONFIG_SOC_S5E9925)
|
|
static void mxman_res_mbox_init_wlan(struct mxman *mxman, u32 firmware_entry_point)
|
|
{
|
|
u32 *mbox0;
|
|
u32 *mbox1;
|
|
u32 *mbox2;
|
|
u32 *mbox3;
|
|
scsc_mifram_ref mifram_ref;
|
|
struct scsc_mx *mx = mxman->mx;
|
|
struct scsc_mif_abs *mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
|
|
/* Place firmware entry address in MIF MBOX 0 so R4 ROM knows where to jump to! */
|
|
mbox0 = mifmboxman_get_mbox_ptr(scsc_mx_get_mboxman(mx), mif, MBOX_INDEX_0);
|
|
mbox1 = mifmboxman_get_mbox_ptr(scsc_mx_get_mboxman(mx), mif, MBOX_INDEX_1);
|
|
|
|
/* Write (and flush) entry point to MailBox 0, config address to MBOX 1 */
|
|
*mbox0 = 0xcafecafe;
|
|
mif->get_mifram_ref(mif, mxman->mxconf, &mifram_ref);
|
|
*mbox1 = mifram_ref; /* must be R4-relative address here */
|
|
|
|
/*
|
|
* write the magic number "0xbcdeedcb" to MIF Mailbox #2 &
|
|
* copy the firmware_startup_flags to MIF Mailbox #3 before starting (reset = 0) the R4
|
|
*/
|
|
mbox2 = mifmboxman_get_mbox_ptr(scsc_mx_get_mboxman(mx), mif, MBOX_INDEX_2);
|
|
*mbox2 = MBOX2_MAGIC_NUMBER;
|
|
mbox3 = mifmboxman_get_mbox_ptr(scsc_mx_get_mboxman(mx), mif, MBOX_INDEX_3);
|
|
*mbox3 = firmware_startup_flags;
|
|
|
|
/* CPU memory barrier */
|
|
smp_wmb();
|
|
}
|
|
#endif
|
|
|
|
static int mxman_res_transports_init_wlan(struct mxman *mxman, void *data, size_t data_sz,
|
|
mxmgmt_channel_handler handler)
|
|
{
|
|
struct mxconf *mxconf;
|
|
int r;
|
|
struct scsc_mif_abs *mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
struct scsc_mx *mx = mxman->mx;
|
|
#if !IS_ENABLED(CONFIG_SCSC_PCIE_PAEAN_X86) && !IS_ENABLED(CONFIG_SOC_S5E9925)
|
|
struct fwhdr_if *whdr_if = mxman->fw_wlan;
|
|
#endif
|
|
|
|
/* Initialise mx management stack */
|
|
r = mxmgmt_transport_init(scsc_mx_get_mxmgmt_transport(mx), mx, SCSC_MIF_ABS_TARGET_WLAN);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "mxmgmt_transport_init() failed %d\n", r);
|
|
return r;
|
|
}
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
r = mxlogger_init_transport_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WLAN);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "mxlogger_init_transport_channel() failed %d for WLAN\n", r);
|
|
/* Ignore return value */
|
|
}
|
|
#endif
|
|
/* Initialise gdb transport for cortex-R4 */
|
|
r = gdb_transport_init(scsc_mx_get_gdb_transport_wlan(mx), mx, GDB_TRANSPORT_WLAN);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "gdb_transport_init() failed %d\n", r);
|
|
mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mx));
|
|
return r;
|
|
}
|
|
|
|
/* Initialise gdb transport for cortex-M4 */
|
|
r = gdb_transport_init(scsc_mx_get_gdb_transport_fxm_1(mx), mx, GDB_TRANSPORT_FXM_1);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "gdb_transport_init() failed %d\n", r);
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_wlan(mx));
|
|
mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mx));
|
|
return r;
|
|
}
|
|
#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
|
|
/* Initialise gdb transport for cortex-M4 */
|
|
r = gdb_transport_init(scsc_mx_get_gdb_transport_fxm_2(mx), mx, GDB_TRANSPORT_FXM_2);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "gdb_transport_init() failed %d\n", r);
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_wlan(mx));
|
|
mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mx));
|
|
return r;
|
|
}
|
|
#endif
|
|
|
|
/* Initialise mxlog transport */
|
|
r = mxlog_transport_init(scsc_mx_get_mxlog_transport(mx), mx);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "mxlog_transport_init() failed %d\n", r);
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_fxm_1(mx));
|
|
#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_fxm_2(mx));
|
|
#endif
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_wlan(mx));
|
|
mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mx));
|
|
return r;
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* Allocate & Initialise Infrastructre Config Structure
|
|
* including the mx management stack config information.
|
|
*/
|
|
mxconf = miframman_alloc(scsc_mx_get_ramman(mx), sizeof(struct mxconf), 4, MIFRAMMAN_OWNER_COMMON);
|
|
if (!mxconf) {
|
|
goto error_alloc;
|
|
}
|
|
mxman->mxconf = mxconf;
|
|
#endif
|
|
/* mxconf is preallocated when initializing the mem layout */
|
|
mxconf = mxman->mxconf;
|
|
|
|
/* Allocate and copy arbiratry service data if exists */
|
|
if (data && data_sz) {
|
|
mxman->data_mxconf = miframman_alloc(scsc_mx_get_ramman(mx), data_sz, 4, MIFRAMMAN_OWNER_COMMON);
|
|
if (!mxman->data_mxconf) {
|
|
miframman_free(scsc_mx_get_ramman(mxman->mx), mxman->mxconf);
|
|
goto error_alloc;
|
|
}
|
|
memcpy(mxman->data_mxconf, data, data_sz);
|
|
mif->get_mifram_ref(mif, mxman->data_mxconf, &mxconf->subsysconf_offset);
|
|
mxconf->subsysconf_length = data_sz;
|
|
SCSC_TAG_INFO(MXMAN, "mxconf subsysconf_offset %d subsysconf_length %d\n", mxconf->subsysconf_offset,
|
|
mxconf->subsysconf_length);
|
|
} else {
|
|
mxman->data_mxconf = NULL;
|
|
}
|
|
|
|
mxconf->magic = MXCONF_MAGIC;
|
|
mxconf->version.major = MXCONF_VERSION_MAJOR;
|
|
|
|
mxconf->version.minor = MXCONF_VERSION_MINOR;
|
|
/* Pass pre-existing FM status to FW */
|
|
mxconf->flags = 0;
|
|
#if IS_ENABLED(CONFIG_SCSC_FM)
|
|
mxconf->flags |= mxman->on_halt_ldos_on ? MXCONF_FLAGS_FM_ON : 0;
|
|
#endif
|
|
SCSC_TAG_INFO(MXMAN, "mxconf flags 0x%08x\n", mxconf->flags);
|
|
|
|
/* serialise mxmgmt transport */
|
|
mxmgmt_transport_config_serialise(scsc_mx_get_mxmgmt_transport(mx), &mxconf->mx_trans_conf);
|
|
/* serialise Cortex-R4 gdb transport */
|
|
gdb_transport_config_serialise(scsc_mx_get_gdb_transport_wlan(mx), &mxconf->monitor_c0_trans_conf);
|
|
/* serialise Cortex-M4 gdb transport */
|
|
gdb_transport_config_serialise(scsc_mx_get_gdb_transport_fxm_1(mx), &mxconf->monitor_c1_trans_conf);
|
|
|
|
/* Default to Fleximac M4_1 monitor channel not in use.
|
|
* Allows CONFIG_SCSC_MX450_GDB_SUPPORT to be turned off in Kconfig even though mxconf
|
|
* struct v5 defines M4_1 channel
|
|
*/
|
|
mxconf->monitor_c2_trans_conf.from_ap_stream_conf.buf_conf.buffer_loc = 0;
|
|
#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
|
|
/* serialise Cortex-M4 gdb transport */
|
|
gdb_transport_config_serialise(scsc_mx_get_gdb_transport_fxm_2(mx), &mxconf->monitor_c2_trans_conf);
|
|
#endif
|
|
/* serialise mxlog transport */
|
|
mxlog_transport_config_serialise(scsc_mx_get_mxlog_transport(mx), &mxconf->mxlogconf);
|
|
SCSC_TAG_DEBUG(
|
|
MXMAN,
|
|
"read_bit_idx=%d write_bit_idx=%d buffer=%p num_packets=%d packet_size=%d read_index=%d write_index=%d\n",
|
|
scsc_mx_get_mxlog_transport(mx)->mif_stream.read_bit_idx,
|
|
scsc_mx_get_mxlog_transport(mx)->mif_stream.write_bit_idx,
|
|
scsc_mx_get_mxlog_transport(mx)->mif_stream.buffer.buffer,
|
|
scsc_mx_get_mxlog_transport(mx)->mif_stream.buffer.num_packets,
|
|
scsc_mx_get_mxlog_transport(mx)->mif_stream.buffer.packet_size,
|
|
*scsc_mx_get_mxlog_transport(mx)->mif_stream.buffer.read_index,
|
|
*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;
|
|
|
|
mxconf->mxlogger_area_offset = 0;
|
|
mxconf->mxlogger_area_length = 0;
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
mxconf->mxlogger_area_offset =
|
|
mxlogger_get_channel_ref(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WLAN);
|
|
mxconf->mxlogger_area_length =
|
|
mxlogger_get_channel_len(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WLAN);
|
|
#endif
|
|
SCSC_TAG_INFO(MXMAN, "mxlogger_area_offset 0x%x mxlogger_area_length 0x%x\n", mxconf->mxlogger_area_offset,
|
|
mxconf->mxlogger_area_length);
|
|
|
|
#ifdef CONFIG_SCSC_COMMON_HCF
|
|
/* Load Common Config HCF */
|
|
mxfwconfig_load(mxman->mx, &mxconf->fwconfig);
|
|
#endif
|
|
|
|
#if !IS_ENABLED(CONFIG_SCSC_PCIE_PAEAN_X86) && !IS_ENABLED(CONFIG_SOC_S5E9925)
|
|
mxman_res_mbox_init_wlan(mxman, whdr_if->get_entry_point(whdr_if));
|
|
#endif
|
|
|
|
mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport(mxman->mx),
|
|
MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, handler, mxman);
|
|
mxlog_init(scsc_mx_get_mxlog(mxman->mx), mxman->mx, mxman->fw_build_id, SCSC_MIF_ABS_TARGET_WLAN);
|
|
|
|
return 0;
|
|
|
|
error_alloc:
|
|
SCSC_TAG_ERR(MXMAN, "miframman_alloc() failed\n");
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_fxm_1(mx));
|
|
#ifdef CONFIG_SCSC_MX450_GDB_SUPPORT
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_fxm_2(mx));
|
|
#endif
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_wlan(mx));
|
|
mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport(mx));
|
|
mxlog_transport_release(scsc_mx_get_mxlog_transport(mx));
|
|
return -ENOMEM;
|
|
}
|
|
|
|
static int mxman_res_transports_init_wpan(struct mxman *mxman, void *data, size_t data_sz,
|
|
mxmgmt_channel_handler handler)
|
|
{
|
|
struct mxconf *mxconf_wpan;
|
|
int r;
|
|
struct scsc_mif_abs *mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
struct scsc_mx *mx = mxman->mx;
|
|
|
|
/* Initialise mx management stack for WPAN */
|
|
r = mxmgmt_transport_init(scsc_mx_get_mxmgmt_transport_wpan(mx), mx, SCSC_MIF_ABS_TARGET_WPAN);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "mxmgmt_transport_init() failed %d for WPAN\n", r);
|
|
return r;
|
|
}
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
r = mxlogger_init_transport_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WPAN);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "mxlogger_init_transport_channel() failed %d for WPAN\n", r);
|
|
/* Ignore return value */
|
|
}
|
|
#endif
|
|
/* Initialise gdb transport for cortex-WPAN */
|
|
r = gdb_transport_init(scsc_mx_get_gdb_transport_wpan(mx), mx, GDB_TRANSPORT_WPAN);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "gdb_transport_init() failed %d\n", r);
|
|
mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport_wpan(mx));
|
|
return r;
|
|
}
|
|
|
|
/* Initialise mxlog transport */
|
|
r = mxlog_transport_init_wpan(scsc_mx_get_mxlog_transport_wpan(mx), mx);
|
|
if (r) {
|
|
SCSC_TAG_ERR(MXMAN, "mxlog_transport_init() failed %d\n", r);
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_wpan(mx));
|
|
mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport_wpan(mx));
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Allocate & Initialise Infrastructre Config Structure
|
|
* including the mx management stack config information.
|
|
*/
|
|
/* mxconf is preallocated when initializing the mem layout */
|
|
mxconf_wpan = mxman->mxconf_wpan;
|
|
|
|
/* Allocate and copy arbiratry service data if exists */
|
|
if (data && data_sz) {
|
|
mxman->data_mxconf_wpan =
|
|
miframman_alloc(scsc_mx_get_ramman_wpan(mx), data_sz, 4, MIFRAMMAN_OWNER_COMMON);
|
|
if (!mxman->data_mxconf_wpan) {
|
|
miframman_free(scsc_mx_get_ramman_wpan(mxman->mx), mxman->mxconf_wpan);
|
|
goto error_alloc;
|
|
}
|
|
memcpy(mxman->data_mxconf_wpan, data, data_sz);
|
|
mif->get_mifram_ref(mif, mxman->data_mxconf_wpan, &mxconf_wpan->subsysconf_offset);
|
|
mxconf_wpan->subsysconf_length = data_sz;
|
|
SCSC_TAG_INFO(MXMAN, "mxconf_wpan subsysconf_offset %d subsysconf_length %d\n",
|
|
mxconf_wpan->subsysconf_offset, mxconf_wpan->subsysconf_length);
|
|
} else {
|
|
mxman->data_mxconf_wpan = NULL;
|
|
}
|
|
|
|
mxconf_wpan->magic = MXCONF_MAGIC;
|
|
mxconf_wpan->version.major = MXCONF_VERSION_MAJOR;
|
|
|
|
mxconf_wpan->version.minor = MXCONF_VERSION_MINOR;
|
|
/* Pass pre-existing FM status to FW */
|
|
mxconf_wpan->flags = 0;
|
|
#if IS_ENABLED(CONFIG_SCSC_FM)
|
|
mxconf_wpan->flags |= mxman->on_halt_ldos_on ? MXCONF_FLAGS_FM_ON : 0;
|
|
#endif
|
|
SCSC_TAG_INFO(MXMAN, "mxconf_wpan flags 0x%08x\n", mxconf_wpan->flags);
|
|
|
|
/* serialise mxmgmt transport */
|
|
mxmgmt_transport_config_serialise(scsc_mx_get_mxmgmt_transport_wpan(mx), &mxconf_wpan->mx_trans_conf);
|
|
/* serialise WPAN gdb transport */
|
|
gdb_transport_config_serialise(scsc_mx_get_gdb_transport_wpan(mx), &mxconf_wpan->monitor_c0_trans_conf);
|
|
|
|
/* serialise mxlog transport */
|
|
mxlog_transport_config_serialise(scsc_mx_get_mxlog_transport_wpan(mx), &mxconf_wpan->mxlogconf);
|
|
SCSC_TAG_DEBUG(
|
|
MXMAN,
|
|
"read_bit_idx=%d write_bit_idx=%d buffer=%p num_packets=%d packet_size=%d read_index=%d write_index=%d\n",
|
|
scsc_mx_get_mxlog_transport_wpan(mx)->mif_stream.read_bit_idx,
|
|
scsc_mx_get_mxlog_transport_wpan(mx)->mif_stream.write_bit_idx,
|
|
scsc_mx_get_mxlog_transport_wpan(mx)->mif_stream.buffer.buffer,
|
|
scsc_mx_get_mxlog_transport_wpan(mx)->mif_stream.buffer.num_packets,
|
|
scsc_mx_get_mxlog_transport_wpan(mx)->mif_stream.buffer.packet_size,
|
|
*scsc_mx_get_mxlog_transport_wpan(mx)->mif_stream.buffer.read_index,
|
|
*scsc_mx_get_mxlog_transport_wpan(mx)->mif_stream.buffer.write_index);
|
|
|
|
/* Need to initialise fwconfig or else random data can make firmware data abort. */
|
|
mxconf_wpan->fwconfig.offset = 0;
|
|
mxconf_wpan->fwconfig.size = 0;
|
|
|
|
mxconf_wpan->mxlogger_area_offset = 0;
|
|
mxconf_wpan->mxlogger_area_length = 0;
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
mxconf_wpan->mxlogger_area_offset =
|
|
mxlogger_get_channel_ref(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WPAN);
|
|
mxconf_wpan->mxlogger_area_length =
|
|
mxlogger_get_channel_len(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WPAN);
|
|
#endif
|
|
SCSC_TAG_INFO(MXMAN, "mxlogger_area_offset 0x%x mxlogger_area_length 0x%x\n", mxconf_wpan->mxlogger_area_offset,
|
|
mxconf_wpan->mxlogger_area_length);
|
|
|
|
SCSC_TAG_INFO(MXMAN, "mxconfig in DRAM\n");
|
|
|
|
mxmgmt_transport_register_channel_handler(scsc_mx_get_mxmgmt_transport_wpan(mxman->mx),
|
|
MMTRANS_CHAN_ID_MAXWELL_MANAGEMENT, handler, mxman);
|
|
mxlog_init(scsc_mx_get_mxlog_wpan(mxman->mx), mxman->mx, mxman->fw_build_id, SCSC_MIF_ABS_TARGET_WPAN);
|
|
|
|
return 0;
|
|
|
|
error_alloc:
|
|
SCSC_TAG_ERR(MXMAN, "miframman_alloc() failed\n");
|
|
gdb_transport_release(scsc_mx_get_gdb_transport_wpan(mx));
|
|
mxmgmt_transport_release(scsc_mx_get_mxmgmt_transport_wpan(mx));
|
|
mxlog_transport_release(scsc_mx_get_mxlog_transport_wpan(mx));
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Initialize common components/subystems */
|
|
int mxman_res_init_common(struct mxman *mxman)
|
|
{
|
|
struct scsc_mif_abs *mif;
|
|
int ret = 0;
|
|
|
|
SCSC_TAG_INFO(MXMAN, "Init common components\n");
|
|
mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
#ifdef CONFIG_SCSC_SMAPPER
|
|
/* Initialize SMAPPER */
|
|
ret = mifsmapper_init(scsc_mx_get_smapper(mxman->mx), mif);
|
|
if(ret)
|
|
return ret;
|
|
#endif
|
|
#ifdef CONFIG_SCSC_QOS
|
|
ret = mifqos_init(scsc_mx_get_qos(mxman->mx), mif);
|
|
if(ret)
|
|
return ret;
|
|
#endif
|
|
#ifdef CONFIG_SCSC_LAST_PANIC_IN_DRAM
|
|
ret = scsc_log_in_dram_mmap_create();
|
|
if(ret)
|
|
return ret;
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
/* Deinitialize common components/subystems */
|
|
int mxman_res_deinit_common(struct mxman *mxman)
|
|
{
|
|
int ret = 0;
|
|
|
|
SCSC_TAG_INFO(MXMAN, "Deinit common components\n");
|
|
#ifdef CONFIG_SCSC_SMAPPER
|
|
ret = mifsmapper_deinit(scsc_mx_get_smapper(mxman->mx));
|
|
if(ret)
|
|
return ret;
|
|
#endif
|
|
#ifdef CONFIG_SCSC_QOS
|
|
ret = mifqos_deinit(scsc_mx_get_qos(mxman->mx));
|
|
if(ret)
|
|
return ret;
|
|
#endif
|
|
#ifdef CONFIG_SCSC_LAST_PANIC_IN_DRAM
|
|
ret = scsc_log_in_dram_mmap_destroy();
|
|
if(ret)
|
|
return ret;
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
int mxman_res_init_subsystem(struct mxman *mxman, enum scsc_subsystem sub, void *data, size_t data_sz,
|
|
mxmgmt_channel_handler handler)
|
|
{
|
|
struct scsc_mif_abs *mif;
|
|
int r = -EIO;
|
|
|
|
mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
|
|
switch (sub) {
|
|
case SCSC_SUBSYSTEM_WLAN:
|
|
mxfwconfig_init(mxman->mx);
|
|
/* INTMIF init before allocating transports */
|
|
mifintrbit_init(scsc_mx_get_intrbit(mxman->mx), mif, SCSC_MIF_ABS_TARGET_WLAN);
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
/* Mxlogger init before allocating transports*/
|
|
/* Ignore return value */
|
|
mxlogger_init_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WLAN);
|
|
#endif
|
|
r = mxman_res_transports_init_wlan(mxman, data, data_sz, handler);
|
|
break;
|
|
case SCSC_SUBSYSTEM_WPAN:
|
|
/* INTMIF init before allocating transports */
|
|
mifintrbit_init(scsc_mx_get_intrbit_wpan(mxman->mx), mif, SCSC_MIF_ABS_TARGET_WPAN);
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
/* Mxlogger init before allocating transports*/
|
|
mxlogger_init_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WPAN);
|
|
#endif
|
|
r = mxman_res_transports_init_wpan(mxman, data, data_sz, handler);
|
|
break;
|
|
default:
|
|
SCSC_TAG_ERR(MXMAN, "Subsystem %d not found\n", sub);
|
|
return -EIO;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
int mxman_res_reset(struct mxman *mxman, bool reset)
|
|
{
|
|
int r;
|
|
struct scsc_mif_abs *mif;
|
|
|
|
mif = scsc_mx_get_mif_abs(mxman->mx);
|
|
|
|
r = mif->reset(mif, reset);
|
|
if (r && !reset) {
|
|
SCSC_TAG_ERR(MXMAN, "HW reset deassertion failed\n");
|
|
return r;
|
|
} else if (r && reset) {
|
|
SCSC_TAG_ERR(MXMAN, "HW reset assertion failed\n");
|
|
return r;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mxman_res_post_init_subsystem(struct mxman *mxman, enum scsc_subsystem sub)
|
|
{
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
int r;
|
|
#endif
|
|
switch (sub) {
|
|
case SCSC_SUBSYSTEM_WLAN:
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
r = mxlogger_start_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WLAN);
|
|
if (r) {
|
|
mxlogger_deinit_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WPAN);
|
|
}
|
|
#endif
|
|
break;
|
|
case SCSC_SUBSYSTEM_WPAN:
|
|
#if IS_ENABLED(CONFIG_SCSC_MXLOGGER)
|
|
r = mxlogger_start_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WPAN);
|
|
if (r) {
|
|
mxlogger_deinit_channel(scsc_mx_get_mxlogger(mxman->mx), SCSC_MIF_ABS_TARGET_WPAN);
|
|
}
|
|
#endif
|
|
break;
|
|
default:
|
|
return -EIO;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int mxman_res_init(struct mxman *mxman)
|
|
{
|
|
return 0;
|
|
}
|