// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2015 MediaTek Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #ifdef CONFIG_OF_RESERVED_MEM #include #endif #include #include #include "mt-plat/mtk_ccci_common.h" #include "ccci_util_log.h" #include "ccci_util_lib_main.h" #include "ccci_util_md_mem.h" /************************************************************************* **** Local debug option for this file only ****************************** ************************************************************************* */ /* #define LK_LOAD_MD_INFO_DEBUG_EN */ #define CCCI_MEM_ALIGN (SZ_32M) #define CCCI_SMEM_ALIGN_MD1 (0x200000) /*2M */ #define CCCI_SMEM_ALIGN_MD2 (0x200000) /*2M */ /*====================================================== */ /* LK LD MD Tag info support section */ /*====================================================== */ #define MAX_LK_INFO_SIZE (0x10000) #define CCCI_TAG_NAME_LEN (16) #define CCCI_TAG_NAME_LEN_V2 (64) #define CCCI_LK_INFO_VER_V2 (2) struct _ccci_lk_info { unsigned long long lk_info_base_addr; unsigned int lk_info_size; unsigned int lk_info_tag_num; }; struct _ccci_lk_info_v2 { unsigned long long lk_info_base_addr; unsigned int lk_info_size; int lk_info_err_no; int lk_info_version; int lk_info_tag_num; unsigned int lk_info_ld_flag; int lk_info_ld_md_errno; }; struct _ccci_tag { char tag_name[CCCI_TAG_NAME_LEN]; unsigned int data_offset; unsigned int data_size; unsigned int next_tag_offset; }; struct _ccci_tag_v2 { char tag_name[CCCI_TAG_NAME_LEN_V2]; unsigned int data_offset; unsigned int data_size; unsigned int next_tag_offset; }; /*====================================================== */ /* Global variable support section */ /*====================================================== */ static unsigned int s_g_md_env_rdy_flag; static unsigned int s_g_md_usage_case; static unsigned int md_type_at_lk; static unsigned int s_g_lk_load_img_status; static int s_g_lk_ld_md_errno; static unsigned int s_g_tag_inf_size; /* ------ tag info for each modem ---------------------- */ struct _modem_info { unsigned long long base_addr; unsigned int size; char md_id; char errno; char md_type; char ver; unsigned int reserved[2]; }; static int lk_load_img_err_no; static void __iomem *s_g_lk_inf_base; static phys_addr_t s_g_tag_phy_addr; static unsigned int s_g_tag_cnt; /* Note, this for tag info solution version */ static unsigned int s_g_lk_info_tag_version; int lk_tag_inf_parsing_to_args_table(void) { unsigned int i; /* For strcmp/strncmp should not be used on device memory, * so prepare a temp buffer. */ char tag_name[64]; unsigned int data_offset = 0; unsigned int data_size = 0; unsigned int next_tag_offset = 0; unsigned char *tmp_buf = NULL; char *curr = NULL; union u_tag { struct _ccci_tag v1; struct _ccci_tag_v2 v2; } tag = {0}; if (s_g_lk_inf_base == NULL) { CCCI_UTIL_INF_MSG("%s: s_g_lk_inf_base NULL\n", __func__); return -1; } curr = (char *)s_g_lk_inf_base; for (i = 0; i < s_g_tag_cnt; i++) { memcpy_fromio(&tag, curr, sizeof(union u_tag)); if (s_g_lk_info_tag_version >= CCCI_LK_INFO_VER_V2) { scnprintf(tag_name, 64, "%s", tag.v2.tag_name); data_offset = tag.v2.data_offset; data_size = tag.v2.data_size; next_tag_offset = tag.v2.next_tag_offset; } else { scnprintf(tag_name, 64, "%s", tag.v1.tag_name); data_offset = tag.v1.data_offset; data_size = tag.v1.data_size; next_tag_offset = tag.v1.next_tag_offset; } tmp_buf = (unsigned char *)(s_g_lk_inf_base + data_offset); mtk_ccci_add_new_args((const char *)tag_name, tmp_buf, data_size, FROM_LK_TAG); curr = (char *)(s_g_lk_inf_base + next_tag_offset); } return 0; } /*====================================================== */ /* Tag info and device tree parsing section */ /*====================================================== */ #define CCCI_FO_VER_02 (2) /* For ubin */ #define LK_LOAD_MD_EN (1<<0) #define LK_LOAD_MD_ERR_INVALID_MD_ID (1<<1) #define LK_LOAD_MD_ERR_NO_MD_LOAD (1<<2) #define LK_LOAD_MD_ERR_LK_INFO_FAIL (1<<3) #define LK_KERNEL_SETTING_MIS_SYNC (1<<4) #define LK_TAG_BUFF_SIZE_NOT_ENOUGH (1<<5) /*---- Memory info parsing section --------------------- */ /* MD ROM+RAM */ static unsigned int md_resv_mem_size; /* share memory */ static unsigned int md_resv_smem_size; static unsigned int md_resv_size_list; static phys_addr_t md_resv_mem_list; static phys_addr_t md_resv_mem_addr; static phys_addr_t md_resv_smem_addr; static phys_addr_t resv_smem_addr; struct _smem_layout { unsigned long long base_addr; unsigned int ap_md1_smem_offset; unsigned int ap_md1_smem_size; unsigned int ap_md3_smem_offset; unsigned int ap_md3_smem_size; unsigned int md1_md3_smem_offset; unsigned int md1_md3_smem_size; unsigned int total_smem_size; }; struct _ccb_layout { unsigned long long ccb_data_buffer_addr; unsigned int ccb_data_buffer_size; }; static struct _ccb_layout ccb_info; static unsigned int md1_phy_cap_size; static int md1_smem_dfd_size = -1; static int smem_amms_pos_size = -1; static int smem_align_padding_size = -1; static unsigned int md1_bank4_cache_offset; struct _udc_info { unsigned int noncache_size; unsigned int cache_size; }; static struct _udc_info udc_size; /* non-cacheable share memory */ struct nc_smem_node { unsigned int ap_offset; unsigned int md_offset; unsigned int size; unsigned int id; }; static struct nc_smem_node *s_nc_layout; static unsigned int s_nc_smem_ext_num; /* cacheable share memory */ struct _csmem_item { unsigned long long csmem_buffer_addr; unsigned int md_offset; unsigned int csmem_buffer_size; unsigned int item_cnt; }; static struct _csmem_item csmem_info; static struct _csmem_item *csmem_layout; struct _sib_item { unsigned long long md1_sib_addr; unsigned int md1_sib_size; }; static struct _sib_item sib_info; static unsigned int md_mtee_support; static void nc_smem_info_parsing(void) { unsigned int size, num = 0, i; if (mtk_ccci_find_args_val("nc_smem_info_ext_num", (unsigned char *)&num, sizeof(unsigned int)) != sizeof(unsigned int)) { CCCI_UTIL_ERR_MSG("nc_smem_info_ext_num get fail\n"); s_nc_smem_ext_num = 0; return; } s_nc_smem_ext_num = num; size = num * sizeof(struct nc_smem_node); s_nc_layout = kzalloc(size, GFP_KERNEL); if (s_nc_layout == NULL) { CCCI_UTIL_ERR_MSG("nc_layout:alloc nc_layout fail\n"); return; } if (mtk_ccci_find_args_val("nc_smem_info_ext", (unsigned char *)s_nc_layout, size) != size) { CCCI_UTIL_ERR_MSG("Invalid nc_layout from tag\n"); return; } for (i = 0; i < num; i++) { CCCI_UTIL_INF_MSG("nc_smem<%d>: ap:0x%08x md:0x%08x[0x%08x]\n", s_nc_layout[i].id, s_nc_layout[i].ap_offset, s_nc_layout[i].md_offset, s_nc_layout[i].size); } /* For compatible of legacy design */ /* DFD part */ if (get_nc_smem_region_info(SMEM_USER_RAW_DFD, NULL, NULL, (unsigned int *)&md1_smem_dfd_size)) CCCI_UTIL_INF_MSG("change dfd to: 0x%x\n", md1_smem_dfd_size); /* AMMS POS part */ if (get_nc_smem_region_info(SMEM_USER_RAW_AMMS_POS, NULL, NULL, (unsigned int *)&smem_amms_pos_size)) CCCI_UTIL_INF_MSG("change POS to: 0x%x\n", smem_amms_pos_size); } int get_nc_smem_region_info(unsigned int id, unsigned int *ap_off, unsigned int *md_off, unsigned int *size) { int i; if (s_nc_layout == NULL || s_nc_smem_ext_num == 0) return 0; for (i = 0; i < s_nc_smem_ext_num; i++) { if (s_nc_layout[i].id == id) { if (ap_off) *ap_off = s_nc_layout[i].ap_offset; if (md_off) *md_off = s_nc_layout[i].md_offset; if (size) *size = s_nc_layout[i].size; return 1; } } return 0; } EXPORT_SYMBOL(get_nc_smem_region_info); static void cshare_memory_info_parsing(void) { unsigned int size; memset(&csmem_info, 0, sizeof(struct _csmem_item)); if (mtk_ccci_find_args_val("md1_bank4_cache_info", (unsigned char *)&csmem_info, sizeof(struct _csmem_item)) != sizeof(struct _csmem_item)) { CCCI_UTIL_ERR_MSG("Invalid csmem_info dt para\n"); if (ccb_info.ccb_data_buffer_addr != 0) goto OLD_LK_CSMEM; return; } size = csmem_info.item_cnt * sizeof(struct _csmem_item); csmem_layout = kzalloc(size, GFP_KERNEL); if (csmem_layout == NULL) { CCCI_UTIL_ERR_MSG("csmem_layout:alloc csmem_layout fail\n"); return; } if (mtk_ccci_find_args_val("md1_bank4_cache_layout", (unsigned char *)csmem_layout, size) != size) { CCCI_UTIL_ERR_MSG("Invalid csmem_layout dt para\n"); return; } return; OLD_LK_CSMEM: /* old LK config compatibility: create ccb item. */ csmem_info.csmem_buffer_addr = ccb_info.ccb_data_buffer_addr; csmem_info.csmem_buffer_size = ccb_info.ccb_data_buffer_size; csmem_info.item_cnt = 1; size = csmem_info.item_cnt * sizeof(struct _csmem_item); csmem_layout = kzalloc(size, GFP_KERNEL); if (csmem_layout == NULL) { CCCI_UTIL_ERR_MSG("csmem_layout:alloc csmem_layout fail\n"); return; } csmem_layout[0].csmem_buffer_addr = csmem_info.csmem_buffer_addr; csmem_layout[0].csmem_buffer_size = csmem_info.csmem_buffer_size; csmem_layout[0].md_offset = 0; csmem_layout[0].item_cnt = SMEM_USER_CCB_START; CCCI_UTIL_INF_MSG("ccci_util get csmem: data:%llx data_size:%d\n", csmem_info.csmem_buffer_addr, csmem_info.csmem_buffer_size); } static void share_memory_info_parsing(void) { struct _smem_layout smem_layout; /* Get share memory layout */ if (mtk_ccci_find_args_val("smem_layout", (unsigned char *)&smem_layout, sizeof(struct _smem_layout)) != sizeof(struct _smem_layout)) { CCCI_UTIL_ERR_MSG("load smem layout fail\n"); s_g_lk_load_img_status |= LK_LOAD_MD_ERR_LK_INFO_FAIL; /* Reset to zero if get share memory info fail */ s_g_md_env_rdy_flag = 0; return; } /* Get ccb memory layout */ memset(&ccb_info, 0, sizeof(struct _ccb_layout)); if (mtk_ccci_find_args_val("ccb_info", (unsigned char *)&ccb_info, sizeof(struct _ccb_layout)) != sizeof(struct _ccb_layout)) { CCCI_UTIL_ERR_MSG("Invalid ccb info dt para\n"); } CCCI_UTIL_INF_MSG("ccci_util get ccb: data:%llx data_size:%d\n", ccb_info.ccb_data_buffer_addr, ccb_info.ccb_data_buffer_size); /* Get udc cache&noncache size */ memset(&udc_size, 0, sizeof(struct _udc_info)); if (mtk_ccci_find_args_val("udc_layout", (unsigned char *)&udc_size, sizeof(struct _udc_info)) != sizeof(struct _udc_info)) CCCI_UTIL_ERR_MSG("Invalid udc layout info dt para\n"); CCCI_UTIL_INF_MSG( "ccci_util get udc: cache_size:0x%x noncache_size:0x%x\n", udc_size.cache_size, udc_size.noncache_size); /*Get sib info */ if (mtk_ccci_find_args_val("md1_sib_info", (unsigned char *)&sib_info, sizeof(sib_info)) != sizeof(sib_info)) CCCI_UTIL_ERR_MSG("get sib info fail\n"); CCCI_UTIL_INF_MSG("ccci_util get sib addr: 0x%llx size: %d\n", sib_info.md1_sib_addr, sib_info.md1_sib_size); /* Get md1_phy_cap_size */ if (mtk_ccci_find_args_val("md1_phy_cap", (unsigned char *)&md1_phy_cap_size, sizeof(md1_phy_cap_size)) != sizeof(md1_phy_cap_size)) CCCI_UTIL_ERR_MSG("using 0 as phy capture size\n"); CCCI_UTIL_INF_MSG("ccci_util get md1_phy_cap_size: 0x%x\n", md1_phy_cap_size); /* Get md1_smem_dfd_size */ if (mtk_ccci_find_args_val("smem_dfd_size", (unsigned char *)&md1_smem_dfd_size, sizeof(md1_smem_dfd_size)) != sizeof(md1_smem_dfd_size)) CCCI_UTIL_ERR_MSG("get smem dfd size fail\n"); CCCI_UTIL_INF_MSG("ccci_util get md1_smem_dfd_size: %d\n", md1_smem_dfd_size); /* Get smem_amms_pos_size */ if (mtk_ccci_find_args_val("smem_amms_pos_size", (unsigned char *)&smem_amms_pos_size, sizeof(smem_amms_pos_size)) != sizeof(smem_amms_pos_size)) CCCI_UTIL_ERR_MSG("get smem amms pos size fail\n"); CCCI_UTIL_INF_MSG("ccci_util get smem_amms_pos_size: %d\n", smem_amms_pos_size); /* Get smem_align_padding_size */ if (mtk_ccci_find_args_val("smem_align_padding_size", (unsigned char *)&smem_align_padding_size, sizeof(smem_align_padding_size)) != sizeof(smem_align_padding_size)) CCCI_UTIL_ERR_MSG("get smem align padding size fail\n"); CCCI_UTIL_INF_MSG("ccci_util get smem_align_padding_size: %d\n", smem_align_padding_size); /* Get smem cachable offset */ md1_bank4_cache_offset = 0; if (mtk_ccci_find_args_val("md1_smem_cahce_offset", (unsigned char *)&md1_bank4_cache_offset, sizeof(md1_bank4_cache_offset)) != sizeof(md1_bank4_cache_offset)) /* Using 128MB offset as default */ md1_bank4_cache_offset = 0x8000000; CCCI_UTIL_INF_MSG("smem cachable offset 0x%X\n", md1_bank4_cache_offset); /* MD*_SMEM_SIZE */ md_resv_smem_size = smem_layout.ap_md1_smem_size; /* MD Share memory layout */ /* AP <--> MD1 */ /* MD1 <--> MD3 */ /* AP <--> MD3 */ md_resv_smem_addr = (phys_addr_t)(smem_layout.base_addr + (unsigned long long)smem_layout.ap_md1_smem_offset); CCCI_UTIL_INF_MSG("AP <--> MD1 SMEM(0x%08X):%016llx~%016llx\n", md_resv_smem_size, (unsigned long long)md_resv_smem_addr, (unsigned long long)(md_resv_smem_addr + md_resv_smem_size-1)); #ifdef CONFIG_MTK_DCS if (md_resv_smem_size) dcs_set_lbw_region(md_resv_smem_addr, (md_resv_smem_addr + md_resv_smem_size)); #endif if (mtk_ccci_find_args_val("mtee_support", (unsigned char *)&md_mtee_support, sizeof(md_mtee_support)) != sizeof(md_mtee_support)) CCCI_UTIL_ERR_MSG("using 0 as MTEE support\n"); else CCCI_UTIL_INF_MSG("MTEE support: 0x%x\n", md_mtee_support); nc_smem_info_parsing(); cshare_memory_info_parsing(); { int i; for (i = 0; i < csmem_info.item_cnt; i++) { CCCI_UTIL_INF_MSG( "csmem_region[%d][%d]: data_offset:%x data_size:%d\n", i, csmem_layout[i].item_cnt, csmem_layout[i].md_offset, csmem_layout[i].csmem_buffer_size); } } } static void md_mem_info_parsing(void) { struct _modem_info md_inf; int md_num = 0; memset(&md_inf, 0, sizeof(md_inf)); if (mtk_ccci_find_args_val("hdr_count", (unsigned char *)&md_num, sizeof(int)) != sizeof(int)) { CCCI_UTIL_ERR_MSG("get hdr_count fail\n"); s_g_lk_load_img_status |= LK_LOAD_MD_ERR_NO_MD_LOAD; return; } if (mtk_ccci_find_args_val("hdr_tbl_inf", (unsigned char *)&md_inf, sizeof(struct _modem_info)) < 0) CCCI_UTIL_INF_MSG("[hdr_tbl_inf] get fail, will pasing invalid data\n"); /* MD ROM and RW part */ #ifdef LK_LOAD_MD_INFO_DEBUG_EN CCCI_UTIL_INF_MSG("===== Dump modem memory info (%d)=====\n", (int)sizeof(struct _modem_info)); CCCI_UTIL_INF_MSG("base address : 0x%llX\n", md_inf.base_addr); CCCI_UTIL_INF_MSG("memory size : 0x%08X\n", md_inf.size); CCCI_UTIL_INF_MSG("ver : %d\n", (int)md_inf.ver); CCCI_UTIL_INF_MSG("type : %d\n", (int)md_inf.md_type); CCCI_UTIL_INF_MSG("errno : %d\n", (int)md_inf.errno); CCCI_UTIL_INF_MSG("=============================\n"); #endif if (md_resv_mem_size == 0) { md_resv_mem_size = md_inf.size; md_resv_mem_addr = (phys_addr_t)md_inf.base_addr; if (md_inf.errno & 0x80) /*signed extension */ lk_load_img_err_no = ((int)md_inf.errno) | 0xFFFFFF00; else lk_load_img_err_no = (int)md_inf.errno; CCCI_UTIL_INF_MSG("md lk_load_img_err_no: %d\n", lk_load_img_err_no); if (lk_load_img_err_no == 0) s_g_md_env_rdy_flag |= 1<<0; md_type_at_lk = (int)md_inf.md_type; CCCI_UTIL_INF_MSG( "md MemStart: 0x%016llx, MemSize:0x%08X\n", (unsigned long long)md_resv_mem_addr, md_resv_mem_size); #ifdef CONFIG_MTK_DCS if (md_resv_mem_size) dcs_set_lbw_region(md_resv_mem_addr, (md_resv_mem_addr + md_resv_mem_size)); #endif } else { CCCI_UTIL_ERR_MSG("Invalid dt para\n"); s_g_lk_load_img_status |= LK_LOAD_MD_ERR_INVALID_MD_ID; } } /*---- Modem check header section --------------------- */ static char *md1_check_hdr_info; static int md1_check_hdr_info_size; static int md1_raw_img_size; void __weak *vmap_reserved_mem(phys_addr_t start, phys_addr_t size, pgprot_t prot) { pr_debug("[ccci/dummy] %s is not supported!\n", __func__); return NULL; } void __iomem *ccci_map_phy_addr(phys_addr_t phy_addr, unsigned int size) { void __iomem *map_addr = NULL; pgprot_t prot; phy_addr &= PAGE_MASK; if (!pfn_is_map_memory(__phys_to_pfn(phy_addr))) { map_addr = ioremap_wc(phy_addr, size); CCCI_UTIL_INF_MSG( "ioremap_wc: (%lx %llx %d)\n", (unsigned long)phy_addr, (u64)map_addr, size); } else { prot = pgprot_writecombine(PAGE_KERNEL); map_addr = (void __iomem *)vmap_reserved_mem( phy_addr, size, prot); CCCI_UTIL_INF_MSG( "vmap_reserved_mem: (%lx %llx %d)\n", (unsigned long)phy_addr, (u64)map_addr, size); } return map_addr; } EXPORT_SYMBOL(ccci_map_phy_addr); static void md_chk_hdr_info_parse(void) { int ret; if (s_g_md_usage_case & (1< MAX_LK_INFO_SIZE) { CCCI_UTIL_ERR_MSG("tag info mem size too large\n"); s_g_lk_load_img_status |= LK_TAG_BUFF_SIZE_NOT_ENOUGH; return; } s_g_lk_info_tag_version = 1; s_g_tag_cnt = (unsigned int)lk_inf.lk_info_tag_num; s_g_lk_inf_base = ccci_map_phy_addr( (phys_addr_t)lk_inf.lk_info_base_addr, MAX_LK_INFO_SIZE); if (s_g_lk_inf_base == NULL) { CCCI_UTIL_ERR_MSG("remap lk info buf fail\n"); s_g_lk_load_img_status |= LK_LOAD_MD_ERR_NO_MD_LOAD; } } static int lk_info_parsing_v2(unsigned int *raw_ptr) { struct _ccci_lk_info_v2 lk_inf; memcpy((void *)&lk_inf, raw_ptr, sizeof(struct _ccci_lk_info_v2)); CCCI_UTIL_INF_MSG("lk info.lk_info_base_addr: 0x%llX\n", lk_inf.lk_info_base_addr); CCCI_UTIL_INF_MSG("lk info.lk_info_size: 0x%x\n", lk_inf.lk_info_size); CCCI_UTIL_INF_MSG("lk info.lk_info_tag_num: 0x%x\n", lk_inf.lk_info_tag_num); s_g_lk_ld_md_errno = lk_inf.lk_info_err_no; s_g_tag_inf_size = lk_inf.lk_info_size; lk_load_img_err_no = lk_inf.lk_info_ld_md_errno; if ((lk_inf.lk_info_base_addr == 0LL) && (s_g_lk_ld_md_errno == 0)) { CCCI_UTIL_ERR_MSG("no image enabled\n"); s_g_lk_inf_base = NULL; s_g_lk_load_img_status = 0; return 1; } if (lk_inf.lk_info_base_addr == 0LL) { CCCI_UTIL_ERR_MSG("no image load success\n"); s_g_lk_load_img_status |= LK_LOAD_MD_ERR_NO_MD_LOAD; return -1; } if (lk_inf.lk_info_size > MAX_LK_INFO_SIZE) { CCCI_UTIL_ERR_MSG("tag info mem size too large\n"); s_g_lk_load_img_status |= LK_TAG_BUFF_SIZE_NOT_ENOUGH; return -1; } s_g_tag_phy_addr = (phys_addr_t)lk_inf.lk_info_base_addr; s_g_lk_info_tag_version = (unsigned int)lk_inf.lk_info_version; s_g_tag_cnt = (unsigned int)lk_inf.lk_info_tag_num; s_g_lk_inf_base = ccci_map_phy_addr( (phys_addr_t)lk_inf.lk_info_base_addr, MAX_LK_INFO_SIZE); if (s_g_lk_inf_base == NULL) { CCCI_UTIL_ERR_MSG("remap lk info buf fail\n"); s_g_lk_load_img_status |= LK_LOAD_MD_ERR_NO_MD_LOAD; } return 0; } static void verify_md_enable_setting(void) { /* Show warning if has some error */ /* MD1 part */ if ((s_g_md_usage_case & (1<= 3) { /* if (!pfn_valid(__phys_to_pfn(s_g_tag_phy_addr))) { iounmap(s_g_lk_inf_base); } else { vunmap(s_g_lk_inf_base); ret = free_reserved_memory(s_g_tag_phy_addr, s_g_tag_phy_addr + MAX_LK_INFO_SIZE); CCCI_UTIL_INF_MSG( "unmap && free reserved tag result=%d\n", ret); } */ } return 0; } /* functions will be called by external */ int get_lk_load_md_info(char buf[], int size) { int has_write; int count; if (s_g_lk_load_img_status & LK_LOAD_MD_EN) has_write = scnprintf(buf, size, "LK Load MD:[Enabled](0x%08x)\n", s_g_lk_load_img_status); else { has_write = scnprintf(buf, size, "LK Load MD:[Disabled](0x%08x)\n", s_g_lk_load_img_status); return has_write; } if ((s_g_lk_load_img_status & (~0x1)) == 0) { has_write += scnprintf(&buf[has_write], size - has_write, "LK load MD success!\n"); return has_write; } has_write += scnprintf(&buf[has_write], size - has_write, "LK load MD has error:\n"); has_write += scnprintf(&buf[has_write], size - has_write, "---- More details ----------------\n"); if (s_g_lk_load_img_status & LK_LOAD_MD_ERR_INVALID_MD_ID) has_write += scnprintf(&buf[has_write], size - has_write, "Err: Got invalid md id(%d:%s)\n", s_g_lk_ld_md_errno, ld_md_errno_to_str(s_g_lk_ld_md_errno)); else if (s_g_lk_load_img_status & LK_LOAD_MD_ERR_NO_MD_LOAD) has_write += scnprintf(&buf[has_write], size - has_write, "Err: No valid md image(%d:%s)\n", s_g_lk_ld_md_errno, ld_md_errno_to_str(s_g_lk_ld_md_errno)); else if (s_g_lk_load_img_status & LK_LOAD_MD_ERR_LK_INFO_FAIL) has_write += scnprintf(&buf[has_write], size - has_write, "Err: Got lk info fail(%d:%s)\n", s_g_lk_ld_md_errno, ld_md_errno_to_str(s_g_lk_ld_md_errno)); else if (s_g_lk_load_img_status & LK_KERNEL_SETTING_MIS_SYNC) has_write += scnprintf(&buf[has_write], size - has_write, "Err: lk kernel setting mis sync\n"); has_write += scnprintf(&buf[has_write], size - has_write, "ERR> 1:[%d]\n", lk_load_img_err_no); count = scnprintf(&buf[has_write], size - has_write, "hint for MD: %s\n", ld_md_errno_to_str(lk_load_img_err_no)); if (count <= 0 || count >= size - has_write) { CCCI_UTIL_INF_MSG("%s: scnprintf hint for MD fail\n", __func__); buf[has_write] = 0; } else { has_write += count; } return has_write; } unsigned int get_mtee_is_enabled(void) { return md_mtee_support; } EXPORT_SYMBOL(get_mtee_is_enabled); int get_md_img_raw_size(void) { return md1_raw_img_size; } int get_raw_check_hdr(char buf[], int size) { char *chk_hdr_ptr = NULL; int cpy_size = 0; int ret = -1; if (buf == NULL) return -1; chk_hdr_ptr = md1_check_hdr_info; cpy_size = md1_check_hdr_info_size; if (chk_hdr_ptr == NULL) return ret; cpy_size = cpy_size > size?size:cpy_size; memcpy(buf, chk_hdr_ptr, cpy_size); return cpy_size; } int modem_run_env_ready(void) { return s_g_md_env_rdy_flag & (1<<0); } int get_md_resv_ccb_info(phys_addr_t *ccb_data_base, unsigned int *ccb_data_size) { *ccb_data_base = ccb_info.ccb_data_buffer_addr; *ccb_data_size = ccb_info.ccb_data_buffer_size; return 0; } EXPORT_SYMBOL(get_md_resv_ccb_info); int get_md_resv_udc_info(unsigned int *udc_noncache_size, unsigned int *udc_cache_size) { *udc_noncache_size = udc_size.noncache_size; *udc_cache_size = udc_size.cache_size; return 0; } EXPORT_SYMBOL(get_md_resv_udc_info); unsigned int get_md_resv_phy_cap_size(void) { return md1_phy_cap_size; } EXPORT_SYMBOL(get_md_resv_phy_cap_size); unsigned int get_md_resv_sib_size(void) { return sib_info.md1_sib_size; } EXPORT_SYMBOL(get_md_resv_sib_size); int get_md_smem_dfd_size(void) { return md1_smem_dfd_size; } EXPORT_SYMBOL(get_md_smem_dfd_size); int get_smem_amms_pos_size(void) { return smem_amms_pos_size; } EXPORT_SYMBOL(get_smem_amms_pos_size); int get_smem_align_padding_size(void) { return smem_align_padding_size; } EXPORT_SYMBOL(get_smem_align_padding_size); unsigned int get_md_smem_cachable_offset(void) { return md1_bank4_cache_offset; } EXPORT_SYMBOL(get_md_smem_cachable_offset); int get_md_resv_csmem_info(phys_addr_t *buf_base, unsigned int *buf_size) { *buf_base = csmem_info.csmem_buffer_addr; *buf_size = csmem_info.csmem_buffer_size; return 0; } EXPORT_SYMBOL(get_md_resv_csmem_info); int get_md_cache_region_info(int region_id, unsigned int *buf_base, unsigned int *buf_size) { int i; *buf_base = 0; *buf_size = 0; if (csmem_layout == NULL || csmem_info.item_cnt == 0) return 0; for (i = 0; i < csmem_info.item_cnt; i++) { if (csmem_layout[i].item_cnt == region_id) { *buf_base = csmem_layout[i].md_offset; *buf_size = csmem_layout[i].csmem_buffer_size; break; } } return 0; } EXPORT_SYMBOL(get_md_cache_region_info); int get_md_sib_mem_info(phys_addr_t *rw_base, unsigned int *rw_size) { if (rw_base != NULL) *rw_base = sib_info.md1_sib_addr; if (rw_size != NULL) *rw_size = sib_info.md1_sib_size; return 0; } EXPORT_SYMBOL(get_md_sib_mem_info); int get_md_resv_mem_info(phys_addr_t *r_rw_base, unsigned int *r_rw_size, phys_addr_t *srw_base, unsigned int *srw_size) { if (r_rw_base != NULL) *r_rw_base = md_resv_mem_addr; if (r_rw_size != NULL) *r_rw_size = md_resv_mem_size; if (srw_base != NULL) *srw_base = md_resv_smem_addr; if (srw_size != NULL) *srw_size = md_resv_smem_size; return 0; } EXPORT_SYMBOL_GPL(get_md_resv_mem_info); unsigned int get_md_smem_align(void) { return 0x4000; } unsigned int get_modem_is_enabled(void) { return !!(s_g_md_usage_case & (1 << 0)); } EXPORT_SYMBOL(get_modem_is_enabled); /**************************************************************/ /* The following functions are back up for old platform */ /**************************************************************/ static void cal_md_settings(void) { char tmp_buf[30]; char *node_name = NULL; char *node_name2 = NULL; struct device_node *node = NULL; struct device_node *node2 = NULL; int val; val = snprintf(tmp_buf, sizeof(tmp_buf), "opt_md_support"); if (val < 0 || val >= sizeof(tmp_buf)) { CCCI_UTIL_ERR_MSG( "%s-%d:snprintf fail.val=%d\n", __func__, __LINE__, val); return; } if (!(s_g_md_usage_case & (1 << 0))) { CCCI_UTIL_INF_MSG("md is disabled\n"); return; } /* For cldma case */ node_name = "mediatek,mddriver"; /* For ccif case */ node_name2 = "mediatek,ap_ccif0"; node = of_find_compatible_node(NULL, NULL, node_name); node2 = of_find_compatible_node(NULL, NULL, node_name2); if (node) of_property_read_u32(node, "mediatek,md_smem_size", &md_resv_smem_size); else if (node2) of_property_read_u32(node2, "mediatek,md_smem_size", &md_resv_smem_size); else { CCCI_UTIL_ERR_MSG( "md smem size is not set in device tree,need to check\n"); s_g_md_usage_case &= ~(1 << 0); return; } /* MD ROM start address should be 32M align * as remap hardware limitation */ md_resv_mem_addr = md_resv_mem_list; /* * for legacy CCCI: make share memory start address to be 2MB align, * as share memory size is 2MB - requested by MD MPU. * for ECCCI: ROM+RAM size will be align to 1M, * and share memory is 2K, 1M alignment is also 2K alignment. */ md_resv_mem_size = round_up(md_resv_size_list - md_resv_smem_size, get_md_smem_align()); md_resv_smem_addr = md_resv_mem_list + md_resv_mem_size; CCCI_UTIL_INF_MSG( "md modem_total_size=0x%x,md_size=0x%x, smem_size=0x%x\n", md_resv_size_list, md_resv_mem_size, md_resv_smem_size); if ((s_g_md_usage_case & (1 << 0)) && ((md_resv_mem_addr & (CCCI_MEM_ALIGN - 1)) != 0)) CCCI_UTIL_ERR_MSG("md memory addr is not 32M align!!!\n"); if ((s_g_md_usage_case & (1 << 0)) && ((md_resv_smem_addr & (CCCI_SMEM_ALIGN_MD1 - 1)) != 0)) CCCI_UTIL_ERR_MSG( "md share memory addr %p is not 0x%x align!!\n", &md_resv_smem_addr, CCCI_SMEM_ALIGN_MD1); CCCI_UTIL_INF_MSG( "MemStart: %016llx, MemSize:0x%08X\n", (unsigned long long)md_resv_mem_addr, md_resv_mem_size); CCCI_UTIL_INF_MSG( "SMemStart: %016llx, SMemSize:0x%08X\n", (unsigned long long)md_resv_smem_addr, md_resv_smem_size); } static void cal_md_settings_v2(struct device_node *node) { unsigned int tmp; char tmp_buf[30]; CCCI_UTIL_INF_MSG("using kernel dt mem setting for md\n"); /* MD*_SMEM_SIZE */ scnprintf(tmp_buf, 30, "mediatek,md-smem-size"); if (!of_property_read_u32(node, tmp_buf, &tmp)) { CCCI_UTIL_INF_MSG("DT[%s]:%08X\n", tmp_buf, tmp); md_resv_smem_size = tmp; } else CCCI_UTIL_INF_MSG("DT[%s]:%08X\n", tmp_buf, md_resv_smem_size); /* CFG version */ scnprintf(tmp_buf, 30, "mediatek,version"); tmp = 0; if (of_property_read_u32(node, tmp_buf, &tmp) < 0) CCCI_UTIL_INF_MSG("DT[mediatek,version]:NA\n"); CCCI_UTIL_INF_MSG("DT[%s]:%08X\n", tmp_buf, tmp); if (tmp != 1) { CCCI_UTIL_INF_MSG("Un-support version:%d\n", tmp); return; } /* MD ROM and RW part */ if (s_g_md_usage_case & (1 << 0)) { md_resv_mem_size = md_resv_size_list; md_resv_mem_addr = md_resv_mem_list; CCCI_UTIL_INF_MSG( "md MemStart: 0x%016llx, MemSize:0x%08X\n", (unsigned long long)md_resv_mem_addr, md_resv_mem_size); } /* MD Share memory part */ /* AP <--> MD1 */ md_resv_smem_addr = resv_smem_addr; CCCI_UTIL_INF_MSG( "AP <--> MD1 SMEM(0x%08X):%016llx~%016llx\n", md_resv_smem_size, (unsigned long long)md_resv_smem_addr, (unsigned long long)(md_resv_smem_addr + md_resv_smem_size-1)); } /********************************************************/ /* Global functions */ /*******************************************************/ int get_md_img_type(void) { /* MD standalone, only one image case */ if (s_g_lk_load_img_status & LK_LOAD_MD_EN) return md_type_at_lk; return 0; } EXPORT_SYMBOL(get_md_img_type); void ccci_md_mem_reserve(void) { CCCI_UTIL_INF_MSG("%s phased out.\n", __func__); } #ifdef CONFIG_OF_RESERVED_MEM #define CCCI_MD1_MEM_RESERVED_KEY "mediatek,reserve-memory-ccci_md1" int ccci_reserve_mem_of_init(struct reserved_mem *rmem) { phys_addr_t rptr = 0; unsigned int rsize = 0; rptr = rmem->base; rsize = (unsigned int)rmem->size; CCCI_UTIL_INF_MSG("reserve_mem_of_init, rptr=0x%pa, rsize=0x%x\n", &rptr, rsize); md_resv_mem_list = rptr; md_resv_size_list = rsize; s_g_md_usage_case |= (1U << 0); return 0; } RESERVEDMEM_OF_DECLARE(ccci_reserve_mem_md1_init, CCCI_MD1_MEM_RESERVED_KEY, ccci_reserve_mem_of_init); #endif /**************************************************************/ /* CCCI Feature option parsiong entry */ /**************************************************************/ int __init ccci_util_fo_init(void) { struct device_node *node = NULL; CCCI_UTIL_INF_MSG("%s 0.\n", __func__); if (collect_lk_boot_arguments() == 0) { CCCI_UTIL_INF_MSG("using v3.\n"); return 0; } node = of_find_compatible_node(NULL, NULL, "mediatek,ccci_util_cfg"); if (node == NULL) { CCCI_UTIL_INF_MSG("using v1.\n"); /* Calculate memory layout */ cal_md_settings(); } else { CCCI_UTIL_INF_MSG("using v2.\n"); cal_md_settings_v2(node); } CCCI_UTIL_INF_MSG("%s 2.\n", __func__); return 0; }