blob: c976d7c1327c207633664894002621f704b6d49b [file] [log] [blame]
/*
* Samsung Exynos SoC series VPU driver
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "vpu-queue.h"
#include "vpu-framemgr.h"
#include "vpu-graph.h"
extern const struct vb_ops vb_ops;
extern const struct vpu_queue_ops vpu_queue_ops;
int vpu_queue_open(struct vpu_queue *queue,
struct vpu_memory *memory,
struct mutex *lock)
{
int ret = 0;
struct vb_queue *inq, *otq;
queue->qops = &vpu_queue_ops;
inq = &queue->inqueue;
otq = &queue->otqueue;
inq->private_data = queue;
otq->private_data = queue;
ret = vb_queue_init(inq, memory->alloc_ctx, memory->vb2_mem_ops, &vb_ops, lock, VS4L_DIRECTION_IN);
if (ret) {
vpu_err("vb_queue_init is fail(%d)\n", ret);
goto p_err;
}
ret = vb_queue_init(otq, memory->alloc_ctx, memory->vb2_mem_ops, &vb_ops, lock, VS4L_DIRECTION_OT);
if (ret) {
vpu_err("vb_queue_init is fail(%d)\n", ret);
goto p_err;
}
p_err:
return ret;
}
int vpu_queue_s_format(struct vpu_queue *queue, struct vs4l_format_list *f)
{
int ret = 0;
struct vb_queue *q, *inq, *otq;
BUG_ON(!queue);
BUG_ON(!f);
inq = &queue->inqueue;
otq = &queue->otqueue;
if (f->direction == VS4L_DIRECTION_IN)
q = inq;
else
q = otq;
ret = CALL_QOPS(queue, format, f);
if (ret) {
vpu_err("CALL_QOPS(format) is fail(%d)\n", ret);
goto p_err;
}
ret = vb_queue_s_format(q, f);
if (ret) {
vpu_err("vb_queue_s_format is fail(%d)\n", ret);
goto p_err;
}
p_err:
return ret;
}
int vpu_queue_start(struct vpu_queue *queue)
{
int ret = 0;
struct vb_queue *inq, *otq;
inq = &queue->inqueue;
otq = &queue->otqueue;
ret = vb_queue_start(inq);
if (ret) {
vpu_err("vb_queue_init is fail(%d)\n", ret);
goto p_err;
}
ret = vb_queue_start(otq);
if (ret) {
vpu_err("vb_queue_init is fail(%d)\n", ret);
goto p_err;
}
ret = CALL_QOPS(queue, start);
if (ret) {
vpu_err("CALL_QOPS(start) is fail(%d)\n", ret);
goto p_err;
}
p_err:
return ret;
}
int vpu_queue_stop(struct vpu_queue *queue)
{
int ret = 0;
struct vb_queue *inq, *otq;
inq = &queue->inqueue;
otq = &queue->otqueue;
ret = CALL_QOPS(queue, stop);
if (ret) {
vpu_err("CALL_QOPS(stop) is fail(%d)\n", ret);
goto p_err;
}
ret = vb_queue_stop(inq);
if (ret) {
vpu_err("vb_queue_init is fail(%d)\n", ret);
goto p_err;
}
ret = vb_queue_stop(otq);
if (ret) {
vpu_err("vb_queue_init is fail(%d)\n", ret);
goto p_err;
}
p_err:
return ret;
}
int vpu_queue_poll(struct vpu_queue *queue, struct file *file, poll_table *poll)
{
int ret = 0;
struct vb_queue *inq, *otq;
unsigned long events;
BUG_ON(!queue);
BUG_ON(!file);
BUG_ON(!poll);
events = poll_requested_events(poll);
inq = &queue->inqueue;
otq = &queue->otqueue;
if (events & POLLIN) {
if (list_empty(&inq->done_list))
poll_wait(file, &inq->done_wq, poll);
if (list_empty(&inq->done_list))
ret |= POLLIN | POLLWRNORM;
}
if (events & POLLOUT) {
if (list_empty(&otq->done_list))
poll_wait(file, &otq->done_wq, poll);
if (list_empty(&otq->done_list))
ret |= POLLOUT | POLLWRNORM;
}
return ret;
}
int vpu_queue_qbuf(struct vpu_queue *queue, struct vs4l_container_list *c)
{
int ret = 0;
struct vb_queue *q, *inq, *otq;
struct vb_bundle *invb, *otvb;
inq = &queue->inqueue;
otq = &queue->otqueue;
if (c->direction == VS4L_DIRECTION_IN)
q = inq;
else
q = otq;
ret = vb_queue_qbuf(q, c);
if (ret) {
vpu_err("vb_queue_qbuf is fail(%d)\n", ret);
goto p_err;
}
if (list_empty(&inq->queued_list))
goto p_err;
if (list_empty(&otq->queued_list))
goto p_err;
invb = list_first_entry(&inq->queued_list, struct vb_bundle, queued_entry);
otvb = list_first_entry(&otq->queued_list, struct vb_bundle, queued_entry);
vb_queue_process(inq, invb);
vb_queue_process(otq, otvb);
ret = CALL_QOPS(queue, queue, &invb->clist, &otvb->clist);
if (ret) {
vpu_err("CALL_QOPS(queue) is fail(%d)\n", ret);
goto p_err;
}
p_err:
return ret;
}
int vpu_queue_dqbuf(struct vpu_queue *queue, struct vs4l_container_list *c, bool nonblocking)
{
int ret = 0;
struct vb_queue *q;
struct vb_bundle *bundle;
BUG_ON(!queue);
if (c->direction == VS4L_DIRECTION_IN)
q = &queue->inqueue;
else
q = &queue->otqueue;
ret = vb_queue_dqbuf(q, c, nonblocking);
if (ret) {
vpu_err("vb_queue_dqbuf is fail(%d)\n", ret);
goto p_err;
}
if (c->index >= VPU_MAX_BUFFER) {
vpu_err("container index(%d) is invalid\n", c->index);
ret = -EINVAL;
goto p_err;
}
bundle = q->bufs[c->index];
if (!bundle) {
vpu_err("bundle(%d) is NULL\n", c->index);
ret = -EINVAL;
goto p_err;
}
if (bundle->clist.index != c->index) {
vpu_err("index is NOT matched(%d != %d)\n", bundle->clist.index, c->index);
ret = -EINVAL;
goto p_err;
}
ret = CALL_QOPS(queue, deque, &bundle->clist);
if (ret) {
vpu_err("CALL_QOPS(deque) is fail(%d)\n", ret);
goto p_err;
}
p_err:
return ret;
}
void vpu_queue_done(struct vpu_queue *queue,
struct vb_container_list *incl,
struct vb_container_list *otcl,
unsigned long flags)
{
struct vb_queue *inq, *otq;
struct vb_bundle *invb, *otvb;
BUG_ON(!queue);
BUG_ON(!incl);
BUG_ON(!otcl);
inq = &queue->inqueue;
otq = &queue->otqueue;
if (list_empty(&inq->process_list)) {
vpu_err("inqueue is empty\n");
BUG();
}
if (list_empty(&otq->process_list)) {
vpu_err("otqueue is empty\n");
BUG();
}
invb = container_of(incl, struct vb_bundle, clist);
otvb = container_of(otcl, struct vb_bundle, clist);
if (invb->state != VB_BUF_STATE_PROCESS) {
vpu_err("invb state(%d) is invalid\n", invb->state);
BUG();
}
if (otvb->state != VB_BUF_STATE_PROCESS) {
vpu_err("otvb state(%d) is invalid\n", otvb->state);
BUG();
}
otvb->flags |= flags;
vb_queue_done(otq, otvb);
invb->flags |= flags;
vb_queue_done(inq, invb);
}