int s5p_mfc_sleep(struct s5p_mfc_dev *dev) { struct s5p_mfc_ctx *ctx; int ret; mfc_debug_enter(); if (!dev) { mfc_err("no mfc device to run\n"); return -EINVAL; } ctx = dev->ctx[dev->curr_ctx]; if (!ctx) { mfc_err("no mfc context to run\n"); return -EINVAL; } ret = wait_event_interruptible_timeout(ctx->queue, (test_bit(ctx->num, &dev->hw_lock) == 0), msecs_to_jiffies(MFC_INT_TIMEOUT)); if (ret == 0) { mfc_err("Waiting for hardware to finish timed out\n"); ret = -EIO; return ret; } spin_lock(&dev->condlock); set_bit(ctx->num, &dev->hw_lock); spin_unlock(&dev->condlock); s5p_mfc_clock_on(); s5p_mfc_clean_dev_int_flags(dev); ret = s5p_mfc_sleep_cmd(dev); if (ret) { mfc_err("Failed to send command to MFC - timeout.\n"); goto err_mfc_sleep; } if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) { mfc_err("Failed to sleep\n"); ret = -EIO; goto err_mfc_sleep; } dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_FIMV_R2H_CMD_SLEEP_RET) { /* Failure. */ mfc_err("Failed to sleep - error: %d" " int: %d.\n", dev->int_err, dev->int_type); ret = -EIO; goto err_mfc_sleep; } err_mfc_sleep: s5p_mfc_clock_off(); mfc_debug_leave(); return ret; }
int s5p_mfc_reset(struct s5p_mfc_dev *dev) { unsigned int mc_status; unsigned long timeout; mfc_debug_enter(); mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); mdelay(10); timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); do { if (time_after(jiffies, timeout)) { mfc_err("Timeout while resetting MFC\n"); return -EIO; } mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); } while (mc_status & 0x3); mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); mfc_debug_leave(); 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; }
int s5p_mfc_sleep(struct s5p_mfc_dev *dev) { int ret; mfc_debug_enter(); s5p_mfc_clock_on(); s5p_mfc_clean_dev_int_flags(dev); ret = s5p_mfc_sleep_cmd(dev); if (ret) { mfc_err("Failed to send command to MFC - timeout.\n"); return ret; } if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) { mfc_err("Failed to sleep\n"); return -EIO; } s5p_mfc_clock_off(); dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_FIMV_R2H_CMD_SLEEP_RET) { /* Failure. */ mfc_err("Failed to sleep - error: %d" " int: %d.\n",dev->int_err, dev->int_type); return -EIO; } mfc_debug_leave(); return ret; }
/* Reset the device */ static int s5p_mfc_reset_v6(struct s5p_mfc_dev *dev) { int i; mfc_debug_enter(); /* Zero Initialization of MFC registers */ mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6); mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6); for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++) mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4)); /* check bus reset control before reset */ if (dev->risc_on) if (s5p_mfc_bus_reset(dev)) return -EIO; /* Reset * set RISC_ON to 0 during power_on & wake_up. * V6 needs RISC_ON set to 0 during reset also. */ if ((!dev->risc_on) || (!IS_MFCV7(dev))) mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6); mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6); mfc_debug_leave(); return 0; }
/* 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; }
int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev) { struct firmware *fw_blob; int err; mfc_debug_enter(); err = request_firmware((const struct firmware **)&fw_blob, "s5p-mfc.fw", 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; } if (fw_blob->size > dev->fw_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); wmb(); release_firmware(fw_blob); mfc_debug_leave(); return 0; }
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; }
/* Reset the device */ static int s5p_mfc_reset(struct s5p_mfc_dev *dev) { int i; unsigned int mc_status; unsigned long timeout; mfc_debug_enter(); /* Stop procedure */ /* FIXME: F/W can be access invalid address */ /* Reset VI */ /* s5p_mfc_write_reg(0x3f7, S5P_FIMV_SW_RESET); */ if (IS_MFCV6(dev)) { /* Reset IP */ s5p_mfc_write_reg(0xFEE, S5P_FIMV_MFC_RESET); /* except RISC, reset */ s5p_mfc_write_reg(0x0, S5P_FIMV_MFC_RESET); /* reset release */ /* Zero Initialization of MFC registers */ s5p_mfc_write_reg(0, S5P_FIMV_RISC2HOST_CMD); s5p_mfc_write_reg(0, S5P_FIMV_HOST2RISC_CMD); s5p_mfc_write_reg(0, S5P_FIMV_FW_VERSION); for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT; i++) s5p_mfc_write_reg(0, S5P_FIMV_REG_CLEAR_BEGIN + (i*4)); /* Reset */ s5p_mfc_write_reg(0, S5P_FIMV_RISC_ON); s5p_mfc_write_reg(0x1FFF, S5P_FIMV_MFC_RESET); s5p_mfc_write_reg(0, S5P_FIMV_MFC_RESET); } else { s5p_mfc_write_reg(0x3f6, S5P_FIMV_SW_RESET); /* reset RISC */ s5p_mfc_write_reg(0x3e2, S5P_FIMV_SW_RESET); /* All reset except for MC */ mdelay(10); timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); /* Check MC status */ do { if (time_after(jiffies, timeout)) { mfc_err("Timeout while resetting MFC.\n"); return -EIO; } mc_status = s5p_mfc_read_reg(S5P_FIMV_MC_STATUS); } while (mc_status & 0x3); s5p_mfc_write_reg(0x0, S5P_FIMV_SW_RESET); s5p_mfc_write_reg(0x3fe, S5P_FIMV_SW_RESET); } mfc_debug_leave(); return 0; }
/* Reset the device */ int s5p_mfc_reset(struct s5p_mfc_dev *dev) { unsigned int mc_status; unsigned long timeout; int i; mfc_debug_enter(); if (IS_MFCV6_PLUS(dev)) { /* Zero Initialization of MFC registers */ mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6); mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6); for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++) mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4)); /* check bus reset control before reset */ if (dev->risc_on) if (s5p_mfc_bus_reset(dev)) return -EIO; /* Reset * set RISC_ON to 0 during power_on & wake_up. * V6 needs RISC_ON set to 0 during reset also. */ if ((!dev->risc_on) || (!IS_MFCV7_PLUS(dev))) mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6); mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6); } else { /* Stop procedure */ /* reset RISC */ mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); /* All reset except for MC */ mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); mdelay(10); timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); /* Check MC status */ do { if (time_after(jiffies, timeout)) { mfc_err("Timeout while resetting MFC\n"); return -EIO; } mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); } while (mc_status & 0x3); mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); } mfc_debug_leave(); return 0; }
/* 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_info("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); dev->fw.dva = s5p_mfc_bitproc_phys; dev->fw.kva = s5p_mfc_bitproc_virt; dev->fw.ctx = s5p_mfc_bitproc_buf; dev->fw.size = fw_blob->size; release_firmware(fw_blob); mfc_debug_leave(); return 0; }
/* Get format */ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); struct v4l2_pix_format_mplane *pix_mp; mfc_debug_enter(); pix_mp = &f->fmt.pix_mp; if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && (ctx->state == MFCINST_GOT_INST || ctx->state == MFCINST_RES_CHANGE_END)) { /* If the MFC is parsing the header, * so wait until it is finished */ s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); } if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && ctx->state >= MFCINST_HEAD_PARSED && ctx->state < MFCINST_ABORT) { /* This is run on CAPTURE (decode output) */ /* Width and height are set to the dimensions of the movie, the buffer is bigger and further processing stages should crop to this rectangle. */ pix_mp->width = ctx->buf_width; pix_mp->height = ctx->buf_height; pix_mp->field = V4L2_FIELD_NONE; pix_mp->num_planes = 2; /* Set pixelformat to the format in which MFC outputs the decoded frame */ pix_mp->pixelformat = ctx->dst_fmt->fourcc; pix_mp->plane_fmt[0].bytesperline = ctx->buf_width; pix_mp->plane_fmt[0].sizeimage = ctx->luma_size; pix_mp->plane_fmt[1].bytesperline = ctx->buf_width; pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size; } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { /* This is run on OUTPUT The buffer contains compressed image so width and height have no meaning */ pix_mp->width = 0; pix_mp->height = 0; pix_mp->field = V4L2_FIELD_NONE; pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size; pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size; pix_mp->pixelformat = ctx->src_fmt->fourcc; pix_mp->num_planes = ctx->src_fmt->num_planes; } else { mfc_err("Format could not be read\n"); mfc_debug(2, "%s-- with error\n", __func__); return -EINVAL; } mfc_debug_leave(); return 0; }
/* Reset the device */ int s5p_mfc_reset(struct s5p_mfc_dev *dev) { unsigned int mc_status; unsigned long timeout; int i; mfc_debug_enter(); if (IS_MFCV6_PLUS(dev)) { /* Reset IP */ /* except RISC, reset */ mfc_write(dev, 0xFEE, S5P_FIMV_MFC_RESET_V6); /* reset release */ mfc_write(dev, 0x0, S5P_FIMV_MFC_RESET_V6); /* Zero Initialization of MFC registers */ mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6); mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6); for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++) mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4)); /* Reset */ mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6); mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6); } else { /* Stop procedure */ /* reset RISC */ mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); /* All reset except for MC */ mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); mdelay(10); timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); /* Check MC status */ do { if (time_after(jiffies, timeout)) { mfc_err("Timeout while resetting MFC\n"); return -EIO; } mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); } while (mc_status & 0x3); mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); } mfc_debug_leave(); return 0; }
int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev) { int ret; mfc_debug_enter(); ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, NULL); mfc_debug_leave(); return ret; }
/* Set format */ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = 0; struct v4l2_pix_format_mplane *pix_mp; struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; mfc_debug_enter(); ret = vidioc_try_fmt(file, priv, f); pix_mp = &f->fmt.pix_mp; if (ret) return ret; if (ctx->vq_src.streaming || ctx->vq_dst.streaming) { v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); ret = -EBUSY; goto out; } if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { /* dst_fmt is validated by call to vidioc_try_fmt */ ctx->dst_fmt = find_format(f, MFC_FMT_RAW); ret = 0; goto out; } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { /* src_fmt is validated by call to vidioc_try_fmt */ ctx->src_fmt = find_format(f, MFC_FMT_DEC); ctx->codec_mode = ctx->src_fmt->codec_mode; mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); pix_mp->height = 0; pix_mp->width = 0; if (pix_mp->plane_fmt[0].sizeimage == 0) pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size = DEF_CPB_SIZE; else if (pix_mp->plane_fmt[0].sizeimage > buf_size->cpb) ctx->dec_src_buf_size = buf_size->cpb; else ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage; pix_mp->plane_fmt[0].bytesperline = 0; ctx->state = MFCINST_INIT; ret = 0; goto out; } else { mfc_err("Wrong type error for S_FMT : %d", f->type); ret = -EINVAL; goto out; } out: mfc_debug_leave(); return ret; }
/* Stream on */ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = -EINVAL; mfc_debug_enter(); if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ret = vb2_streamon(&ctx->vq_src, type); else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ret = vb2_streamon(&ctx->vq_dst, type); mfc_debug_leave(); return ret; }
/* Close instance */ int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; int ret; mfc_debug_enter(); s5p_mfc_write_reg(dev, ctx->inst_no, S5P_FIMV_INSTANCE_ID); ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, NULL); mfc_debug_leave(); return ret; }
int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; int ret; mfc_debug_enter(); memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args); mfc_debug_leave(); return ret; }
int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; int ret; mfc_debug_enter(); memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); h2r_args.arg[0] = FIRMWARE_CODE_SIZE; ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args); mfc_debug_leave(); return ret; }
/* 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; }
int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; int ret; mfc_debug_enter(); memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); h2r_args.arg[0] = buf_size->firmware_code; ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args); mfc_debug_leave(); return ret; }
/* Set format */ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = 0; struct s5p_mfc_fmt *fmt; struct v4l2_pix_format_mplane *pix_mp; mfc_debug_enter(); ret = vidioc_try_fmt(file, priv, f); pix_mp = &f->fmt.pix_mp; if (ret) return ret; if (ctx->vq_src.streaming || ctx->vq_dst.streaming) { v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); ret = -EBUSY; goto out; } fmt = find_format(f, MFC_FMT_DEC); if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) { mfc_err("Unknown codec\n"); ret = -EINVAL; goto out; } if (fmt->type != MFC_FMT_DEC) { mfc_err("Wrong format selected, you should choose " "format for decoding\n"); ret = -EINVAL; goto out; } ctx->src_fmt = fmt; ctx->codec_mode = fmt->codec_mode; mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); pix_mp->height = 0; pix_mp->width = 0; if (pix_mp->plane_fmt[0].sizeimage) ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage; else pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size = DEF_CPB_SIZE; pix_mp->plane_fmt[0].bytesperline = 0; ctx->state = MFCINST_INIT; out: mfc_debug_leave(); return ret; }
int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) { int ret; mfc_debug_enter(); 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"); s5p_mfc_init_memctrl(dev); s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); ret = s5p_mfc_wakeup_cmd(dev); if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); return ret; } mfc_write(dev, 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) { mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err, dev->int_type); return -EIO; } mfc_debug_leave(); return 0; }
/* Initialize MFC V6 hardware */ static int s5p_mfc_init_hw_v6(struct s5p_mfc_dev *dev) { unsigned int ver; int ret; mfc_debug_enter(); ret = s5p_mfc_load_firmware(dev); if (ret) { mfc_err("Failed to reload FW\n"); return ret; } /* 0. MFC reset */ mfc_debug(2, "MFC reset..\n"); WARN_ON(dev->risc_on); s5p_mfc_clock_on(dev); ret = s5p_mfc_ctrl_ops_call(dev, reset, dev); if (ret) { mfc_err("Failed to reset MFC - timeout\n"); s5p_mfc_clock_off(dev); return ret; } mfc_debug(2, "Done MFC reset..\n"); /* 1. Set DRAM base Addr */ s5p_mfc_init_memctrl_v6(dev); /* 2. Release reset signal to the RISC */ s5p_mfc_clean_dev_int_flags(dev); mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); ret = s5p_mfc_init_fw(dev); if (ret) { s5p_mfc_clock_off(dev); return ret; } ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6); mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); s5p_mfc_clock_off(dev); dev->risc_on = 1; mfc_debug_leave(); return ret; }
int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->buf; int ret; mfc_debug_enter(); s5p_mfc_alloc_dev_context_buffer(dev); s5p_mfc_write_reg(dev->ctx_buf.ofs, S5P_FIMV_CONTEXT_MEM_ADDR); s5p_mfc_write_reg(buf_size->dev_ctx, S5P_FIMV_CONTEXT_MEM_SIZE); ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args); mfc_debug_leave(); return ret; }
/* Stream on */ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); struct s5p_mfc_dev *dev = ctx->dev; int ret = -EINVAL; mfc_debug_enter(); if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (ctx->state == MFCINST_INIT) { ctx->dst_bufs_cnt = 0; ctx->src_bufs_cnt = 0; ctx->capture_state = QUEUE_FREE; ctx->output_state = QUEUE_FREE; s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, ctx); s5p_mfc_hw_call(dev->mfc_ops, alloc_dec_temp_buffers, ctx); set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); if (s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) { /* Error or timeout */ mfc_err("Error getting instance from hardware\n"); s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx); return -EIO; } mfc_debug(2, "Got instance number: %d\n", ctx->inst_no); } ret = vb2_streamon(&ctx->vq_src, type); } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ret = vb2_streamon(&ctx->vq_dst, type); mfc_debug_leave(); return ret; }
static int s5p_mfc_wakeup_v6(struct s5p_mfc_dev *dev) { int ret; mfc_debug_enter(); /* 0. MFC reset */ mfc_debug(2, "MFC reset..\n"); WARN_ON(dev->risc_on); s5p_mfc_clock_on(dev); ret = s5p_mfc_ctrl_ops_call(dev, reset, dev); if (ret) { mfc_err("Failed to reset MFC - timeout\n"); s5p_mfc_clock_off(dev); return ret; } mfc_debug(2, "Done MFC reset..\n"); /* 1. Set DRAM base Addr */ s5p_mfc_init_memctrl_v6(dev); /* 2. Initialize registers of channel I/F */ s5p_mfc_clean_dev_int_flags(dev); /* 3. Send MFC wakeup command and wait for completion*/ if (IS_MFCV8(dev)) ret = s5p_mfc_wait_wakeup_v8(dev); else ret = s5p_mfc_wait_wakeup_v6(dev); s5p_mfc_clock_off(dev); if (ret) return ret; dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_MFC_R2H_CMD_WAKEUP_RET) { /* Failure. */ mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err, dev->int_type); return -EIO; } dev->risc_on = 1; mfc_debug_leave(); return 0; }
/* Close instance */ int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_cmd_args h2r_args; int ret = 0; mfc_debug_enter(); if (ctx->state != MFCINST_FREE) { s5p_mfc_write_reg(ctx->inst_no, S5P_FIMV_INSTANCE_ID); ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, &h2r_args); } else { ret = -EINVAL; } mfc_debug_leave(); 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; int ret; mfc_debug_enter(); mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode); memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); h2r_args.arg[0] = ctx->codec_mode; h2r_args.arg[1] = 0; /* no crc & no pixelcache */ h2r_args.arg[2] = ctx->context_ofs; h2r_args.arg[3] = ctx->context_size; ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_OPEN_INSTANCE, &h2r_args); mfc_debug_leave(); return ret; }
/* Close instance */ int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_cmd_args h2r_args; int ret = 0; mfc_debug_enter(); if (ctx->state != MFCINST_FREE) { memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); h2r_args.arg[0] = ctx->inst_no; ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, &h2r_args); } else { ret = -EINVAL; } mfc_debug_leave(); return ret; }