/*
* Samsung EXYNOS FIMC-LITE (camera host interface) driver
*
* Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@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.
*/
#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
#include <linux/bug.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
#include <media/s5p_fimc.h>
#include "common.h"
#include "fimc-core.h"
#include "fimc-lite.h"
#include "fimc-lite-reg.h"
static int debug;
module_param(debug, int, 0644);
static const struct fimc_fmt fimc_lite_formats[] = {
{
.name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
.colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
.color = FIMC_FMT_YCBYCR422,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
.name = "YUV 4:2:2 packed, CbYCrY",
.fourcc = V4L2_PIX_FMT_UYVY,
.colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
.color = FIMC_FMT_CBYCRY422,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
.name = "YUV 4:2:2 packed, CrYCbY",
.fourcc = V4L2_PIX_FMT_VYUY,
.colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
.color = FIMC_FMT_CRYCBY422,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
.name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
.colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
.color = FIMC_FMT_YCRYCB422,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
.name = "RAW8 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG8,
.colorspace = V4L2_COLORSPACE_SRGB,
.depth = { 8 },
.color = FIMC_FMT_RAW8,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8,
.flags = FMT_FLAGS_RAW_BAYER,
}, {
.name = "RAW10 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG10,
.colorspace = V4L2_COLORSPACE_SRGB,
.depth = { 16 },
.color = FIMC_FMT_RAW10,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10,
.flags = FMT_FLAGS_RAW_BAYER,
}, {
.name = "RAW12 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG12,
.colorspace = V4L2_COLORSPACE_SRGB,
.depth = { 16 },
.color = FIMC_FMT_RAW12,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12,
.flags = FMT_FLAGS_RAW_BAYER,
},
};
/**
* fimc_lite_find_format - lookup fimc color format by fourcc or media bus code
* @pixelformat: fourcc to match, ignored if null
* @mbus_code: media bus code to match, ignored if null
* @mask: the color format flags to match
* @index: index to the fimc_lite_formats array, ignored if negative
*/
static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat,
const u32 *mbus_code, unsigned int mask, int index)
{
const struct fimc_fmt *fmt, *def_fmt = NULL;
unsigned int i;
int id = 0;
if (index >= (int)ARRAY_SIZE(fimc_lite_formats))
return NULL;
for (i = 0; i < ARRAY_SIZE(fimc_lite_formats); ++i) {
fmt = &fimc_lite_formats[i];
if (mask && !(fmt->flags & mask))
continue;
if (pixelformat && fmt->fourcc == *pixelformat)
return fmt;
if (mbus_code && fmt->mbus_code == *mbus_code)
return fmt;
if (index == id)
def_fmt = fmt;
id++;
}
return def_fmt;
}
static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output)
{
struct fimc_source_info *si;
unsigned long flags;
if (fimc->sensor == NULL)
return -ENXIO;
if (fimc->inp_frame.fmt == NULL || fimc->out_frame.fmt == NULL)
return -EINVAL;
/* Get sensor configuration data from the sensor subdev */
si = v4l2_get_subdev_hostdata(fimc->sensor);
if (!si)
return -EINVAL;
spin_lock_irqsave(&fimc->slock, flags);
flite_hw_set_camera_bus(fimc, si);
flite_hw_set_source_format(fimc, &fimc->inp_frame);
flite_hw_set_window_offset(fimc, &fimc->inp_frame);
flite_hw_set_dma_buf_mask(fimc, 0);
flite_hw_set_output_dma(fimc, &fimc->out_frame, !isp_output);
flite_hw_set_interrupt_mask(fimc);
flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
if (debug > 0)
flite_hw_dump_regs(fimc, __func__);
spin_unlock_irqrestore(&fimc->slock, flags);
return 0;
}
/*
* Reinitialize the driver so it is ready to start the streaming again.
* Set fimc->state to indicate stream off and the hardware shut down state.
* If not suspending (@suspend is false), return any buffers to videobuf2.
* Otherwise put any owned buffers onto the pending buffers queue, so they
* can be re-spun when the device is being resumed. Also perform FIMC
* software reset and disable streaming on the whole pipeline if required.
*/
static int fimc_lite_reinit(struct fimc_lite *fimc, bool suspend)
{
struct flite_buffer *buf;
unsigned long flags;
bool streaming;
spin_lock_irqsave(&fimc->slock, flags);
streaming = fimc->state & (1 << ST_SENSOR_STREAM);
fimc->state &= ~(1 << ST_FLITE_RUN | 1 << ST_FLITE_OFF |
1 << ST_FLITE_STREAM | 1 << ST_SENSOR_STREAM);
if (suspend)
fimc->state |= (1 << ST_FLITE_SUSPENDED);
else
fimc->state &= ~(1 << ST_FLITE_PENDING |
1 << ST_FLITE_SUSPENDED);
/* Release unused buffers */
while (!suspend && !list_empty(&fimc->pending_buf_q)) {
buf = fimc_lite_pending_queue_pop(fimc);
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
}
/* If suspending put unused buffers onto pending queue */
while (!list_empty(&fimc->active_buf_q)) {
buf = fimc_lite_active_queue_pop(fimc);
if (suspend)
fimc_lite_pending_queue_add(fimc, buf);
else
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
}
spin_unlock_irqrestore(&fimc->slock, flags);
flite_hw_reset(fimc);
if (!streaming)
return 0;
return fimc_pipeline_call(&fimc->ve, set_stream, 0);
}
static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend)
{
unsigned long flags;
if (!fimc_lite_active(fimc))
return 0;
spin_lock_irqsave(&fimc->slock, flags);
set_bit(ST_FLITE_OFF, &fimc->state);
flite_hw_capture_stop(fimc);
spin_unlock_irqrestore(&fimc->slock, flags);
wait_event_timeout(fimc->irq_queue,
!test_bit(ST_FLITE_OFF, &fimc->state),
(2*HZ/10)); /* 200 ms */
return fimc_lite_reinit(fimc, suspend);
}
/* Must be called with fimc.slock spinlock held. */
static void fimc_lite_config_update(struct fimc_lite *fimc)
{
flite_hw_set_window_offset(fimc, &fimc->inp_frame);
flite_hw_set_dma_window(fimc, &fimc->out_frame);
flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
clear_bit(ST_FLITE_CONFIG, &fimc->state);
}
static irqreturn_t flite_irq_handler(int irq, void *priv)
{
struct fimc_lite *fimc = priv;
struct flite_buffer *vbuf;
unsigned long flags;
struct timeval *tv;
struct timespec ts;
u32 intsrc;
spin_lock_irqsave(&fimc->slock, flags);
intsrc = flite_hw_get_interrupt_source(fimc);
flite_hw_clear_pending_irq(fimc);
if (test_and_clear_bit(ST_FLITE_OFF, &fimc->state)) {
wake_up(&fimc->irq_queue);
goto done;
}
if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW) {
clear_bit(ST_FLITE_RUN, &fimc->state);
fimc->events.data_overflow++;
}
if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND) {
flite_hw_clear_last_capture_end(fimc);
clear_bit(ST_FLITE_STREAM, &fimc->state);
wake_up(&fimc->irq_queue);
}
if (atomic_read(&fimc->out_path) != FIMC_IO_DMA)
goto done;
if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) &&
test_bit(ST_FLITE_RUN, &fimc->state) &&
!list_empty(&fimc->pending_buf_q)) {
vbuf = fimc_lite_pen
fimc-lite.rar_V2 _fimc
版权申诉
86 浏览量
2022-09-24
06:40:43
上传
评论
收藏 13KB RAR 举报
Kinonoyomeo
- 粉丝: 75
- 资源: 1万+
最新资源
- XILINXFPGA源码Xilinxspratan3xcs100E(VGAPS2)
- XILINXFPGA源码XilinxSPARTAN-3E入门开发板实例
- XILINXFPGA源码XilinxSdramVerilog和VHDL版本文档
- 物联网智能家居方案-基于Nucleo-STM32L073&机智云(大赛作品,文档齐全,可直接运行)(文档加Matlab源码)
- XILINXFPGA源码XilinxISE9.xFPGACPLD设计源码
- 成都市地图含高新区(高新南区,高新西区),天府新区,东部新区虚拟行政区划
- XILINXFPGA源码XilinxEDK设计试验
- XILINXFPGA源码XilinxEDKMicroBlaze内置USB固件程序
- 基于 django 的视频点播后台管理系统源代码+数据库
- 基于Java的网上医院预约挂号系统的设计与实现(部署视频)-kaic.mp4
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈