1af935746781088f28904601469671d244d2f653bKamil Debski/* 2af935746781088f28904601469671d244d2f653bKamil Debski * Samsung S5P Multi Format Codec v 5.1 3af935746781088f28904601469671d244d2f653bKamil Debski * 4af935746781088f28904601469671d244d2f653bKamil Debski * Copyright (c) 2011 Samsung Electronics Co., Ltd. 5af935746781088f28904601469671d244d2f653bKamil Debski * Kamil Debski, <k.debski@samsung.com> 6af935746781088f28904601469671d244d2f653bKamil Debski * 7af935746781088f28904601469671d244d2f653bKamil Debski * This program is free software; you can redistribute it and/or modify 8af935746781088f28904601469671d244d2f653bKamil Debski * it under the terms of the GNU General Public License as published by 9af935746781088f28904601469671d244d2f653bKamil Debski * the Free Software Foundation; either version 2 of the License, or 10af935746781088f28904601469671d244d2f653bKamil Debski * (at your option) any later version. 11af935746781088f28904601469671d244d2f653bKamil Debski */ 12af935746781088f28904601469671d244d2f653bKamil Debski 13af935746781088f28904601469671d244d2f653bKamil Debski#include <linux/clk.h> 14af935746781088f28904601469671d244d2f653bKamil Debski#include <linux/delay.h> 15af935746781088f28904601469671d244d2f653bKamil Debski#include <linux/interrupt.h> 16af935746781088f28904601469671d244d2f653bKamil Debski#include <linux/io.h> 17af935746781088f28904601469671d244d2f653bKamil Debski#include <linux/module.h> 18af935746781088f28904601469671d244d2f653bKamil Debski#include <linux/platform_device.h> 19af935746781088f28904601469671d244d2f653bKamil Debski#include <linux/sched.h> 20af935746781088f28904601469671d244d2f653bKamil Debski#include <linux/slab.h> 21af935746781088f28904601469671d244d2f653bKamil Debski#include <linux/videodev2.h> 22af935746781088f28904601469671d244d2f653bKamil Debski#include <linux/workqueue.h> 23af935746781088f28904601469671d244d2f653bKamil Debski#include <media/videobuf2-core.h> 24af935746781088f28904601469671d244d2f653bKamil Debski#include "regs-mfc.h" 25af935746781088f28904601469671d244d2f653bKamil Debski#include "s5p_mfc_ctrl.h" 26af935746781088f28904601469671d244d2f653bKamil Debski#include "s5p_mfc_debug.h" 27af935746781088f28904601469671d244d2f653bKamil Debski#include "s5p_mfc_dec.h" 28af935746781088f28904601469671d244d2f653bKamil Debski#include "s5p_mfc_enc.h" 29af935746781088f28904601469671d244d2f653bKamil Debski#include "s5p_mfc_intr.h" 30af935746781088f28904601469671d244d2f653bKamil Debski#include "s5p_mfc_opr.h" 31af935746781088f28904601469671d244d2f653bKamil Debski#include "s5p_mfc_pm.h" 32af935746781088f28904601469671d244d2f653bKamil Debski#include "s5p_mfc_shm.h" 33af935746781088f28904601469671d244d2f653bKamil Debski 34af935746781088f28904601469671d244d2f653bKamil Debski#define S5P_MFC_NAME "s5p-mfc" 35af935746781088f28904601469671d244d2f653bKamil Debski#define S5P_MFC_DEC_NAME "s5p-mfc-dec" 36af935746781088f28904601469671d244d2f653bKamil Debski#define S5P_MFC_ENC_NAME "s5p-mfc-enc" 37af935746781088f28904601469671d244d2f653bKamil Debski 38af935746781088f28904601469671d244d2f653bKamil Debskiint debug; 39af935746781088f28904601469671d244d2f653bKamil Debskimodule_param(debug, int, S_IRUGO | S_IWUSR); 40af935746781088f28904601469671d244d2f653bKamil DebskiMODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages"); 41af935746781088f28904601469671d244d2f653bKamil Debski 42af935746781088f28904601469671d244d2f653bKamil Debski/* Helper functions for interrupt processing */ 43af935746781088f28904601469671d244d2f653bKamil Debski/* Remove from hw execution round robin */ 44af935746781088f28904601469671d244d2f653bKamil Debskistatic void clear_work_bit(struct s5p_mfc_ctx *ctx) 45af935746781088f28904601469671d244d2f653bKamil Debski{ 46af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev = ctx->dev; 47af935746781088f28904601469671d244d2f653bKamil Debski 48af935746781088f28904601469671d244d2f653bKamil Debski spin_lock(&dev->condlock); 49af935746781088f28904601469671d244d2f653bKamil Debski clear_bit(ctx->num, &dev->ctx_work_bits); 50af935746781088f28904601469671d244d2f653bKamil Debski spin_unlock(&dev->condlock); 51af935746781088f28904601469671d244d2f653bKamil Debski} 52af935746781088f28904601469671d244d2f653bKamil Debski 53af935746781088f28904601469671d244d2f653bKamil Debski/* Wake up context wait_queue */ 54af935746781088f28904601469671d244d2f653bKamil Debskistatic void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason, 55af935746781088f28904601469671d244d2f653bKamil Debski unsigned int err) 56af935746781088f28904601469671d244d2f653bKamil Debski{ 57af935746781088f28904601469671d244d2f653bKamil Debski ctx->int_cond = 1; 58af935746781088f28904601469671d244d2f653bKamil Debski ctx->int_type = reason; 59af935746781088f28904601469671d244d2f653bKamil Debski ctx->int_err = err; 60af935746781088f28904601469671d244d2f653bKamil Debski wake_up(&ctx->queue); 61af935746781088f28904601469671d244d2f653bKamil Debski} 62af935746781088f28904601469671d244d2f653bKamil Debski 63af935746781088f28904601469671d244d2f653bKamil Debski/* Wake up device wait_queue */ 64af935746781088f28904601469671d244d2f653bKamil Debskistatic void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason, 65af935746781088f28904601469671d244d2f653bKamil Debski unsigned int err) 66af935746781088f28904601469671d244d2f653bKamil Debski{ 67af935746781088f28904601469671d244d2f653bKamil Debski dev->int_cond = 1; 68af935746781088f28904601469671d244d2f653bKamil Debski dev->int_type = reason; 69af935746781088f28904601469671d244d2f653bKamil Debski dev->int_err = err; 70af935746781088f28904601469671d244d2f653bKamil Debski wake_up(&dev->queue); 71af935746781088f28904601469671d244d2f653bKamil Debski} 72af935746781088f28904601469671d244d2f653bKamil Debski 73af935746781088f28904601469671d244d2f653bKamil Debskivoid s5p_mfc_watchdog(unsigned long arg) 74af935746781088f28904601469671d244d2f653bKamil Debski{ 75af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg; 76af935746781088f28904601469671d244d2f653bKamil Debski 77af935746781088f28904601469671d244d2f653bKamil Debski if (test_bit(0, &dev->hw_lock)) 78af935746781088f28904601469671d244d2f653bKamil Debski atomic_inc(&dev->watchdog_cnt); 79af935746781088f28904601469671d244d2f653bKamil Debski if (atomic_read(&dev->watchdog_cnt) >= MFC_WATCHDOG_CNT) { 80af935746781088f28904601469671d244d2f653bKamil Debski /* This means that hw is busy and no interrupts were 81af935746781088f28904601469671d244d2f653bKamil Debski * generated by hw for the Nth time of running this 82af935746781088f28904601469671d244d2f653bKamil Debski * watchdog timer. This usually means a serious hw 83af935746781088f28904601469671d244d2f653bKamil Debski * error. Now it is time to kill all instances and 84af935746781088f28904601469671d244d2f653bKamil Debski * reset the MFC. */ 85af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Time out during waiting for HW\n"); 86af935746781088f28904601469671d244d2f653bKamil Debski queue_work(dev->watchdog_workqueue, &dev->watchdog_work); 87af935746781088f28904601469671d244d2f653bKamil Debski } 88af935746781088f28904601469671d244d2f653bKamil Debski dev->watchdog_timer.expires = jiffies + 89af935746781088f28904601469671d244d2f653bKamil Debski msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); 90af935746781088f28904601469671d244d2f653bKamil Debski add_timer(&dev->watchdog_timer); 91af935746781088f28904601469671d244d2f653bKamil Debski} 92af935746781088f28904601469671d244d2f653bKamil Debski 93af935746781088f28904601469671d244d2f653bKamil Debskistatic void s5p_mfc_watchdog_worker(struct work_struct *work) 94af935746781088f28904601469671d244d2f653bKamil Debski{ 95af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev; 96af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_ctx *ctx; 97af935746781088f28904601469671d244d2f653bKamil Debski unsigned long flags; 98af935746781088f28904601469671d244d2f653bKamil Debski int mutex_locked; 99af935746781088f28904601469671d244d2f653bKamil Debski int i, ret; 100af935746781088f28904601469671d244d2f653bKamil Debski 101af935746781088f28904601469671d244d2f653bKamil Debski dev = container_of(work, struct s5p_mfc_dev, watchdog_work); 102af935746781088f28904601469671d244d2f653bKamil Debski 103af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Driver timeout error handling\n"); 104af935746781088f28904601469671d244d2f653bKamil Debski /* Lock the mutex that protects open and release. 105af935746781088f28904601469671d244d2f653bKamil Debski * This is necessary as they may load and unload firmware. */ 106af935746781088f28904601469671d244d2f653bKamil Debski mutex_locked = mutex_trylock(&dev->mfc_mutex); 107af935746781088f28904601469671d244d2f653bKamil Debski if (!mutex_locked) 108af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Error: some instance may be closing/opening\n"); 109af935746781088f28904601469671d244d2f653bKamil Debski spin_lock_irqsave(&dev->irqlock, flags); 110af935746781088f28904601469671d244d2f653bKamil Debski 111af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 112af935746781088f28904601469671d244d2f653bKamil Debski 113af935746781088f28904601469671d244d2f653bKamil Debski for (i = 0; i < MFC_NUM_CONTEXTS; i++) { 114af935746781088f28904601469671d244d2f653bKamil Debski ctx = dev->ctx[i]; 115af935746781088f28904601469671d244d2f653bKamil Debski if (!ctx) 116af935746781088f28904601469671d244d2f653bKamil Debski continue; 117af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_ERROR; 118af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); 119af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); 120af935746781088f28904601469671d244d2f653bKamil Debski clear_work_bit(ctx); 121af935746781088f28904601469671d244d2f653bKamil Debski wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0); 122af935746781088f28904601469671d244d2f653bKamil Debski } 123af935746781088f28904601469671d244d2f653bKamil Debski clear_bit(0, &dev->hw_lock); 124af935746781088f28904601469671d244d2f653bKamil Debski spin_unlock_irqrestore(&dev->irqlock, flags); 125af935746781088f28904601469671d244d2f653bKamil Debski /* Double check if there is at least one instance running. 126af935746781088f28904601469671d244d2f653bKamil Debski * If no instance is in memory than no firmware should be present */ 127af935746781088f28904601469671d244d2f653bKamil Debski if (dev->num_inst > 0) { 128af935746781088f28904601469671d244d2f653bKamil Debski ret = s5p_mfc_reload_firmware(dev); 129af935746781088f28904601469671d244d2f653bKamil Debski if (ret) { 130af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Failed to reload FW\n"); 131af935746781088f28904601469671d244d2f653bKamil Debski goto unlock; 132af935746781088f28904601469671d244d2f653bKamil Debski } 133af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_on(); 134af935746781088f28904601469671d244d2f653bKamil Debski ret = s5p_mfc_init_hw(dev); 135af935746781088f28904601469671d244d2f653bKamil Debski if (ret) 136af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Failed to reinit FW\n"); 137af935746781088f28904601469671d244d2f653bKamil Debski } 138af935746781088f28904601469671d244d2f653bKamil Debskiunlock: 139af935746781088f28904601469671d244d2f653bKamil Debski if (mutex_locked) 140af935746781088f28904601469671d244d2f653bKamil Debski mutex_unlock(&dev->mfc_mutex); 141af935746781088f28904601469671d244d2f653bKamil Debski} 142af935746781088f28904601469671d244d2f653bKamil Debski 143af935746781088f28904601469671d244d2f653bKamil Debskistatic enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file) 144af935746781088f28904601469671d244d2f653bKamil Debski{ 145af935746781088f28904601469671d244d2f653bKamil Debski struct video_device *vdev = video_devdata(file); 146af935746781088f28904601469671d244d2f653bKamil Debski 147af935746781088f28904601469671d244d2f653bKamil Debski if (!vdev) { 148af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("failed to get video_device"); 149af935746781088f28904601469671d244d2f653bKamil Debski return MFCNODE_INVALID; 150af935746781088f28904601469671d244d2f653bKamil Debski } 151af935746781088f28904601469671d244d2f653bKamil Debski if (vdev->index == 0) 152af935746781088f28904601469671d244d2f653bKamil Debski return MFCNODE_DECODER; 153af935746781088f28904601469671d244d2f653bKamil Debski else if (vdev->index == 1) 154af935746781088f28904601469671d244d2f653bKamil Debski return MFCNODE_ENCODER; 155af935746781088f28904601469671d244d2f653bKamil Debski return MFCNODE_INVALID; 156af935746781088f28904601469671d244d2f653bKamil Debski} 157af935746781088f28904601469671d244d2f653bKamil Debski 158af935746781088f28904601469671d244d2f653bKamil Debskistatic void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev) 159af935746781088f28904601469671d244d2f653bKamil Debski{ 160af935746781088f28904601469671d244d2f653bKamil Debski mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); 161af935746781088f28904601469671d244d2f653bKamil Debski mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); 162af935746781088f28904601469671d244d2f653bKamil Debski mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID); 163af935746781088f28904601469671d244d2f653bKamil Debski} 164af935746781088f28904601469671d244d2f653bKamil Debski 165af935746781088f28904601469671d244d2f653bKamil Debskistatic void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) 166af935746781088f28904601469671d244d2f653bKamil Debski{ 167af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_buf *dst_buf; 168af935746781088f28904601469671d244d2f653bKamil Debski 169af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_FINISHED; 170af935746781088f28904601469671d244d2f653bKamil Debski ctx->sequence++; 171af935746781088f28904601469671d244d2f653bKamil Debski while (!list_empty(&ctx->dst_queue)) { 172af935746781088f28904601469671d244d2f653bKamil Debski dst_buf = list_entry(ctx->dst_queue.next, 173af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_buf, list); 174af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "Cleaning up buffer: %d\n", 175af935746781088f28904601469671d244d2f653bKamil Debski dst_buf->b->v4l2_buf.index); 176af935746781088f28904601469671d244d2f653bKamil Debski vb2_set_plane_payload(dst_buf->b, 0, 0); 177af935746781088f28904601469671d244d2f653bKamil Debski vb2_set_plane_payload(dst_buf->b, 1, 0); 178af935746781088f28904601469671d244d2f653bKamil Debski list_del(&dst_buf->list); 179af935746781088f28904601469671d244d2f653bKamil Debski ctx->dst_queue_cnt--; 180af935746781088f28904601469671d244d2f653bKamil Debski dst_buf->b->v4l2_buf.sequence = (ctx->sequence++); 181af935746781088f28904601469671d244d2f653bKamil Debski 182af935746781088f28904601469671d244d2f653bKamil Debski if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) == 183af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_read_shm(ctx, PIC_TIME_BOT)) 184af935746781088f28904601469671d244d2f653bKamil Debski dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; 185af935746781088f28904601469671d244d2f653bKamil Debski else 186af935746781088f28904601469671d244d2f653bKamil Debski dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED; 187af935746781088f28904601469671d244d2f653bKamil Debski 188af935746781088f28904601469671d244d2f653bKamil Debski ctx->dec_dst_flag &= ~(1 << dst_buf->b->v4l2_buf.index); 189af935746781088f28904601469671d244d2f653bKamil Debski vb2_buffer_done(dst_buf->b, VB2_BUF_STATE_DONE); 190af935746781088f28904601469671d244d2f653bKamil Debski } 191af935746781088f28904601469671d244d2f653bKamil Debski} 192af935746781088f28904601469671d244d2f653bKamil Debski 193af935746781088f28904601469671d244d2f653bKamil Debskistatic void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) 194af935746781088f28904601469671d244d2f653bKamil Debski{ 195af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev = ctx->dev; 196af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_buf *dst_buf, *src_buf; 197af935746781088f28904601469671d244d2f653bKamil Debski size_t dec_y_addr = s5p_mfc_get_dec_y_adr(); 198af935746781088f28904601469671d244d2f653bKamil Debski unsigned int frame_type = s5p_mfc_get_frame_type(); 199af935746781088f28904601469671d244d2f653bKamil Debski 200af935746781088f28904601469671d244d2f653bKamil Debski /* Copy timestamp / timecode from decoded src to dst and set 201af935746781088f28904601469671d244d2f653bKamil Debski appropraite flags */ 202af935746781088f28904601469671d244d2f653bKamil Debski src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); 203af935746781088f28904601469671d244d2f653bKamil Debski list_for_each_entry(dst_buf, &ctx->dst_queue, list) { 204ba7fcb0c954921534707f08ebc4d8beeb2eb17e7Marek Szyprowski if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dec_y_addr) { 205af935746781088f28904601469671d244d2f653bKamil Debski memcpy(&dst_buf->b->v4l2_buf.timecode, 206af935746781088f28904601469671d244d2f653bKamil Debski &src_buf->b->v4l2_buf.timecode, 207af935746781088f28904601469671d244d2f653bKamil Debski sizeof(struct v4l2_timecode)); 208af935746781088f28904601469671d244d2f653bKamil Debski memcpy(&dst_buf->b->v4l2_buf.timestamp, 209af935746781088f28904601469671d244d2f653bKamil Debski &src_buf->b->v4l2_buf.timestamp, 210af935746781088f28904601469671d244d2f653bKamil Debski sizeof(struct timeval)); 211af935746781088f28904601469671d244d2f653bKamil Debski switch (frame_type) { 212af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_DECODE_FRAME_I_FRAME: 213af935746781088f28904601469671d244d2f653bKamil Debski dst_buf->b->v4l2_buf.flags |= 214af935746781088f28904601469671d244d2f653bKamil Debski V4L2_BUF_FLAG_KEYFRAME; 215af935746781088f28904601469671d244d2f653bKamil Debski break; 216af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_DECODE_FRAME_P_FRAME: 217af935746781088f28904601469671d244d2f653bKamil Debski dst_buf->b->v4l2_buf.flags |= 218af935746781088f28904601469671d244d2f653bKamil Debski V4L2_BUF_FLAG_PFRAME; 219af935746781088f28904601469671d244d2f653bKamil Debski break; 220af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_DECODE_FRAME_B_FRAME: 221af935746781088f28904601469671d244d2f653bKamil Debski dst_buf->b->v4l2_buf.flags |= 222af935746781088f28904601469671d244d2f653bKamil Debski V4L2_BUF_FLAG_BFRAME; 223af935746781088f28904601469671d244d2f653bKamil Debski break; 224af935746781088f28904601469671d244d2f653bKamil Debski } 225af935746781088f28904601469671d244d2f653bKamil Debski break; 226af935746781088f28904601469671d244d2f653bKamil Debski } 227af935746781088f28904601469671d244d2f653bKamil Debski } 228af935746781088f28904601469671d244d2f653bKamil Debski} 229af935746781088f28904601469671d244d2f653bKamil Debski 230af935746781088f28904601469671d244d2f653bKamil Debskistatic void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) 231af935746781088f28904601469671d244d2f653bKamil Debski{ 232af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev = ctx->dev; 233af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_buf *dst_buf; 234af935746781088f28904601469671d244d2f653bKamil Debski size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr(); 235af935746781088f28904601469671d244d2f653bKamil Debski unsigned int frame_type = s5p_mfc_get_frame_type(); 236af935746781088f28904601469671d244d2f653bKamil Debski unsigned int index; 237af935746781088f28904601469671d244d2f653bKamil Debski 238af935746781088f28904601469671d244d2f653bKamil Debski /* If frame is same as previous then skip and do not dequeue */ 239af935746781088f28904601469671d244d2f653bKamil Debski if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) { 240af935746781088f28904601469671d244d2f653bKamil Debski if (!ctx->after_packed_pb) 241af935746781088f28904601469671d244d2f653bKamil Debski ctx->sequence++; 242af935746781088f28904601469671d244d2f653bKamil Debski ctx->after_packed_pb = 0; 243af935746781088f28904601469671d244d2f653bKamil Debski return; 244af935746781088f28904601469671d244d2f653bKamil Debski } 245af935746781088f28904601469671d244d2f653bKamil Debski ctx->sequence++; 246af935746781088f28904601469671d244d2f653bKamil Debski /* The MFC returns address of the buffer, now we have to 247af935746781088f28904601469671d244d2f653bKamil Debski * check which videobuf does it correspond to */ 248af935746781088f28904601469671d244d2f653bKamil Debski list_for_each_entry(dst_buf, &ctx->dst_queue, list) { 249af935746781088f28904601469671d244d2f653bKamil Debski /* Check if this is the buffer we're looking for */ 250ba7fcb0c954921534707f08ebc4d8beeb2eb17e7Marek Szyprowski if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dspl_y_addr) { 251af935746781088f28904601469671d244d2f653bKamil Debski list_del(&dst_buf->list); 252af935746781088f28904601469671d244d2f653bKamil Debski ctx->dst_queue_cnt--; 253af935746781088f28904601469671d244d2f653bKamil Debski dst_buf->b->v4l2_buf.sequence = ctx->sequence; 254af935746781088f28904601469671d244d2f653bKamil Debski if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) == 255af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_read_shm(ctx, PIC_TIME_BOT)) 256af935746781088f28904601469671d244d2f653bKamil Debski dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; 257af935746781088f28904601469671d244d2f653bKamil Debski else 258af935746781088f28904601469671d244d2f653bKamil Debski dst_buf->b->v4l2_buf.field = 259af935746781088f28904601469671d244d2f653bKamil Debski V4L2_FIELD_INTERLACED; 260af935746781088f28904601469671d244d2f653bKamil Debski vb2_set_plane_payload(dst_buf->b, 0, ctx->luma_size); 261af935746781088f28904601469671d244d2f653bKamil Debski vb2_set_plane_payload(dst_buf->b, 1, ctx->chroma_size); 262af935746781088f28904601469671d244d2f653bKamil Debski clear_bit(dst_buf->b->v4l2_buf.index, 263af935746781088f28904601469671d244d2f653bKamil Debski &ctx->dec_dst_flag); 264af935746781088f28904601469671d244d2f653bKamil Debski 265af935746781088f28904601469671d244d2f653bKamil Debski vb2_buffer_done(dst_buf->b, 266af935746781088f28904601469671d244d2f653bKamil Debski err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); 267af935746781088f28904601469671d244d2f653bKamil Debski 268af935746781088f28904601469671d244d2f653bKamil Debski index = dst_buf->b->v4l2_buf.index; 269af935746781088f28904601469671d244d2f653bKamil Debski break; 270af935746781088f28904601469671d244d2f653bKamil Debski } 271af935746781088f28904601469671d244d2f653bKamil Debski } 272af935746781088f28904601469671d244d2f653bKamil Debski} 273af935746781088f28904601469671d244d2f653bKamil Debski 274af935746781088f28904601469671d244d2f653bKamil Debski/* Handle frame decoding interrupt */ 275af935746781088f28904601469671d244d2f653bKamil Debskistatic void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, 276af935746781088f28904601469671d244d2f653bKamil Debski unsigned int reason, unsigned int err) 277af935746781088f28904601469671d244d2f653bKamil Debski{ 278af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev = ctx->dev; 279af935746781088f28904601469671d244d2f653bKamil Debski unsigned int dst_frame_status; 280af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_buf *src_buf; 281af935746781088f28904601469671d244d2f653bKamil Debski unsigned long flags; 282af935746781088f28904601469671d244d2f653bKamil Debski unsigned int res_change; 283af935746781088f28904601469671d244d2f653bKamil Debski 284af935746781088f28904601469671d244d2f653bKamil Debski unsigned int index; 285af935746781088f28904601469671d244d2f653bKamil Debski 286af935746781088f28904601469671d244d2f653bKamil Debski dst_frame_status = s5p_mfc_get_dspl_status() 287af935746781088f28904601469671d244d2f653bKamil Debski & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; 288af935746781088f28904601469671d244d2f653bKamil Debski res_change = s5p_mfc_get_dspl_status() 289af935746781088f28904601469671d244d2f653bKamil Debski & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK; 290af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "Frame Status: %x\n", dst_frame_status); 291af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->state == MFCINST_RES_CHANGE_INIT) 292af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_RES_CHANGE_FLUSH; 293af935746781088f28904601469671d244d2f653bKamil Debski if (res_change) { 294af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_RES_CHANGE_INIT; 295af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clear_int_flags(dev); 296af935746781088f28904601469671d244d2f653bKamil Debski wake_up_ctx(ctx, reason, err); 297af935746781088f28904601469671d244d2f653bKamil Debski if (test_and_clear_bit(0, &dev->hw_lock) == 0) 298af935746781088f28904601469671d244d2f653bKamil Debski BUG(); 299af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 300af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_try_run(dev); 301af935746781088f28904601469671d244d2f653bKamil Debski return; 302af935746781088f28904601469671d244d2f653bKamil Debski } 303af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->dpb_flush_flag) 304af935746781088f28904601469671d244d2f653bKamil Debski ctx->dpb_flush_flag = 0; 305af935746781088f28904601469671d244d2f653bKamil Debski 306af935746781088f28904601469671d244d2f653bKamil Debski spin_lock_irqsave(&dev->irqlock, flags); 307af935746781088f28904601469671d244d2f653bKamil Debski /* All frames remaining in the buffer have been extracted */ 308af935746781088f28904601469671d244d2f653bKamil Debski if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) { 309af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->state == MFCINST_RES_CHANGE_FLUSH) { 310af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_handle_frame_all_extracted(ctx); 311af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_RES_CHANGE_END; 312af935746781088f28904601469671d244d2f653bKamil Debski goto leave_handle_frame; 313af935746781088f28904601469671d244d2f653bKamil Debski } else { 314af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_handle_frame_all_extracted(ctx); 315af935746781088f28904601469671d244d2f653bKamil Debski } 316af935746781088f28904601469671d244d2f653bKamil Debski } 317af935746781088f28904601469671d244d2f653bKamil Debski 318af935746781088f28904601469671d244d2f653bKamil Debski if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY || 319af935746781088f28904601469671d244d2f653bKamil Debski dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY) 320af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_handle_frame_copy_time(ctx); 321af935746781088f28904601469671d244d2f653bKamil Debski 322af935746781088f28904601469671d244d2f653bKamil Debski /* A frame has been decoded and is in the buffer */ 323af935746781088f28904601469671d244d2f653bKamil Debski if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY || 324af935746781088f28904601469671d244d2f653bKamil Debski dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) { 325af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_handle_frame_new(ctx, err); 326af935746781088f28904601469671d244d2f653bKamil Debski } else { 327af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "No frame decode\n"); 328af935746781088f28904601469671d244d2f653bKamil Debski } 329af935746781088f28904601469671d244d2f653bKamil Debski /* Mark source buffer as complete */ 330af935746781088f28904601469671d244d2f653bKamil Debski if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY 331af935746781088f28904601469671d244d2f653bKamil Debski && !list_empty(&ctx->src_queue)) { 332af935746781088f28904601469671d244d2f653bKamil Debski src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, 333af935746781088f28904601469671d244d2f653bKamil Debski list); 334af935746781088f28904601469671d244d2f653bKamil Debski ctx->consumed_stream += s5p_mfc_get_consumed_stream(); 335af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC && 336af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME 337af935746781088f28904601469671d244d2f653bKamil Debski && ctx->consumed_stream + STUFF_BYTE < 338af935746781088f28904601469671d244d2f653bKamil Debski src_buf->b->v4l2_planes[0].bytesused) { 339af935746781088f28904601469671d244d2f653bKamil Debski /* Run MFC again on the same buffer */ 340af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "Running again the same buffer\n"); 341af935746781088f28904601469671d244d2f653bKamil Debski ctx->after_packed_pb = 1; 342af935746781088f28904601469671d244d2f653bKamil Debski } else { 343af935746781088f28904601469671d244d2f653bKamil Debski index = src_buf->b->v4l2_buf.index; 344af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "MFC needs next buffer\n"); 345af935746781088f28904601469671d244d2f653bKamil Debski ctx->consumed_stream = 0; 346af935746781088f28904601469671d244d2f653bKamil Debski list_del(&src_buf->list); 347af935746781088f28904601469671d244d2f653bKamil Debski ctx->src_queue_cnt--; 348af935746781088f28904601469671d244d2f653bKamil Debski if (s5p_mfc_err_dec(err) > 0) 349af935746781088f28904601469671d244d2f653bKamil Debski vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR); 350af935746781088f28904601469671d244d2f653bKamil Debski else 351af935746781088f28904601469671d244d2f653bKamil Debski vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE); 352af935746781088f28904601469671d244d2f653bKamil Debski } 353af935746781088f28904601469671d244d2f653bKamil Debski } 354af935746781088f28904601469671d244d2f653bKamil Debskileave_handle_frame: 355af935746781088f28904601469671d244d2f653bKamil Debski spin_unlock_irqrestore(&dev->irqlock, flags); 356af935746781088f28904601469671d244d2f653bKamil Debski if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING) 357af935746781088f28904601469671d244d2f653bKamil Debski || ctx->dst_queue_cnt < ctx->dpb_count) 358af935746781088f28904601469671d244d2f653bKamil Debski clear_work_bit(ctx); 359af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clear_int_flags(dev); 360af935746781088f28904601469671d244d2f653bKamil Debski wake_up_ctx(ctx, reason, err); 361af935746781088f28904601469671d244d2f653bKamil Debski if (test_and_clear_bit(0, &dev->hw_lock) == 0) 362af935746781088f28904601469671d244d2f653bKamil Debski BUG(); 363af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 364af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_try_run(dev); 365af935746781088f28904601469671d244d2f653bKamil Debski} 366af935746781088f28904601469671d244d2f653bKamil Debski 367af935746781088f28904601469671d244d2f653bKamil Debski/* Error handling for interrupt */ 368af935746781088f28904601469671d244d2f653bKamil Debskistatic void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx, 369af935746781088f28904601469671d244d2f653bKamil Debski unsigned int reason, unsigned int err) 370af935746781088f28904601469671d244d2f653bKamil Debski{ 371af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev; 372af935746781088f28904601469671d244d2f653bKamil Debski unsigned long flags; 373af935746781088f28904601469671d244d2f653bKamil Debski 374af935746781088f28904601469671d244d2f653bKamil Debski /* If no context is available then all necessary 375af935746781088f28904601469671d244d2f653bKamil Debski * processing has been done. */ 376af935746781088f28904601469671d244d2f653bKamil Debski if (ctx == 0) 377af935746781088f28904601469671d244d2f653bKamil Debski return; 378af935746781088f28904601469671d244d2f653bKamil Debski 379af935746781088f28904601469671d244d2f653bKamil Debski dev = ctx->dev; 380af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Interrupt Error: %08x\n", err); 381af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clear_int_flags(dev); 382af935746781088f28904601469671d244d2f653bKamil Debski wake_up_dev(dev, reason, err); 383af935746781088f28904601469671d244d2f653bKamil Debski 384af935746781088f28904601469671d244d2f653bKamil Debski /* Error recovery is dependent on the state of context */ 385af935746781088f28904601469671d244d2f653bKamil Debski switch (ctx->state) { 386af935746781088f28904601469671d244d2f653bKamil Debski case MFCINST_INIT: 387af935746781088f28904601469671d244d2f653bKamil Debski /* This error had to happen while acquireing instance */ 388af935746781088f28904601469671d244d2f653bKamil Debski case MFCINST_GOT_INST: 389af935746781088f28904601469671d244d2f653bKamil Debski /* This error had to happen while parsing the header */ 390af935746781088f28904601469671d244d2f653bKamil Debski case MFCINST_HEAD_PARSED: 391af935746781088f28904601469671d244d2f653bKamil Debski /* This error had to happen while setting dst buffers */ 392af935746781088f28904601469671d244d2f653bKamil Debski case MFCINST_RETURN_INST: 393af935746781088f28904601469671d244d2f653bKamil Debski /* This error had to happen while releasing instance */ 394af935746781088f28904601469671d244d2f653bKamil Debski clear_work_bit(ctx); 395af935746781088f28904601469671d244d2f653bKamil Debski wake_up_ctx(ctx, reason, err); 396af935746781088f28904601469671d244d2f653bKamil Debski if (test_and_clear_bit(0, &dev->hw_lock) == 0) 397af935746781088f28904601469671d244d2f653bKamil Debski BUG(); 398af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 399af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_ERROR; 400af935746781088f28904601469671d244d2f653bKamil Debski break; 401af935746781088f28904601469671d244d2f653bKamil Debski case MFCINST_FINISHING: 402af935746781088f28904601469671d244d2f653bKamil Debski case MFCINST_FINISHED: 403af935746781088f28904601469671d244d2f653bKamil Debski case MFCINST_RUNNING: 404af935746781088f28904601469671d244d2f653bKamil Debski /* It is higly probable that an error occured 405af935746781088f28904601469671d244d2f653bKamil Debski * while decoding a frame */ 406af935746781088f28904601469671d244d2f653bKamil Debski clear_work_bit(ctx); 407af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_ERROR; 408af935746781088f28904601469671d244d2f653bKamil Debski /* Mark all dst buffers as having an error */ 409af935746781088f28904601469671d244d2f653bKamil Debski spin_lock_irqsave(&dev->irqlock, flags); 410af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); 411af935746781088f28904601469671d244d2f653bKamil Debski /* Mark all src buffers as having an error */ 412af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); 413af935746781088f28904601469671d244d2f653bKamil Debski spin_unlock_irqrestore(&dev->irqlock, flags); 414af935746781088f28904601469671d244d2f653bKamil Debski if (test_and_clear_bit(0, &dev->hw_lock) == 0) 415af935746781088f28904601469671d244d2f653bKamil Debski BUG(); 416af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 417af935746781088f28904601469671d244d2f653bKamil Debski break; 418af935746781088f28904601469671d244d2f653bKamil Debski default: 419af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Encountered an error interrupt which had not been handled\n"); 420af935746781088f28904601469671d244d2f653bKamil Debski break; 421af935746781088f28904601469671d244d2f653bKamil Debski } 422af935746781088f28904601469671d244d2f653bKamil Debski return; 423af935746781088f28904601469671d244d2f653bKamil Debski} 424af935746781088f28904601469671d244d2f653bKamil Debski 425af935746781088f28904601469671d244d2f653bKamil Debski/* Header parsing interrupt handling */ 426af935746781088f28904601469671d244d2f653bKamil Debskistatic void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, 427af935746781088f28904601469671d244d2f653bKamil Debski unsigned int reason, unsigned int err) 428af935746781088f28904601469671d244d2f653bKamil Debski{ 429af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev; 430af935746781088f28904601469671d244d2f653bKamil Debski unsigned int guard_width, guard_height; 431af935746781088f28904601469671d244d2f653bKamil Debski 432af935746781088f28904601469671d244d2f653bKamil Debski if (ctx == 0) 433af935746781088f28904601469671d244d2f653bKamil Debski return; 434af935746781088f28904601469671d244d2f653bKamil Debski dev = ctx->dev; 435af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->c_ops->post_seq_start) { 436af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->c_ops->post_seq_start(ctx)) 437af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("post_seq_start() failed\n"); 438af935746781088f28904601469671d244d2f653bKamil Debski } else { 439af935746781088f28904601469671d244d2f653bKamil Debski ctx->img_width = s5p_mfc_get_img_width(); 440af935746781088f28904601469671d244d2f653bKamil Debski ctx->img_height = s5p_mfc_get_img_height(); 441af935746781088f28904601469671d244d2f653bKamil Debski 442af935746781088f28904601469671d244d2f653bKamil Debski ctx->buf_width = ALIGN(ctx->img_width, 443af935746781088f28904601469671d244d2f653bKamil Debski S5P_FIMV_NV12MT_HALIGN); 444af935746781088f28904601469671d244d2f653bKamil Debski ctx->buf_height = ALIGN(ctx->img_height, 445af935746781088f28904601469671d244d2f653bKamil Debski S5P_FIMV_NV12MT_VALIGN); 446af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, " 447af935746781088f28904601469671d244d2f653bKamil Debski "buffer dimensions: %dx%d\n", ctx->img_width, 448af935746781088f28904601469671d244d2f653bKamil Debski ctx->img_height, ctx->buf_width, 449af935746781088f28904601469671d244d2f653bKamil Debski ctx->buf_height); 450af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) { 451af935746781088f28904601469671d244d2f653bKamil Debski ctx->luma_size = ALIGN(ctx->buf_width * 452af935746781088f28904601469671d244d2f653bKamil Debski ctx->buf_height, S5P_FIMV_DEC_BUF_ALIGN); 453af935746781088f28904601469671d244d2f653bKamil Debski ctx->chroma_size = ALIGN(ctx->buf_width * 454af935746781088f28904601469671d244d2f653bKamil Debski ALIGN((ctx->img_height >> 1), 455af935746781088f28904601469671d244d2f653bKamil Debski S5P_FIMV_NV12MT_VALIGN), 456af935746781088f28904601469671d244d2f653bKamil Debski S5P_FIMV_DEC_BUF_ALIGN); 457af935746781088f28904601469671d244d2f653bKamil Debski ctx->mv_size = ALIGN(ctx->buf_width * 458af935746781088f28904601469671d244d2f653bKamil Debski ALIGN((ctx->buf_height >> 2), 459af935746781088f28904601469671d244d2f653bKamil Debski S5P_FIMV_NV12MT_VALIGN), 460af935746781088f28904601469671d244d2f653bKamil Debski S5P_FIMV_DEC_BUF_ALIGN); 461af935746781088f28904601469671d244d2f653bKamil Debski } else { 462af935746781088f28904601469671d244d2f653bKamil Debski guard_width = ALIGN(ctx->img_width + 24, 463af935746781088f28904601469671d244d2f653bKamil Debski S5P_FIMV_NV12MT_HALIGN); 464af935746781088f28904601469671d244d2f653bKamil Debski guard_height = ALIGN(ctx->img_height + 16, 465af935746781088f28904601469671d244d2f653bKamil Debski S5P_FIMV_NV12MT_VALIGN); 466af935746781088f28904601469671d244d2f653bKamil Debski ctx->luma_size = ALIGN(guard_width * 467af935746781088f28904601469671d244d2f653bKamil Debski guard_height, S5P_FIMV_DEC_BUF_ALIGN); 468af935746781088f28904601469671d244d2f653bKamil Debski guard_width = ALIGN(ctx->img_width + 16, 469af935746781088f28904601469671d244d2f653bKamil Debski S5P_FIMV_NV12MT_HALIGN); 470af935746781088f28904601469671d244d2f653bKamil Debski guard_height = ALIGN((ctx->img_height >> 1) + 4, 471af935746781088f28904601469671d244d2f653bKamil Debski S5P_FIMV_NV12MT_VALIGN); 472af935746781088f28904601469671d244d2f653bKamil Debski ctx->chroma_size = ALIGN(guard_width * 473af935746781088f28904601469671d244d2f653bKamil Debski guard_height, S5P_FIMV_DEC_BUF_ALIGN); 474af935746781088f28904601469671d244d2f653bKamil Debski ctx->mv_size = 0; 475af935746781088f28904601469671d244d2f653bKamil Debski } 476af935746781088f28904601469671d244d2f653bKamil Debski ctx->dpb_count = s5p_mfc_get_dpb_count(); 477bb869368f36abecc427ffa94193439a05c0aac8dJulia Lawall if (ctx->img_width == 0 || ctx->img_height == 0) 478af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_ERROR; 479af935746781088f28904601469671d244d2f653bKamil Debski else 480af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_HEAD_PARSED; 481af935746781088f28904601469671d244d2f653bKamil Debski } 482af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clear_int_flags(dev); 483af935746781088f28904601469671d244d2f653bKamil Debski clear_work_bit(ctx); 484af935746781088f28904601469671d244d2f653bKamil Debski if (test_and_clear_bit(0, &dev->hw_lock) == 0) 485af935746781088f28904601469671d244d2f653bKamil Debski BUG(); 486af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 487af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_try_run(dev); 488af935746781088f28904601469671d244d2f653bKamil Debski wake_up_ctx(ctx, reason, err); 489af935746781088f28904601469671d244d2f653bKamil Debski} 490af935746781088f28904601469671d244d2f653bKamil Debski 491af935746781088f28904601469671d244d2f653bKamil Debski/* Header parsing interrupt handling */ 492af935746781088f28904601469671d244d2f653bKamil Debskistatic void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, 493af935746781088f28904601469671d244d2f653bKamil Debski unsigned int reason, unsigned int err) 494af935746781088f28904601469671d244d2f653bKamil Debski{ 495af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_buf *src_buf; 496af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev; 497af935746781088f28904601469671d244d2f653bKamil Debski unsigned long flags; 498af935746781088f28904601469671d244d2f653bKamil Debski 499af935746781088f28904601469671d244d2f653bKamil Debski if (ctx == 0) 500af935746781088f28904601469671d244d2f653bKamil Debski return; 501af935746781088f28904601469671d244d2f653bKamil Debski dev = ctx->dev; 502af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clear_int_flags(dev); 503af935746781088f28904601469671d244d2f653bKamil Debski ctx->int_type = reason; 504af935746781088f28904601469671d244d2f653bKamil Debski ctx->int_err = err; 505af935746781088f28904601469671d244d2f653bKamil Debski ctx->int_cond = 1; 506af935746781088f28904601469671d244d2f653bKamil Debski spin_lock(&dev->condlock); 507af935746781088f28904601469671d244d2f653bKamil Debski clear_bit(ctx->num, &dev->ctx_work_bits); 508af935746781088f28904601469671d244d2f653bKamil Debski spin_unlock(&dev->condlock); 509af935746781088f28904601469671d244d2f653bKamil Debski if (err == 0) { 510af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_RUNNING; 511af935746781088f28904601469671d244d2f653bKamil Debski if (!ctx->dpb_flush_flag) { 512af935746781088f28904601469671d244d2f653bKamil Debski spin_lock_irqsave(&dev->irqlock, flags); 513af935746781088f28904601469671d244d2f653bKamil Debski if (!list_empty(&ctx->src_queue)) { 514af935746781088f28904601469671d244d2f653bKamil Debski src_buf = list_entry(ctx->src_queue.next, 515af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_buf, list); 516af935746781088f28904601469671d244d2f653bKamil Debski list_del(&src_buf->list); 517af935746781088f28904601469671d244d2f653bKamil Debski ctx->src_queue_cnt--; 518af935746781088f28904601469671d244d2f653bKamil Debski vb2_buffer_done(src_buf->b, 519af935746781088f28904601469671d244d2f653bKamil Debski VB2_BUF_STATE_DONE); 520af935746781088f28904601469671d244d2f653bKamil Debski } 521af935746781088f28904601469671d244d2f653bKamil Debski spin_unlock_irqrestore(&dev->irqlock, flags); 522af935746781088f28904601469671d244d2f653bKamil Debski } else { 523af935746781088f28904601469671d244d2f653bKamil Debski ctx->dpb_flush_flag = 0; 524af935746781088f28904601469671d244d2f653bKamil Debski } 525af935746781088f28904601469671d244d2f653bKamil Debski if (test_and_clear_bit(0, &dev->hw_lock) == 0) 526af935746781088f28904601469671d244d2f653bKamil Debski BUG(); 527af935746781088f28904601469671d244d2f653bKamil Debski 528af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 529af935746781088f28904601469671d244d2f653bKamil Debski 530af935746781088f28904601469671d244d2f653bKamil Debski wake_up(&ctx->queue); 531af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_try_run(dev); 532af935746781088f28904601469671d244d2f653bKamil Debski } else { 533af935746781088f28904601469671d244d2f653bKamil Debski if (test_and_clear_bit(0, &dev->hw_lock) == 0) 534af935746781088f28904601469671d244d2f653bKamil Debski BUG(); 535af935746781088f28904601469671d244d2f653bKamil Debski 536af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 537af935746781088f28904601469671d244d2f653bKamil Debski 538af935746781088f28904601469671d244d2f653bKamil Debski wake_up(&ctx->queue); 539af935746781088f28904601469671d244d2f653bKamil Debski } 540af935746781088f28904601469671d244d2f653bKamil Debski} 541af935746781088f28904601469671d244d2f653bKamil Debski 542af935746781088f28904601469671d244d2f653bKamil Debski/* Interrupt processing */ 543af935746781088f28904601469671d244d2f653bKamil Debskistatic irqreturn_t s5p_mfc_irq(int irq, void *priv) 544af935746781088f28904601469671d244d2f653bKamil Debski{ 545af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev = priv; 546af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_ctx *ctx; 547af935746781088f28904601469671d244d2f653bKamil Debski unsigned int reason; 548af935746781088f28904601469671d244d2f653bKamil Debski unsigned int err; 549af935746781088f28904601469671d244d2f653bKamil Debski 550af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug_enter(); 551af935746781088f28904601469671d244d2f653bKamil Debski /* Reset the timeout watchdog */ 552af935746781088f28904601469671d244d2f653bKamil Debski atomic_set(&dev->watchdog_cnt, 0); 553af935746781088f28904601469671d244d2f653bKamil Debski ctx = dev->ctx[dev->curr_ctx]; 554af935746781088f28904601469671d244d2f653bKamil Debski /* Get the reason of interrupt and the error code */ 555af935746781088f28904601469671d244d2f653bKamil Debski reason = s5p_mfc_get_int_reason(); 556af935746781088f28904601469671d244d2f653bKamil Debski err = s5p_mfc_get_int_err(); 557af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err); 558af935746781088f28904601469671d244d2f653bKamil Debski switch (reason) { 559af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_R2H_CMD_ERR_RET: 560af935746781088f28904601469671d244d2f653bKamil Debski /* An error has occured */ 561af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->state == MFCINST_RUNNING && 562af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START) 563af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_handle_frame(ctx, reason, err); 564af935746781088f28904601469671d244d2f653bKamil Debski else 565af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_handle_error(ctx, reason, err); 566af935746781088f28904601469671d244d2f653bKamil Debski clear_bit(0, &dev->enter_suspend); 567af935746781088f28904601469671d244d2f653bKamil Debski break; 568af935746781088f28904601469671d244d2f653bKamil Debski 569af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_R2H_CMD_SLICE_DONE_RET: 570af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_R2H_CMD_FRAME_DONE_RET: 571af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->c_ops->post_frame_start) { 572af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->c_ops->post_frame_start(ctx)) 573af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("post_frame_start() failed\n"); 574af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clear_int_flags(dev); 575af935746781088f28904601469671d244d2f653bKamil Debski wake_up_ctx(ctx, reason, err); 576af935746781088f28904601469671d244d2f653bKamil Debski if (test_and_clear_bit(0, &dev->hw_lock) == 0) 577af935746781088f28904601469671d244d2f653bKamil Debski BUG(); 578af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 579af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_try_run(dev); 580af935746781088f28904601469671d244d2f653bKamil Debski } else { 581af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_handle_frame(ctx, reason, err); 582af935746781088f28904601469671d244d2f653bKamil Debski } 583af935746781088f28904601469671d244d2f653bKamil Debski break; 584af935746781088f28904601469671d244d2f653bKamil Debski 585af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_R2H_CMD_SEQ_DONE_RET: 586af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_handle_seq_done(ctx, reason, err); 587af935746781088f28904601469671d244d2f653bKamil Debski break; 588af935746781088f28904601469671d244d2f653bKamil Debski 589af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET: 590af935746781088f28904601469671d244d2f653bKamil Debski ctx->inst_no = s5p_mfc_get_inst_no(); 591af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_GOT_INST; 592af935746781088f28904601469671d244d2f653bKamil Debski clear_work_bit(ctx); 593af935746781088f28904601469671d244d2f653bKamil Debski wake_up(&ctx->queue); 594af935746781088f28904601469671d244d2f653bKamil Debski goto irq_cleanup_hw; 595af935746781088f28904601469671d244d2f653bKamil Debski 596af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET: 597af935746781088f28904601469671d244d2f653bKamil Debski clear_work_bit(ctx); 598af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_FREE; 599af935746781088f28904601469671d244d2f653bKamil Debski wake_up(&ctx->queue); 600af935746781088f28904601469671d244d2f653bKamil Debski goto irq_cleanup_hw; 601af935746781088f28904601469671d244d2f653bKamil Debski 602af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_R2H_CMD_SYS_INIT_RET: 603af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_R2H_CMD_FW_STATUS_RET: 604af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_R2H_CMD_SLEEP_RET: 605af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_R2H_CMD_WAKEUP_RET: 606af935746781088f28904601469671d244d2f653bKamil Debski if (ctx) 607af935746781088f28904601469671d244d2f653bKamil Debski clear_work_bit(ctx); 608af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clear_int_flags(dev); 609af935746781088f28904601469671d244d2f653bKamil Debski wake_up_dev(dev, reason, err); 610af935746781088f28904601469671d244d2f653bKamil Debski clear_bit(0, &dev->hw_lock); 611af935746781088f28904601469671d244d2f653bKamil Debski clear_bit(0, &dev->enter_suspend); 612af935746781088f28904601469671d244d2f653bKamil Debski break; 613af935746781088f28904601469671d244d2f653bKamil Debski 614af935746781088f28904601469671d244d2f653bKamil Debski case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: 615af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_handle_init_buffers(ctx, reason, err); 616af935746781088f28904601469671d244d2f653bKamil Debski break; 617af935746781088f28904601469671d244d2f653bKamil Debski default: 618af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "Unknown int reason\n"); 619af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clear_int_flags(dev); 620af935746781088f28904601469671d244d2f653bKamil Debski } 621af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug_leave(); 622af935746781088f28904601469671d244d2f653bKamil Debski return IRQ_HANDLED; 623af935746781088f28904601469671d244d2f653bKamil Debskiirq_cleanup_hw: 624af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clear_int_flags(dev); 625af935746781088f28904601469671d244d2f653bKamil Debski ctx->int_type = reason; 626af935746781088f28904601469671d244d2f653bKamil Debski ctx->int_err = err; 627af935746781088f28904601469671d244d2f653bKamil Debski ctx->int_cond = 1; 628af935746781088f28904601469671d244d2f653bKamil Debski if (test_and_clear_bit(0, &dev->hw_lock) == 0) 629af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Failed to unlock hw\n"); 630af935746781088f28904601469671d244d2f653bKamil Debski 631af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 632af935746781088f28904601469671d244d2f653bKamil Debski 633af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_try_run(dev); 634af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "Exit via irq_cleanup_hw\n"); 635af935746781088f28904601469671d244d2f653bKamil Debski return IRQ_HANDLED; 636af935746781088f28904601469671d244d2f653bKamil Debski} 637af935746781088f28904601469671d244d2f653bKamil Debski 638af935746781088f28904601469671d244d2f653bKamil Debski/* Open an MFC node */ 639af935746781088f28904601469671d244d2f653bKamil Debskistatic int s5p_mfc_open(struct file *file) 640af935746781088f28904601469671d244d2f653bKamil Debski{ 641af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev = video_drvdata(file); 642af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_ctx *ctx = NULL; 643af935746781088f28904601469671d244d2f653bKamil Debski struct vb2_queue *q; 644af935746781088f28904601469671d244d2f653bKamil Debski unsigned long flags; 645af935746781088f28904601469671d244d2f653bKamil Debski int ret = 0; 646af935746781088f28904601469671d244d2f653bKamil Debski 647af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug_enter(); 648af935746781088f28904601469671d244d2f653bKamil Debski dev->num_inst++; /* It is guarded by mfc_mutex in vfd */ 649af935746781088f28904601469671d244d2f653bKamil Debski /* Allocate memory for context */ 650af935746781088f28904601469671d244d2f653bKamil Debski ctx = kzalloc(sizeof *ctx, GFP_KERNEL); 651af935746781088f28904601469671d244d2f653bKamil Debski if (!ctx) { 652af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Not enough memory\n"); 653af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENOMEM; 654af935746781088f28904601469671d244d2f653bKamil Debski goto err_alloc; 655af935746781088f28904601469671d244d2f653bKamil Debski } 656af935746781088f28904601469671d244d2f653bKamil Debski v4l2_fh_init(&ctx->fh, video_devdata(file)); 657af935746781088f28904601469671d244d2f653bKamil Debski file->private_data = &ctx->fh; 658af935746781088f28904601469671d244d2f653bKamil Debski v4l2_fh_add(&ctx->fh); 659af935746781088f28904601469671d244d2f653bKamil Debski ctx->dev = dev; 660af935746781088f28904601469671d244d2f653bKamil Debski INIT_LIST_HEAD(&ctx->src_queue); 661af935746781088f28904601469671d244d2f653bKamil Debski INIT_LIST_HEAD(&ctx->dst_queue); 662af935746781088f28904601469671d244d2f653bKamil Debski ctx->src_queue_cnt = 0; 663af935746781088f28904601469671d244d2f653bKamil Debski ctx->dst_queue_cnt = 0; 664af935746781088f28904601469671d244d2f653bKamil Debski /* Get context number */ 665af935746781088f28904601469671d244d2f653bKamil Debski ctx->num = 0; 666af935746781088f28904601469671d244d2f653bKamil Debski while (dev->ctx[ctx->num]) { 667af935746781088f28904601469671d244d2f653bKamil Debski ctx->num++; 668af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->num >= MFC_NUM_CONTEXTS) { 669af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Too many open contexts\n"); 670af935746781088f28904601469671d244d2f653bKamil Debski ret = -EBUSY; 671af935746781088f28904601469671d244d2f653bKamil Debski goto err_no_ctx; 672af935746781088f28904601469671d244d2f653bKamil Debski } 673af935746781088f28904601469671d244d2f653bKamil Debski } 674af935746781088f28904601469671d244d2f653bKamil Debski /* Mark context as idle */ 675af935746781088f28904601469671d244d2f653bKamil Debski spin_lock_irqsave(&dev->condlock, flags); 676af935746781088f28904601469671d244d2f653bKamil Debski clear_bit(ctx->num, &dev->ctx_work_bits); 677af935746781088f28904601469671d244d2f653bKamil Debski spin_unlock_irqrestore(&dev->condlock, flags); 678af935746781088f28904601469671d244d2f653bKamil Debski dev->ctx[ctx->num] = ctx; 679af935746781088f28904601469671d244d2f653bKamil Debski if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { 680af935746781088f28904601469671d244d2f653bKamil Debski ctx->type = MFCINST_DECODER; 681af935746781088f28904601469671d244d2f653bKamil Debski ctx->c_ops = get_dec_codec_ops(); 682af935746781088f28904601469671d244d2f653bKamil Debski /* Setup ctrl handler */ 683af935746781088f28904601469671d244d2f653bKamil Debski ret = s5p_mfc_dec_ctrls_setup(ctx); 684af935746781088f28904601469671d244d2f653bKamil Debski if (ret) { 685af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Failed to setup mfc controls\n"); 686af935746781088f28904601469671d244d2f653bKamil Debski goto err_ctrls_setup; 687af935746781088f28904601469671d244d2f653bKamil Debski } 688af935746781088f28904601469671d244d2f653bKamil Debski } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { 689af935746781088f28904601469671d244d2f653bKamil Debski ctx->type = MFCINST_ENCODER; 690af935746781088f28904601469671d244d2f653bKamil Debski ctx->c_ops = get_enc_codec_ops(); 691af935746781088f28904601469671d244d2f653bKamil Debski /* only for encoder */ 692af935746781088f28904601469671d244d2f653bKamil Debski INIT_LIST_HEAD(&ctx->ref_queue); 693af935746781088f28904601469671d244d2f653bKamil Debski ctx->ref_queue_cnt = 0; 694af935746781088f28904601469671d244d2f653bKamil Debski /* Setup ctrl handler */ 695af935746781088f28904601469671d244d2f653bKamil Debski ret = s5p_mfc_enc_ctrls_setup(ctx); 696af935746781088f28904601469671d244d2f653bKamil Debski if (ret) { 697af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Failed to setup mfc controls\n"); 698af935746781088f28904601469671d244d2f653bKamil Debski goto err_ctrls_setup; 699af935746781088f28904601469671d244d2f653bKamil Debski } 700af935746781088f28904601469671d244d2f653bKamil Debski } else { 701af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENOENT; 702af935746781088f28904601469671d244d2f653bKamil Debski goto err_bad_node; 703af935746781088f28904601469671d244d2f653bKamil Debski } 704af935746781088f28904601469671d244d2f653bKamil Debski ctx->fh.ctrl_handler = &ctx->ctrl_handler; 705af935746781088f28904601469671d244d2f653bKamil Debski ctx->inst_no = -1; 706af935746781088f28904601469671d244d2f653bKamil Debski /* Load firmware if this is the first instance */ 707af935746781088f28904601469671d244d2f653bKamil Debski if (dev->num_inst == 1) { 708af935746781088f28904601469671d244d2f653bKamil Debski dev->watchdog_timer.expires = jiffies + 709af935746781088f28904601469671d244d2f653bKamil Debski msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); 710af935746781088f28904601469671d244d2f653bKamil Debski add_timer(&dev->watchdog_timer); 711af935746781088f28904601469671d244d2f653bKamil Debski ret = s5p_mfc_power_on(); 712af935746781088f28904601469671d244d2f653bKamil Debski if (ret < 0) { 713af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("power on failed\n"); 714af935746781088f28904601469671d244d2f653bKamil Debski goto err_pwr_enable; 715af935746781088f28904601469671d244d2f653bKamil Debski } 716af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_on(); 717af935746781088f28904601469671d244d2f653bKamil Debski ret = s5p_mfc_alloc_and_load_firmware(dev); 718af935746781088f28904601469671d244d2f653bKamil Debski if (ret) 719af935746781088f28904601469671d244d2f653bKamil Debski goto err_alloc_fw; 720af935746781088f28904601469671d244d2f653bKamil Debski /* Init the FW */ 721af935746781088f28904601469671d244d2f653bKamil Debski ret = s5p_mfc_init_hw(dev); 722af935746781088f28904601469671d244d2f653bKamil Debski if (ret) 723af935746781088f28904601469671d244d2f653bKamil Debski goto err_init_hw; 724af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 725af935746781088f28904601469671d244d2f653bKamil Debski } 726af935746781088f28904601469671d244d2f653bKamil Debski /* Init videobuf2 queue for CAPTURE */ 727af935746781088f28904601469671d244d2f653bKamil Debski q = &ctx->vq_dst; 728af935746781088f28904601469671d244d2f653bKamil Debski q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 729af935746781088f28904601469671d244d2f653bKamil Debski q->drv_priv = &ctx->fh; 730af935746781088f28904601469671d244d2f653bKamil Debski if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { 731af935746781088f28904601469671d244d2f653bKamil Debski q->io_modes = VB2_MMAP; 732af935746781088f28904601469671d244d2f653bKamil Debski q->ops = get_dec_queue_ops(); 733af935746781088f28904601469671d244d2f653bKamil Debski } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { 734af935746781088f28904601469671d244d2f653bKamil Debski q->io_modes = VB2_MMAP | VB2_USERPTR; 735af935746781088f28904601469671d244d2f653bKamil Debski q->ops = get_enc_queue_ops(); 736af935746781088f28904601469671d244d2f653bKamil Debski } else { 737af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENOENT; 738af935746781088f28904601469671d244d2f653bKamil Debski goto err_queue_init; 739af935746781088f28904601469671d244d2f653bKamil Debski } 740af935746781088f28904601469671d244d2f653bKamil Debski q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; 741af935746781088f28904601469671d244d2f653bKamil Debski ret = vb2_queue_init(q); 742af935746781088f28904601469671d244d2f653bKamil Debski if (ret) { 743af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Failed to initialize videobuf2 queue(capture)\n"); 744af935746781088f28904601469671d244d2f653bKamil Debski goto err_queue_init; 745af935746781088f28904601469671d244d2f653bKamil Debski } 746af935746781088f28904601469671d244d2f653bKamil Debski /* Init videobuf2 queue for OUTPUT */ 747af935746781088f28904601469671d244d2f653bKamil Debski q = &ctx->vq_src; 748af935746781088f28904601469671d244d2f653bKamil Debski q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 749af935746781088f28904601469671d244d2f653bKamil Debski q->io_modes = VB2_MMAP; 750af935746781088f28904601469671d244d2f653bKamil Debski q->drv_priv = &ctx->fh; 751af935746781088f28904601469671d244d2f653bKamil Debski if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { 752af935746781088f28904601469671d244d2f653bKamil Debski q->io_modes = VB2_MMAP; 753af935746781088f28904601469671d244d2f653bKamil Debski q->ops = get_dec_queue_ops(); 754af935746781088f28904601469671d244d2f653bKamil Debski } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { 755af935746781088f28904601469671d244d2f653bKamil Debski q->io_modes = VB2_MMAP | VB2_USERPTR; 756af935746781088f28904601469671d244d2f653bKamil Debski q->ops = get_enc_queue_ops(); 757af935746781088f28904601469671d244d2f653bKamil Debski } else { 758af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENOENT; 759af935746781088f28904601469671d244d2f653bKamil Debski goto err_queue_init; 760af935746781088f28904601469671d244d2f653bKamil Debski } 761af935746781088f28904601469671d244d2f653bKamil Debski q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; 762af935746781088f28904601469671d244d2f653bKamil Debski ret = vb2_queue_init(q); 763af935746781088f28904601469671d244d2f653bKamil Debski if (ret) { 764af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Failed to initialize videobuf2 queue(output)\n"); 765af935746781088f28904601469671d244d2f653bKamil Debski goto err_queue_init; 766af935746781088f28904601469671d244d2f653bKamil Debski } 767af935746781088f28904601469671d244d2f653bKamil Debski init_waitqueue_head(&ctx->queue); 768af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug_leave(); 769af935746781088f28904601469671d244d2f653bKamil Debski return ret; 770af935746781088f28904601469671d244d2f653bKamil Debski /* Deinit when failure occured */ 771af935746781088f28904601469671d244d2f653bKamil Debskierr_queue_init: 772af935746781088f28904601469671d244d2f653bKamil Debskierr_init_hw: 773af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_release_firmware(dev); 774af935746781088f28904601469671d244d2f653bKamil Debskierr_alloc_fw: 775af935746781088f28904601469671d244d2f653bKamil Debski dev->ctx[ctx->num] = 0; 776af935746781088f28904601469671d244d2f653bKamil Debski del_timer_sync(&dev->watchdog_timer); 777af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 778af935746781088f28904601469671d244d2f653bKamil Debskierr_pwr_enable: 779af935746781088f28904601469671d244d2f653bKamil Debski if (dev->num_inst == 1) { 780af935746781088f28904601469671d244d2f653bKamil Debski if (s5p_mfc_power_off() < 0) 781af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("power off failed\n"); 782af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_release_firmware(dev); 783af935746781088f28904601469671d244d2f653bKamil Debski } 784af935746781088f28904601469671d244d2f653bKamil Debskierr_ctrls_setup: 785af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_dec_ctrls_delete(ctx); 786af935746781088f28904601469671d244d2f653bKamil Debskierr_bad_node: 787af935746781088f28904601469671d244d2f653bKamil Debskierr_no_ctx: 788af935746781088f28904601469671d244d2f653bKamil Debski v4l2_fh_del(&ctx->fh); 789af935746781088f28904601469671d244d2f653bKamil Debski v4l2_fh_exit(&ctx->fh); 790af935746781088f28904601469671d244d2f653bKamil Debski kfree(ctx); 791af935746781088f28904601469671d244d2f653bKamil Debskierr_alloc: 792af935746781088f28904601469671d244d2f653bKamil Debski dev->num_inst--; 793af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug_leave(); 794af935746781088f28904601469671d244d2f653bKamil Debski return ret; 795af935746781088f28904601469671d244d2f653bKamil Debski} 796af935746781088f28904601469671d244d2f653bKamil Debski 797af935746781088f28904601469671d244d2f653bKamil Debski/* Release MFC context */ 798af935746781088f28904601469671d244d2f653bKamil Debskistatic int s5p_mfc_release(struct file *file) 799af935746781088f28904601469671d244d2f653bKamil Debski{ 800af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); 801af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev = ctx->dev; 802af935746781088f28904601469671d244d2f653bKamil Debski unsigned long flags; 803af935746781088f28904601469671d244d2f653bKamil Debski 804af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug_enter(); 805af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_on(); 806af935746781088f28904601469671d244d2f653bKamil Debski vb2_queue_release(&ctx->vq_src); 807af935746781088f28904601469671d244d2f653bKamil Debski vb2_queue_release(&ctx->vq_dst); 808af935746781088f28904601469671d244d2f653bKamil Debski /* Mark context as idle */ 809af935746781088f28904601469671d244d2f653bKamil Debski spin_lock_irqsave(&dev->condlock, flags); 810af935746781088f28904601469671d244d2f653bKamil Debski clear_bit(ctx->num, &dev->ctx_work_bits); 811af935746781088f28904601469671d244d2f653bKamil Debski spin_unlock_irqrestore(&dev->condlock, flags); 812af935746781088f28904601469671d244d2f653bKamil Debski /* If instance was initialised then 813af935746781088f28904601469671d244d2f653bKamil Debski * return instance and free reosurces */ 814af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->inst_no != MFC_NO_INSTANCE_SET) { 815af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "Has to free instance\n"); 816af935746781088f28904601469671d244d2f653bKamil Debski ctx->state = MFCINST_RETURN_INST; 817af935746781088f28904601469671d244d2f653bKamil Debski spin_lock_irqsave(&dev->condlock, flags); 818af935746781088f28904601469671d244d2f653bKamil Debski set_bit(ctx->num, &dev->ctx_work_bits); 819af935746781088f28904601469671d244d2f653bKamil Debski spin_unlock_irqrestore(&dev->condlock, flags); 820af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clean_ctx_int_flags(ctx); 821af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_try_run(dev); 822af935746781088f28904601469671d244d2f653bKamil Debski /* Wait until instance is returned or timeout occured */ 823af935746781088f28904601469671d244d2f653bKamil Debski if (s5p_mfc_wait_for_done_ctx 824af935746781088f28904601469671d244d2f653bKamil Debski (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET, 0)) { 825af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 826af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Err returning instance\n"); 827af935746781088f28904601469671d244d2f653bKamil Debski } 828af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "After free instance\n"); 829af935746781088f28904601469671d244d2f653bKamil Debski /* Free resources */ 830af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_release_codec_buffers(ctx); 831af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_release_instance_buffer(ctx); 832af935746781088f28904601469671d244d2f653bKamil Debski if (ctx->type == MFCINST_DECODER) 833af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_release_dec_desc_buffer(ctx); 834af935746781088f28904601469671d244d2f653bKamil Debski 835af935746781088f28904601469671d244d2f653bKamil Debski ctx->inst_no = MFC_NO_INSTANCE_SET; 836af935746781088f28904601469671d244d2f653bKamil Debski } 837af935746781088f28904601469671d244d2f653bKamil Debski /* hardware locking scheme */ 838af935746781088f28904601469671d244d2f653bKamil Debski if (dev->curr_ctx == ctx->num) 839af935746781088f28904601469671d244d2f653bKamil Debski clear_bit(0, &dev->hw_lock); 840af935746781088f28904601469671d244d2f653bKamil Debski dev->num_inst--; 841af935746781088f28904601469671d244d2f653bKamil Debski if (dev->num_inst == 0) { 842af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "Last instance - release firmware\n"); 843af935746781088f28904601469671d244d2f653bKamil Debski /* reset <-> F/W release */ 844af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_reset(dev); 845af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_release_firmware(dev); 846af935746781088f28904601469671d244d2f653bKamil Debski del_timer_sync(&dev->watchdog_timer); 847af935746781088f28904601469671d244d2f653bKamil Debski if (s5p_mfc_power_off() < 0) 848af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Power off failed\n"); 849af935746781088f28904601469671d244d2f653bKamil Debski } 850af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "Shutting down clock\n"); 851af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_clock_off(); 852af935746781088f28904601469671d244d2f653bKamil Debski dev->ctx[ctx->num] = 0; 853af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_dec_ctrls_delete(ctx); 854af935746781088f28904601469671d244d2f653bKamil Debski v4l2_fh_del(&ctx->fh); 855af935746781088f28904601469671d244d2f653bKamil Debski v4l2_fh_exit(&ctx->fh); 856af935746781088f28904601469671d244d2f653bKamil Debski kfree(ctx); 857af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug_leave(); 858af935746781088f28904601469671d244d2f653bKamil Debski return 0; 859af935746781088f28904601469671d244d2f653bKamil Debski} 860af935746781088f28904601469671d244d2f653bKamil Debski 861af935746781088f28904601469671d244d2f653bKamil Debski/* Poll */ 862af935746781088f28904601469671d244d2f653bKamil Debskistatic unsigned int s5p_mfc_poll(struct file *file, 863af935746781088f28904601469671d244d2f653bKamil Debski struct poll_table_struct *wait) 864af935746781088f28904601469671d244d2f653bKamil Debski{ 865af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); 866af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev = ctx->dev; 867af935746781088f28904601469671d244d2f653bKamil Debski struct vb2_queue *src_q, *dst_q; 868af935746781088f28904601469671d244d2f653bKamil Debski struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; 869af935746781088f28904601469671d244d2f653bKamil Debski unsigned int rc = 0; 870af935746781088f28904601469671d244d2f653bKamil Debski unsigned long flags; 871af935746781088f28904601469671d244d2f653bKamil Debski 872af935746781088f28904601469671d244d2f653bKamil Debski src_q = &ctx->vq_src; 873af935746781088f28904601469671d244d2f653bKamil Debski dst_q = &ctx->vq_dst; 874af935746781088f28904601469671d244d2f653bKamil Debski /* 875af935746781088f28904601469671d244d2f653bKamil Debski * There has to be at least one buffer queued on each queued_list, which 876af935746781088f28904601469671d244d2f653bKamil Debski * means either in driver already or waiting for driver to claim it 877af935746781088f28904601469671d244d2f653bKamil Debski * and start processing. 878af935746781088f28904601469671d244d2f653bKamil Debski */ 879af935746781088f28904601469671d244d2f653bKamil Debski if ((!src_q->streaming || list_empty(&src_q->queued_list)) 880af935746781088f28904601469671d244d2f653bKamil Debski && (!dst_q->streaming || list_empty(&dst_q->queued_list))) { 881af935746781088f28904601469671d244d2f653bKamil Debski rc = POLLERR; 882af935746781088f28904601469671d244d2f653bKamil Debski goto end; 883af935746781088f28904601469671d244d2f653bKamil Debski } 884af935746781088f28904601469671d244d2f653bKamil Debski mutex_unlock(&dev->mfc_mutex); 885af935746781088f28904601469671d244d2f653bKamil Debski poll_wait(file, &src_q->done_wq, wait); 886af935746781088f28904601469671d244d2f653bKamil Debski poll_wait(file, &dst_q->done_wq, wait); 887af935746781088f28904601469671d244d2f653bKamil Debski mutex_lock(&dev->mfc_mutex); 888af935746781088f28904601469671d244d2f653bKamil Debski spin_lock_irqsave(&src_q->done_lock, flags); 889af935746781088f28904601469671d244d2f653bKamil Debski if (!list_empty(&src_q->done_list)) 890af935746781088f28904601469671d244d2f653bKamil Debski src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer, 891af935746781088f28904601469671d244d2f653bKamil Debski done_entry); 892af935746781088f28904601469671d244d2f653bKamil Debski if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE 893af935746781088f28904601469671d244d2f653bKamil Debski || src_vb->state == VB2_BUF_STATE_ERROR)) 894af935746781088f28904601469671d244d2f653bKamil Debski rc |= POLLOUT | POLLWRNORM; 895af935746781088f28904601469671d244d2f653bKamil Debski spin_unlock_irqrestore(&src_q->done_lock, flags); 896af935746781088f28904601469671d244d2f653bKamil Debski spin_lock_irqsave(&dst_q->done_lock, flags); 897af935746781088f28904601469671d244d2f653bKamil Debski if (!list_empty(&dst_q->done_list)) 898af935746781088f28904601469671d244d2f653bKamil Debski dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer, 899af935746781088f28904601469671d244d2f653bKamil Debski done_entry); 900af935746781088f28904601469671d244d2f653bKamil Debski if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE 901af935746781088f28904601469671d244d2f653bKamil Debski || dst_vb->state == VB2_BUF_STATE_ERROR)) 902af935746781088f28904601469671d244d2f653bKamil Debski rc |= POLLIN | POLLRDNORM; 903af935746781088f28904601469671d244d2f653bKamil Debski spin_unlock_irqrestore(&dst_q->done_lock, flags); 904af935746781088f28904601469671d244d2f653bKamil Debskiend: 905af935746781088f28904601469671d244d2f653bKamil Debski return rc; 906af935746781088f28904601469671d244d2f653bKamil Debski} 907af935746781088f28904601469671d244d2f653bKamil Debski 908af935746781088f28904601469671d244d2f653bKamil Debski/* Mmap */ 909af935746781088f28904601469671d244d2f653bKamil Debskistatic int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma) 910af935746781088f28904601469671d244d2f653bKamil Debski{ 911af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); 912af935746781088f28904601469671d244d2f653bKamil Debski unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 913af935746781088f28904601469671d244d2f653bKamil Debski int ret; 914af935746781088f28904601469671d244d2f653bKamil Debski if (offset < DST_QUEUE_OFF_BASE) { 915af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "mmaping source\n"); 916af935746781088f28904601469671d244d2f653bKamil Debski ret = vb2_mmap(&ctx->vq_src, vma); 917af935746781088f28904601469671d244d2f653bKamil Debski } else { /* capture */ 918af935746781088f28904601469671d244d2f653bKamil Debski mfc_debug(2, "mmaping destination\n"); 919af935746781088f28904601469671d244d2f653bKamil Debski vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT); 920af935746781088f28904601469671d244d2f653bKamil Debski ret = vb2_mmap(&ctx->vq_dst, vma); 921af935746781088f28904601469671d244d2f653bKamil Debski } 922af935746781088f28904601469671d244d2f653bKamil Debski return ret; 923af935746781088f28904601469671d244d2f653bKamil Debski} 924af935746781088f28904601469671d244d2f653bKamil Debski 925af935746781088f28904601469671d244d2f653bKamil Debski/* v4l2 ops */ 926af935746781088f28904601469671d244d2f653bKamil Debskistatic const struct v4l2_file_operations s5p_mfc_fops = { 927af935746781088f28904601469671d244d2f653bKamil Debski .owner = THIS_MODULE, 928af935746781088f28904601469671d244d2f653bKamil Debski .open = s5p_mfc_open, 929af935746781088f28904601469671d244d2f653bKamil Debski .release = s5p_mfc_release, 930af935746781088f28904601469671d244d2f653bKamil Debski .poll = s5p_mfc_poll, 931af935746781088f28904601469671d244d2f653bKamil Debski .unlocked_ioctl = video_ioctl2, 932af935746781088f28904601469671d244d2f653bKamil Debski .mmap = s5p_mfc_mmap, 933af935746781088f28904601469671d244d2f653bKamil Debski}; 934af935746781088f28904601469671d244d2f653bKamil Debski 935af935746781088f28904601469671d244d2f653bKamil Debskistatic int match_child(struct device *dev, void *data) 936af935746781088f28904601469671d244d2f653bKamil Debski{ 937af935746781088f28904601469671d244d2f653bKamil Debski if (!dev_name(dev)) 938af935746781088f28904601469671d244d2f653bKamil Debski return 0; 939af935746781088f28904601469671d244d2f653bKamil Debski return !strcmp(dev_name(dev), (char *)data); 940af935746781088f28904601469671d244d2f653bKamil Debski} 941af935746781088f28904601469671d244d2f653bKamil Debski 942af935746781088f28904601469671d244d2f653bKamil Debski/* MFC probe function */ 9431e393e90ab444dd24d28448e92bab099703fd006Kamil Debskistatic int s5p_mfc_probe(struct platform_device *pdev) 944af935746781088f28904601469671d244d2f653bKamil Debski{ 945af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev; 946af935746781088f28904601469671d244d2f653bKamil Debski struct video_device *vfd; 947af935746781088f28904601469671d244d2f653bKamil Debski struct resource *res; 948af935746781088f28904601469671d244d2f653bKamil Debski int ret; 949af935746781088f28904601469671d244d2f653bKamil Debski 950af935746781088f28904601469671d244d2f653bKamil Debski pr_debug("%s++\n", __func__); 951af935746781088f28904601469671d244d2f653bKamil Debski dev = kzalloc(sizeof *dev, GFP_KERNEL); 952af935746781088f28904601469671d244d2f653bKamil Debski if (!dev) { 953af935746781088f28904601469671d244d2f653bKamil Debski dev_err(&pdev->dev, "Not enough memory for MFC device\n"); 954af935746781088f28904601469671d244d2f653bKamil Debski return -ENOMEM; 955af935746781088f28904601469671d244d2f653bKamil Debski } 956af935746781088f28904601469671d244d2f653bKamil Debski 957af935746781088f28904601469671d244d2f653bKamil Debski spin_lock_init(&dev->irqlock); 958af935746781088f28904601469671d244d2f653bKamil Debski spin_lock_init(&dev->condlock); 959af935746781088f28904601469671d244d2f653bKamil Debski dev->plat_dev = pdev; 960af935746781088f28904601469671d244d2f653bKamil Debski if (!dev->plat_dev) { 961af935746781088f28904601469671d244d2f653bKamil Debski dev_err(&pdev->dev, "No platform data specified\n"); 962af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENODEV; 963af935746781088f28904601469671d244d2f653bKamil Debski goto err_dev; 964af935746781088f28904601469671d244d2f653bKamil Debski } 965af935746781088f28904601469671d244d2f653bKamil Debski 966af935746781088f28904601469671d244d2f653bKamil Debski ret = s5p_mfc_init_pm(dev); 967af935746781088f28904601469671d244d2f653bKamil Debski if (ret < 0) { 968af935746781088f28904601469671d244d2f653bKamil Debski dev_err(&pdev->dev, "failed to get mfc clock source\n"); 969af935746781088f28904601469671d244d2f653bKamil Debski goto err_clk; 970af935746781088f28904601469671d244d2f653bKamil Debski } 971af935746781088f28904601469671d244d2f653bKamil Debski 972af935746781088f28904601469671d244d2f653bKamil Debski res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 973af935746781088f28904601469671d244d2f653bKamil Debski if (res == NULL) { 974af935746781088f28904601469671d244d2f653bKamil Debski dev_err(&pdev->dev, "failed to get memory region resource\n"); 975af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENOENT; 976af935746781088f28904601469671d244d2f653bKamil Debski goto err_res; 977af935746781088f28904601469671d244d2f653bKamil Debski } 978af935746781088f28904601469671d244d2f653bKamil Debski 979af935746781088f28904601469671d244d2f653bKamil Debski dev->mfc_mem = request_mem_region(res->start, resource_size(res), 980af935746781088f28904601469671d244d2f653bKamil Debski pdev->name); 981af935746781088f28904601469671d244d2f653bKamil Debski if (dev->mfc_mem == NULL) { 982af935746781088f28904601469671d244d2f653bKamil Debski dev_err(&pdev->dev, "failed to get memory region\n"); 983af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENOENT; 984af935746781088f28904601469671d244d2f653bKamil Debski goto err_mem_reg; 985af935746781088f28904601469671d244d2f653bKamil Debski } 986af935746781088f28904601469671d244d2f653bKamil Debski dev->regs_base = ioremap(dev->mfc_mem->start, resource_size(dev->mfc_mem)); 987af935746781088f28904601469671d244d2f653bKamil Debski if (dev->regs_base == NULL) { 988af935746781088f28904601469671d244d2f653bKamil Debski dev_err(&pdev->dev, "failed to ioremap address region\n"); 989af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENOENT; 990af935746781088f28904601469671d244d2f653bKamil Debski goto err_ioremap; 991af935746781088f28904601469671d244d2f653bKamil Debski } 992af935746781088f28904601469671d244d2f653bKamil Debski 993af935746781088f28904601469671d244d2f653bKamil Debski res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 994af935746781088f28904601469671d244d2f653bKamil Debski if (res == NULL) { 995af935746781088f28904601469671d244d2f653bKamil Debski dev_err(&pdev->dev, "failed to get irq resource\n"); 996af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENOENT; 997af935746781088f28904601469671d244d2f653bKamil Debski goto err_get_res; 998af935746781088f28904601469671d244d2f653bKamil Debski } 999af935746781088f28904601469671d244d2f653bKamil Debski dev->irq = res->start; 1000af935746781088f28904601469671d244d2f653bKamil Debski ret = request_irq(dev->irq, s5p_mfc_irq, IRQF_DISABLED, pdev->name, 1001af935746781088f28904601469671d244d2f653bKamil Debski dev); 1002af935746781088f28904601469671d244d2f653bKamil Debski if (ret) { 1003af935746781088f28904601469671d244d2f653bKamil Debski dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret); 1004af935746781088f28904601469671d244d2f653bKamil Debski goto err_req_irq; 1005af935746781088f28904601469671d244d2f653bKamil Debski } 1006af935746781088f28904601469671d244d2f653bKamil Debski 1007af935746781088f28904601469671d244d2f653bKamil Debski dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, "s5p-mfc-l", 1008af935746781088f28904601469671d244d2f653bKamil Debski match_child); 1009af935746781088f28904601469671d244d2f653bKamil Debski if (!dev->mem_dev_l) { 1010af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Mem child (L) device get failed\n"); 1011af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENODEV; 1012af935746781088f28904601469671d244d2f653bKamil Debski goto err_find_child; 1013af935746781088f28904601469671d244d2f653bKamil Debski } 1014af935746781088f28904601469671d244d2f653bKamil Debski dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r", 1015af935746781088f28904601469671d244d2f653bKamil Debski match_child); 1016af935746781088f28904601469671d244d2f653bKamil Debski if (!dev->mem_dev_r) { 1017af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Mem child (R) device get failed\n"); 1018af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENODEV; 1019af935746781088f28904601469671d244d2f653bKamil Debski goto err_find_child; 1020af935746781088f28904601469671d244d2f653bKamil Debski } 1021af935746781088f28904601469671d244d2f653bKamil Debski 1022af935746781088f28904601469671d244d2f653bKamil Debski dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l); 1023af935746781088f28904601469671d244d2f653bKamil Debski if (IS_ERR_OR_NULL(dev->alloc_ctx[0])) { 1024af935746781088f28904601469671d244d2f653bKamil Debski ret = PTR_ERR(dev->alloc_ctx[0]); 1025af935746781088f28904601469671d244d2f653bKamil Debski goto err_mem_init_ctx_0; 1026af935746781088f28904601469671d244d2f653bKamil Debski } 1027af935746781088f28904601469671d244d2f653bKamil Debski dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r); 1028af935746781088f28904601469671d244d2f653bKamil Debski if (IS_ERR_OR_NULL(dev->alloc_ctx[1])) { 1029af935746781088f28904601469671d244d2f653bKamil Debski ret = PTR_ERR(dev->alloc_ctx[1]); 1030af935746781088f28904601469671d244d2f653bKamil Debski goto err_mem_init_ctx_1; 1031af935746781088f28904601469671d244d2f653bKamil Debski } 1032af935746781088f28904601469671d244d2f653bKamil Debski 1033af935746781088f28904601469671d244d2f653bKamil Debski mutex_init(&dev->mfc_mutex); 1034af935746781088f28904601469671d244d2f653bKamil Debski 1035af935746781088f28904601469671d244d2f653bKamil Debski ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); 1036af935746781088f28904601469671d244d2f653bKamil Debski if (ret) 1037af935746781088f28904601469671d244d2f653bKamil Debski goto err_v4l2_dev_reg; 1038af935746781088f28904601469671d244d2f653bKamil Debski init_waitqueue_head(&dev->queue); 1039af935746781088f28904601469671d244d2f653bKamil Debski 1040af935746781088f28904601469671d244d2f653bKamil Debski /* decoder */ 1041af935746781088f28904601469671d244d2f653bKamil Debski vfd = video_device_alloc(); 1042af935746781088f28904601469671d244d2f653bKamil Debski if (!vfd) { 1043af935746781088f28904601469671d244d2f653bKamil Debski v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); 1044af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENOMEM; 1045af935746781088f28904601469671d244d2f653bKamil Debski goto err_dec_alloc; 1046af935746781088f28904601469671d244d2f653bKamil Debski } 1047af935746781088f28904601469671d244d2f653bKamil Debski vfd->fops = &s5p_mfc_fops, 1048af935746781088f28904601469671d244d2f653bKamil Debski vfd->ioctl_ops = get_dec_v4l2_ioctl_ops(); 1049af935746781088f28904601469671d244d2f653bKamil Debski vfd->release = video_device_release, 1050af935746781088f28904601469671d244d2f653bKamil Debski vfd->lock = &dev->mfc_mutex; 1051af935746781088f28904601469671d244d2f653bKamil Debski vfd->v4l2_dev = &dev->v4l2_dev; 1052af935746781088f28904601469671d244d2f653bKamil Debski snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME); 1053af935746781088f28904601469671d244d2f653bKamil Debski dev->vfd_dec = vfd; 1054af935746781088f28904601469671d244d2f653bKamil Debski ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); 1055af935746781088f28904601469671d244d2f653bKamil Debski if (ret) { 1056af935746781088f28904601469671d244d2f653bKamil Debski v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); 1057af935746781088f28904601469671d244d2f653bKamil Debski video_device_release(vfd); 1058af935746781088f28904601469671d244d2f653bKamil Debski goto err_dec_reg; 1059af935746781088f28904601469671d244d2f653bKamil Debski } 1060af935746781088f28904601469671d244d2f653bKamil Debski v4l2_info(&dev->v4l2_dev, 1061af935746781088f28904601469671d244d2f653bKamil Debski "decoder registered as /dev/video%d\n", vfd->num); 1062af935746781088f28904601469671d244d2f653bKamil Debski video_set_drvdata(vfd, dev); 1063af935746781088f28904601469671d244d2f653bKamil Debski 1064af935746781088f28904601469671d244d2f653bKamil Debski /* encoder */ 1065af935746781088f28904601469671d244d2f653bKamil Debski vfd = video_device_alloc(); 1066af935746781088f28904601469671d244d2f653bKamil Debski if (!vfd) { 1067af935746781088f28904601469671d244d2f653bKamil Debski v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); 1068af935746781088f28904601469671d244d2f653bKamil Debski ret = -ENOMEM; 1069af935746781088f28904601469671d244d2f653bKamil Debski goto err_enc_alloc; 1070af935746781088f28904601469671d244d2f653bKamil Debski } 1071af935746781088f28904601469671d244d2f653bKamil Debski vfd->fops = &s5p_mfc_fops, 1072af935746781088f28904601469671d244d2f653bKamil Debski vfd->ioctl_ops = get_enc_v4l2_ioctl_ops(); 1073af935746781088f28904601469671d244d2f653bKamil Debski vfd->release = video_device_release, 1074af935746781088f28904601469671d244d2f653bKamil Debski vfd->lock = &dev->mfc_mutex; 1075af935746781088f28904601469671d244d2f653bKamil Debski vfd->v4l2_dev = &dev->v4l2_dev; 1076af935746781088f28904601469671d244d2f653bKamil Debski snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME); 1077af935746781088f28904601469671d244d2f653bKamil Debski dev->vfd_enc = vfd; 1078af935746781088f28904601469671d244d2f653bKamil Debski ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); 1079af935746781088f28904601469671d244d2f653bKamil Debski if (ret) { 1080af935746781088f28904601469671d244d2f653bKamil Debski v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); 1081af935746781088f28904601469671d244d2f653bKamil Debski video_device_release(vfd); 1082af935746781088f28904601469671d244d2f653bKamil Debski goto err_enc_reg; 1083af935746781088f28904601469671d244d2f653bKamil Debski } 1084af935746781088f28904601469671d244d2f653bKamil Debski v4l2_info(&dev->v4l2_dev, 1085af935746781088f28904601469671d244d2f653bKamil Debski "encoder registered as /dev/video%d\n", vfd->num); 1086af935746781088f28904601469671d244d2f653bKamil Debski video_set_drvdata(vfd, dev); 1087af935746781088f28904601469671d244d2f653bKamil Debski platform_set_drvdata(pdev, dev); 1088af935746781088f28904601469671d244d2f653bKamil Debski 1089af935746781088f28904601469671d244d2f653bKamil Debski dev->hw_lock = 0; 1090af935746781088f28904601469671d244d2f653bKamil Debski dev->watchdog_workqueue = create_singlethread_workqueue(S5P_MFC_NAME); 1091af935746781088f28904601469671d244d2f653bKamil Debski INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker); 1092af935746781088f28904601469671d244d2f653bKamil Debski atomic_set(&dev->watchdog_cnt, 0); 1093af935746781088f28904601469671d244d2f653bKamil Debski init_timer(&dev->watchdog_timer); 1094af935746781088f28904601469671d244d2f653bKamil Debski dev->watchdog_timer.data = (unsigned long)dev; 1095af935746781088f28904601469671d244d2f653bKamil Debski dev->watchdog_timer.function = s5p_mfc_watchdog; 1096af935746781088f28904601469671d244d2f653bKamil Debski 1097af935746781088f28904601469671d244d2f653bKamil Debski pr_debug("%s--\n", __func__); 1098af935746781088f28904601469671d244d2f653bKamil Debski return 0; 1099af935746781088f28904601469671d244d2f653bKamil Debski 1100af935746781088f28904601469671d244d2f653bKamil Debski/* Deinit MFC if probe had failed */ 1101af935746781088f28904601469671d244d2f653bKamil Debskierr_enc_reg: 1102af935746781088f28904601469671d244d2f653bKamil Debski video_device_release(dev->vfd_enc); 1103af935746781088f28904601469671d244d2f653bKamil Debskierr_enc_alloc: 1104af935746781088f28904601469671d244d2f653bKamil Debski video_unregister_device(dev->vfd_dec); 1105af935746781088f28904601469671d244d2f653bKamil Debskierr_dec_reg: 1106af935746781088f28904601469671d244d2f653bKamil Debski video_device_release(dev->vfd_dec); 1107af935746781088f28904601469671d244d2f653bKamil Debskierr_dec_alloc: 1108af935746781088f28904601469671d244d2f653bKamil Debski v4l2_device_unregister(&dev->v4l2_dev); 1109af935746781088f28904601469671d244d2f653bKamil Debskierr_v4l2_dev_reg: 1110af935746781088f28904601469671d244d2f653bKamil Debski vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]); 1111af935746781088f28904601469671d244d2f653bKamil Debskierr_mem_init_ctx_1: 1112af935746781088f28904601469671d244d2f653bKamil Debski vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]); 1113af935746781088f28904601469671d244d2f653bKamil Debskierr_mem_init_ctx_0: 1114af935746781088f28904601469671d244d2f653bKamil Debskierr_find_child: 1115af935746781088f28904601469671d244d2f653bKamil Debski free_irq(dev->irq, dev); 1116af935746781088f28904601469671d244d2f653bKamil Debskierr_req_irq: 1117af935746781088f28904601469671d244d2f653bKamil Debskierr_get_res: 1118af935746781088f28904601469671d244d2f653bKamil Debski iounmap(dev->regs_base); 1119af935746781088f28904601469671d244d2f653bKamil Debski dev->regs_base = NULL; 1120af935746781088f28904601469671d244d2f653bKamil Debskierr_ioremap: 1121af935746781088f28904601469671d244d2f653bKamil Debski release_resource(dev->mfc_mem); 1122af935746781088f28904601469671d244d2f653bKamil Debski kfree(dev->mfc_mem); 1123af935746781088f28904601469671d244d2f653bKamil Debskierr_mem_reg: 1124af935746781088f28904601469671d244d2f653bKamil Debskierr_res: 1125af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_final_pm(dev); 1126af935746781088f28904601469671d244d2f653bKamil Debskierr_clk: 1127af935746781088f28904601469671d244d2f653bKamil Debskierr_dev: 1128af935746781088f28904601469671d244d2f653bKamil Debski kfree(dev); 1129af935746781088f28904601469671d244d2f653bKamil Debski pr_debug("%s-- with error\n", __func__); 1130af935746781088f28904601469671d244d2f653bKamil Debski return ret; 1131af935746781088f28904601469671d244d2f653bKamil Debski 1132af935746781088f28904601469671d244d2f653bKamil Debski} 1133af935746781088f28904601469671d244d2f653bKamil Debski 1134af935746781088f28904601469671d244d2f653bKamil Debski/* Remove the driver */ 1135af935746781088f28904601469671d244d2f653bKamil Debskistatic int __devexit s5p_mfc_remove(struct platform_device *pdev) 1136af935746781088f28904601469671d244d2f653bKamil Debski{ 1137af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *dev = platform_get_drvdata(pdev); 1138af935746781088f28904601469671d244d2f653bKamil Debski 1139af935746781088f28904601469671d244d2f653bKamil Debski v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name); 1140af935746781088f28904601469671d244d2f653bKamil Debski 1141af935746781088f28904601469671d244d2f653bKamil Debski del_timer_sync(&dev->watchdog_timer); 1142af935746781088f28904601469671d244d2f653bKamil Debski flush_workqueue(dev->watchdog_workqueue); 1143af935746781088f28904601469671d244d2f653bKamil Debski destroy_workqueue(dev->watchdog_workqueue); 1144af935746781088f28904601469671d244d2f653bKamil Debski 1145af935746781088f28904601469671d244d2f653bKamil Debski video_unregister_device(dev->vfd_enc); 1146af935746781088f28904601469671d244d2f653bKamil Debski video_unregister_device(dev->vfd_dec); 1147af935746781088f28904601469671d244d2f653bKamil Debski v4l2_device_unregister(&dev->v4l2_dev); 1148af935746781088f28904601469671d244d2f653bKamil Debski vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]); 1149af935746781088f28904601469671d244d2f653bKamil Debski vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]); 1150af935746781088f28904601469671d244d2f653bKamil Debski 1151af935746781088f28904601469671d244d2f653bKamil Debski free_irq(dev->irq, dev); 1152af935746781088f28904601469671d244d2f653bKamil Debski iounmap(dev->regs_base); 1153af935746781088f28904601469671d244d2f653bKamil Debski if (dev->mfc_mem) { 1154af935746781088f28904601469671d244d2f653bKamil Debski release_resource(dev->mfc_mem); 1155af935746781088f28904601469671d244d2f653bKamil Debski kfree(dev->mfc_mem); 1156af935746781088f28904601469671d244d2f653bKamil Debski dev->mfc_mem = NULL; 1157af935746781088f28904601469671d244d2f653bKamil Debski } 1158af935746781088f28904601469671d244d2f653bKamil Debski s5p_mfc_final_pm(dev); 1159af935746781088f28904601469671d244d2f653bKamil Debski kfree(dev); 1160af935746781088f28904601469671d244d2f653bKamil Debski return 0; 1161af935746781088f28904601469671d244d2f653bKamil Debski} 1162af935746781088f28904601469671d244d2f653bKamil Debski 1163af935746781088f28904601469671d244d2f653bKamil Debski#ifdef CONFIG_PM_SLEEP 1164af935746781088f28904601469671d244d2f653bKamil Debski 1165af935746781088f28904601469671d244d2f653bKamil Debskistatic int s5p_mfc_suspend(struct device *dev) 1166af935746781088f28904601469671d244d2f653bKamil Debski{ 1167af935746781088f28904601469671d244d2f653bKamil Debski struct platform_device *pdev = to_platform_device(dev); 1168af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); 1169af935746781088f28904601469671d244d2f653bKamil Debski int ret; 1170af935746781088f28904601469671d244d2f653bKamil Debski 1171af935746781088f28904601469671d244d2f653bKamil Debski if (m_dev->num_inst == 0) 1172af935746781088f28904601469671d244d2f653bKamil Debski return 0; 1173af935746781088f28904601469671d244d2f653bKamil Debski return s5p_mfc_sleep(m_dev); 1174af935746781088f28904601469671d244d2f653bKamil Debski if (test_and_set_bit(0, &m_dev->enter_suspend) != 0) { 1175af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Error: going to suspend for a second time\n"); 1176af935746781088f28904601469671d244d2f653bKamil Debski return -EIO; 1177af935746781088f28904601469671d244d2f653bKamil Debski } 1178af935746781088f28904601469671d244d2f653bKamil Debski 1179af935746781088f28904601469671d244d2f653bKamil Debski /* Check if we're processing then wait if it necessary. */ 1180af935746781088f28904601469671d244d2f653bKamil Debski while (test_and_set_bit(0, &m_dev->hw_lock) != 0) { 1181af935746781088f28904601469671d244d2f653bKamil Debski /* Try and lock the HW */ 1182af935746781088f28904601469671d244d2f653bKamil Debski /* Wait on the interrupt waitqueue */ 1183af935746781088f28904601469671d244d2f653bKamil Debski ret = wait_event_interruptible_timeout(m_dev->queue, 1184af935746781088f28904601469671d244d2f653bKamil Debski m_dev->int_cond || m_dev->ctx[m_dev->curr_ctx]->int_cond, 1185af935746781088f28904601469671d244d2f653bKamil Debski msecs_to_jiffies(MFC_INT_TIMEOUT)); 1186af935746781088f28904601469671d244d2f653bKamil Debski 1187af935746781088f28904601469671d244d2f653bKamil Debski if (ret == 0) { 1188af935746781088f28904601469671d244d2f653bKamil Debski mfc_err("Waiting for hardware to finish timed out\n"); 1189af935746781088f28904601469671d244d2f653bKamil Debski return -EIO; 1190af935746781088f28904601469671d244d2f653bKamil Debski } 1191af935746781088f28904601469671d244d2f653bKamil Debski } 1192af935746781088f28904601469671d244d2f653bKamil Debski return 0; 1193af935746781088f28904601469671d244d2f653bKamil Debski} 1194af935746781088f28904601469671d244d2f653bKamil Debski 1195af935746781088f28904601469671d244d2f653bKamil Debskistatic int s5p_mfc_resume(struct device *dev) 1196af935746781088f28904601469671d244d2f653bKamil Debski{ 1197af935746781088f28904601469671d244d2f653bKamil Debski struct platform_device *pdev = to_platform_device(dev); 1198af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); 1199af935746781088f28904601469671d244d2f653bKamil Debski 1200af935746781088f28904601469671d244d2f653bKamil Debski if (m_dev->num_inst == 0) 1201af935746781088f28904601469671d244d2f653bKamil Debski return 0; 1202af935746781088f28904601469671d244d2f653bKamil Debski return s5p_mfc_wakeup(m_dev); 1203af935746781088f28904601469671d244d2f653bKamil Debski} 1204af935746781088f28904601469671d244d2f653bKamil Debski#endif 1205af935746781088f28904601469671d244d2f653bKamil Debski 1206af935746781088f28904601469671d244d2f653bKamil Debski#ifdef CONFIG_PM_RUNTIME 1207af935746781088f28904601469671d244d2f653bKamil Debskistatic int s5p_mfc_runtime_suspend(struct device *dev) 1208af935746781088f28904601469671d244d2f653bKamil Debski{ 1209af935746781088f28904601469671d244d2f653bKamil Debski struct platform_device *pdev = to_platform_device(dev); 1210af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); 1211af935746781088f28904601469671d244d2f653bKamil Debski 1212af935746781088f28904601469671d244d2f653bKamil Debski atomic_set(&m_dev->pm.power, 0); 1213af935746781088f28904601469671d244d2f653bKamil Debski return 0; 1214af935746781088f28904601469671d244d2f653bKamil Debski} 1215af935746781088f28904601469671d244d2f653bKamil Debski 1216af935746781088f28904601469671d244d2f653bKamil Debskistatic int s5p_mfc_runtime_resume(struct device *dev) 1217af935746781088f28904601469671d244d2f653bKamil Debski{ 1218af935746781088f28904601469671d244d2f653bKamil Debski struct platform_device *pdev = to_platform_device(dev); 1219af935746781088f28904601469671d244d2f653bKamil Debski struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); 1220af935746781088f28904601469671d244d2f653bKamil Debski int pre_power; 1221af935746781088f28904601469671d244d2f653bKamil Debski 1222af935746781088f28904601469671d244d2f653bKamil Debski if (!m_dev->alloc_ctx) 1223af935746781088f28904601469671d244d2f653bKamil Debski return 0; 1224af935746781088f28904601469671d244d2f653bKamil Debski pre_power = atomic_read(&m_dev->pm.power); 1225af935746781088f28904601469671d244d2f653bKamil Debski atomic_set(&m_dev->pm.power, 1); 1226af935746781088f28904601469671d244d2f653bKamil Debski return 0; 1227af935746781088f28904601469671d244d2f653bKamil Debski} 1228af935746781088f28904601469671d244d2f653bKamil Debski#endif 1229af935746781088f28904601469671d244d2f653bKamil Debski 1230af935746781088f28904601469671d244d2f653bKamil Debski/* Power management */ 1231af935746781088f28904601469671d244d2f653bKamil Debskistatic const struct dev_pm_ops s5p_mfc_pm_ops = { 1232af935746781088f28904601469671d244d2f653bKamil Debski SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume) 1233af935746781088f28904601469671d244d2f653bKamil Debski SET_RUNTIME_PM_OPS(s5p_mfc_runtime_suspend, s5p_mfc_runtime_resume, 1234af935746781088f28904601469671d244d2f653bKamil Debski NULL) 1235af935746781088f28904601469671d244d2f653bKamil Debski}; 1236af935746781088f28904601469671d244d2f653bKamil Debski 12371e393e90ab444dd24d28448e92bab099703fd006Kamil Debskistatic struct platform_driver s5p_mfc_driver = { 1238af935746781088f28904601469671d244d2f653bKamil Debski .probe = s5p_mfc_probe, 1239af935746781088f28904601469671d244d2f653bKamil Debski .remove = __devexit_p(s5p_mfc_remove), 1240af935746781088f28904601469671d244d2f653bKamil Debski .driver = { 1241af935746781088f28904601469671d244d2f653bKamil Debski .name = S5P_MFC_NAME, 1242af935746781088f28904601469671d244d2f653bKamil Debski .owner = THIS_MODULE, 1243af935746781088f28904601469671d244d2f653bKamil Debski .pm = &s5p_mfc_pm_ops 1244af935746781088f28904601469671d244d2f653bKamil Debski }, 1245af935746781088f28904601469671d244d2f653bKamil Debski}; 1246af935746781088f28904601469671d244d2f653bKamil Debski 12471d6629b1561ad34a6e6d17ece00bd65e1bab3724Axel Linmodule_platform_driver(s5p_mfc_driver); 1248af935746781088f28904601469671d244d2f653bKamil Debski 1249af935746781088f28904601469671d244d2f653bKamil DebskiMODULE_LICENSE("GPL"); 1250af935746781088f28904601469671d244d2f653bKamil DebskiMODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>"); 1251af935746781088f28904601469671d244d2f653bKamil DebskiMODULE_DESCRIPTION("Samsung S5P Multi Format Codec V4L2 driver"); 1252af935746781088f28904601469671d244d2f653bKamil Debski 1253