@@ -11,10 +11,14 @@
#ifndef FIMC_CORE_H_
#define FIMC_CORE_H_
/* #define DEBUG*/
#include < linux/types.h>
#include < media/videobuf-core.h>
#include < media/v4l2-device.h>
#include < media/v4l2-mem2mem.h>
#include < media/v4l2-mediabus.h>
#include < media/s3c_fimc.h>
#include < linux/videodev2.h>
#include " regs-fimc.h"
@@ -28,6 +32,8 @@
#define dbg (fmt, args... )
#endif
/* Time to wait for next frame VSYNC interrupt while stopping operation. */
#define FIMC_SHUTDOWN_TIMEOUT ((100 *HZ)/1000 )
#define NUM_FIMC_CLOCKS 2
#define MODULE_NAME " s5p-fimc"
#define FIMC_MAX_DEVS 3
@@ -36,19 +42,41 @@
#define SCALER_MAX_VRATIO 64
#define DMA_MIN_SIZE 8
enum {
/* FIMC device state flags */
enum fimc_dev_flags {
/* for m2m node */
ST_IDLE,
ST_OUTDMA_RUN,
ST_M2M_PEND,
/* for capture node */
ST_CAPT_PEND,
ST_CAPT_RUN,
ST_CAPT_STREAM,
ST_CAPT_SHUT,
};
#define fimc_m2m_active (dev ) test_bit(ST_OUTDMA_RUN, &(dev)->state)
#define fimc_m2m_pending (dev ) test_bit(ST_M2M_PEND, &(dev)->state)
#define fimc_capture_running (dev ) test_bit(ST_CAPT_RUN, &(dev)->state)
#define fimc_capture_pending (dev ) test_bit(ST_CAPT_PEND, &(dev)->state)
#define fimc_capture_active (dev ) \
(test_bit(ST_CAPT_RUN, &(dev)->state) || \
test_bit (ST_CAPT_PEND, &(dev)->state))
#define fimc_capture_streaming (dev ) \
test_bit (ST_CAPT_STREAM, &(dev)->state)
#define fimc_buf_finish (dev, vid_buf ) do { \
spin_lock (&(dev)->irqlock ); \
(vid_buf)->vb .state = VIDEOBUF_DONE; \
spin_unlock (&(dev)->irqlock ); \
wake_up (&(vid_buf)->vb .done ); \
} while (0 )
enum fimc_datapath {
FIMC_ITU_CAM_A,
FIMC_ITU_CAM_B,
FIMC_MIPI_CAM,
FIMC_CAMERA,
FIMC_DMA,
FIMC_LCDFIFO,
FIMC_WRITEBACK
@@ -123,20 +151,25 @@ enum fimc_color_fmt {
/* *
* struct fimc_fmt - the driver's internal color format data
* @mbus_code: Media Bus pixel code, -1 if not applicable
* @name: format description
* @fourcc: the fourcc code for this format
* @fourcc: the fourcc code for this format, 0 if not applicable
* @color: the corresponding fimc_color_fmt
* @depth: number of bits per pixel
* @depth: driver's private ' number of bits per pixel'
* @buff_cnt: number of physically non-contiguous data planes
* @planes_cnt: number of physically contiguous data planes
*/
struct fimc_fmt {
enum v4l2_mbus_pixelcode mbus_code;
char *name;
u32 fourcc;
u32 color;
u32 depth;
u16 buff_cnt;
u16 planes_cnt;
u16 depth;
u16 flags;
#define FMT_FLAGS_CAM (1 << 0 )
#define FMT_FLAGS_M2M (1 << 1 )
};
/* *
@@ -220,10 +253,14 @@ struct fimc_addr {
/* *
* struct fimc_vid_buffer - the driver's video buffer
* @vb: v4l videobuf buffer
* @vb: v4l videobuf buffer
* @paddr: precalculated physical address set
* @index: buffer index for the output DMA engine
*/
struct fimc_vid_buffer {
struct videobuf_buffer vb;
struct fimc_addr paddr;
int index ;
};
/* *
@@ -273,6 +310,40 @@ struct fimc_m2m_device {
int refcnt;
};
/* *
* struct fimc_vid_cap - camera capture device information
* @ctx: hardware context data
* @vfd: video device node for camera capture mode
* @v4l2_dev: v4l2_device struct to manage subdevs
* @sd: pointer to camera sensor subdevice currently in use
* @fmt: Media Bus format configured at selected image sensor
* @pending_buf_q: the pending buffer queue head
* @active_buf_q: the queue head of buffers scheduled in hardware
* @vbq: the capture am video buffer queue
* @active_buf_cnt: number of video buffers scheduled in hardware
* @buf_index: index for managing the output DMA buffers
* @frame_count: the frame counter for statistics
* @reqbufs_count: the number of buffers requested in REQBUFS ioctl
* @input_index: input (camera sensor) index
* @refcnt: driver's private reference counter
*/
struct fimc_vid_cap {
struct fimc_ctx *ctx;
struct video_device *vfd;
struct v4l2_device v4l2_dev;
struct v4l2_subdev *sd;
struct v4l2_mbus_framefmt fmt;
struct list_head pending_buf_q;
struct list_head active_buf_q;
struct videobuf_queue vbq;
int active_buf_cnt;
int buf_index;
unsigned int frame_count;
unsigned int reqbufs_count;
int input_index;
int refcnt;
};
/* *
* struct samsung_fimc_variant - camera interface variant information
*
@@ -308,10 +379,12 @@ struct samsung_fimc_variant {
*
* @variant: the variant information for this driver.
* @dev_cnt: number of fimc sub-devices available in SoC
* @lclk_frequency: fimc bus clock frequency
*/
struct samsung_fimc_driverdata {
struct samsung_fimc_variant *variant[FIMC_MAX_DEVS];
int devs_cnt;
unsigned long lclk_frequency;
int devs_cnt;
};
struct fimc_ctx;
@@ -322,27 +395,33 @@ struct fimc_ctx;
* @slock: the spinlock protecting this data structure
* @lock: the mutex protecting this data structure
* @pdev: pointer to the FIMC platform device
* @pdata: pointer to the device platform data
* @id: FIMC device index (0..2)
* @clock[]: the clocks required for FIMC operation
* @regs: the mapped hardware registers
* @regs_res: the resource claimed for IO registers
* @irq: interrupt number of the FIMC subdevice
* @irqlock: spinlock protecting videobuffer queue
* @irq_queue:
* @m2m: memory-to-memory V4L2 device information
* @state: the FIMC device state flags
* @vid_cap: camera capture device information
* @state: flags used to synchronize m2m and capture mode operation
*/
struct fimc_dev {
spinlock_t slock;
struct mutex lock;
struct platform_device *pdev;
struct s3c_platform_fimc *pdata;
struct samsung_fimc_variant *variant;
int id;
struct clk *clock [NUM_FIMC_CLOCKS];
void __iomem *regs;
struct resource *regs_res;
int irq;
spinlock_t irqlock;
wait_queue_head_t irq_queue;
struct fimc_m2m_device m2m;
struct fimc_vid_cap vid_cap;
unsigned long state;
};
@@ -387,6 +466,7 @@ struct fimc_ctx {
struct v4l2_m2m_ctx *m2m_ctx;
};
extern struct videobuf_queue_ops fimc_qops;
static inline int tiled_fmt (struct fimc_fmt *fmt)
{
@@ -433,7 +513,10 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
struct fimc_frame *frame;
if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) {
frame = &ctx->s_frame ;
if (ctx->state & FIMC_CTX_M2M)
frame = &ctx->s_frame ;
else
return ERR_PTR (-EINVAL);
} else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) {
frame = &ctx->d_frame ;
} else {
@@ -445,6 +528,13 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
return frame;
}
static inline u32 fimc_hw_get_frame_index (struct fimc_dev *dev)
{
u32 reg = readl (dev->regs + S5P_CISTATUS);
return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
S5P_CISTATUS_FRAMECNT_SHIFT;
}
/* -----------------------------------------------------*/
/* fimc-reg.c */
void fimc_hw_reset (struct fimc_dev *fimc);
@@ -462,6 +552,52 @@ void fimc_hw_set_output_path(struct fimc_ctx *ctx);
void fimc_hw_set_input_addr (struct fimc_dev *fimc, struct fimc_addr *paddr);
void fimc_hw_set_output_addr (struct fimc_dev *fimc, struct fimc_addr *paddr,
int index);
int fimc_hw_set_camera_source (struct fimc_dev *fimc,
struct s3c_fimc_isp_info *cam);
int fimc_hw_set_camera_offset (struct fimc_dev *fimc, struct fimc_frame *f);
int fimc_hw_set_camera_polarity (struct fimc_dev *fimc,
struct s3c_fimc_isp_info *cam);
int fimc_hw_set_camera_type (struct fimc_dev *fimc,
struct s3c_fimc_isp_info *cam);
/* -----------------------------------------------------*/
/* fimc-core.c */
int fimc_vidioc_enum_fmt (struct file *file, void *priv,
struct v4l2_fmtdesc *f);
int fimc_vidioc_g_fmt (struct file *file, void *priv,
struct v4l2_format *f);
int fimc_vidioc_try_fmt (struct file *file, void *priv,
struct v4l2_format *f);
int fimc_vidioc_g_crop (struct file *file, void *fh,
struct v4l2_crop *cr);
int fimc_vidioc_cropcap (struct file *file, void *fh,
struct v4l2_cropcap *cr);
int fimc_vidioc_queryctrl (struct file *file, void *priv,
struct v4l2_queryctrl *qc);
int fimc_vidioc_g_ctrl (struct file *file, void *priv,
struct v4l2_control *ctrl);
int fimc_try_crop (struct fimc_ctx *ctx, struct v4l2_crop *cr);
int check_ctrl_val (struct fimc_ctx *ctx, struct v4l2_control *ctrl);
int fimc_s_ctrl (struct fimc_ctx *ctx, struct v4l2_control *ctrl);
struct fimc_fmt *find_format (struct v4l2_format *f, unsigned int mask);
struct fimc_fmt *find_mbus_format (struct v4l2_mbus_framefmt *f,
unsigned int mask);
int fimc_check_scaler_ratio (struct v4l2_rect *r, struct fimc_frame *f);
int fimc_set_scaler_info (struct fimc_ctx *ctx);
int fimc_prepare_config (struct fimc_ctx *ctx, u32 flags);
int fimc_prepare_addr (struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
struct fimc_frame *frame, struct fimc_addr *paddr);
/* -----------------------------------------------------*/
/* fimc-capture.c */
int fimc_register_capture_device (struct fimc_dev *fimc);
void fimc_unregister_capture_device (struct fimc_dev *fimc);
int fimc_sensor_sd_init (struct fimc_dev *fimc, int index);
int fimc_vid_cap_buf_queue (struct fimc_dev *fimc,
struct fimc_vid_buffer *fimc_vb);
/* Locking: the caller holds fimc->slock */
static inline void fimc_activate_capture (struct fimc_ctx *ctx)
@@ -478,4 +614,51 @@ static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
fimc_hw_en_lastirq (fimc, false );
}
/*
* Add video buffer to the active buffers queue.
* The caller holds irqlock spinlock.
*/
static inline void active_queue_add (struct fimc_vid_cap *vid_cap,
struct fimc_vid_buffer *buf)
{
buf->vb .state = VIDEOBUF_ACTIVE;
list_add_tail (&buf->vb .queue , &vid_cap->active_buf_q );
vid_cap->active_buf_cnt ++;
}
/*
* Pop a video buffer from the capture active buffers queue
* Locking: Need to be called with dev->slock held.
*/
static inline struct fimc_vid_buffer *
active_queue_pop (struct fimc_vid_cap *vid_cap)
{
struct fimc_vid_buffer *buf;
buf = list_entry (vid_cap->active_buf_q .next ,
struct fimc_vid_buffer, vb.queue );
list_del (&buf->vb .queue );
vid_cap->active_buf_cnt --;
return buf;
}
/* Add video buffer to the capture pending buffers queue */
static inline void fimc_pending_queue_add (struct fimc_vid_cap *vid_cap,
struct fimc_vid_buffer *buf)
{
buf->vb .state = VIDEOBUF_QUEUED;
list_add_tail (&buf->vb .queue , &vid_cap->pending_buf_q );
}
/* Add video buffer to the capture pending buffers queue */
static inline struct fimc_vid_buffer *
pending_queue_pop (struct fimc_vid_cap *vid_cap)
{
struct fimc_vid_buffer *buf;
buf = list_entry (vid_cap->pending_buf_q .next ,
struct fimc_vid_buffer, vb.queue );
list_del (&buf->vb .queue );
return buf;
}
#endif /* FIMC_CORE_H_ */