blob: 767bb3f7f3aed1a925d8a9e66134c88544c96b84 [file] [log] [blame]
/*
* include/media/m2m1shot2.h
*
* Copyright (C) 2015 Samsung Electronics Co., Ltd.
*
* Contact: Cho KyongHo <pullip.cho@samsung.com>
*
* 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.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*/
#ifndef _M2M1SHOT2_H_
#define _M2M1SHOT2_H_
#include <linux/kernel.h>
#include <linux/videodev2.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/dma-direction.h>
#include <linux/kref.h>
#include <linux/completion.h>
#include <linux/dma-buf.h>
#include <uapi/linux/m2m1shot2.h>
#include "../../drivers/staging/android/sw_sync.h"
struct m2m1shot2_device;
struct m2m1shot2_context;
/**
* struct m2m1shot2_dma_buffer - buffer description of a plane of an image
*
* @payload : length of the effective data
* @offset : the offset where the effective dta is stored from the start
* of the buffer if the buffer type is dmabuf.
* @dmabuf : the pointer to dmabuf structure if the buffer type is dmabuf
* @attachment : the pointer to attachment structure if the buffer type is
* @length : length of the buffer if the buffer type is userptr
* @addr : userptr address if the memory type is userptr
* @vma : copy of the head vma of the list of vm_area_struct that
* describes the user area [@addr, @addr + @length)
* @sgt : scatterlist table if the buffer type is dmabuf
* @dma_addr : DMA address for the client device
* @priv : for the private use of the client device driver
*/
struct m2m1shot2_dma_buffer {
u32 payload;
union {
struct {
u32 offset;
struct dma_buf *dmabuf;
struct dma_buf_attachment *attachment;
} dmabuf;
struct {
u32 length;
unsigned long addr;
struct vm_area_struct *vma;
} userptr;
};
struct sg_table *sgt;
dma_addr_t dma_addr;
void *priv;
};
/**
* struct m2m1shot2_context_format - image format description of an image
*
* @fmt : the image format information given by the userspace
* @priv : the client drivers' private data that can be initialized in
* m2m1shot2_devops.prepare_format(). It must be static data so
* hat the resources related to the data don't need to be
* released. The framework does not provide a chance to release
* any resouce related to @priv.
*/
struct m2m1shot2_context_format {
struct m2m1shot2_format fmt;
void *priv;
u32 colorspace;
};
/**
* struct m2m1shot2_context_image
* - description for both of source and target images
*
* @index : index of the current image in m2m1shot2_context.source array
* @flags : flags about the image configured in the userspace.
* See include/uapi/linux/m2m1shot2.h
* @fmt : image format information given by the userspace
* @memory : memory type of all buffers in @plane
* @plane : buffer information of all planes of the image
* @fence_waiter: waiter object of @fence of the image to support for
* asynchronous fence waiter
* @fence : acquire fence of the image. The image processing deos not
* start until @fence is signaled.
*/
struct m2m1shot2_context_image {
unsigned int index;
u32 flags;
struct m2m1shot2_context_format fmt;
u32 memory;
unsigned int num_planes;
struct m2m1shot2_dma_buffer plane[M2M1SHOT2_MAX_PLANES];
struct sync_fence_waiter waiter;
struct sync_fence *fence;
};
/**
* struct m2m1shot2_source_image - source image description
*
* @img : image description
* @ext : extra image processing description.
* See include/uapi/linux/m2m1shot2.h
*/
struct m2m1shot2_source_image {
struct m2m1shot2_context_image img;
struct m2m1shot2_extra ext;
};
/**
* struct m2m1shot2_devops
*
* @init_context : [MANDATORY]
* called on creation of a context. The given parameter
* is initialized by the caller. The callee can register
* its private data to m2m1shot2_context.priv. A context
* is created when a userspace opens the device node.
* @free_context : [MANDATORY]
* called on destruction of a context. The given context
* has complete information until its return. The callee
* should cleaning up all the relevant data in this
* function.
* @prepare_format : [MANDATORY]
* called when userspace pushes a work to the device
* through m2m1shot2. m2m1shot2 calls this function for
* every image provided from the userspace and the callee
* should initializes @payload and @num_planes on return
* according to the format. @num_planes should not be
* greater than M2M1SHOT2_MAX_PLANES and @num_planes
* number of elements in @payload should be initialized
* by the callee.
* @prepare_source : [OPTIONAL]
* called when userspace pushes a task to the device
* through m2m1shot2 and the driver verified that the
* image format and the buffer do not have a problem.
* The callee then should identify and confirm the rest
* of attributes specified in m2m1shot2_source_image.
* @device_run : [MANDATORY]
* called when work is ready to be processed by H/W.
*/
struct m2m1shot2_devops {
int (*init_context)(struct m2m1shot2_context *ctx);
int (*free_context)(struct m2m1shot2_context *ctx);
int (*prepare_format)(struct m2m1shot2_context_format *fmt,
unsigned int index,
enum dma_data_direction dir,
size_t payload[],
unsigned int *num_planes);
int (*prepare_source)(struct m2m1shot2_context *ctx,
unsigned int index,
struct m2m1shot2_source_image *img);
int (*prepare_target)(struct m2m1shot2_context *ctx,
struct m2m1shot2_context_image *img);
int (*prepare_perf)(struct m2m1shot2_context *ctx,
struct m2m1shot2_performance_data *data);
int (*device_run)(struct m2m1shot2_context *ctx);
int (*custom_ioctl)(struct m2m1shot2_context *ctx,
unsigned int cmd,
unsigned int arg);
};
/* m2m1shot2_context.state flags */
/* H/W is working on the context or it is waiting for H/W time */
#define M2M1S2_CTXSTATE_PROCESSING 0
/* The context is waiting for H/W time */
#define M2M1S2_CTXSTATE_PENDING 1
/* A process is waiting for a context to finish*/
#define M2M1S2_CTXSTATE_WAITING 2
/* The context is finished but userspace does not yet subscribe */
#define M2M1S2_CTXSTATE_PROCESSED 8
/* A error is occurred during processing the context */
#define M2M1S2_CTXSTATE_ERROR 9
/* force clean all the caches before DMA for better performance */
#define M2M1S2_CTXSTATE_CACHECLEANALL 16
/* force invalidate all the caches after DMA for better performance */
#define M2M1S2_CTXSTATE_CACHEINVALALL 17
#define M2M1S2_CTXSTATE_CACHEFLUSH 18
#define M2M1S2_CTXSTATE_CACHEFLUSHALL 19
#define M2M1S2_CTXSTATE_IDLE(ctx) (((ctx)->state & 0xFF) == 0)
/* PROCESSIG | PENDING */
#define M2M1S2_CTXSTATE_BUSY(ctx) (((ctx)->state & 0x3) != 0)
#define BTS_PEAK_FPS_RATIO 1667
#define M2M1S2_TIMEOUT_INTERVAL 1000
/**
* struct m2m1shot2_context - context of tasks
*
* @node : node entry to m2m1shot2_device.contexts
* @state : state of the context
* @starter : counter of acquire fences to wait.
* @m21dev : the singleton device instance that the context is born
* @priv : private data that is allowed to store client drivers' private
* @mutex : serialization of user's requests
* @complete : sync point between the waiter and the driver
* @work : work to schedule the context that is scheduled by a fence
* because asynchronous waiter of an Android fence is invoked
* with IRQ disabled.
* @dwork : work to schedule the destruction of the context because it
* is required to wait until a pending context to be finished.
* @flags : flags specified in m2m1shot2.flags.
* @num_sources : the number of effective elements in @source
* @source : source image information
* @target : destination image information
* @timeline : monotonic timeline of Android sync that signals the release
* fences
* @timeline_max: the timestamp of the most recent release fence
* @ctx_private : the framework' private use
* @work_delay_in_nsec : delay in processing (nsec)
* @timer : timeout that the acquire fence can't receive the signal
* for some time.
* @release_fence : release fence of ctx. It is only used for debugging.
*/
struct m2m1shot2_context {
struct list_head node;
unsigned long state;
struct kref starter;
struct m2m1shot2_device *m21dev;
void *priv;
struct mutex mutex;
struct completion complete;
struct work_struct work;
struct work_struct dwork;
unsigned int flags;
unsigned int num_sources;
struct m2m1shot2_source_image source[M2M1SHOT2_MAX_IMAGES];
struct m2m1shot2_context_image target;
struct sw_sync_timeline *timeline;
enum m2m1shot2_priority priority;
u32 timeline_max;
u32 ctx_private;
u32 ctx_private2;
u64 work_delay_in_nsec;
struct timer_list timer;
struct sync_fence *release_fence;
spinlock_t fence_timeout_lock;
};
#define M2M1SHOT2_DEVATTR_COHERENT (1 << 0)
/**
* struct m2m1shot2_device
*
* @misc : misc device desciptor for user-kernel interface
* @attr : attribute flags that describes the characteristics of the
* client device.
* @dev : the client device desciptor
* @contexts : list of instances of m2m1shot2_context that are not currently
* under processing request.
* - a node added in m2m1shot2_open() and
* __m2m1shot2_finish_context()
* - a node removed in m2m1shot2_start_context() and
* m2m1shot2_cancel_context().
* @active_contexts: the list of the contexts that is waiting to be serviced
* - a node added in m2m1shot2_start_context().
* - a node removed in m2m1shot2_schedule() and
* m2m1shot2_cancel_context().
* @current_task: indicate the context that is currently being processed
* - a value set in m2m1shot2_schedule()
* - NULL is set in __m2m1shot2_finish_context().
* @lock_ctx : lock to protect the consistency of @contexts, @active_contexts
* and @current_task.
* @ops : callback functions that the client device driver must
* implement according to the events.
* @schedule_workqueue: queue of work to schedule a image processing task.
* An workqueue is needed to run m2m1shot2_schedule() in a
* process context when the task need to wait for a fence because
* the callback of the fence waiter is in IRQ disabled context.
*
* LIFECYCLE of m2m1shot2_context:
* - added to @contexts on creation
* - moved from @contexts to @active_contexts on process request
* - moved from @active_contexts to @current_task on processing
* - moved from @current_task to @contexts on completion
* - removed from @contexts on destruction
*/
struct m2m1shot2_device {
struct miscdevice misc;
unsigned long attr;
struct device *dev;
struct list_head contexts;
struct list_head active_contexts;
struct m2m1shot2_context *current_ctx;
spinlock_t lock_ctx;
spinlock_t lock_priority;
const struct m2m1shot2_devops *ops;
struct workqueue_struct *schedule_workqueue;
struct workqueue_struct *destroy_workqueue;
unsigned char prior_stats[M2M1SHOT2_PRIORITY_END];
struct mutex lock_qos;
struct list_head qos_contexts;
};
#ifdef CONFIG_MEDIA_M2M1SHOT2
struct m2m1shot2_context *m2m1shot2_current_context(
const struct m2m1shot2_device *m21dev);
struct m2m1shot2_device *m2m1shot2_create_device(struct device *dev,
const struct m2m1shot2_devops *ops,
const char *nodename, int id, unsigned long attr);
void m2m1shot2_destroy_device(struct m2m1shot2_device *m21dev);
void m2m1shot2_finish_context(struct m2m1shot2_context *ctx, bool success);
void m2m1shot2_schedule(struct m2m1shot2_device *m21dev);
static inline u32 m2m1shot2_get_payload(struct m2m1shot2_context *ctx,
unsigned int index, unsigned int plane)
{
BUG_ON(index >= M2M1SHOT2_MAX_IMAGES);
BUG_ON(plane >= ctx->source[index].img.num_planes);
return ctx->source[index].img.plane[plane].payload;
}
static inline void m2m1shot2_set_payload(struct m2m1shot2_context *ctx,
unsigned int plane, u32 payload)
{
BUG_ON(plane >= ctx->target.num_planes);
BUG_ON((ctx->target.memory == M2M1SHOT2_BUFTYPE_DMABUF)
&& (payload > ctx->target.plane[plane].dmabuf.dmabuf->size));
BUG_ON((ctx->target.memory == M2M1SHOT2_BUFTYPE_USERPTR)
&& (payload > ctx->target.plane[plane].userptr.length));
ctx->target.plane[plane].payload = payload;
}
static inline dma_addr_t m2m1shot2_src_dma_addr(struct m2m1shot2_context *ctx,
unsigned int index, unsigned int plane)
{
BUG_ON(index >= M2M1SHOT2_MAX_IMAGES);
BUG_ON(plane >= ctx->source[index].img.num_planes);
return ctx->source[index].img.plane[plane].dma_addr;
}
static inline dma_addr_t m2m1shot2_dst_dma_addr(struct m2m1shot2_context *ctx,
unsigned int plane)
{
BUG_ON(plane >= ctx->target.num_planes);
return ctx->target.plane[plane].dma_addr;
}
static inline struct m2m1shot2_context_format *m2m1shot2_src_format(
struct m2m1shot2_context *ctx, unsigned int index)
{
BUG_ON(index >= M2M1SHOT2_MAX_IMAGES);
return &ctx->source[index].img.fmt;
}
static inline struct m2m1shot2_context_format *m2m1shot2_dst_format(
struct m2m1shot2_context *ctx)
{
return &ctx->target.fmt;
}
#else /* !CONFIG_MEDIA_M2M1SHOT2 */
static inline struct m2m1shot2_context *m2m1shot2_current_context(
const struct m2m1shot2_device *m21dev)
{
return NULL;
}
static inline struct m2m1shot2_device *m2m1shot2_create_device(
struct device *dev, const struct m2m1shot2_devops *ops,
const char *nodename, int id, unsigned long attr)
{
return NULL;
}
#define m2m1shot2_destroy_device(m21dev) do { } while (0)
#define m2m1shot2_finish_context(ctx, success) do { } while (0)
static inline u32 m2m1shot2_get_payload(struct m2m1shot2_context *ctx,
unsigned int index, unsigned int plane)
{
return 0;
}
#define m2m1shot2_set_payload(ctx, plane, payload) do { } while (0)
static inline dma_addr_t m2m1shot2_src_dma_addr(struct m2m1shot2_context *ctx,
unsigned int index, unsigned int plane)
{
return 0;
}
static inline dma_addr_t m2m1shot2_dst_dma_addr(struct m2m1shot2_context *ctx,
unsigned int plane)
{
return 0;
}
#endif /* CONFIG_MEDIA_M2M1SHOT2 */
#endif /* _M2M1SHOT2_H_ */