From 6ae65bceedf928129fd463076d145b9c9d92842a Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 30 Apr 2014 14:28:44 +0800 Subject: [PATCH] rk3288: vcodec specialize the registers address transform (buffer id to virtual address) table for every video coding format --- arch/arm/mach-rockchip/vcodec_service.c | 418 +++++++++++++----------- 1 file changed, 235 insertions(+), 183 deletions(-) diff --git a/arch/arm/mach-rockchip/vcodec_service.c b/arch/arm/mach-rockchip/vcodec_service.c index 43a60f295cfb..a3207fbc4906 100755 --- a/arch/arm/mach-rockchip/vcodec_service.c +++ b/arch/arm/mach-rockchip/vcodec_service.c @@ -187,19 +187,59 @@ static VPU_HW_INFO_E vpu_hw_set[] = { #define VPU_REG_DEC_PP_GATE_BIT (1<<8) #if defined(CONFIG_VCODEC_MMU) -static u8 addr_tbl_vpu_dec[] = { - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 40, 41 +static u8 addr_tbl_vpu_h264dec[] = { + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 40, 41 +}; + +static u8 addr_tbl_vpu_vp8dec[] = { + 10,12,13, 14, 18, 19, 27, 40 +}; + +static u8 addr_tbl_vpu_vp6dec[] = { + 12, 13, 14, 18, 27, 40 +}; + +static u8 addr_tbl_vpu_vc1dec[] = { + 12, 13, 14, 15, 16, 17, 27, 41 +}; + +static u8 addr_tbl_vpu_jpegdec[] = { + 12, 40, 66, 67 +}; + +static u8 addr_tbl_vpu_defaultdec[] = { + 12, 13, 14, 15, 16, 17, 40, 41 }; static u8 addr_tbl_vpu_enc[] = { - 5, 6, 7, 8, 9, 10, 11, 12, 13, 51 + 5, 6, 7, 8, 9, 10, 11, 12, 13, 51 }; static u8 addr_tbl_hevc_dec[] = { - 4, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 42, 43 + 4, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 42, 43 }; #endif +enum VPU_DEC_FMT { + VPU_DEC_FMT_H264, + VPU_DEC_FMT_MPEG4, + VPU_DEC_FMT_H263, + VPU_DEC_FMT_JPEG, + VPU_DEC_FMT_VC1, + VPU_DEC_FMT_MPEG2, + VPU_DEC_FMT_MPEG1, + VPU_DEC_FMT_VP6, + VPU_DEC_FMT_RV, + VPU_DEC_FMT_VP7, + VPU_DEC_FMT_VP8, + VPU_DEC_FMT_AVS, + VPU_DEC_FMT_SVC, + VPU_DEC_FMT_VC2, + VPU_DEC_FMT_MVC, + VPU_DEC_FMT_THEORA, + VPU_DEC_FMT_RES +}; + /** * struct for process session which connect to vpu * @@ -232,9 +272,9 @@ typedef struct vpu_reg { struct list_head session_link; /* link to vpu service session */ struct list_head status_link; /* link to register set list */ unsigned long size; -#if defined(CONFIG_VCODEC_MMU) - struct list_head mem_region_list; -#endif +#if defined(CONFIG_VCODEC_MMU) + struct list_head mem_region_list; +#endif unsigned long *reg; } vpu_reg; @@ -597,10 +637,10 @@ static inline bool reg_check_interlace(vpu_reg *reg) return (type > 0); } -static inline bool reg_check_avc(vpu_reg *reg) +static inline enum VPU_DEC_FMT reg_check_fmt(vpu_reg *reg) { - unsigned long type = (reg->reg[3] & 0xF0000000) >> 28; - return (type == 0); + enum VPU_DEC_FMT type = (enum VPU_DEC_FMT)((reg->reg[3] & 0xF0000000) >> 28); + return type; } static inline int reg_probe_width(vpu_reg *reg) @@ -611,107 +651,128 @@ static inline int reg_probe_width(vpu_reg *reg) } #if defined(CONFIG_VCODEC_MMU) - static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, int size, vpu_reg *reg) { - int i; - int usr_fd = 0; - int offset = 0; - - if (tbl == NULL || size <= 0) { - dev_err(pservice->dev, "input arguments invalidate\n"); - return -1; - } - - vpu_service_power_on(pservice); - - for (i=0; ireg[addr_tbl_vpu_dec[i]], sizeof(usr_fd))) - return -EFAULT; -#else - usr_fd = reg->reg[tbl[i]] & 0x3FF; - offset = reg->reg[tbl[i]] >> 10; - -#endif - if (usr_fd != 0) { - struct ion_handle *hdl; - - hdl = ion_import_dma_buf(pservice->ion_client, usr_fd); - if (IS_ERR(hdl)) { - dev_err(pservice->dev, "import dma-buf from fd %d failed, reg[%d]\n", usr_fd, tbl[i]); - return PTR_ERR(hdl); - } + int i; + int usr_fd = 0; + int offset = 0; -#if 0 - { - ion_phys_addr_t phy_addr; - size_t len; - ion_phys(pservice->ion_client, hdl, &phy_addr, &len); - - reg->reg[tbl[i]] = phy_addr + offset; - - ion_free(pservice->ion_client, hdl); - } -#else - { - int ret; - struct vcodec_mem_region *mem_region; - mem_region = kzalloc(sizeof(struct vcodec_mem_region), GFP_KERNEL); - - if (mem_region == NULL) { - dev_err(pservice->dev, "allocate memory for iommu memory region failed\n"); - ion_free(pservice->ion_client, hdl); - return -1; - } - - mem_region->hdl = hdl; - - ret = ion_map_iommu(pservice->dev, pservice->ion_client, mem_region->hdl, &mem_region->iova, &mem_region->len); - if (ret < 0) { - dev_err(pservice->dev, "ion map iommu failed\n"); - kfree(mem_region); - ion_free(pservice->ion_client, hdl); - return ret; - } - - reg->reg[tbl[i]] = mem_region->iova + offset; - INIT_LIST_HEAD(&mem_region->reg_lnk); - list_add_tail(&mem_region->reg_lnk, ®->mem_region_list); - } -#endif - } - } - - return 0; + if (tbl == NULL || size <= 0) { + dev_err(pservice->dev, "input arguments invalidate\n"); + return -1; + } + + vpu_service_power_on(pservice); + + for (i = 0; i < size; i++) { + usr_fd = reg->reg[tbl[i]] & 0x3FF; + + if (tbl[i] == 41 && pservice->hw_info->hw_id != HEVC_ID && (reg->type == VPU_DEC || reg->type == VPU_DEC_PP)) { + /* special for vpu dec num 41 regitster */ + offset = reg->reg[tbl[i]] >> 10 << 4; + } else { + offset = reg->reg[tbl[i]] >> 10; + } + + if (usr_fd != 0) { + struct ion_handle *hdl; + int ret; + struct vcodec_mem_region *mem_region; + + hdl = ion_import_dma_buf(pservice->ion_client, usr_fd); + if (IS_ERR(hdl)) { + dev_err(pservice->dev, "import dma-buf from fd %d failed, reg[%d]\n", usr_fd, tbl[i]); + return PTR_ERR(hdl); + } + + mem_region = kzalloc(sizeof(struct vcodec_mem_region), GFP_KERNEL); + + if (mem_region == NULL) { + dev_err(pservice->dev, "allocate memory for iommu memory region failed\n"); + ion_free(pservice->ion_client, hdl); + return -1; + } + + mem_region->hdl = hdl; + + ret = ion_map_iommu(pservice->dev, pservice->ion_client, mem_region->hdl, &mem_region->iova, &mem_region->len); + if (ret < 0) { + dev_err(pservice->dev, "ion map iommu failed\n"); + kfree(mem_region); + ion_free(pservice->ion_client, hdl); + return ret; + } + reg->reg[tbl[i]] = mem_region->iova + offset; + INIT_LIST_HEAD(&mem_region->reg_lnk); + list_add_tail(&mem_region->reg_lnk, ®->mem_region_list); + } + } + return 0; } static int vcodec_reg_address_translate(struct vpu_service_info *pservice, vpu_reg *reg) { - VPU_HW_ID hw_id; - u8 *tbl; - int size = 0; - - hw_id = pservice->hw_info->hw_id; - - if (hw_id == HEVC_ID) { - tbl = addr_tbl_hevc_dec; - size = sizeof(addr_tbl_hevc_dec); - } else { - if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) { - tbl = addr_tbl_vpu_dec; - size = sizeof(addr_tbl_vpu_dec); - } else if (reg->type == VPU_ENC) { - tbl = addr_tbl_vpu_enc; - size = sizeof(addr_tbl_vpu_enc); - } - } - - if (size != 0) { - return vcodec_bufid_to_iova(pservice, tbl, size, reg); - } else { - return -1; - } + VPU_HW_ID hw_id; + u8 *tbl; + int size = 0; + + hw_id = pservice->hw_info->hw_id; + + if (hw_id == HEVC_ID) { + tbl = addr_tbl_hevc_dec; + size = sizeof(addr_tbl_hevc_dec); + } else { + if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) { + switch (reg_check_fmt(reg)) { + case VPU_DEC_FMT_H264: + { + tbl = addr_tbl_vpu_h264dec; + size = sizeof(addr_tbl_vpu_h264dec); + break; + } + case VPU_DEC_FMT_VP8: + case VPU_DEC_FMT_VP7: + { + tbl = addr_tbl_vpu_vp8dec; + size = sizeof(addr_tbl_vpu_vp8dec); + break; + } + + case VPU_DEC_FMT_VP6: + { + tbl = addr_tbl_vpu_vp6dec; + size = sizeof(addr_tbl_vpu_vp6dec); + break; + } + case VPU_DEC_FMT_VC1: + { + tbl = addr_tbl_vpu_vc1dec; + size = sizeof(addr_tbl_vpu_vc1dec); + break; + } + + case VPU_DEC_FMT_JPEG: + { + tbl = addr_tbl_vpu_jpegdec; + size = sizeof(addr_tbl_vpu_jpegdec); + break; + } + default: + tbl = addr_tbl_vpu_defaultdec; + size = sizeof(addr_tbl_vpu_defaultdec); + break; + } + } else if (reg->type == VPU_ENC) { + tbl = addr_tbl_vpu_enc; + size = sizeof(addr_tbl_vpu_enc); + } + } + + if (size != 0) { + return vcodec_bufid_to_iova(pservice, tbl, size, reg); + } else { + return -1; + } } #endif @@ -736,8 +797,8 @@ static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session INIT_LIST_HEAD(®->status_link); #if defined(CONFIG_VCODEC_MMU) - INIT_LIST_HEAD(®->mem_region_list); -#endif + INIT_LIST_HEAD(®->mem_region_list); +#endif if (copy_from_user(®->reg[0], (void __user *)src, size)) { pr_err("error: copy_from_user failed in reg_init\n"); @@ -746,11 +807,11 @@ static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session } #if defined(CONFIG_VCODEC_MMU) - if (0 > vcodec_reg_address_translate(pservice, reg)) { - pr_err("error: translate reg address failed\n"); - kfree(reg); - return NULL; - } + if (0 > vcodec_reg_address_translate(pservice, reg)) { + pr_err("error: translate reg address failed\n"); + kfree(reg); + return NULL; + } #endif mutex_lock(&pservice->lock); @@ -763,12 +824,12 @@ static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) { if (reg_check_rmvb_wmv(reg)) { reg->freq = VPU_FREQ_200M; - } else if (reg_check_avc(reg)) { - if (reg_probe_width(reg) > 3200) { - // raise frequency for 4k avc. - reg->freq = VPU_FREQ_500M; - } - } else { + } else if (reg_check_fmt(reg) == VPU_DEC_FMT_H264) { + if (reg_probe_width(reg) > 3200) { + // raise frequency for 4k avc. + reg->freq = VPU_FREQ_500M; + } + } else { if (reg_check_interlace(reg)) { reg->freq = VPU_FREQ_400M; } @@ -785,31 +846,33 @@ static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session static void reg_deinit(struct vpu_service_info *pservice, vpu_reg *reg) { -#if defined(CONFIG_VCODEC_MMU) - struct vcodec_mem_region *mem_region = NULL, *n; +#if defined(CONFIG_VCODEC_MMU) + struct vcodec_mem_region *mem_region = NULL, *n; #endif - - list_del_init(®->session_link); - list_del_init(®->status_link); - if (reg == pservice->reg_codec) pservice->reg_codec = NULL; - if (reg == pservice->reg_pproc) pservice->reg_pproc = NULL; - + + list_del_init(®->session_link); + list_del_init(®->status_link); + if (reg == pservice->reg_codec) + pservice->reg_codec = NULL; + if (reg == pservice->reg_pproc) + pservice->reg_pproc = NULL; + #if defined(CONFIG_VCODEC_MMU) - // release memory region attach to this registers table. - list_for_each_entry_safe(mem_region, n, ®->mem_region_list, reg_lnk) { - ion_unmap_iommu(pservice->dev, pservice->ion_client, mem_region->hdl); - ion_free(pservice->ion_client, mem_region->hdl); - list_del_init(&mem_region->reg_lnk); - kfree(mem_region); - } -#endif - - kfree(reg); + // release memory region attach to this registers table. + list_for_each_entry_safe(mem_region, n, ®->mem_region_list, reg_lnk) { + ion_unmap_iommu(pservice->dev, pservice->ion_client, mem_region->hdl); + ion_free(pservice->ion_client, mem_region->hdl); + list_del_init(&mem_region->reg_lnk); + kfree(mem_region); + } +#endif + + kfree(reg); } static void reg_from_wait_to_run(struct vpu_service_info *pservice, vpu_reg *reg) { - list_del_init(®->status_link); + list_del_init(®->status_link); list_add_tail(®->status_link, &pservice->running); list_del_init(®->session_link); @@ -821,12 +884,12 @@ static void reg_copy_from_hw(vpu_reg *reg, volatile u32 *src, u32 count) int i; u32 *dst = (u32 *)®->reg[0]; for (i = 0; i < count; i++) - *dst++ = *src++; + *dst++ = *src++; } static void reg_from_run_to_done(struct vpu_service_info *pservice, vpu_reg *reg) { - int irq_reg = -1; + int irq_reg = -1; list_del_init(®->status_link); list_add_tail(®->status_link, &pservice->done); @@ -837,14 +900,14 @@ static void reg_from_run_to_done(struct vpu_service_info *pservice, vpu_reg *reg case VPU_ENC : { pservice->reg_codec = NULL; reg_copy_from_hw(reg, pservice->enc_dev.hwregs, pservice->hw_info->enc_reg_num); - irq_reg = ENC_INTERRUPT_REGISTER; + irq_reg = ENC_INTERRUPT_REGISTER; break; } case VPU_DEC : { - int reg_len = pservice->hw_info->hw_id == HEVC_ID ? REG_NUM_HEVC_DEC : REG_NUM_9190_DEC; + int reg_len = pservice->hw_info->hw_id == HEVC_ID ? REG_NUM_HEVC_DEC : REG_NUM_9190_DEC; pservice->reg_codec = NULL; reg_copy_from_hw(reg, pservice->dec_dev.hwregs, reg_len); - irq_reg = DEC_INTERRUPT_REGISTER; + irq_reg = DEC_INTERRUPT_REGISTER; break; } case VPU_PP : { @@ -866,9 +929,9 @@ static void reg_from_run_to_done(struct vpu_service_info *pservice, vpu_reg *reg } } - if (irq_reg != -1) { - reg->reg[irq_reg] = pservice->irq_status; - } + if (irq_reg != -1) { + reg->reg[irq_reg] = pservice->irq_status; + } atomic_sub(1, ®->session->task_running); atomic_sub(1, &pservice->total_running); @@ -899,12 +962,12 @@ static void vpu_service_set_freq(struct vpu_service_info *pservice, vpu_reg *reg clk_set_rate(pservice->aclk_vcodec, 400*MHZ); //printk("default: 400M\n"); } break; - case VPU_FREQ_500M : { - clk_set_rate(pservice->aclk_vcodec, 500*MHZ); - } break; - case VPU_FREQ_600M : { - clk_set_rate(pservice->aclk_vcodec, 600*MHZ); - } break; + case VPU_FREQ_500M : { + clk_set_rate(pservice->aclk_vcodec, 500*MHZ); + } break; + case VPU_FREQ_600M : { + clk_set_rate(pservice->aclk_vcodec, 600*MHZ); + } break; default : { if (soc_is_rk2928g()) { clk_set_rate(pservice->aclk_vcodec, 400*MHZ); @@ -932,18 +995,7 @@ static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg) case VPU_ENC : { int enc_count = pservice->hw_info->enc_reg_num; u32 *dst = (u32 *)pservice->enc_dev.hwregs; -#if 0 - if (pservice->bug_dec_addr) { -#if !defined(CONFIG_ARCH_RK319X) - cru_set_soft_reset(SOFT_RST_CPU_VCODEC, true); -#endif - cru_set_soft_reset(SOFT_RST_VCODEC_AHB, true); - cru_set_soft_reset(SOFT_RST_VCODEC_AHB, false); -#if !defined(CONFIG_ARCH_RK319X) - cru_set_soft_reset(SOFT_RST_CPU_VCODEC, false); -#endif - } -#endif + pservice->reg_codec = reg; dst[VPU_REG_EN_ENC] = src[VPU_REG_EN_ENC] & 0x6; @@ -969,13 +1021,13 @@ static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg) pservice->reg_codec = reg; - if (pservice->hw_info->hw_id != HEVC_ID) { + if (pservice->hw_info->hw_id != HEVC_ID) { for (i = REG_NUM_9190_DEC - 1; i > VPU_REG_DEC_GATE; i--) dst[i] = src[i]; - } else { - for (i = REG_NUM_HEVC_DEC - 1; i > VPU_REG_EN_DEC; i--) { + } else { + for (i = REG_NUM_HEVC_DEC - 1; i > VPU_REG_EN_DEC; i--) { dst[i] = src[i]; - } + } } dsb(); @@ -987,8 +1039,8 @@ static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg) dst[VPU_REG_EN_DEC] = src[VPU_REG_EN_DEC]; } - dsb(); - dmb(); + dsb(); + dmb(); #if VPU_SERVICE_SHOW_TIME do_gettimeofday(&dec_start); @@ -1042,9 +1094,9 @@ static void reg_copy_to_hw(struct vpu_service_info *pservice, vpu_reg *reg) } #if HEVC_SIM_ENABLE - if (pservice->hw_info->hw_id == HEVC_ID) { - simulate_start(pservice); - } + if (pservice->hw_info->hw_id == HEVC_ID) { + simulate_start(pservice); + } #endif } @@ -1107,7 +1159,7 @@ static int return_reg(struct vpu_service_info *pservice, vpu_reg *reg, u32 __use break; } case VPU_DEC : { - int reg_len = pservice->hw_info->hw_id == HEVC_ID ? REG_NUM_HEVC_DEC : REG_NUM_9190_DEC; + int reg_len = pservice->hw_info->hw_id == HEVC_ID ? REG_NUM_HEVC_DEC : REG_NUM_9190_DEC; if (copy_to_user(dst, ®->reg[0], SIZE_REG(reg_len))) ret = -EFAULT; break; @@ -1255,16 +1307,16 @@ static int vpu_service_check_hw(vpu_service_info *p, unsigned long hw_addr) u32 enc_id = *tmp; #if HEVC_SIM_ENABLE - /// temporary, hevc driver test. - if (strncmp(dev_name(p->dev), "hevc_service", strlen("hevc_service")) == 0) { - p->hw_info = &vpu_hw_set[2]; - return 0; - } + /// temporary, hevc driver test. + if (strncmp(dev_name(p->dev), "hevc_service", strlen("hevc_service")) == 0) { + p->hw_info = &vpu_hw_set[2]; + return 0; + } #endif enc_id = (enc_id >> 16) & 0xFFFF; pr_info("checking hw id %x\n", enc_id); - p->hw_info = NULL; + p->hw_info = NULL; for (i = 0; i < ARRAY_SIZE(vpu_hw_set); i++) { if (enc_id == vpu_hw_set[i].hw_id) { p->hw_info = &vpu_hw_set[i]; @@ -1278,7 +1330,7 @@ static int vpu_service_check_hw(vpu_service_info *p, unsigned long hw_addr) static int vpu_service_open(struct inode *inode, struct file *filp) { - struct vpu_service_info *pservice = container_of(inode->i_cdev, struct vpu_service_info, cdev); + struct vpu_service_info *pservice = container_of(inode->i_cdev, struct vpu_service_info, cdev); vpu_session *session = (vpu_session *)kmalloc(sizeof(vpu_session), GFP_KERNEL); if (NULL == session) { pr_err("error: unable to allocate memory for vpu_session."); @@ -1304,7 +1356,7 @@ static int vpu_service_open(struct inode *inode, struct file *filp) static int vpu_service_release(struct inode *inode, struct file *filp) { - struct vpu_service_info *pservice = container_of(inode->i_cdev, struct vpu_service_info, cdev); + struct vpu_service_info *pservice = container_of(inode->i_cdev, struct vpu_service_info, cdev); int task_running; vpu_session *session = (vpu_session *)filp->private_data; if (NULL == session) @@ -1325,7 +1377,7 @@ static int vpu_service_release(struct inode *inode, struct file *filp) filp->private_data = NULL; mutex_unlock(&pservice->lock); - pr_debug("dev closed\n"); + pr_debug("dev closed\n"); return 0; } @@ -1373,7 +1425,7 @@ static void simulate_start(struct vpu_service_info *pservice) #if HEVC_TEST_ENABLE static int hevc_test_case0(vpu_service_info *pservice); #endif -#if defined(CONFIG_VCODEC_MMU) & defined(CONFIG_ION_ROCKCHIP) +#if defined(CONFIG_ION_ROCKCHIP) extern struct ion_client *rockchip_ion_client_create(const char * name); #endif static int vcodec_probe(struct platform_device *pdev) @@ -1536,7 +1588,7 @@ static int vcodec_probe(struct platform_device *pdev) &debug_vcodec_fops); #endif -#if defined(CONFIG_VCODEC_MMU) & defined(CONFIG_ION_ROCKCHIP) +#if defined(CONFIG_VCODEC_MMU) pservice->ion_client = rockchip_ion_client_create("vpu"); if (IS_ERR(pservice->ion_client)) { dev_err(&pdev->dev, "failed to create ion client for vcodec"); -- 2.34.1