/* * Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2019. All rights reserved. * Description: decoder * Author: Hisilicon * Create: 2012-04-22 */ #include "dmcu_mem.h" #include "dmcu_hal.h" #include "dmcu_adapt.h" #include "drv_mbx.h" #include "los_dynshm.h" #include "los_memory.h" static dmcu_mem_ctx g_ctx; static td_void *g_dmcu_mem_pool = NULL; static td_u32 dmcu_vam_flush_tlb(td_u32 flush_cache) { return dmcu_iommu_flush_tlb(flush_cache); } static td_u32 dmcu_vam_bulk_alloc(DynShmBulkMem *mem) { td_u32 ret = TD_SUCCESS; if (mem == NULL || mem->name == NULL || mem->size == 0) { soc_log_err("mem is NULL!\n"); return TD_FAILURE; } dmcu_mem_record report = { 0 }; report.length = mem->size; report.type = mem->type; if (memcpy_s(report.mem_name, DMCU_MEM_NAME_MAX_LEN, mem->name, strlen(mem->name) + 1) != EOK) { soc_log_err("mem_name memcpy fail\n"); return TD_FAILURE; } ret = dmcu_client_send_process(DMCU_CMD_VAM_ALLOC, (td_void *)&report, sizeof(dmcu_mem_record)); mem->phyAddr = report.phy_addr; mem->dmaBuf = report.dma_buf; return ret; } static td_u32 dmcu_vam_bulk_free(DynShmBulkMem *mem) { td_u32 ret = TD_SUCCESS; if (mem == NULL || mem->size == 0 || mem->phyAddr == 0 || mem->dmaBuf == 0) { soc_log_err("mem is NULL!\n"); return TD_FAILURE; } dmcu_mem_record report = { 0 }; report.type = mem->type; report.phy_addr = mem->phyAddr; report.length = mem->size; report.dma_buf = mem->dmaBuf; ret = dmcu_client_send_process(DMCU_CMD_VAM_FREE, (td_void *)&report, sizeof(dmcu_mem_record)); return ret; } td_s32 dmcu_pool_mem_init(UADDR phy_addr, td_u32 size, dmcu_mem_type type, UADDR *vir_addr) { td_u32 ret; td_u32 pool_vir_addr; if ((g_dmcu_mem_pool != NULL) || (vir_addr == NULL)) { soc_log_err("Invalid parameter\n"); return TD_FAILURE; } ret = LOS_DynShmMap(phy_addr, size, type, &pool_vir_addr); if (ret != TD_SUCCESS) { soc_log_err("LOS_DynShmMap fail\n"); return TD_FAILURE; } ret = LOS_MemInit((td_void *)(UINTPTR)pool_vir_addr, size); if (ret != TD_SUCCESS) { soc_log_err("LOS_MemInit fail, ret:%#x\n", ret); ret = LOS_DynShmUnmap(pool_vir_addr, size); if (ret != TD_SUCCESS) { soc_log_err("LOS_DynShmUnmap fail\n"); return TD_FAILURE; } return TD_FAILURE; } *vir_addr = pool_vir_addr; g_dmcu_mem_pool = (td_void *)(UINTPTR)pool_vir_addr; return TD_SUCCESS; } td_void *dmcu_pool_mem_malloc(td_u32 size) { if (g_dmcu_mem_pool == NULL) { soc_log_err("g_dmcu_mem_pool not null\n"); return NULL; } return LOS_MemAlloc(g_dmcu_mem_pool, size); } td_s32 dmcu_pool_mem_free(td_void *addr) { td_u32 ret; if (g_dmcu_mem_pool == NULL) { soc_log_err("g_dmcu_mem_pool is null\n"); return TD_FAILURE; } ret = LOS_MemFree(g_dmcu_mem_pool, addr); if (ret != TD_SUCCESS) { soc_log_err("LOS_MemFree fail\n"); return TD_FAILURE; } return TD_SUCCESS; } td_s32 dmcu_pool_mem_deinit(UADDR vir_addr, td_u32 size) { td_u32 ret; if (g_dmcu_mem_pool == NULL) { soc_log_err("g_dmcu_mem_pool is null\n"); return TD_FAILURE; } ret = LOS_MemDeInit((void *)(uintptr_t)vir_addr); if (ret != TD_SUCCESS) { soc_log_err("LOS_MemDeInit fail, ret:%#x\n", ret); } ret = LOS_DynShmUnmap(vir_addr, size); if (ret != TD_SUCCESS) { soc_log_err("LOS_DynShmUnmap fail\n"); return TD_FAILURE; } g_dmcu_mem_pool = NULL; return TD_SUCCESS; } static dmcu_mem_ctx *dmcu_mem_get_ctx(td_void) { return &g_ctx; } static td_void dmcu_mem_init_page(td_void) { td_u32 page_size; dmcu_mem_ctx *ctx = TD_NULL; ctx = dmcu_mem_get_ctx(); page_size = PAGE_SIZE_4K; if (page_size >= PAGE_SIZE_MAX) { soc_log_err("err %d\n", page_size); } ctx->page_size = 0x1000 << (page_size << 1); return; } static td_s32 dmcu_mem_get_no_cache_scale(td_void) { return DMCU_ADDR_LEN_NC_SCALE; } static td_void dmcu_mem_set_iommu_pt_addr(dmcu_iommu_pt_addr *pt_addr) { dmcu_mem_ctx *ctx = TD_NULL; ctx = dmcu_mem_get_ctx(); pt_addr->pt_no_sec_addr = ctx->dmcu_pt[MEM_PT_NS].base_addr; pt_addr->pt_no_sec_err_rd_addr = ctx->dmcu_pt[MEM_PT_NS].err_read_addr; pt_addr->pt_no_sec_err_wt_addr = ctx->dmcu_pt[MEM_PT_NS].err_write_addr; return; } static td_void dmcu_mem_debug_info(DynShmConfig *cfg) { int i = 0; printf("[dmcu]: arm pt addr:0x%x, dmcu pt addr:0x%x, pageSize:0x%x\n", cfg->outerPageTable.nonsec.baseAddr, cfg->innerPageTable.nonsec.baseAddr, cfg->pageSize); for (i = 0; i < cfg->regionCnt; i++) { printf("[dmcu]: num:%d, regionStart:0x%x, regionSize:0x%x, type:0x%x\n", i, cfg->regions[i].startAddr, cfg->regions[i].size, cfg->regions[i].type); } return; } td_s32 dmcu_mem_vam_init(void) { dmcu_mem_ctx *ctx = TD_NULL; ctx = dmcu_mem_get_ctx(); td_s32 no_cache_scale = dmcu_mem_get_no_cache_scale(); td_u32 total_size = ctx->iommu_total_size; td_u32 no_cache_addr = ctx->iommu_base_vir_addr; td_u32 no_cache_size = (td_u32)((td_u64)total_size * (td_u64)no_cache_scale / DMCU_SCALE_NUM); no_cache_size = dmcu_align_dn(no_cache_size, ctx->page_size); td_u32 cache_addr = no_cache_addr + no_cache_size; td_u32 cache_size = total_size - no_cache_size; cache_size = dmcu_align_dn(cache_size, ctx->page_size); DynShmConfig cfg = { .outerPageTable.nonsec.baseAddr = ctx->arm_pt[MEM_PT_NS].base_addr, .outerPageTable.nonsec.tableSize = DMCU_NS_PT_SIZE, .innerPageTable.nonsec.baseAddr = ctx->dmcu_pt[MEM_PT_NS].base_addr, .innerPageTable.nonsec.tableSize = DMCU_NS_PT_SIZE, .pageSize = ctx->page_size, .flushTlbHandler = dmcu_vam_flush_tlb, .bulkAllocHandler = dmcu_vam_bulk_alloc, .bulkFreeHandler = dmcu_vam_bulk_free, .regionCnt = 2, .regions = { {.startAddr = no_cache_addr, .size = no_cache_size, .type = DMCU_IOMMU_NOSEC_NOCACHE}, {.startAddr = cache_addr, .size = cache_size, .type = DMCU_IOMMU_NOSEC_CACHE}, } }; dmcu_iommu_pt_addr pt_addr = { 0 }; dmcu_mem_set_iommu_pt_addr(&pt_addr); dmcu_iommu_init(&pt_addr); dmcu_mem_debug_info(&cfg); return LOS_DynShmInit(&cfg); } static td_void dmcu_mem_calc_vir_base_addr(td_void) { dmcu_mem_ctx *ctx = TD_NULL; ctx = dmcu_mem_get_ctx(); ctx->iommu_base_vir_addr = dmcu_max(ctx->mmz_info.base_addr + ctx->mmz_info.mmz_size, DMCU_RESERVED_START_ADDR + DMCU_RESERVED_START_SIZE); ctx->iommu_base_vir_addr = dmcu_max(ctx->iommu_base_vir_addr, ctx->arm_pt[MEM_PT_NS].base_addr + MEM_PT_SIZE_MAX); ctx->iommu_total_size = DMCU_IOMMU_MAX_ADDR - (ctx->iommu_base_vir_addr); soc_log_info("dmcu vir base_addr = 0x%llx size = 0x%x\n", ctx->iommu_base_vir_addr, ctx->iommu_total_size); return; } static td_void dmcu_mem_fill_pt_addr(td_void) { dmcu_mem_ctx *ctx; ctx = dmcu_mem_get_ctx(); ctx->dmcu_pt[MEM_PT_NS].base_addr = DMCU_NS_PT_BASEADDR; ctx->dmcu_pt[MEM_PT_NS].err_read_addr = DMCU_NS_PT_ERRADDR_RD; ctx->dmcu_pt[MEM_PT_NS].err_write_addr = DMCU_NS_PT_ERRADDR_WR; ctx->dmcu_pt[MEM_PT_S].base_addr = DMCU_PT_BASEADDR_S; ctx->dmcu_pt[MEM_PT_S].err_read_addr = DMCU_PT_ERRADDR_RD_S; ctx->dmcu_pt[MEM_PT_S].err_write_addr = DMCU_PT_ERRADDR_WR_S; return; } static td_s32 dmcu_mem_init_pre(td_void) { td_s32 ret = TD_SUCCESS; dmcu_mem_init_data mem_init_data = { 0 }; mem_init_data.flag = 0x5a5a; ret = dmcu_client_send_process(DMCU_CMD_MEM_INIT, (td_void *)&mem_init_data, sizeof(dmcu_mem_init_data)); if (ret != TD_SUCCESS) { soc_log_err("send DMCU_CMD_MEM_INIT Messages failed\n"); return ret; } dmcu_mem_ctx *ctx = TD_NULL; ctx = dmcu_mem_get_ctx(); ctx->arm_pt[MEM_PT_S].base_addr = mem_init_data.pt_sec_addr; ctx->arm_pt[MEM_PT_NS].base_addr = mem_init_data.pt_nosec_addr; ctx->mmz_info.base_addr = mem_init_data.pt_mmz_addr; ctx->mmz_info.mmz_size = mem_init_data.pt_mmz_size; return TD_SUCCESS; } td_s32 dmcu_mem_init(td_void) { td_s32 ret = TD_SUCCESS; ret = dmcu_mem_init_pre(); if (ret != TD_SUCCESS) { soc_log_err("dmcu_mem_init_pre failed, ret: %d\n", ret); return TD_FAILURE; } dmcu_mem_calc_vir_base_addr(); dmcu_mem_fill_pt_addr(); dmcu_mem_init_page(); ret = dmcu_mem_vam_init(); if (ret != TD_SUCCESS) { soc_log_err("dmcu_mem_vam_init failed, ret: %d\n", ret); return TD_FAILURE; } return TD_SUCCESS; } td_void dmcu_mem_resume(td_void) { dmcu_mem_ctx *ctx = TD_NULL; ctx = dmcu_mem_get_ctx(); const dmcu_iommu_pt_addr pt_addr = { .pt_no_sec_addr = ctx->dmcu_pt[MEM_PT_NS].base_addr, .pt_no_sec_err_rd_addr = ctx->dmcu_pt[MEM_PT_NS].err_read_addr, .pt_no_sec_err_wt_addr = ctx->dmcu_pt[MEM_PT_NS].err_write_addr, }; dmcu_iommu_deinit(); dmcu_iommu_init(&pt_addr); return; }