You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1213 lines
45 KiB

/*
* Copyright (C) 2016 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
*/
#include <linux/list.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/kdev_t.h>
#include <linux/slab.h>
#include <linux/kobject.h>
#include <linux/atomic.h>
#include "ccci_config.h"
#include "ccci_platform.h"
#include "ccci_core.h"
#include "ccci_bm.h"
#include "modem_sys.h"
#include "ccci_hif.h"
#include <mt-plat/mtk_meminfo.h>
#include <mt-plat/mtk_ccci_common.h>
#include <mt-plat/mtk_boot_common.h>
#if defined(ENABLE_32K_CLK_LESS)
#include <mt-plat/mtk_rtc.h>
#endif
#define TAG "md"
struct ccci_modem *modem_sys[MAX_MD_NUM];
/* flag for MD1_MD3_SMEM clear.
* if it is been cleared by md1 bootup flow, set it to 1.
* then it will not be cleared by md1 bootup flow
*/
static atomic_t md1_md3_smem_clear = ATOMIC_INIT(0);
#define DBM_S (CCCI_SMEM_SIZE_DBM + CCCI_SMEM_SIZE_DBM_GUARD * 2)
struct ccci_smem_region md1_6293_noncacheable_fat[] = {
{SMEM_USER_RAW_MDCCCI_DBG, 0, 2*1024, 0, },
{SMEM_USER_RAW_MDSS_DBG, 2*1024, 10*1024, 0, },
{SMEM_USER_RAW_RESERVED, 12*1024, 46*1024, 0, },
{SMEM_USER_RAW_RUNTIME_DATA, 58*1024, 4*1024, 0, },
{SMEM_USER_RAW_FORCE_ASSERT, 62*1024, 1*1024, 0, },
{SMEM_USER_RAW_DBM, 64*1024-DBM_S, DBM_S, 0, },
{SMEM_USER_CCISM_SCP, 64*1024, 32*1024, 0, },
{SMEM_USER_RAW_CCB_CTRL, 96*1024, 4*1024, SMF_NCLR_FIRST, },
{SMEM_USER_RAW_NETD, 100*1024, 4*1024, 0, },
{SMEM_USER_RAW_USB, 104*1024, 4*1024, 0, },
{SMEM_USER_RAW_AUDIO, 108*1024, 52*1024, SMF_NCLR_FIRST, },
{SMEM_USER_CCISM_MCU, 160*1024, (704+1)*1024, 0, },
{SMEM_USER_CCISM_MCU_EXP, 865*1024, (120+1)*1024, 0, },
/* for SIB */
{SMEM_USER_RAW_LWA, 1*1024*1024, 0*1024*1024, 0, },
{SMEM_USER_RAW_MD_CONSYS, 1*1024*1024, 0*1024*1024, 0, },
{SMEM_USER_RAW_PHY_CAP, 1*1024*1024, 0*1024*1024, SMF_NCLR_FIRST, },
{SMEM_USER_MAX, }, /* tail guard */
};
#define CCB_CACHE_MIN_SIZE (2 * 1024 * 1024)
struct ccci_smem_region md1_6293_cacheable[] = {
/*
* all CCB user should be put together, and the total size is set in the first one, all reset
* CCB users' address, offset and size will be re-calculated during port initialization.
* and please be aware of that CCB user's size will be aligned to 4KB.
*/
{SMEM_USER_CCB_DHL, 0*1024*1024, CCB_CACHE_MIN_SIZE, 0, },
{SMEM_USER_CCB_MD_MONITOR, 0*1024*1024, CCB_CACHE_MIN_SIZE, 0, },
{SMEM_USER_CCB_META, 0*1024*1024, CCB_CACHE_MIN_SIZE, 0, },
{SMEM_USER_RAW_DHL, CCB_CACHE_MIN_SIZE, 20*1024*1024, 0, },
{SMEM_USER_RAW_MDM, CCB_CACHE_MIN_SIZE, 20*1024*1024, 0, },
{SMEM_USER_MAX, },
};
struct ccci_smem_region md1_6292_noncacheable_fat[] = {
{SMEM_USER_RAW_MDCCCI_DBG, 0, 2*1024, 0, },
{SMEM_USER_RAW_MDSS_DBG, 2*1024, 10*1024, 0, },
{SMEM_USER_RAW_RESERVED, 12*1024, 46*1024, 0, },
{SMEM_USER_RAW_RUNTIME_DATA, 58*1024, 4*1024, 0, },
{SMEM_USER_RAW_FORCE_ASSERT, 62*1024, 1*1024, 0, },
{SMEM_USER_RAW_DBM, 64*1024-DBM_S, DBM_S, 0, },
{SMEM_USER_CCISM_SCP, 64*1024, 32*1024, 0, },
/* {SMEM_USER_RAW_CCB_CTRL, 96*1024, 4*1024, SMF_NCLR_FIRST, }, */
{SMEM_USER_RAW_NETD, 100*1024, 4*1024, 0, },
{SMEM_USER_RAW_USB, 104*1024, 4*1024, 0, },
{SMEM_USER_RAW_AUDIO, 108*1024, 20*1024, 0, },
#if defined(CONFIG_MTK_MD3_SUPPORT) && (CONFIG_MTK_MD3_SUPPORT > 0)
{SMEM_USER_RAW_MD2MD, 2*1024*1024, 2*1024*1024, SMF_MD3_RELATED, },
#endif
{SMEM_USER_MAX, }, /* tail guard */
};
struct ccci_smem_region md1_6292_cacheable[] = {
/*
* all CCB user should be put together, and the total size is set in the first one, all reset
* CCB users' address, offset and size will be re-calculated during port initialization.
* and please be aware of that CCB user's size will be aligned to 4KB.
*/
#if 0
{SMEM_USER_CCB_DHL, 0*1024*1024, 16*1024*1024, 0, },
{SMEM_USER_CCB_MD_MONITOR, 0*1024*1024, 16*1024*1024, 0, },
{SMEM_USER_CCB_META, 0*1024*1024, 16*1024*1024, 0, },
{SMEM_USER_RAW_DHL, 16*1024*1024, 16*1024*1024, 0, },
#endif
{SMEM_USER_RAW_LWA, 32*1024*1024, 0*1024*1024, 0, },
{SMEM_USER_MAX, },
};
struct ccci_smem_region md3_6292_noncacheable_fat[] = {
{SMEM_USER_RAW_MD2MD, 0, 2*1024*1024, 0, },
{SMEM_USER_RAW_MDCCCI_DBG, 2*1024*1024, 2*1024, 0, },
{SMEM_USER_RAW_MDSS_DBG, (2*1024 + 2)*1024, 2*1024, 0, },
{SMEM_USER_RAW_RESERVED, (2*1024 + 4)*1024, 54*1024, 0, },
{SMEM_USER_RAW_RUNTIME_DATA, (2*1024 + 58)*1024, 4*1024, 0, },
{SMEM_USER_RAW_FORCE_ASSERT, (2*1024 + 62)*1024, 1*1024, 0, },
{SMEM_USER_RAW_DBM, (2*1024 + 64)*1024-DBM_S, DBM_S, 0, },
{SMEM_USER_CCISM_SCP, (2*1024 + 64)*1024, 32*1024, 0, },
{SMEM_USER_RAW_AUDIO, (2*1024 + 96)*1024, 20*1024, 0, },
{SMEM_USER_CCISM_MCU, (2*1024 + 116)*1024, 1*1024*1024, 0, },
{SMEM_USER_MAX, },
};
struct ccci_smem_region md1_6291_noncacheable_fat[] = {
{SMEM_USER_RAW_MDCCCI_DBG, 0, 2*1024, 0, },
{SMEM_USER_RAW_MDSS_DBG, 2*1024, 10*1024, 0, },
{SMEM_USER_RAW_RESERVED, 12*1024, 50*1024, 0, },
{SMEM_USER_RAW_FORCE_ASSERT, 62*1024, 1*1024, 0, },
{SMEM_USER_RAW_DBM, 64*1024-DBM_S, DBM_S, 0, },
{SMEM_USER_RAW_RUNTIME_DATA, 64*1024, 4*1024, 0, },
{SMEM_USER_CCISM_SCP, 68*1024, 32*1024, 0, },
{SMEM_USER_RAW_NETD, 100*1024, 4*1024, 0, },
{SMEM_USER_RAW_USB, 104*1024, 4*1024, 0, },
#if defined(CONFIG_MTK_MD3_SUPPORT) && (CONFIG_MTK_MD3_SUPPORT > 0)
{SMEM_USER_RAW_MD2MD, 2*1024*1024, 2*1024*1024, SMF_MD3_RELATED, },
#endif
{SMEM_USER_MAX, },
};
struct ccci_smem_region md3_6291_noncacheable_fat[] = {
{SMEM_USER_RAW_MD2MD, 0, 2*1024*1024, 0, },
{SMEM_USER_RAW_MDCCCI_DBG, 2*1024*1024, 2*1024, 0, },
{SMEM_USER_RAW_MDSS_DBG, (2*1024 + 2)*1024, 2*1024, 0, },
{SMEM_USER_RAW_RESERVED, (2*1024 + 4)*1024, 58*1024, 0, },
{SMEM_USER_RAW_FORCE_ASSERT, (2*1024 + 62)*1024, 1*1024, 0, },
{SMEM_USER_RAW_DBM, (2*1024 + 64)*1024-DBM_S, DBM_S, 0, },
{SMEM_USER_RAW_RUNTIME_DATA, (2*1024 + 64)*1024, 4*1024, 0, },
{SMEM_USER_CCISM_SCP, (2*1024 + 68)*1024, 32*1024, 0, },
{SMEM_USER_CCISM_MCU, (2*1024 + 100)*1024, 1*1024*1024, 0, },
{SMEM_USER_MAX, },
};
static struct ccci_smem_region *get_smem_by_user_id(struct ccci_smem_region *regions, enum SMEM_USER_ID user_id)
{
int i;
for (i = 0; ; i++) {
if (!regions || regions[i].id == SMEM_USER_MAX)
return NULL;
if (regions[i].id == user_id) {
if (!get_modem_is_enabled(MD_SYS3) && (regions[i].flag & SMF_MD3_RELATED))
return NULL;
else
return regions + i;
}
}
return NULL;
}
static void init_smem_regions(struct ccci_smem_region *regions,
phys_addr_t base_ap_view_phy,
void __iomem *base_ap_view_vir,
phys_addr_t base_md_view_phy)
{
int i;
for (i = 0; ; i++) {
if (!regions || regions[i].id == SMEM_USER_MAX)
break;
if (!get_modem_is_enabled(MD_SYS3) && (regions[i].flag & SMF_MD3_RELATED))
continue;
regions[i].base_ap_view_phy = base_ap_view_phy + regions[i].offset;
regions[i].base_ap_view_vir = base_ap_view_vir + regions[i].offset;
regions[i].base_md_view_phy = base_md_view_phy + regions[i].offset;
CCCI_BOOTUP_LOG(-1, TAG, "init_smem_regions: reg[%d](%lx %p %lx)",
i, (unsigned long)regions[i].base_ap_view_phy,
regions[i].base_ap_view_vir, (unsigned long)regions[i].base_md_view_phy);
}
}
static void clear_smem_region(struct ccci_smem_region *regions, int first_boot)
{
int i;
for (i = 0; ; i++) {
if (!regions || regions[i].id == SMEM_USER_MAX)
break;
if (!get_modem_is_enabled(MD_SYS3) && (regions[i].flag & SMF_MD3_RELATED))
continue;
if (first_boot) {
if (!(regions[i].flag & SMF_NCLR_FIRST)) {
if (regions[i].id == SMEM_USER_RAW_MD2MD) {
if (atomic_add_unless(&md1_md3_smem_clear, 1, 1))
memset_io(regions[i].base_ap_view_vir, 0, regions[i].size);
} else {
memset_io(regions[i].base_ap_view_vir, 0, regions[i].size);
}
}
} else {
if (regions[i].flag & SMF_CLR_RESET)
memset_io(regions[i].base_ap_view_vir, 0, regions[i].size);
}
}
}
/* setup function is only for data structure initialization */
struct ccci_modem *ccci_md_alloc(int private_size)
{
struct ccci_modem *md = kzalloc(sizeof(struct ccci_modem), GFP_KERNEL);
if (!md) {
CCCI_ERROR_LOG(-1, TAG, "fail to allocate memory for modem structure\n");
goto out;
}
if (private_size > 0)
md->private_data = kzalloc(private_size, GFP_KERNEL);
else
md->private_data = NULL;
md->per_md_data.config.setting |= MD_SETTING_FIRST_BOOT;
md->per_md_data.is_in_ee_dump = 0;
md->is_force_asserted = 0;
md->per_md_data.md_dbg_dump_flag = MD_DBG_DUMP_AP_REG;
out:
return md;
}
static inline int log2_remain(unsigned int value)
{
int x = 0;
int y;
if (value < 32)
return -1;
/* value = (2^x)*y */
while (!(value & (1 << x)))
x++;
y = (value >> x);
if ((1 << x) * y != value)
WARN_ON(1);
return y;
}
void ccci_md_config(struct ccci_modem *md)
{
phys_addr_t md_resv_mem_addr = 0, md_resv_smem_addr = 0, md1_md3_smem_phy = 0;
unsigned int md_resv_mem_size = 0, md_resv_smem_size = 0, md1_md3_smem_size = 0;
int ret;
/* setup config */
md->per_md_data.config.load_type = get_md_img_type(md->index);
if (get_modem_is_enabled(md->index))
md->per_md_data.config.setting |= MD_SETTING_ENABLE;
else
md->per_md_data.config.setting &= ~MD_SETTING_ENABLE;
/* Get memory info */
get_md_resv_mem_info(md->index, &md_resv_mem_addr, &md_resv_mem_size, &md_resv_smem_addr, &md_resv_smem_size);
get_md1_md3_resv_smem_info(md->index, &md1_md3_smem_phy, &md1_md3_smem_size);
/* setup memory layout */
/* MD image */
md->mem_layout.md_bank0.base_ap_view_phy = md_resv_mem_addr;
md->mem_layout.md_bank0.size = md_resv_mem_size;
/* Share memory */
/*
* MD bank4 is remap to nearest 32M aligned address
* assume share memoy layout is:
* |---AP/MD1--| <--MD1 bank4 0x0 (non-cacheable)
* |--MD1/MD3--| <--MD3 bank4 0x0 (non-cacheable)
* |---AP/MD3--|
* |--non-used_-|
* |--cacheable--| <-- MD1 bank4 0x8000000 (for 6292)
* this should align with LK's remap setting
*/
/* non-cacheable region */
if (md->index == MD_SYS1)
md->mem_layout.md_bank4_noncacheable_total.base_ap_view_phy = md_resv_smem_addr;
else if (md->index == MD_SYS3)
md->mem_layout.md_bank4_noncacheable_total.base_ap_view_phy = md1_md3_smem_phy;
md->mem_layout.md_bank4_noncacheable_total.size = md_resv_smem_size + md1_md3_smem_size;
md->mem_layout.md_bank4_noncacheable_total.base_ap_view_vir =
ioremap_nocache(md->mem_layout.md_bank4_noncacheable_total.base_ap_view_phy,
md->mem_layout.md_bank4_noncacheable_total.size);
md->mem_layout.md_bank4_noncacheable_total.base_md_view_phy =
0x40000000 + md->mem_layout.md_bank4_noncacheable_total.base_ap_view_phy -
round_down(md->mem_layout.md_bank4_noncacheable_total.base_ap_view_phy, 0x02000000);
/* cacheable region */
#if (MD_GENERATION >= 6292)
get_md_resv_ccb_info(md->index,
&md->mem_layout.md_bank4_cacheable_total.base_ap_view_phy,
&md->mem_layout.md_bank4_cacheable_total.size);
if (md->mem_layout.md_bank4_cacheable_total.base_ap_view_phy &&
md->mem_layout.md_bank4_cacheable_total.size)
md->mem_layout.md_bank4_cacheable_total.base_ap_view_vir =
ioremap_nocache(md->mem_layout.md_bank4_cacheable_total.base_ap_view_phy,
md->mem_layout.md_bank4_cacheable_total.size);
else
CCCI_ERROR_LOG(md->index, TAG, "get ccb info base:%lx size:%x\n",
(unsigned long)md->mem_layout.md_bank4_cacheable_total.base_ap_view_phy,
md->mem_layout.md_bank4_cacheable_total.size);
#if (MD_GENERATION >= 6293)
if (md->index == MD_SYS1) {
md->mem_layout.md_bank4_cacheable_total.base_md_view_phy = 0x40000000
+ (224 * 1024 * 1024)
+ md->mem_layout.md_bank4_cacheable_total.base_ap_view_phy -
round_down(md->mem_layout.md_bank4_cacheable_total.base_ap_view_phy, 0x00100000);
}
#else
if (md->index == MD_SYS1) {
md->mem_layout.md_bank4_cacheable_total.base_md_view_phy = 0x40000000
+ get_md_smem_cachable_offset(MD_SYS1)
+ md->mem_layout.md_bank4_cacheable_total.base_ap_view_phy -
round_down(md->mem_layout.md_bank4_cacheable_total.base_ap_view_phy, 0x00100000);
}
#endif
#endif
CCCI_BOOTUP_LOG(md->index, TAG, "smem info: (%lx %lx %p %d) (%lx %lx %p %d)\n",
(unsigned long)md->mem_layout.md_bank4_noncacheable_total.base_ap_view_phy,
(unsigned long)md->mem_layout.md_bank4_noncacheable_total.base_md_view_phy,
md->mem_layout.md_bank4_noncacheable_total.base_ap_view_vir,
md->mem_layout.md_bank4_noncacheable_total.size,
(unsigned long)md->mem_layout.md_bank4_cacheable_total.base_ap_view_phy,
(unsigned long)md->mem_layout.md_bank4_cacheable_total.base_md_view_phy,
md->mem_layout.md_bank4_cacheable_total.base_ap_view_vir,
md->mem_layout.md_bank4_cacheable_total.size);
/* add alignment check */
#if (MD_GENERATION >= 6293)
ret = log2_remain(md->mem_layout.md_bank4_noncacheable_total.size);
if (md->mem_layout.md_bank4_noncacheable_total.size && (ret < 0 || ret > 16))
WARN_ON(1);
ret = log2_remain(md->mem_layout.md_bank4_cacheable_total.size);
if (md->mem_layout.md_bank4_cacheable_total.size && (ret < 0 || ret > 16))
WARN_ON(1);
#elif (MD_GENERATION == 6292)
if (md->mem_layout.md_bank4_noncacheable_total.size > (4 * 1024 * 1024))
WARN_ON(1);
if (md->mem_layout.md_bank4_cacheable_total.size > (128 * 1024 * 1024))
WARN_ON(1);
ret = 0;
#elif (MD_GENERATION == 6291)
ret = log2_remain(md->mem_layout.md_bank4_noncacheable_total.size);
if (md->mem_layout.md_bank4_noncacheable_total.size && (ret < 0 || ret > 8))
WARN_ON(1);
ret = log2_remain(md->mem_layout.md_bank4_cacheable_total.size);
if (md->mem_layout.md_bank4_cacheable_total.size && (ret < 0 || ret > 8))
WARN_ON(1);
#endif
#if (MD_GENERATION >= 6293)
if (md->index == MD_SYS1) {
md->mem_layout.md_bank4_noncacheable = md1_6293_noncacheable_fat;
md->mem_layout.md_bank4_cacheable = md1_6293_cacheable;
{
/* Runtime adjust md_phy_capture size */
unsigned int i;
for (i = 0; i < (sizeof(md1_6293_noncacheable_fat)/sizeof(struct ccci_smem_region)); i++) {
if (md1_6293_noncacheable_fat[i].id == SMEM_USER_RAW_PHY_CAP) {
md1_6293_noncacheable_fat[i].size = get_md_resv_phy_cap_size(MD_SYS1);
CCCI_BOOTUP_LOG(md->index, TAG, "PHY size:%d\n",
md1_6293_noncacheable_fat[i].size);
break;
}
}
if (md->mem_layout.md_bank4_cacheable_total.size >= CCB_CACHE_MIN_SIZE) {
/*
* 2M is control part size, md1_6293_cacheable[0].size
* initial value but changed by collect_ccb_info
*/
for (i = (SMEM_USER_CCB_END - SMEM_USER_CCB_START + 1);
i < (sizeof(md1_6293_cacheable)/sizeof(struct ccci_smem_region)); i++) {
if (md1_6293_cacheable[i].id > SMEM_USER_CCB_END) {
md1_6293_cacheable[i].size =
md->mem_layout.md_bank4_cacheable_total.size -
CCB_CACHE_MIN_SIZE;
CCCI_BOOTUP_LOG(md->index, TAG, "RAW size:%d\n",
md1_6293_cacheable[i].size);
}
}
} else
md->mem_layout.md_bank4_cacheable = NULL;
}
} else {
WARN_ON(1);
}
#elif (MD_GENERATION == 6292)
if (md->index == MD_SYS1) {
md->mem_layout.md_bank4_noncacheable = md1_6292_noncacheable_fat;
md->mem_layout.md_bank4_cacheable = md1_6292_cacheable;
} else if (md->index == MD_SYS3) {
md->mem_layout.md_bank4_noncacheable = md3_6292_noncacheable_fat;
}
#elif (MD_GENERATION == 6291)
if (md->index == MD_SYS1)
md->mem_layout.md_bank4_noncacheable = md1_6291_noncacheable_fat;
else if (md->index == MD_SYS3)
md->mem_layout.md_bank4_noncacheable = md3_6291_noncacheable_fat;
#endif
init_smem_regions(md->mem_layout.md_bank4_noncacheable,
md->mem_layout.md_bank4_noncacheable_total.base_ap_view_phy,
md->mem_layout.md_bank4_noncacheable_total.base_ap_view_vir,
md->mem_layout.md_bank4_noncacheable_total.base_md_view_phy);
init_smem_regions(md->mem_layout.md_bank4_cacheable,
md->mem_layout.md_bank4_cacheable_total.base_ap_view_phy,
md->mem_layout.md_bank4_cacheable_total.base_ap_view_vir,
md->mem_layout.md_bank4_cacheable_total.base_md_view_phy);
/* updae image info */
md->per_md_data.img_info[IMG_MD].type = IMG_MD;
md->per_md_data.img_info[IMG_MD].address = md->mem_layout.md_bank0.base_ap_view_phy;
md->per_md_data.img_info[IMG_DSP].type = IMG_DSP;
md->per_md_data.img_info[IMG_ARMV7].type = IMG_ARMV7;
}
int ccci_md_register(struct ccci_modem *md)
{
int ret;
/* init per-modem sub-system */
CCCI_INIT_LOG(md->index, TAG, "register modem\n");
/* init modem */
ret = md->ops->init(md);
if (ret < 0)
return ret;
ccci_md_config(md);
modem_sys[md->index] = md;
ccci_sysfs_add_md(md->index, (void *)&md->kobj);
ccci_platform_init(md);
ccci_fsm_init(md->index);
ccci_port_init(md->index);
return 0;
}
int ccci_md_set_boot_data(unsigned char md_id, unsigned int data[], int len)
{
int ret = 0;
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
if (len < 0 || data == NULL)
return -1;
md->mdlg_mode = data[MD_CFG_MDLOG_MODE];
md->sbp_code = data[MD_CFG_SBP_CODE];
md->per_md_data.md_dbg_dump_flag = data[MD_CFG_DUMP_FLAG] == MD_DBG_DUMP_INVALID ?
md->per_md_data.md_dbg_dump_flag : data[MD_CFG_DUMP_FLAG];
return ret;
}
struct ccci_mem_layout *ccci_md_get_mem(int md_id)
{
if (md_id >= MAX_MD_NUM)
return NULL;
return &modem_sys[md_id]->mem_layout;
}
struct ccci_smem_region *ccci_md_get_smem_by_user_id(int md_id, enum SMEM_USER_ID user_id)
{
struct ccci_smem_region *curr = NULL;
if (md_id >= MAX_MD_NUM)
return NULL;
curr = get_smem_by_user_id(modem_sys[md_id]->mem_layout.md_bank4_noncacheable, user_id);
if (curr)
return curr;
curr = get_smem_by_user_id(modem_sys[md_id]->mem_layout.md_bank4_cacheable, user_id);
return curr;
}
void ccci_md_clear_smem(int md_id, int first_boot)
{
struct ccci_smem_region *region;
unsigned int size;
/* MD will clear share memory itself after the first boot */
clear_smem_region(modem_sys[md_id]->mem_layout.md_bank4_noncacheable, first_boot);
clear_smem_region(modem_sys[md_id]->mem_layout.md_bank4_cacheable, first_boot);
if (!first_boot) {
CCCI_NORMAL_LOG(-1, TAG, "clear buffer ! first_boot\n");
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_CCB_DHL);
if (region) {
/*clear ccb data smem*/
memset_io(region->base_ap_view_vir, 0, region->size);
}
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_DHL);
if (region) {
/* clear first 1k bytes in dsp log buffer */
size = (region->size > (128 * sizeof(long long))) ? (128 * sizeof(long long)) : region->size;
memset_io(region->base_ap_view_vir, 0, size);
CCCI_NORMAL_LOG(-1, TAG, "clear buffer user_id = SMEM_USER_RAW_DHL, szie = 0x%x\n", size);
}
}
}
void __attribute__((weak)) mmdvfs_set_md_on(bool to_on)
{
CCCI_NORMAL_LOG(-1, TAG, "call weak mmdvfs_set_md_on with %d\n", (int)to_on);
}
void notify_md_on(int md_id)
{
if (md_id == MD_SYS1)
mmdvfs_set_md_on(1);
}
void notify_md_off(int md_id, int off_level)
{
if (md_id != MD_SYS1)
return;
switch (off_level) {
case MD_OFF_LVL_0:
mmdvfs_set_md_on(0);
break;
case MD_OFF_LVL_1:
mmdvfs_set_md_on(0);
break;
default:
CCCI_NORMAL_LOG(-1, TAG, "invalid off lvl %d\n", off_level);
break;
}
}
int ccci_md_pre_stop(unsigned char md_id, unsigned int stop_type)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
return md->ops->pre_stop(md, stop_type);
}
int ccci_md_stop(unsigned char md_id, unsigned int stop_type)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
return md->ops->stop(md, stop_type);
}
int __weak md_cd_vcore_config(unsigned int md_id, unsigned int hold_req)
{
pr_debug("[ccci/dummy] %s is not supported!\n", __func__);
return 0;
}
int ccci_md_pre_start(unsigned char md_id)
{
return md_cd_vcore_config(md_id, 1);
}
int ccci_md_start(unsigned char md_id)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
return md->ops->start(md);
}
int ccci_md_post_start(unsigned char md_id)
{
return md_cd_vcore_config(md_id, 0);
}
int ccci_md_soft_stop(unsigned char md_id, unsigned int sim_mode)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
if (md->ops->soft_stop)
return md->ops->soft_stop(md, sim_mode);
return -1;
}
int ccci_md_soft_start(unsigned char md_id, unsigned int sim_mode)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
if (md->ops->soft_start)
return md->ops->soft_start(md, sim_mode);
return -1;
}
int ccci_md_send_runtime_data(unsigned char md_id)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
return md->ops->send_runtime_data(md, CCCI_CONTROL_TX, 0, 0);
}
int ccci_md_reset_pccif(unsigned char md_id)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
if (md->ops->reset_pccif)
return md->ops->reset_pccif(md);
return -1;
}
void ccci_md_dump_info(unsigned char md_id, MODEM_DUMP_FLAG flag, void *buff, int length)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
if (md)
md->ops->dump_info(md, flag, buff, length);
else
CCCI_ERROR_LOG(md_id, TAG, "invalid md_id %d!!\n", md_id);
}
void ccci_md_exception_handshake(unsigned char md_id, int timeout)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
md->ops->ee_handshake(md, timeout);
}
int ccci_md_send_ccb_tx_notify(unsigned char md_id, int core_id)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
return md->ops->send_ccb_tx_notify(md, core_id);
}
int ccci_md_force_assert(unsigned char md_id, MD_FORCE_ASSERT_TYPE type, char *param, int len)
{
int ret = 0;
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
struct ccci_force_assert_shm_fmt *ccci_fa_smem_ptr = NULL;
struct ccci_smem_region *force_assert = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_FORCE_ASSERT);
if (md->is_force_asserted != 0)
return ret;
mdee_set_ex_time_str(md_id, type, param);
if (type == MD_FORCE_ASSERT_BY_AP_MPU) {
ret = md->ops->force_assert(md, CCIF_MPU_INTR);
} else {
ccci_fa_smem_ptr = (struct ccci_force_assert_shm_fmt *)force_assert->base_ap_view_vir;
if (ccci_fa_smem_ptr) {
ccci_fa_smem_ptr->error_code = type;
if (param != NULL && len > 0) {
if (len > force_assert->size - sizeof(struct ccci_force_assert_shm_fmt))
len = force_assert->size - sizeof(struct ccci_force_assert_shm_fmt);
memcpy_toio(ccci_fa_smem_ptr->param, param, len);
}
}
ret = md->ops->force_assert(md, CCIF_INTERRUPT);
}
md->is_force_asserted = 1;
return ret;
}
static void append_runtime_feature(char **p_rt_data, struct ccci_runtime_feature *rt_feature, void *data)
{
CCCI_DEBUG_LOG(-1, TAG, "append rt_data %p, feature %u len %u\n",
*p_rt_data, rt_feature->feature_id, rt_feature->data_len);
memcpy_toio(*p_rt_data, rt_feature, sizeof(struct ccci_runtime_feature));
*p_rt_data += sizeof(struct ccci_runtime_feature);
if (data != NULL) {
memcpy_toio(*p_rt_data, data, rt_feature->data_len);
*p_rt_data += rt_feature->data_len;
}
}
static unsigned int get_booting_start_id(struct ccci_modem *md)
{
LOGGING_MODE mdlog_flag = MODE_IDLE;
u32 booting_start_id;
mdlog_flag = md->mdlg_mode;
if (md->per_md_data.md_boot_mode != MD_BOOT_MODE_INVALID) {
if (md->per_md_data.md_boot_mode == MD_BOOT_MODE_META)
booting_start_id = ((char)mdlog_flag << 8 | META_BOOT_ID);
else if ((get_boot_mode() == FACTORY_BOOT || get_boot_mode() == ATE_FACTORY_BOOT))
booting_start_id = ((char)mdlog_flag << 8 | FACTORY_BOOT_ID);
else
booting_start_id = ((char)mdlog_flag << 8 | NORMAL_BOOT_ID);
} else {
if (is_meta_mode() || is_advanced_meta_mode())
booting_start_id = ((char)mdlog_flag << 8 | META_BOOT_ID);
else if ((get_boot_mode() == FACTORY_BOOT || get_boot_mode() == ATE_FACTORY_BOOT))
booting_start_id = ((char)mdlog_flag << 8 | FACTORY_BOOT_ID);
else
booting_start_id = ((char)mdlog_flag << 8 | NORMAL_BOOT_ID);
}
CCCI_BOOTUP_LOG(md->index, TAG, "get_booting_start_id 0x%x\n", booting_start_id);
return booting_start_id;
}
static void config_ap_side_feature(struct ccci_modem *md, struct md_query_ap_feature *ap_side_md_feature)
{
md->runtime_version = AP_MD_HS_V2;
ap_side_md_feature->feature_set[BOOT_INFO].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[EXCEPTION_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
#if (MD_GENERATION >= 6293)
ap_side_md_feature->feature_set[CCIF_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
#else
if (md->index == MD_SYS1)
ap_side_md_feature->feature_set[CCIF_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
else
ap_side_md_feature->feature_set[CCIF_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
#endif
#ifdef FEATURE_SCP_CCCI_SUPPORT
ap_side_md_feature->feature_set[CCISM_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
#else
ap_side_md_feature->feature_set[CCISM_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
#endif
#if (MD_GENERATION >= 6293)
ap_side_md_feature->feature_set[CCISM_SHARE_MEMORY_EXP].support_mask = CCCI_FEATURE_MUST_SUPPORT;
if ((md->index == MD_SYS1) && (get_md_resv_phy_cap_size(MD_SYS1) > 0))
ap_side_md_feature->feature_set[MD_PHY_CAPTURE].support_mask = CCCI_FEATURE_MUST_SUPPORT;
else
ap_side_md_feature->feature_set[MD_PHY_CAPTURE].support_mask = CCCI_FEATURE_NOT_SUPPORT;
ap_side_md_feature->feature_set[MD_CONSYS_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[MD1MD3_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
#else
ap_side_md_feature->feature_set[CCISM_SHARE_MEMORY_EXP].support_mask = CCCI_FEATURE_NOT_SUPPORT;
ap_side_md_feature->feature_set[MD_PHY_CAPTURE].support_mask = CCCI_FEATURE_NOT_SUPPORT;
ap_side_md_feature->feature_set[MD_CONSYS_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
if (get_modem_is_enabled(MD_SYS3))
ap_side_md_feature->feature_set[MD1MD3_SHARE_MEMORY].support_mask =
CCCI_FEATURE_MUST_SUPPORT;
else
ap_side_md_feature->feature_set[MD1MD3_SHARE_MEMORY].support_mask =
CCCI_FEATURE_NOT_SUPPORT;
#endif
#if (MD_GENERATION >= 6293)
/* notice: CCB_SHARE_MEMORY should be set to support when at least one CCB region exists */
ap_side_md_feature->feature_set[CCB_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[DHL_RAW_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[LWA_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[DT_NETD_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[DT_USB_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[AUDIO_RAW_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
#elif (MD_GENERATION == 6292)
/* notice: CCB_SHARE_MEMORY should be set to support when at least one CCB region exists */
ap_side_md_feature->feature_set[CCB_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
ap_side_md_feature->feature_set[DHL_RAW_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
ap_side_md_feature->feature_set[LWA_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[DT_NETD_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[DT_USB_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[AUDIO_RAW_SHARE_MEMORY].support_mask = CCCI_FEATURE_MUST_SUPPORT;
#else
ap_side_md_feature->feature_set[CCB_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
ap_side_md_feature->feature_set[DHL_RAW_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
ap_side_md_feature->feature_set[LWA_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
ap_side_md_feature->feature_set[DT_NETD_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
ap_side_md_feature->feature_set[DT_USB_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
ap_side_md_feature->feature_set[AUDIO_RAW_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
#endif
ap_side_md_feature->feature_set[MISC_INFO_HIF_DMA_REMAP].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[MULTI_MD_MPU].support_mask = CCCI_FEATURE_MUST_SUPPORT;
#ifdef ENABLE_32K_CLK_LESS
if (crystal_exist_status()) {
CCCI_DEBUG_LOG(md->index, TAG, "MISC_32K_LESS no support, crystal_exist_status 1\n");
ap_side_md_feature->feature_set[MISC_INFO_RTC_32K_LESS].support_mask = CCCI_FEATURE_NOT_SUPPORT;
} else {
CCCI_DEBUG_LOG(md->index, TAG, "MISC_32K_LESS support\n");
ap_side_md_feature->feature_set[MISC_INFO_RTC_32K_LESS].support_mask = CCCI_FEATURE_MUST_SUPPORT;
}
#else
CCCI_DEBUG_LOG(md->index, TAG, "ENABLE_32K_CLK_LESS disabled\n");
ap_side_md_feature->feature_set[MISC_INFO_RTC_32K_LESS].support_mask = CCCI_FEATURE_NOT_SUPPORT;
#endif
ap_side_md_feature->feature_set[MISC_INFO_RANDOM_SEED_NUM].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[MISC_INFO_GPS_COCLOCK].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[MISC_INFO_SBP_ID].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[MISC_INFO_CCCI].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[MISC_INFO_CLIB_TIME].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[MISC_INFO_C2K].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[MD_IMAGE_START_MEMORY].support_mask = CCCI_FEATURE_OPTIONAL_SUPPORT;
ap_side_md_feature->feature_set[EE_AFTER_EPOF].support_mask = CCCI_FEATURE_MUST_SUPPORT;
ap_side_md_feature->feature_set[AP_CCMNI_MTU].support_mask = CCCI_FEATURE_MUST_SUPPORT;
#ifdef ENABLE_FAST_HEADER
ap_side_md_feature->feature_set[CCCI_FAST_HEADER].support_mask = CCCI_FEATURE_MUST_SUPPORT;
#endif
/* tire1 features */
#ifdef FEATURE_TC1_CUSTOMER_VAL
ap_side_md_feature->feature_set[MISC_INFO_CUSTOMER_VAL].support_mask = CCCI_FEATURE_MUST_SUPPORT;
#else
ap_side_md_feature->feature_set[MISC_INFO_CUSTOMER_VAL].support_mask = CCCI_FEATURE_NOT_SUPPORT;
#endif
#ifdef FEATURE_SYNC_C2K_MEID
ap_side_md_feature->feature_set[MISC_INFO_C2K_MEID].support_mask = CCCI_FEATURE_MUST_SUPPORT;
#else
ap_side_md_feature->feature_set[MISC_INFO_C2K_MEID].support_mask = CCCI_FEATURE_NOT_SUPPORT;
#endif
ap_side_md_feature->feature_set[SMART_LOGGING_SHARE_MEMORY].support_mask = CCCI_FEATURE_NOT_SUPPORT;
}
unsigned int align_to_2_power(unsigned int n)
{
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++;
return n;
}
int ccci_md_prepare_runtime_data(unsigned char md_id, unsigned char *data, int length)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
u8 i = 0;
u32 total_len;
int j;
/*runtime data buffer */
struct ccci_smem_region *region;
struct ccci_smem_region *rt_data_region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_RUNTIME_DATA);
char *rt_data = (char *)rt_data_region->base_ap_view_vir;
struct ccci_runtime_feature rt_feature;
/*runtime feature type */
struct ccci_runtime_share_memory rt_shm;
struct ccci_misc_info_element rt_f_element;
struct md_query_ap_feature *md_feature;
struct md_query_ap_feature md_feature_ap;
struct ccci_runtime_boot_info boot_info;
unsigned int random_seed = 0;
struct timeval t;
unsigned int c2k_flags = 0;
CCCI_BOOTUP_LOG(md->index, TAG, "prepare_runtime_data AP total %u features\n", MD_RUNTIME_FEATURE_ID_MAX);
memset(&md_feature_ap, 0, sizeof(struct md_query_ap_feature));
config_ap_side_feature(md, &md_feature_ap);
md_feature = (struct md_query_ap_feature *)(data + sizeof(struct ccci_header));
if (md_feature->head_pattern != MD_FEATURE_QUERY_PATTERN ||
md_feature->tail_pattern != MD_FEATURE_QUERY_PATTERN) {
CCCI_BOOTUP_LOG(md->index, TAG, "md_feature pattern is wrong: head 0x%x, tail 0x%x\n",
md_feature->head_pattern, md_feature->tail_pattern);
if (md->index == MD_SYS3)
md->ops->dump_info(md, DUMP_FLAG_CCIF, NULL, 0);
return -1;
}
for (i = BOOT_INFO; i < FEATURE_COUNT; i++) {
memset(&rt_feature, 0, sizeof(struct ccci_runtime_feature));
memset(&rt_shm, 0, sizeof(struct ccci_runtime_share_memory));
memset(&rt_f_element, 0, sizeof(struct ccci_misc_info_element));
rt_feature.feature_id = i;
if (md_feature->feature_set[i].support_mask == CCCI_FEATURE_MUST_SUPPORT &&
md_feature_ap.feature_set[i].support_mask < CCCI_FEATURE_MUST_SUPPORT) {
CCCI_BOOTUP_LOG(md->index, TAG, "feature %u not support for AP\n", rt_feature.feature_id);
return -1;
}
CCCI_DEBUG_LOG(md->index, TAG, "ftr %u mask %u, ver %u\n",
rt_feature.feature_id, md_feature->feature_set[i].support_mask,
md_feature->feature_set[i].version);
if (md_feature->feature_set[i].support_mask == CCCI_FEATURE_NOT_EXIST) {
rt_feature.support_info = md_feature->feature_set[i];
} else if (md_feature->feature_set[i].support_mask == CCCI_FEATURE_MUST_SUPPORT) {
rt_feature.support_info = md_feature->feature_set[i];
} else if (md_feature->feature_set[i].support_mask == CCCI_FEATURE_OPTIONAL_SUPPORT) {
if (md_feature->feature_set[i].version == md_feature_ap.feature_set[i].version &&
md_feature_ap.feature_set[i].support_mask >= CCCI_FEATURE_MUST_SUPPORT) {
rt_feature.support_info.support_mask = CCCI_FEATURE_MUST_SUPPORT;
rt_feature.support_info.version = md_feature_ap.feature_set[i].version;
} else {
rt_feature.support_info.support_mask = CCCI_FEATURE_NOT_SUPPORT;
rt_feature.support_info.version = md_feature_ap.feature_set[i].version;
}
} else if (md_feature->feature_set[i].support_mask == CCCI_FEATURE_SUPPORT_BACKWARD_COMPAT) {
if (md_feature->feature_set[i].version >= md_feature_ap.feature_set[i].version) {
rt_feature.support_info.support_mask = CCCI_FEATURE_MUST_SUPPORT;
rt_feature.support_info.version = md_feature_ap.feature_set[i].version;
} else {
rt_feature.support_info.support_mask = CCCI_FEATURE_NOT_SUPPORT;
rt_feature.support_info.version = md_feature_ap.feature_set[i].version;
}
}
if (rt_feature.support_info.support_mask == CCCI_FEATURE_MUST_SUPPORT) {
switch (rt_feature.feature_id) {
case BOOT_INFO:
memset(&boot_info, 0, sizeof(boot_info));
rt_feature.data_len = sizeof(boot_info);
boot_info.boot_channel = CCCI_CONTROL_RX;
boot_info.booting_start_id = get_booting_start_id(md);
append_runtime_feature(&rt_data, &rt_feature, &boot_info);
break;
case EXCEPTION_SHARE_MEMORY:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_MDCCCI_DBG);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = CCCI_EE_SMEM_TOTAL_SIZE;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case CCIF_SHARE_MEMORY:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_CCISM_MCU);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case CCISM_SHARE_MEMORY:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_CCISM_SCP);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case CCB_SHARE_MEMORY:
/* notice: we should add up all CCB region size here */
/* ctrl control first */
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_CCB_CTRL);
if (region) {
rt_feature.data_len = sizeof(struct ccci_misc_info_element);
rt_f_element.feature[0] = region->base_md_view_phy;
rt_f_element.feature[1] = region->size;
}
/* ccb data second */
for (j = SMEM_USER_CCB_START; j <= SMEM_USER_CCB_END; j++) {
region = ccci_md_get_smem_by_user_id(md_id, j);
if (j == SMEM_USER_CCB_START && region) {
rt_f_element.feature[2] = region->base_md_view_phy;
rt_f_element.feature[3] = 0;
} else if (j == SMEM_USER_CCB_START && region == NULL)
break;
if (region)
rt_f_element.feature[3] += region->size;
}
CCCI_BOOTUP_LOG(md->index, TAG, "ccb data size (include dsp raw): %X\n",
rt_f_element.feature[3]);
append_runtime_feature(&rt_data, &rt_feature, &rt_f_element);
break;
case DHL_RAW_SHARE_MEMORY:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_DHL);
if (region) {
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
} else {
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = 0;
rt_shm.size = 0;
}
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case LWA_SHARE_MEMORY:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_LWA);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case MULTI_MD_MPU:
CCCI_BOOTUP_LOG(md->index, TAG, "new version md use multi-MPU.\n");
md->multi_md_mpu_support = 1;
rt_feature.data_len = 0;
append_runtime_feature(&rt_data, &rt_feature, NULL);
break;
case DT_NETD_SHARE_MEMORY:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_NETD);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case DT_USB_SHARE_MEMORY:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_USB);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case SMART_LOGGING_SHARE_MEMORY:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_SMART_LOGGING);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case MD1MD3_SHARE_MEMORY:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_MD2MD);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case MISC_INFO_HIF_DMA_REMAP:
rt_feature.data_len = sizeof(struct ccci_misc_info_element);
append_runtime_feature(&rt_data, &rt_feature, &rt_f_element);
break;
case MISC_INFO_RTC_32K_LESS:
rt_feature.data_len = sizeof(struct ccci_misc_info_element);
append_runtime_feature(&rt_data, &rt_feature, &rt_f_element);
break;
case MISC_INFO_RANDOM_SEED_NUM:
rt_feature.data_len = sizeof(struct ccci_misc_info_element);
get_random_bytes(&random_seed, sizeof(int));
rt_f_element.feature[0] = random_seed;
append_runtime_feature(&rt_data, &rt_feature, &rt_f_element);
break;
case MISC_INFO_GPS_COCLOCK:
rt_feature.data_len = sizeof(struct ccci_misc_info_element);
append_runtime_feature(&rt_data, &rt_feature, &rt_f_element);
break;
case MISC_INFO_SBP_ID:
rt_feature.data_len = sizeof(struct ccci_misc_info_element);
rt_f_element.feature[0] = md->sbp_code;
if (md->per_md_data.config.load_type < modem_ultg)
rt_f_element.feature[1] = 0;
else
rt_f_element.feature[1] = get_wm_bitmap_for_ubin();
CCCI_BOOTUP_LOG(md->index, TAG, "sbp=0x%x,wmid[%d]\n",
rt_f_element.feature[0], rt_f_element.feature[1]);
append_runtime_feature(&rt_data, &rt_feature, &rt_f_element);
break;
case MISC_INFO_CCCI:
rt_feature.data_len = sizeof(struct ccci_misc_info_element);
rt_f_element.feature[0] |= (1 << 0); /* sequence check */
rt_f_element.feature[0] |= (1 << 1); /* polling MD status */
append_runtime_feature(&rt_data, &rt_feature, &rt_f_element);
break;
case MISC_INFO_CLIB_TIME:
rt_feature.data_len = sizeof(struct ccci_misc_info_element);
do_gettimeofday(&t);
/*set seconds information */
rt_f_element.feature[0] = ((unsigned int *)&t.tv_sec)[0];
rt_f_element.feature[1] = ((unsigned int *)&t.tv_sec)[1];
/*sys_tz.tz_minuteswest; */
rt_f_element.feature[2] = current_time_zone;
/*not used for now */
rt_f_element.feature[3] = sys_tz.tz_dsttime;
append_runtime_feature(&rt_data, &rt_feature, &rt_f_element);
break;
case MISC_INFO_C2K:
rt_feature.data_len = sizeof(struct ccci_misc_info_element);
c2k_flags = 0;
#if defined(CONFIG_MTK_MD3_SUPPORT) && (CONFIG_MTK_MD3_SUPPORT > 0)
c2k_flags |= (1 << 0);
#endif
if (ccci_get_opt_val("opt_c2k_lte_mode") == 1) /* SVLTE_MODE */
c2k_flags |= (1 << 1);
if (ccci_get_opt_val("opt_c2k_lte_mode") == 2) /* SRLTE_MODE */
c2k_flags |= (1 << 2);
#ifdef CONFIG_MTK_C2K_OM_SOLUTION1
c2k_flags |= (1 << 3);
#endif
#ifdef CONFIG_CT6M_SUPPORT
c2k_flags |= (1 << 4)
#endif
rt_f_element.feature[0] = c2k_flags;
append_runtime_feature(&rt_data, &rt_feature, &rt_f_element);
break;
case MD_IMAGE_START_MEMORY:
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = md->per_md_data.img_info[IMG_MD].address;
rt_shm.size = md->per_md_data.img_info[IMG_MD].size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case EE_AFTER_EPOF:
rt_feature.data_len = sizeof(struct ccci_misc_info_element);
append_runtime_feature(&rt_data, &rt_feature, &rt_f_element);
break;
case AP_CCMNI_MTU:
rt_feature.data_len = sizeof(unsigned int);
random_seed = NET_RX_BUF - sizeof(struct ccci_header);
append_runtime_feature(&rt_data, &rt_feature, &random_seed);
break;
case CCCI_FAST_HEADER:
rt_feature.data_len = sizeof(unsigned int);
random_seed = 1;
append_runtime_feature(&rt_data, &rt_feature, &random_seed);
break;
case AUDIO_RAW_SHARE_MEMORY:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_AUDIO);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case CCISM_SHARE_MEMORY_EXP:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_CCISM_MCU_EXP);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case MD_PHY_CAPTURE:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_PHY_CAP);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
case MD_CONSYS_SHARE_MEMORY:
region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_MD_CONSYS);
rt_feature.data_len = sizeof(struct ccci_runtime_share_memory);
rt_shm.addr = region->base_md_view_phy;
rt_shm.size = region->size;
append_runtime_feature(&rt_data, &rt_feature, &rt_shm);
break;
default:
break;
};
} else {
rt_feature.data_len = 0;
append_runtime_feature(&rt_data, &rt_feature, NULL);
}
}
total_len = rt_data - (char *)rt_data_region->base_ap_view_vir;
CCCI_BOOTUP_DUMP_LOG(md->index, TAG, "AP runtime data\n");
ccci_util_mem_dump(md->index, CCCI_DUMP_BOOTUP, rt_data_region->base_ap_view_vir, total_len);
return 0;
}
struct ccci_runtime_feature *ccci_md_get_rt_feature_by_id(unsigned char md_id, u8 feature_id, u8 ap_query_md)
{
struct ccci_runtime_feature *rt_feature = NULL;
u8 i = 0;
u8 max_id = 0;
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
struct ccci_smem_region *rt_data_region = ccci_md_get_smem_by_user_id(md_id, SMEM_USER_RAW_RUNTIME_DATA);
if (ap_query_md) {
rt_feature = (struct ccci_runtime_feature *)(rt_data_region->base_ap_view_vir +
CCCI_SMEM_SIZE_RUNTIME_AP);
max_id = AP_RUNTIME_FEATURE_ID_MAX;
} else {
rt_feature = (struct ccci_runtime_feature *)(rt_data_region->base_ap_view_vir);
max_id = MD_RUNTIME_FEATURE_ID_MAX;
}
while (i < max_id) {
if (feature_id == rt_feature->feature_id)
return rt_feature;
if (rt_feature->data_len > sizeof(struct ccci_misc_info_element)) {
CCCI_ERROR_LOG(md->index, TAG, "get invalid feature, id %u\n", i);
return NULL;
}
rt_feature = (struct ccci_runtime_feature *) ((char *)rt_feature->data + rt_feature->data_len);
i++;
}
return NULL;
}
int ccci_md_parse_rt_feature(unsigned char md_id, struct ccci_runtime_feature *rt_feature, void *data, u32 data_len)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
if (unlikely(!rt_feature)) {
CCCI_ERROR_LOG(md->index, TAG, "parse_md_rt_feature: rt_feature == NULL\n");
return -EFAULT;
}
if (unlikely(rt_feature->data_len > data_len || rt_feature->data_len == 0)) {
CCCI_ERROR_LOG(md->index, TAG, "rt_feature %u data_len = %u, expected data_len %u\n",
rt_feature->feature_id, rt_feature->data_len, data_len);
return -EFAULT;
}
memcpy(data, (const void *)((char *)rt_feature->data), rt_feature->data_len);
return 0;
}
struct ccci_per_md *ccci_get_per_md_data(unsigned char md_id)
{
struct ccci_modem *md = ccci_md_get_modem_by_id(md_id);
if (md)
return &md->per_md_data;
else
return NULL;
}