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.
310 lines
9.4 KiB
310 lines
9.4 KiB
/*
|
|
* 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;
|
|
}
|