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.

263 lines
8.1 KiB

/*
* Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2019. All rights reserved.
* Description: decoder
* Author: Hisilicon
* Create: 2012-04-22
*/
#include "dmcu_hal.h"
#include "dmcu_common.h"
#include "drv_mbx.h"
#include "los_exc.h"
td_void mem_print(const td_u32 *mem_addr, td_u32 length)
{
td_u32 read_offset = 0;
while ((read_offset < length) && (mem_addr != TD_NULL)) {
if (read_offset % 16 == 0) { /* 16 :a number */
printf("\n0x%08x : ", (td_u32)ptr_uint64(mem_addr) + read_offset);
}
printf("0x%08x ", *(volatile td_u32 *)(mem_addr + read_offset / 4)); /* 4 :a number */
read_offset += 4; /* 4 :a number */
}
printf("\n");
return;
}
#define dmcu_svr_mem_print_pos(ptr, size) \
do { \
printf("\n%s %d print mem:", __func__, __LINE__); \
mem_print(ptr, size); \
} while (0)
td_void liteos_iounmap(td_u8 *viraddr)
{
return;
}
td_u8 *liteos_ioremap(UADDR phyaddr, td_u32 len)
{
return (td_u8 *)uint64_ptr(phyaddr);
}
td_u32 liteos_get_page_size(td_void)
{
return PAGE_SIZE_4K;
}
static iommu_ctx g_iommu_ctx;
void dmcu_flush_d_cache_by_all(void)
{
td_u32 cmd = 12;
write_custom_csr(DCMAINT, cmd); /* cache clean and cache invalid */
__asm__ __volatile__("fence");
}
void dmcu_fence_cmd(void)
{
__asm__ __volatile__("fence");
}
static td_s32 dmcu_iommu_isr_no_sec(td_s32 irq, td_void *dev_id)
{
iommu_ctx *ctx = &g_iommu_ctx;
printf("Ops!!! %s error reported!!!\n", __func__);
printf("iommu common reg:\n");
dmcu_svr_mem_print_pos((td_u32 *)ctx->comm_base_reg, DMCU_IOMMU_REG_INFO_SIZE);
printf("The data on read err addr is :\n");
dmcu_svr_mem_print_pos((td_u32 *)uint64_ptr(ctx->pt_addr.pt_no_sec_err_rd_addr), DMCU_IOMMU_ERR_ADDR_SIZE);
printf("The data on write err addr is :\n");
dmcu_svr_mem_print_pos((td_u32 *)uint64_ptr(ctx->pt_addr.pt_no_sec_err_wt_addr), DMCU_IOMMU_ERR_ADDR_SIZE);
WR_IOMMU_REG(0, ctx->comm_base_reg + INT_MASK_NO_SEC); /* mask all 6 bit no sec mmu int avoid int report */
WR_IOMMU_REG(0x3F, ctx->comm_base_reg + INT_CLR_NO_SEC); /* clear all 6 bit no sec mmu int is 0x3F */
return TD_SUCCESS;
}
static td_void dmcu_iommu_cfg_no_sec_pt_addr(td_u8 *base_reg, td_u32 base_addr, td_u32 err_read_addr,
td_u32 err_write_addr)
{
td_u32 data;
data = base_addr;
WR_IOMMU_REG(data, base_reg + CB_TTBR);
data = err_read_addr;
WR_IOMMU_REG(data, base_reg + ERR_NS_RD_ADDR);
data = err_write_addr;
WR_IOMMU_REG(data, base_reg + ERR_NS_WR_ADDR);
return;
}
td_void dmcu_iommu_init_sub(td_u8 *base_reg)
{
td_u32 data;
const td_u32 global_bypass = 0;
#if (defined(LOSCFG_FAMILY_RESERVED19) || defined(LOSCFG_FAMILY_HI3751V811))
data = 0x0; /* unmask all 6 bit no sec mmu int is 0x3F */
WR_IOMMU_REG(data, base_reg + INT_MASK_NO_SEC);
data = (global_bypass & 0x1); /* bit 31 4 1 match reg */
WR_IOMMU_REG(data, base_reg + SMMU_SCR);
#else
const td_u32 out_standing = 1;
td_u32 page_type; /* 0:4K 1:16K 2:64k */
const td_u32 int_en = 1; /* int en valid is 1 */
const td_u32 src_lock = 0;
data = 0x3F; /* unmask all 6 bit no sec mmu int is 0x3F */
WR_IOMMU_REG(data, base_reg + INT_MASK_NO_SEC);
data = 0; /* disalbe non sec tag */
WR_IOMMU_REG(data, base_reg + CMD_TAG_RD_EN);
WR_IOMMU_REG(data, base_reg + CMD_TAG_WR_EN);
page_type = liteos_get_page_size();
data = ((out_standing & 0xf) << 16) | ((page_type & 0xf) << 4) | (int_en << 3); /* bit 16 4 3 match reg */
WR_IOMMU_REG(data, base_reg + COMMON_CTRL);
data = ((src_lock & 0x1) << 31) | ((page_type & 0xf) << 4) | (global_bypass & 0x1); /* bit 31 4 1 match reg */
WR_IOMMU_REG(data, base_reg + SMMU_SCR);
#endif
return;
}
td_s32 dmcu_iommu_init(const dmcu_iommu_pt_addr *pt_addr)
{
td_u8 *base_reg = TD_NULL;
td_s32 ret;
iommu_ctx *ctx = &g_iommu_ctx;
if (pt_addr == TD_NULL) {
printf("Assert Warning: condition pt_addr != TD_NULL not match");
return TD_FAILURE;
}
dmcu_check_sec_func(memset_s(ctx, sizeof(iommu_ctx), 0, sizeof(iommu_ctx)));
base_reg = liteos_ioremap(IOMMU_COMMON_BASE_REG, IOMMU_MAP_SIZE);
if (base_reg == TD_NULL) {
printf("Assert Warning: condition base_reg != TD_NULL not match");
return TD_FAILURE;
}
ctx->comm_base_reg = base_reg;
ctx->master_base_reg = liteos_ioremap(IOMMU_MASTER_BASE_REG, IOMMU_MAP_SIZE);
dmcu_check_sec_func(memcpy_s(&ctx->pt_addr, sizeof(ctx->pt_addr), pt_addr, sizeof(dmcu_iommu_pt_addr)));
#if (defined(LOSCFG_FAMILY_RESERVED19) || defined(LOSCFG_FAMILY_HI3751V811))
WR_IOMMU_REG(0xF, ctx->comm_base_reg + INT_CLR_NO_SEC);
WR_IOMMU_REG(0xF, ctx->comm_base_reg + INT_MASK_NO_SEC);
WR_IOMMU_REG(0xF, ctx->comm_base_reg + INT_CLR_NO_SEC);
#else
WR_IOMMU_REG(0x3F, ctx->comm_base_reg + INT_CLR_NO_SEC);
WR_IOMMU_REG(0, ctx->comm_base_reg + INT_MASK_NO_SEC);
WR_IOMMU_REG(0x3F, ctx->comm_base_reg + INT_CLR_NO_SEC);
#endif
dmcu_iommu_cfg_no_sec_pt_addr(base_reg, pt_addr->pt_no_sec_addr, pt_addr->pt_no_sec_err_rd_addr,
pt_addr->pt_no_sec_err_wt_addr);
ret = osal_irq_request(IOMMU_NO_SEC_IRQ_NUM, dmcu_iommu_isr_no_sec, 0, "iommu_no_sec", TD_NULL);
if (ret != TD_SUCCESS) {
printf("%s req no sec irq failed ret = 0x%x\n", __func__, ret);
}
osal_irq_enable(IOMMU_NO_SEC_IRQ_NUM); // 使能中断
dmcu_iommu_init_sub(base_reg);
osal_spin_lock_init(&ctx->spin_lock);
return TD_SUCCESS;
}
td_s32 dmcu_iommu_deinit(td_void)
{
iommu_ctx *ctx = &g_iommu_ctx;
#if (defined(LOSCFG_FAMILY_RESERVED19) || defined(LOSCFG_FAMILY_HI3751V811))
WR_IOMMU_REG(0xF, ctx->comm_base_reg + INT_CLR_NO_SEC);
WR_IOMMU_REG(0xF, ctx->comm_base_reg + INT_MASK_NO_SEC);
WR_IOMMU_REG(0xF, ctx->comm_base_reg + INT_CLR_NO_SEC);
#else
WR_IOMMU_REG(0x3F, ctx->comm_base_reg + INT_CLR_NO_SEC);
WR_IOMMU_REG(0, ctx->comm_base_reg + INT_MASK_NO_SEC);
WR_IOMMU_REG(0x3F, ctx->comm_base_reg + INT_CLR_NO_SEC);
#endif
osal_irq_free(IOMMU_NO_SEC_IRQ_NUM, TD_NULL);
liteos_iounmap(ctx->master_base_reg);
liteos_iounmap(ctx->comm_base_reg);
osal_spin_lock_destroy(&ctx->spin_lock);
return TD_SUCCESS;
}
td_s32 dmcu_iommu_flush_tlb(td_bool flush_cache)
{
td_u8 *master_base;
td_u32 data;
td_u32 cmd_buff_empty;
#if !defined(LOSCFG_FAMILY_RESERVED19) && !defined(LOSCFG_FAMILY_HI3751V811)
td_u32 common_tcu_idle;
#endif
td_s32 try_cnt = 10000;
iommu_ctx *ctx = &g_iommu_ctx;
master_base = ctx->master_base_reg;
/* disable isr */
osal_spin_lock(&ctx->spin_lock);
/* clean and invalid dcache */
if (flush_cache == TD_TRUE) {
dmcu_flush_d_cache_by_all();
}
dmcu_fence_cmd();
/* cmd buff ilde */
while (try_cnt > 0) {
RD_IOMMU_REG(data, master_base + CMD_BUF_STATE);
cmd_buff_empty = (data >> 14) & 0x1; /* cmd_buff_empty flag bit 14 */
#if (defined(LOSCFG_FAMILY_RESERVED19) || defined(LOSCFG_FAMILY_HI3751V811))
if (cmd_buff_empty) {
break;
}
#else
common_tcu_idle = (data >> 13) & 0x1; /* common_tcu_idle flag bit 13 */
if (cmd_buff_empty && common_tcu_idle) {
break;
}
#endif
try_cnt--;
}
if (try_cnt <= 0) {
printf("iommu cmd is not ilde\n");
}
WR_IOMMU_REG(0xF, master_base + TLB_FLUSH);
WR_IOMMU_REG(0, master_base + TLB_FLUSH);
/* add fence cmd */
dmcu_fence_cmd();
/* enable isr */
osal_spin_unlock(&ctx->spin_lock);
return TD_SUCCESS;
}
td_void dmcu_hal_set_uart_pinmux(td_void)
{
#ifndef CONFIG_SOCT_LOG_OUTPUT_TO_CPU
dmcu_wr_reg(DMCU_RXD_PINMUX_ADDR, 0, 0x1);
dmcu_wr_reg(DMCU_TXD_PINMUX_ADDR, 0, 0x1);
#endif
return;
}