/* * 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; }