static MFC_ERROR_CODE s3c_mfc_set_dec_frame_buffer(s3c_mfc_inst_ctx *MfcCtx, int buf_addr, unsigned int buf_size) { unsigned int Width, Height, FrameSize, dec_dpb_addr; mfc_debug("buf_addr : 0x%08x buf_size : %d\n", buf_addr, buf_size); Width = (MfcCtx->img_width + 15)/16*16; Height = (MfcCtx->img_height + 31)/32*32; FrameSize = (Width*Height*3)>>1; mfc_debug("width : %d height : %d framesize : %d buf_size : %d MfcCtx->DPBCnt :%d\n", \ Width, Height, FrameSize, buf_size, MfcCtx->DPBCnt); if(buf_size < FrameSize*MfcCtx->totalDPBCnt){ mfc_err("MFCINST_ERR_FRM_BUF_SIZE\n"); return MFCINST_ERR_FRM_BUF_SIZE; } WRITEL(Align(buf_addr, BUF_ALIGN_UNIT), S3C_FIMV_DEC_DPB_ADR); dec_dpb_addr = READL(S3C_FIMV_DEC_DPB_ADR); WRITEL(Align(dec_dpb_addr + FrameSize*MfcCtx->DPBCnt, BUF_ALIGN_UNIT), S3C_FIMV_DPB_COMV_ADR); if((MfcCtx->MfcCodecType == MPEG4_DEC) ||(MfcCtx->MfcCodecType == MPEG2_DEC) ||(MfcCtx->MfcCodecType == XVID_DEC) ||(MfcCtx->MfcCodecType == DIVX_DEC) ) { dec_dpb_addr = READL(S3C_FIMV_DEC_DPB_ADR); WRITEL(Align(dec_dpb_addr + ((3*FrameSize*MfcCtx->DPBCnt)>>1), BUF_ALIGN_UNIT), S3C_FIMV_POST_ADR); }
static int mfc_mmap(struct file *filp, struct vm_area_struct *vma) { unsigned long vir_size = vma->vm_end - vma->vm_start; unsigned long phy_size, firmware_size; unsigned long page_frame_no = 0; struct mfc_inst_ctx *mfc_ctx; mfc_debug("vma->vm_start = 0x%08x, vma->vm_end = 0x%08x\n", (unsigned int)vma->vm_start, (unsigned int)vma->vm_end); mfc_debug("vma->vm_end - vma->vm_start = %ld\n", vir_size); mfc_ctx = (struct mfc_inst_ctx *)filp->private_data; firmware_size = mfc_get_port0_buff_paddr() - mfc_get_fw_buff_paddr(); phy_size = (unsigned long)(mfc_port0_memsize - firmware_size + mfc_port1_memsize); /* if memory size required from appl. mmap() is bigger than max data memory * size allocated in the driver */ if (vir_size > phy_size) { mfc_err("virtual requested mem(%ld) is bigger than physical mem(%ld)\n", vir_size, phy_size); return -EINVAL; } #ifdef CONFIG_MACH_ARIES mfc_ctx->port0_mmap_size = mfc_port0_memsize - firmware_size; #else // CONFIG_MACH_P1 mfc_ctx->port0_mmap_size = (vir_size / 2); #endif vma->vm_flags |= VM_RESERVED | VM_IO; if (mfc_ctx->buf_type != MFC_BUFFER_CACHE) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* * port0 mapping for stream buf & frame buf (chroma + MV) */ page_frame_no = __phys_to_pfn(mfc_get_port0_buff_paddr()); if (remap_pfn_range(vma, vma->vm_start, page_frame_no, mfc_ctx->port0_mmap_size, vma->vm_page_prot)) { mfc_err("mfc remap port0 error\n"); return -EAGAIN; } vma->vm_flags |= VM_RESERVED | VM_IO; if (mfc_ctx->buf_type != MFC_BUFFER_CACHE) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* * port1 mapping for frame buf (luma) */ page_frame_no = __phys_to_pfn(mfc_get_port1_buff_paddr()); if (remap_pfn_range(vma, vma->vm_start + mfc_ctx->port0_mmap_size, page_frame_no, vir_size - mfc_ctx->port0_mmap_size, vma->vm_page_prot)) { mfc_err("mfc remap port1 error\n"); return -EAGAIN; } mfc_debug("virtual requested mem = %ld, physical reserved data mem = %ld\n", vir_size, phy_size); return 0; }
/* Remove Fragmentation in FreeMemList */ void s3c_mfc_merge_frag(int inst_no) { s3c_mfc_free_mem_t *node1, *node2; node1 = s3c_mfc_free_mem_head; while (node1 != s3c_mfc_free_mem_tail) { node2 = s3c_mfc_free_mem_head; while (node2 != s3c_mfc_free_mem_tail) { if ((node1->start_addr + node1->size == node2->start_addr) && (node1->cache_flag == node2->cache_flag)) { node1->size += node2->size; mfc_debug("find merge area !! ( node1->start_addr + node1->size == node2->start_addr)\n"); s3c_mfc_del_node_from_free_list(node2, inst_no); break; } else if((node1->start_addr == node2->start_addr + node2->size) && (node1->cache_flag == node2->cache_flag) ) { mfc_debug("find merge area !! ( node1->start_addr == node2->start_addr + node2->size)\n"); node1->start_addr = node2->start_addr; node1->size += node2->size; s3c_mfc_del_node_from_free_list(node2, inst_no); break; } node2 = node2->next; } node1 = node1->next; } }
int s5p_mfc_clock_on(struct s5p_mfc_dev *dev) { int ret = 0; int state, val; unsigned long flags; dev->pm.clock_on_steps = 1; MFC_TRACE_DEV("++ clock_on: Set clock rate(%d)\n", dev->curr_rate); ret = clk_enable(dev->pm.clock); if (ret < 0) return ret; if (dev->pm.base_type != MFCBUF_INVALID) s5p_mfc_init_memctrl(dev, dev->pm.base_type); dev->pm.clock_on_steps |= 0x1 << 1; if (dev->curr_ctx_drm && dev->is_support_smc) { spin_lock_irqsave(&dev->pm.clklock, flags); mfc_debug(3, "Begin: enable protection\n"); ret = exynos_smc(SMC_PROTECTION_SET, 0, dev->id, SMC_PROTECTION_ENABLE); dev->pm.clock_on_steps |= 0x1 << 2; if (!ret) { printk("Protection Enable failed! ret(%u)\n", ret); spin_unlock_irqrestore(&dev->pm.clklock, flags); clk_disable(dev->pm.clock); return -EACCES; } mfc_debug(3, "End: enable protection\n"); spin_unlock_irqrestore(&dev->pm.clklock, flags); } else { ret = s5p_mfc_mem_resume(dev->alloc_ctx[0]); if (ret < 0) { dev->pm.clock_on_steps |= 0x1 << 3; clk_disable(dev->pm.clock); return ret; } } dev->pm.clock_on_steps |= 0x1 << 4; if (IS_MFCV6(dev)) { spin_lock_irqsave(&dev->pm.clklock, flags); if ((atomic_inc_return(&dev->clk_ref) == 1) && FW_HAS_BUS_RESET(dev)) { val = s5p_mfc_read_reg(dev, S5P_FIMV_MFC_BUS_RESET_CTRL); val &= ~(0x1); s5p_mfc_write_reg(dev, val, S5P_FIMV_MFC_BUS_RESET_CTRL); } spin_unlock_irqrestore(&dev->pm.clklock, flags); } else { atomic_inc_return(&dev->clk_ref); } dev->pm.clock_on_steps |= 0x1 << 5; state = atomic_read(&dev->clk_ref); mfc_debug(2, "+ %d\n", state); MFC_TRACE_DEV("-- clock_on : ref state(%d)\n", state); return 0; }
void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev, enum mfc_buf_usage_type buf_type) { struct s5p_mfc_extra_buf *fw_info; fw_info = &dev->fw_info; if (IS_MFCV6(dev)) { #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION if (buf_type == MFCBUF_DRM) fw_info = &dev->drm_fw_info; s5p_mfc_write_reg(dev, fw_info->ofs, S5P_FIMV_RISC_BASE_ADDRESS); mfc_info_dev("[%d] Base Address : %08lx\n", buf_type, fw_info->ofs); #else s5p_mfc_write_reg(dev, dev->port_a, S5P_FIMV_RISC_BASE_ADDRESS); mfc_debug(2, "Base Address : %08zu\n", dev->port_a); #endif } else { /* channelA, port0 */ s5p_mfc_write_reg(dev, dev->port_a, S5P_FIMV_MC_DRAMBASE_ADR_A); /* channelB, port1 */ s5p_mfc_write_reg(dev, dev->port_b, S5P_FIMV_MC_DRAMBASE_ADR_B); mfc_debug(2, "Port A: %08zu, Port B: %08zu\n", dev->port_a, dev->port_b); } }
int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) { int ret; mfc_debug_enter(); /* 0. MFC reset */ mfc_debug(2, "MFC reset...\n"); s5p_mfc_clock_on(); ret = s5p_mfc_reset(dev); if (ret) { mfc_err("Failed to reset MFC - timeout.\n"); return ret; } mfc_debug(2, "Done MFC reset...\n"); /* 1. Set DRAM base Addr */ s5p_mfc_init_memctrl(dev); /* 2. Initialize registers of channel I/F */ s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); /* 3. Initialize firmware */ ret = s5p_mfc_wakeup_cmd(dev); if (ret) { mfc_err("Failed to send command to MFC - timeout.\n"); return ret; } /* 4. Release reset signal to the RISC */ if (IS_MFCV6(dev)) s5p_mfc_write_reg(0x1, S5P_FIMV_RISC_ON); else s5p_mfc_write_reg(0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) { mfc_err("Failed to load firmware\n"); return -EIO; } s5p_mfc_clock_off(); dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_FIMV_R2H_CMD_WAKEUP_RET) { /* Failure. */ mfc_err("Failed to wakeup - error: %d" " int: %d.\n",dev->int_err, dev->int_type); return -EIO; } mfc_debug_leave(); return 0; }
static unsigned int s3c_mfc_get_mem_area(int allocSize, int inst_no, char cache_flag) { s3c_mfc_free_mem_t *node, *match_node = NULL; unsigned int allocAddr = 0; mfc_debug("request Size : %ld\n", allocSize); if (s3c_mfc_free_mem_head == s3c_mfc_free_mem_tail) { mfc_err("all memory is gone\n"); return(allocAddr); } /* find best chunk of memory */ for (node = s3c_mfc_free_mem_head; node != s3c_mfc_free_mem_tail; node = node->next) { if (match_node != NULL) { if (cache_flag) { if ((node->size >= allocSize) && (node->size < match_node->size) && (node->cache_flag)) match_node = node; } else { if ((node->size >= allocSize) && (node->size < match_node->size) && (!node->cache_flag)) match_node = node; } } else { if (cache_flag) { if ((node->size >= allocSize) && (node->cache_flag)) match_node = node; } else { if ((node->size >= allocSize) && (!node->cache_flag)) match_node = node; } } } if (match_node != NULL) { mfc_debug("match : startAddr(0x%08x) size(%ld) cache flag(%d)\n", match_node->start_addr, match_node->size, match_node->cache_flag); } /* rearange FreeMemArea */ if (match_node != NULL) { allocAddr = match_node->start_addr; match_node->start_addr += allocSize; match_node->size -= allocSize; if(match_node->size == 0) /* delete match_node. */ s3c_mfc_del_node_from_free_list(match_node, inst_no); return(allocAddr); } else { printk("there is no suitable chunk\n"); return 0; } return(allocAddr); }
int s5p_mfc_clock_on(struct s5p_mfc_dev *dev) { int ret = 0; int state, val; unsigned long flags; #ifdef CONFIG_MFC_USE_BUS_DEVFREQ MFC_TRACE_DEV("++ clock_on: Set clock rate(%d)\n", dev->curr_rate); mutex_lock(&dev->curr_rate_lock); s5p_mfc_clock_set_rate(dev, dev->curr_rate); mutex_unlock(&dev->curr_rate_lock); #endif ret = clk_enable(dev->pm.clock); if (ret < 0) return ret; if (dev->curr_ctx_drm && dev->is_support_smc) { spin_lock_irqsave(&dev->pm.clklock, flags); mfc_debug(3, "Begin: enable protection\n"); ret = exynos_smc(SMC_PROTECTION_SET, 0, dev->id, SMC_PROTECTION_ENABLE); if (!ret) { printk("Protection Enable failed! ret(%u)\n", ret); spin_unlock_irqrestore(&dev->pm.clklock, flags); clk_disable(dev->pm.clock); return ret; } mfc_debug(3, "End: enable protection\n"); spin_unlock_irqrestore(&dev->pm.clklock, flags); } else { ret = s5p_mfc_mem_resume(dev->alloc_ctx[0]); if (ret < 0) { clk_disable(dev->pm.clock); return ret; } } if (IS_MFCV6(dev)) { spin_lock_irqsave(&dev->pm.clklock, flags); if ((atomic_inc_return(&dev->clk_ref) == 1) && FW_HAS_BUS_RESET(dev)) { val = s5p_mfc_read_reg(dev, S5P_FIMV_MFC_BUS_RESET_CTRL); val &= ~(0x1); s5p_mfc_write_reg(dev, val, S5P_FIMV_MFC_BUS_RESET_CTRL); } spin_unlock_irqrestore(&dev->pm.clklock, flags); } else { atomic_inc_return(&dev->clk_ref); } state = atomic_read(&dev->clk_ref); mfc_debug(2, "+ %d\n", state); MFC_TRACE_DEV("-- clock_on : ref state(%d)\n", state); return 0; }
void s5p_mfc_clock_off(struct s5p_mfc_dev *dev) { int state, val; unsigned long timeout, flags; int ret = 0; if (IS_MFCV6(dev)) { spin_lock_irqsave(&dev->pm.clklock, flags); if ((atomic_dec_return(&dev->clk_ref) == 0) && FW_HAS_BUS_RESET(dev)) { s5p_mfc_write_reg(dev, 0x1, S5P_FIMV_MFC_BUS_RESET_CTRL); timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); /* Check bus status */ do { if (time_after(jiffies, timeout)) { mfc_err_dev("Timeout while resetting MFC.\n"); break; } val = s5p_mfc_read_reg(dev, S5P_FIMV_MFC_BUS_RESET_CTRL); } while ((val & 0x2) == 0); } spin_unlock_irqrestore(&dev->pm.clklock, flags); } else { atomic_dec_return(&dev->clk_ref); } state = atomic_read(&dev->clk_ref); if (state < 0) { mfc_err_dev("Clock state is wrong(%d)\n", state); atomic_set(&dev->clk_ref, 0); } else { if (dev->curr_ctx_drm && dev->is_support_smc) { mfc_debug(3, "Begin: disable protection\n"); spin_lock_irqsave(&dev->pm.clklock, flags); ret = exynos_smc(SMC_PROTECTION_SET, 0, dev->id, SMC_PROTECTION_DISABLE); if (!ret) { printk("Protection Disable failed! ret(%u)\n", ret); spin_unlock_irqrestore(&dev->pm.clklock, flags); clk_disable(dev->pm.clock); return; } mfc_debug(3, "End: disable protection\n"); spin_unlock_irqrestore(&dev->pm.clklock, flags); } else { s5p_mfc_mem_suspend(dev->alloc_ctx[0]); } clk_disable(dev->pm.clock); } mfc_debug(2, "- %d\n", state); }
static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, struct v4l2_requestbuffers *reqbufs) { int ret = 0; s5p_mfc_clock_on(); if (reqbufs->count == 0) { mfc_debug(2, "Freeing buffers\n"); ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); if (ret) goto out; s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx); ctx->dst_bufs_cnt = 0; } else if (ctx->capture_state == QUEUE_FREE) { WARN_ON(ctx->dst_bufs_cnt != 0); mfc_debug(2, "Allocating %d buffers for CAPTURE queue\n", reqbufs->count); ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); if (ret) goto out; ctx->capture_state = QUEUE_BUFS_REQUESTED; ctx->total_dpb_count = reqbufs->count; ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_codec_buffers, ctx); if (ret) { mfc_err("Failed to allocate decoding buffers\n"); reqbufs->count = 0; vb2_reqbufs(&ctx->vq_dst, reqbufs); ret = -ENOMEM; ctx->capture_state = QUEUE_FREE; goto out; } WARN_ON(ctx->dst_bufs_cnt != ctx->total_dpb_count); ctx->capture_state = QUEUE_BUFS_MMAPED; if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET, 0); } else { mfc_err("Buffers have already been requested\n"); ret = -EINVAL; } out: s5p_mfc_clock_off(); if (ret) mfc_err("Failed allocating buffers for CAPTURE queue\n"); return ret; }
static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) { if (IS_MFCV6_PLUS(dev)) { mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6); mfc_debug(2, "Base Address : %pad\n", &dev->bank1); } else { mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); mfc_debug(2, "Bank1: %pad, Bank2: %pad\n", &dev->bank1, &dev->bank2); } }
static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dec *dec = ctx->dec_priv; struct s5p_mfc_buf *dst_buf; int index, is_first = 1; mfc_debug(2, "Decided to finish\n"); ctx->sequence++; while (!list_empty(&ctx->dst_queue)) { dst_buf = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); mfc_debug(2, "Cleaning up buffer: %d\n", dst_buf->vb.v4l2_buf.index); vb2_set_plane_payload(&dst_buf->vb, 0, 0); vb2_set_plane_payload(&dst_buf->vb, 1, 0); list_del(&dst_buf->list); ctx->dst_queue_cnt--; dst_buf->vb.v4l2_buf.sequence = (ctx->sequence++); if (s5p_mfc_read_info(ctx, PIC_TIME_TOP) == s5p_mfc_read_info(ctx, PIC_TIME_BOT)) dst_buf->vb.v4l2_buf.field = V4L2_FIELD_NONE; else dst_buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; clear_bit(dst_buf->vb.v4l2_buf.index, &dec->dpb_status); index = dst_buf->vb.v4l2_buf.index; if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0) mfc_err("failed in get_buf_ctrls_val\n"); if (is_first) { call_cop(ctx, get_buf_update_val, ctx, &ctx->dst_ctrls[index], V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG, dec->eos_tag); is_first = 0; } else { call_cop(ctx, get_buf_update_val, ctx, &ctx->dst_ctrls[index], V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG, DEFAULT_TAG); } vb2_buffer_done(&dst_buf->vb, VB2_BUF_STATE_DONE); mfc_debug(2, "Cleaned up buffer: %d\n", dst_buf->vb.v4l2_buf.index); } if (ctx->state != MFCINST_ABORT && ctx->state != MFCINST_RES_CHANGE_FLUSH) ctx->state = MFCINST_RUNNING; mfc_debug(2, "After cleanup\n"); }
/* Load firmware to MFC */ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) { struct firmware *fw_blob; unsigned int firmware_size; int err; if (!dev) { mfc_err("no mfc device to run\n"); return -EINVAL; } firmware_size = dev->variant->buf_size->firmware_code; /* Firmare has to be present as a separate file or compiled * into kernel. */ mfc_debug_enter(); mfc_debug(2, "Requesting fw\n"); err = request_firmware((const struct firmware **)&fw_blob, MFC_FW_NAME, dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel.\n"); return -EINVAL; } mfc_debug(2, "Ret of request_firmware: %d Size: %d\n", err, fw_blob->size); if (fw_blob->size > firmware_size) { mfc_err("MFC firmware is too big to be loaded.\n"); release_firmware(fw_blob); return -ENOMEM; } if (s5p_mfc_bitproc_buf == 0 || s5p_mfc_bitproc_phys == 0) { mfc_err("MFC firmware is not allocated or was not mapped correctly.\n"); release_firmware(fw_blob); return -EINVAL; } memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); /* s5p_mfc_bitproc_dma = dma_map_single(dev->v4l2_dev.dev, s5p_mfc_bitproc_virt, FIRMWARE_CODE_SIZE, DMA_TO_DEVICE); */ s5p_mfc_mem_clean_priv(s5p_mfc_bitproc_buf, s5p_mfc_bitproc_virt, 0, fw_blob->size); release_firmware(fw_blob); mfc_debug_leave(); return 0; }
static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) { if (IS_MFCV6(dev)) { s5p_mfc_write_reg(dev->port_a, S5P_FIMV_RISC_BASE_ADDRESS); mfc_debug(2, "Base Address : %08x\n", dev->port_a); } else { /* channelA, port0 */ s5p_mfc_write_reg(dev->port_a, S5P_FIMV_MC_DRAMBASE_ADR_A); /* channelB, port1 */ s5p_mfc_write_reg(dev->port_b, S5P_FIMV_MC_DRAMBASE_ADR_B); mfc_debug(2, "Port A: %08x, Port B: %08x\n", dev->port_a, dev->port_b); } }
static int reqbufs_output(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, struct v4l2_requestbuffers *reqbufs) { int ret = 0; s5p_mfc_clock_on(); if (reqbufs->count == 0) { mfc_debug(2, "Freeing buffers\n"); ret = vb2_reqbufs(&ctx->vq_src, reqbufs); if (ret) goto out; s5p_mfc_close_mfc_inst(dev, ctx); ctx->src_bufs_cnt = 0; ctx->output_state = QUEUE_FREE; } else if (ctx->output_state == QUEUE_FREE) { /* Can only request buffers when we have a valid format set. */ WARN_ON(ctx->src_bufs_cnt != 0); if (ctx->state != MFCINST_INIT) { mfc_err("Reqbufs called in an invalid state\n"); ret = -EINVAL; goto out; } mfc_debug(2, "Allocating %d buffers for OUTPUT queue\n", reqbufs->count); ret = vb2_reqbufs(&ctx->vq_src, reqbufs); if (ret) goto out; ret = s5p_mfc_open_mfc_inst(dev, ctx); if (ret) { reqbufs->count = 0; vb2_reqbufs(&ctx->vq_src, reqbufs); goto out; } ctx->output_state = QUEUE_BUFS_REQUESTED; } else { mfc_err("Buffers have already been requested\n"); ret = -EINVAL; } out: s5p_mfc_clock_off(); if (ret) mfc_err("Failed allocating buffers for OUTPUT queue\n"); return ret; }
/* Open a new instance and get its number */ int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_cmd_args h2r_args; unsigned int crc = 0; struct s5p_mfc_dec *dec = ctx->dec_priv; int ret; mfc_debug_enter(); mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode); if (ctx->type == MFCINST_DECODER) crc = dec->crc_enable; memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); h2r_args.arg[0] = ctx->codec_mode; h2r_args.arg[1] = crc << 31; /* no pixelcache */ h2r_args.arg[2] = ctx->ctx.ofs; h2r_args.arg[3] = ctx->ctx_buf_size; ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_OPEN_INSTANCE, &h2r_args); mfc_debug_leave(); return ret; }
/* Try format */ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_fmt *fmt; mfc_debug(2, "Type is %d\n", f->type); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { fmt = find_format(f, MFC_FMT_DEC); if (!fmt) { mfc_err("Unsupported format for source.\n"); return -EINVAL; } if (fmt->codec_mode == S5P_FIMV_CODEC_NONE) { mfc_err("Unknown codec\n"); return -EINVAL; } if ((dev->variant->version_bit & fmt->versions) == 0) { mfc_err("Unsupported format by this MFC version.\n"); return -EINVAL; } } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { fmt = find_format(f, MFC_FMT_RAW); if (!fmt) { mfc_err("Unsupported format for destination.\n"); return -EINVAL; } if ((dev->variant->version_bit & fmt->versions) == 0) { mfc_err("Unsupported format by this MFC version.\n"); return -EINVAL; } } return 0; }
static int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_cmd_args h2r_args; int ret; if (ctx->state == MFCINST_FREE) { mfc_err("Instance already returned\n"); ctx->state = MFCINST_ERROR; return -EINVAL; } /* Closing decoding instance */ mfc_debug(2, "Returning instance number %d\n", ctx->inst_no); dev->curr_ctx = ctx->num; memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); h2r_args.arg[0] = ctx->inst_no; ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, &h2r_args); if (ret) { mfc_err("Failed to return an instance\n"); ctx->state = MFCINST_ERROR; return -EINVAL; } return 0; }
int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->buf; void *shm_alloc_ctx = dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX]; ctx->shm.alloc = s5p_mfc_mem_alloc(shm_alloc_ctx, buf_size->shared_buf); if (IS_ERR(ctx->shm.alloc)) { mfc_err("failed to allocate shared memory\n"); return PTR_ERR(ctx->shm.alloc); } /* shm_ofs only keeps the offset from base (port a) */ ctx->shm.ofs = s5p_mfc_mem_daddr(ctx->shm.alloc) - dev->port_a; ctx->shm.virt = s5p_mfc_mem_vaddr(ctx->shm.alloc); if (!ctx->shm.virt) { s5p_mfc_mem_free(ctx->shm.alloc); ctx->shm.ofs = 0; ctx->shm.alloc = NULL; mfc_err("failed to virt addr of shared memory\n"); return -ENOMEM; } memset((void *)ctx->shm.virt, 0, buf_size->shared_buf); s5p_mfc_cache_clean_priv(ctx->shm.alloc); mfc_debug(2, "shm info addr: 0x%08x, phys: 0x%08lx\n", (unsigned int)ctx->shm.virt, ctx->shm.ofs); return 0; }
int s5p_mfc_alloc_priv_buf(struct device *dev, struct s5p_mfc_priv_buf *b) { mfc_debug(3, "Allocating priv: %d\n", b->size); b->virt = dma_alloc_coherent(dev, b->size, &b->dma, GFP_KERNEL); if (!b->virt) { mfc_err("Allocating private buffer failed\n"); return -ENOMEM; } mfc_debug(3, "Allocated addr %p %08x\n", b->virt, b->dma); return 0; }
/* Open a new instance and get its number */ int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev; int ret; mfc_debug_enter(); if (!ctx) { mfc_err("no mfc context to run\n"); return -EINVAL; } dev = ctx->dev; mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode); s5p_mfc_write_reg(dev, ctx->codec_mode, S5P_FIMV_CODEC_TYPE); s5p_mfc_write_reg(dev, ctx->ctx.ofs, S5P_FIMV_CONTEXT_MEM_ADDR); s5p_mfc_write_reg(dev, ctx->ctx_buf_size, S5P_FIMV_CONTEXT_MEM_SIZE); if (ctx->type == MFCINST_DECODER) s5p_mfc_write_reg(dev, ctx->dec_priv->crc_enable, S5P_FIMV_D_CRC_CTRL); ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, NULL); mfc_debug_leave(); return ret; }
static int s5p_mfc_v8_wait_wakeup(struct s5p_mfc_dev *dev) { int ret; /* Release reset signal to the RISC */ dev->risc_on = 1; mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { mfc_err("Failed to reset MFCV8\n"); return -EIO; } mfc_debug(2, "Write command to wakeup MFCV8\n"); ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev); if (ret) { mfc_err("Failed to send command to MFCV8 - timeout\n"); return ret; } if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { mfc_err("Failed to wakeup MFC\n"); return -EIO; } return ret; }
/* Try format */ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_fmt *fmt; mfc_debug(2, "Type is %d\n", f->type); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { fmt = find_format(f, MFC_FMT_DEC); if (!fmt) { mfc_err("Unsupported format for source.\n"); return -EINVAL; } if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { mfc_err("Not supported format.\n"); return -EINVAL; } } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { fmt = find_format(f, MFC_FMT_RAW); if (!fmt) { mfc_err("Unsupported format for destination.\n"); return -EINVAL; } if (IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { mfc_err("Not supported format.\n"); return -EINVAL; } else if (!IS_MFCV6(dev) && (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) { mfc_err("Not supported format.\n"); return -EINVAL; } } return 0; }
/* Get cropping information */ static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *cr) { struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); struct s5p_mfc_dev *dev = ctx->dev; u32 left, right, top, bottom; if (ctx->state != MFCINST_HEAD_PARSED && ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING && ctx->state != MFCINST_FINISHED) { mfc_err("Cannont set crop\n"); return -EINVAL; } if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { left = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_h, ctx); right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK; top = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_v, ctx); bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT; top = top & S5P_FIMV_SHARED_CROP_TOP_MASK; cr->c.left = left; cr->c.top = top; cr->c.width = ctx->img_width - left - right; cr->c.height = ctx->img_height - top - bottom; mfc_debug(2, "Cropping info [h264]: l=%d t=%d " "w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top, cr->c.width, cr->c.height, right, bottom, ctx->buf_width, ctx->buf_height); } else {
int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, int command, int interrupt) { int ret; if (interrupt) { ret = wait_event_interruptible_timeout(ctx->queue, (ctx->int_cond && (ctx->int_type == command || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), msecs_to_jiffies(MFC_INT_TIMEOUT)); } else { ret = wait_event_timeout(ctx->queue, (ctx->int_cond && (ctx->int_type == command || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), msecs_to_jiffies(MFC_INT_TIMEOUT)); } if (ret == 0) { mfc_err("Interrupt (ctx->int_type:%d, command:%d) timed out\n", ctx->int_type, command); return 1; } else if (ret == -ERESTARTSYS) { mfc_err("Interrupted by a signal\n"); return 1; } mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n", ctx->int_type, command); if (ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET) return 1; return 0; }
/* Query buffer */ static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret; int i; if (buf->memory != V4L2_MEMORY_MMAP) { mfc_err("Only mmaped buffers can be used\n"); return -EINVAL; } mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type); if (ctx->state == MFCINST_INIT && buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ret = vb2_querybuf(&ctx->vq_src, buf); } else if (ctx->state == MFCINST_RUNNING && buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ret = vb2_querybuf(&ctx->vq_dst, buf); for (i = 0; i < buf->length; i++) buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE; } else { mfc_err("vidioc_querybuf called in an inappropriate state\n"); ret = -EINVAL; } mfc_debug_leave(); return ret; }
/* Check whether a context should be run on hardware */ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) { /* Context is to parse header */ if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST) return 1; /* Context is to decode a frame */ if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_RUNNING && ctx->dst_queue_cnt >= ctx->dpb_count) return 1; /* Context is to return last frame */ if (ctx->state == MFCINST_FINISHING && ctx->dst_queue_cnt >= ctx->dpb_count) return 1; /* Context is to set buffers */ if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_HEAD_PARSED && ctx->capture_state == QUEUE_BUFS_MMAPED) return 1; /* Resolution change */ if ((ctx->state == MFCINST_RES_CHANGE_INIT || ctx->state == MFCINST_RES_CHANGE_FLUSH) && ctx->dst_queue_cnt >= ctx->dpb_count) return 1; if (ctx->state == MFCINST_RES_CHANGE_END && ctx->src_queue_cnt >= 1) return 1; mfc_debug(2, "ctx is not ready\n"); return 0; }
/* Open a new instance and get its number */ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_cmd_args h2r_args; int codec_type; mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode); dev->curr_ctx = ctx->num; switch (ctx->codec_mode) { case S5P_MFC_CODEC_H264_DEC: codec_type = S5P_FIMV_CODEC_H264_DEC_V6; break; case S5P_MFC_CODEC_H264_MVC_DEC: codec_type = S5P_FIMV_CODEC_H264_MVC_DEC_V6; break; case S5P_MFC_CODEC_VC1_DEC: codec_type = S5P_FIMV_CODEC_VC1_DEC_V6; break; case S5P_MFC_CODEC_MPEG4_DEC: codec_type = S5P_FIMV_CODEC_MPEG4_DEC_V6; break; case S5P_MFC_CODEC_MPEG2_DEC: codec_type = S5P_FIMV_CODEC_MPEG2_DEC_V6; break; case S5P_MFC_CODEC_H263_DEC: codec_type = S5P_FIMV_CODEC_H263_DEC_V6; break; case S5P_MFC_CODEC_VC1RCV_DEC: codec_type = S5P_FIMV_CODEC_VC1RCV_DEC_V6; break; case S5P_MFC_CODEC_VP8_DEC: codec_type = S5P_FIMV_CODEC_VP8_DEC_V6; break; case S5P_MFC_CODEC_H264_ENC: codec_type = S5P_FIMV_CODEC_H264_ENC_V6; break; case S5P_MFC_CODEC_H264_MVC_ENC: codec_type = S5P_FIMV_CODEC_H264_MVC_ENC_V6; break; case S5P_MFC_CODEC_MPEG4_ENC: codec_type = S5P_FIMV_CODEC_MPEG4_ENC_V6; break; case S5P_MFC_CODEC_H263_ENC: codec_type = S5P_FIMV_CODEC_H263_ENC_V6; break; case S5P_MFC_CODEC_VP8_ENC: codec_type = S5P_FIMV_CODEC_VP8_ENC_V7; break; default: codec_type = S5P_FIMV_CODEC_NONE_V6; }; mfc_write(dev, codec_type, S5P_FIMV_CODEC_TYPE_V6); mfc_write(dev, ctx->ctx.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); mfc_write(dev, ctx->ctx.size, S5P_FIMV_CONTEXT_MEM_SIZE_V6); mfc_write(dev, 0, S5P_FIMV_D_CRC_CTRL_V6); /* no crc */ return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6, &h2r_args); }
/* Deinitialize hardware */ void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) { mfc_debug(2, "mfc deinit start\n"); if (!dev) { mfc_err("no mfc device to run\n"); return; } if (!IS_MFCv7X(dev)) { s5p_mfc_clock_on(); s5p_mfc_reset(dev); s5p_mfc_clock_off(); } mfc_debug(2, "mfc deinit completed\n"); }
/* Load firmware to MFC */ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) { struct firmware *fw_blob; size_t firmware_size; int err; if (!dev) { mfc_err("no mfc device to run\n"); return -EINVAL; } firmware_size = dev->variant->buf_size->firmware_code; /* Firmare has to be present as a separate file or compiled * into kernel. */ mfc_debug_enter(); mfc_debug(2, "Requesting fw\n"); err = request_firmware((const struct firmware **)&fw_blob, MFC_FW_NAME, dev->v4l2_dev.dev); if (err != 0) { mfc_err_dev("Firmware is not present in the /lib/firmware directory nor compiled in kernel.\n"); return -EINVAL; } mfc_debug(2, "Ret of request_firmware: %d Size: %zu\n", err, fw_blob->size); if (fw_blob->size > firmware_size) { mfc_err_dev("MFC firmware is too big to be loaded.\n"); release_firmware(fw_blob); return -ENOMEM; } if (dev->fw_info.alloc == 0 || dev->fw_info.ofs == 0) { mfc_err_dev("MFC firmware is not allocated or was not mapped correctly.\n"); release_firmware(fw_blob); return -EINVAL; } dev->fw_size = fw_blob->size; memcpy(dev->fw_info.virt, fw_blob->data, fw_blob->size); s5p_mfc_mem_clean_priv(dev->fw_info.alloc, dev->fw_info.virt, 0, fw_blob->size); release_firmware(fw_blob); mfc_debug_leave(); return 0; }