Commit 34947b8a authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab

[media] exynos4-is: Add the FIMC-IS ISP capture DMA driver

Add a video capture node for the FIMC-IS ISP IP block. The Exynos4x12
FIMC-IS ISP IP block has 2 DMA interfaces that allow to capture raw
Bayer and YUV data to memory.  Currently only the DMA2 output is and
raw Bayer data capture is supported.
Signed-off-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Acked-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent fa91f105
...@@ -64,4 +64,13 @@ config VIDEO_EXYNOS4_FIMC_IS ...@@ -64,4 +64,13 @@ config VIDEO_EXYNOS4_FIMC_IS
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called exynos4-fimc-is. module will be called exynos4-fimc-is.
config VIDEO_EXYNOS4_ISP_DMA_CAPTURE
bool "EXYNOS4x12 FIMC-IS ISP Direct DMA capture support"
depends on VIDEO_EXYNOS4_FIMC_IS
select VIDEO_EXYNOS4_IS_COMMON
default y
help
This option enables an additional video device node exposing a V4L2
video capture interface for the FIMC-IS ISP raw (Bayer) capture DMA.
endif # VIDEO_SAMSUNG_EXYNOS4_IS endif # VIDEO_SAMSUNG_EXYNOS4_IS
...@@ -6,6 +6,10 @@ exynos4-is-common-objs := common.o ...@@ -6,6 +6,10 @@ exynos4-is-common-objs := common.o
exynos-fimc-is-objs := fimc-is.o fimc-isp.o fimc-is-sensor.o fimc-is-regs.o exynos-fimc-is-objs := fimc-is.o fimc-isp.o fimc-is-sensor.o fimc-is-regs.o
exynos-fimc-is-objs += fimc-is-param.o fimc-is-errno.o fimc-is-i2c.o exynos-fimc-is-objs += fimc-is-param.o fimc-is-errno.o fimc-is-i2c.o
ifeq ($(CONFIG_VIDEO_EXYNOS4_ISP_DMA_CAPTURE),y)
exynos-fimc-is-objs += fimc-isp-video.o
endif
obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o
obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += exynos-fimc-lite.o obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += exynos-fimc-lite.o
obj-$(CONFIG_VIDEO_EXYNOS4_FIMC_IS) += exynos-fimc-is.o obj-$(CONFIG_VIDEO_EXYNOS4_FIMC_IS) += exynos-fimc-is.o
......
...@@ -56,7 +56,7 @@ static void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is) ...@@ -56,7 +56,7 @@ static void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is)
__hw_param_copy(dst, src); __hw_param_copy(dst, src);
} }
static int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset) int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset)
{ {
struct is_param_region *par = &is->is_p_region->parameter; struct is_param_region *par = &is->is_p_region->parameter;
struct chain_config *cfg = &is->config[is->config_index]; struct chain_config *cfg = &is->config[is->config_index];
......
...@@ -911,6 +911,10 @@ struct is_region { ...@@ -911,6 +911,10 @@ struct is_region {
u32 shared[MAX_SHARED_COUNT]; u32 shared[MAX_SHARED_COUNT];
} __packed; } __packed;
/* Offset to the ISP DMA2 output buffer address array. */
#define DMA2_OUTPUT_ADDR_ARRAY_OFFS \
(offsetof(struct is_region, shared) + 32 * sizeof(u32))
struct is_debug_frame_descriptor { struct is_debug_frame_descriptor {
u32 sensor_frame_time; u32 sensor_frame_time;
u32 sensor_exposure_time; u32 sensor_exposure_time;
...@@ -988,6 +992,7 @@ struct sensor_open_extended { ...@@ -988,6 +992,7 @@ struct sensor_open_extended {
struct fimc_is; struct fimc_is;
int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is); int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is);
int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset);
void fimc_is_set_initial_params(struct fimc_is *is); void fimc_is_set_initial_params(struct fimc_is *is);
unsigned int __get_pending_param_count(struct fimc_is *is); unsigned int __get_pending_param_count(struct fimc_is *is);
......
...@@ -105,6 +105,20 @@ int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num_args) ...@@ -105,6 +105,20 @@ int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num_args)
return 0; return 0;
} }
void fimc_is_hw_set_isp_buf_mask(struct fimc_is *is, unsigned int mask)
{
if (hweight32(mask) == 1) {
dev_err(&is->pdev->dev, "%s(): not enough buffers (mask %#x)\n",
__func__, mask);
return;
}
if (mcuctl_read(is, MCUCTL_REG_ISSR(23)) != 0)
dev_dbg(&is->pdev->dev, "non-zero DMA buffer mask\n");
mcuctl_write(mask, is, MCUCTL_REG_ISSR(23));
}
void fimc_is_hw_set_sensor_num(struct fimc_is *is) void fimc_is_hw_set_sensor_num(struct fimc_is *is)
{ {
pr_debug("setting sensor index to: %d\n", is->sensor_index); pr_debug("setting sensor index to: %d\n", is->sensor_index);
......
...@@ -147,6 +147,7 @@ int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num); ...@@ -147,6 +147,7 @@ int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num);
void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is); void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is);
int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is); int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is);
void fimc_is_hw_set_sensor_num(struct fimc_is *is); void fimc_is_hw_set_sensor_num(struct fimc_is *is);
void fimc_is_hw_set_isp_buf_mask(struct fimc_is *is, unsigned int mask);
void fimc_is_hw_stream_on(struct fimc_is *is); void fimc_is_hw_stream_on(struct fimc_is *is);
void fimc_is_hw_stream_off(struct fimc_is *is); void fimc_is_hw_stream_off(struct fimc_is *is);
int fimc_is_hw_set_param(struct fimc_is *is); int fimc_is_hw_set_param(struct fimc_is *is);
......
...@@ -204,6 +204,9 @@ static int fimc_is_register_subdevs(struct fimc_is *is) ...@@ -204,6 +204,9 @@ static int fimc_is_register_subdevs(struct fimc_is *is)
if (ret < 0) if (ret < 0)
return ret; return ret;
/* Initialize memory allocator context for the ISP DMA. */
is->isp.alloc_ctx = is->alloc_ctx;
for_each_compatible_node(i2c_bus, NULL, FIMC_IS_I2C_COMPATIBLE) { for_each_compatible_node(i2c_bus, NULL, FIMC_IS_I2C_COMPATIBLE) {
for_each_available_child_of_node(i2c_bus, child) { for_each_available_child_of_node(i2c_bus, child) {
ret = fimc_is_parse_sensor_config(is, index, child); ret = fimc_is_parse_sensor_config(is, index, child);
......
...@@ -292,6 +292,11 @@ static inline struct fimc_is *fimc_isp_to_is(struct fimc_isp *isp) ...@@ -292,6 +292,11 @@ static inline struct fimc_is *fimc_isp_to_is(struct fimc_isp *isp)
return container_of(isp, struct fimc_is, isp); return container_of(isp, struct fimc_is, isp);
} }
static inline struct chain_config *__get_curr_is_config(struct fimc_is *is)
{
return &is->config[is->config_index];
}
static inline void fimc_is_mem_barrier(void) static inline void fimc_is_mem_barrier(void)
{ {
mb(); mb();
......
This diff is collapsed.
/*
* Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* 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.
*/
#ifndef FIMC_ISP_VIDEO__
#define FIMC_ISP_VIDEO__
#include <media/videobuf2-core.h>
#include "fimc-isp.h"
#ifdef CONFIG_VIDEO_EXYNOS4_ISP_DMA_CAPTURE
int fimc_isp_video_device_register(struct fimc_isp *isp,
struct v4l2_device *v4l2_dev,
enum v4l2_buf_type type);
void fimc_isp_video_device_unregister(struct fimc_isp *isp,
enum v4l2_buf_type type);
void fimc_isp_video_irq_handler(struct fimc_is *is);
#else
static inline void fimc_isp_video_irq_handler(struct fimc_is *is)
{
}
static inline int fimc_isp_video_device_register(struct fimc_isp *isp,
struct v4l2_device *v4l2_dev,
enum v4l2_buf_type type)
{
return 0;
}
void fimc_isp_video_device_unregister(struct fimc_isp *isp,
enum v4l2_buf_type type)
{
}
#endif /* !CONFIG_VIDEO_EXYNOS4_ISP_DMA_CAPTURE */
#endif /* FIMC_ISP_VIDEO__ */
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
#include "media-dev.h" #include "media-dev.h"
#include "fimc-isp-video.h"
#include "fimc-is-command.h" #include "fimc-is-command.h"
#include "fimc-is-param.h" #include "fimc-is-param.h"
#include "fimc-is-regs.h" #include "fimc-is-regs.h"
...@@ -93,8 +94,8 @@ void fimc_isp_irq_handler(struct fimc_is *is) ...@@ -93,8 +94,8 @@ void fimc_isp_irq_handler(struct fimc_is *is)
is->i2h_cmd.args[1] = mcuctl_read(is, MCUCTL_REG_ISSR(21)); is->i2h_cmd.args[1] = mcuctl_read(is, MCUCTL_REG_ISSR(21));
fimc_is_fw_clear_irq1(is, FIMC_IS_INT_FRAME_DONE_ISP); fimc_is_fw_clear_irq1(is, FIMC_IS_INT_FRAME_DONE_ISP);
fimc_isp_video_irq_handler(is);
/* TODO: Complete ISP DMA interrupt handler */
wake_up(&is->irq_queue); wake_up(&is->irq_queue);
} }
...@@ -388,7 +389,33 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd, ...@@ -388,7 +389,33 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd,
return 0; return 0;
} }
static int fimc_isp_subdev_registered(struct v4l2_subdev *sd)
{
struct fimc_isp *isp = v4l2_get_subdevdata(sd);
int ret;
/* Use pipeline object allocated by the media device. */
isp->video_capture.ve.pipe = v4l2_get_subdev_hostdata(sd);
ret = fimc_isp_video_device_register(isp, sd->v4l2_dev,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (ret < 0)
isp->video_capture.ve.pipe = NULL;
return ret;
}
static void fimc_isp_subdev_unregistered(struct v4l2_subdev *sd)
{
struct fimc_isp *isp = v4l2_get_subdevdata(sd);
fimc_isp_video_device_unregister(isp,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
}
static const struct v4l2_subdev_internal_ops fimc_is_subdev_internal_ops = { static const struct v4l2_subdev_internal_ops fimc_is_subdev_internal_ops = {
.registered = fimc_isp_subdev_registered,
.unregistered = fimc_isp_subdev_unregistered,
.open = fimc_isp_subdev_open, .open = fimc_isp_subdev_open,
}; };
......
...@@ -35,17 +35,18 @@ extern int fimc_isp_debug; ...@@ -35,17 +35,18 @@ extern int fimc_isp_debug;
#define FIMC_ISP_SINK_WIDTH_MIN (16 + 8) #define FIMC_ISP_SINK_WIDTH_MIN (16 + 8)
#define FIMC_ISP_SINK_HEIGHT_MIN (12 + 8) #define FIMC_ISP_SINK_HEIGHT_MIN (12 + 8)
#define FIMC_ISP_SOURCE_WIDTH_MIN 8 #define FIMC_ISP_SOURCE_WIDTH_MIN 8
#define FIMC_ISP_SOURC_HEIGHT_MIN 8 #define FIMC_ISP_SOURCE_HEIGHT_MIN 8
#define FIMC_ISP_CAC_MARGIN_WIDTH 16 #define FIMC_ISP_CAC_MARGIN_WIDTH 16
#define FIMC_ISP_CAC_MARGIN_HEIGHT 12 #define FIMC_ISP_CAC_MARGIN_HEIGHT 12
#define FIMC_ISP_SINK_WIDTH_MAX (4000 - 16) #define FIMC_ISP_SINK_WIDTH_MAX (4000 - 16)
#define FIMC_ISP_SINK_HEIGHT_MAX (4000 + 12) #define FIMC_ISP_SINK_HEIGHT_MAX (4000 + 12)
#define FIMC_ISP_SOURCE_WIDTH_MAX 4000 #define FIMC_ISP_SOURCE_WIDTH_MAX 4000
#define FIMC_ISP_SOURC_HEIGHT_MAX 4000 #define FIMC_ISP_SOURCE_HEIGHT_MAX 4000
#define FIMC_ISP_NUM_FORMATS 3 #define FIMC_ISP_NUM_FORMATS 3
#define FIMC_ISP_REQ_BUFS_MIN 2 #define FIMC_ISP_REQ_BUFS_MIN 2
#define FIMC_ISP_REQ_BUFS_MAX 32
#define FIMC_ISP_SD_PAD_SINK 0 #define FIMC_ISP_SD_PAD_SINK 0
#define FIMC_ISP_SD_PAD_SRC_FIFO 1 #define FIMC_ISP_SD_PAD_SRC_FIFO 1
...@@ -100,6 +101,16 @@ struct fimc_isp_ctrls { ...@@ -100,6 +101,16 @@ struct fimc_isp_ctrls {
struct v4l2_ctrl *colorfx; struct v4l2_ctrl *colorfx;
}; };
struct isp_video_buf {
struct vb2_buffer vb;
dma_addr_t dma_addr[FIMC_ISP_MAX_PLANES];
unsigned int index;
};
#define to_isp_video_buf(_b) container_of(_b, struct isp_video_buf, vb)
#define FIMC_ISP_MAX_BUFS 4
/** /**
* struct fimc_is_video - fimc-is video device structure * struct fimc_is_video - fimc-is video device structure
* @vdev: video_device structure * @vdev: video_device structure
...@@ -114,18 +125,26 @@ struct fimc_isp_ctrls { ...@@ -114,18 +125,26 @@ struct fimc_isp_ctrls {
* @format: current pixel format * @format: current pixel format
*/ */
struct fimc_is_video { struct fimc_is_video {
struct video_device vdev; struct exynos_video_entity ve;
enum v4l2_buf_type type; enum v4l2_buf_type type;
struct media_pad pad; struct media_pad pad;
struct list_head pending_buf_q; struct list_head pending_buf_q;
struct list_head active_buf_q; struct list_head active_buf_q;
struct vb2_queue vb_queue; struct vb2_queue vb_queue;
unsigned int frame_count;
unsigned int reqbufs_count; unsigned int reqbufs_count;
unsigned int buf_count;
unsigned int buf_mask;
unsigned int frame_count;
int streaming; int streaming;
struct isp_video_buf *buffers[FIMC_ISP_MAX_BUFS];
const struct fimc_fmt *format; const struct fimc_fmt *format;
struct v4l2_pix_format_mplane pixfmt;
}; };
/* struct fimc_isp:state bit definitions */
#define ST_ISP_VID_CAP_BUF_PREP 0
#define ST_ISP_VID_CAP_STREAMING 1
/** /**
* struct fimc_isp - FIMC-IS ISP data structure * struct fimc_isp - FIMC-IS ISP data structure
* @pdev: pointer to FIMC-IS platform device * @pdev: pointer to FIMC-IS platform device
......
...@@ -684,8 +684,16 @@ static int register_csis_entity(struct fimc_md *fmd, ...@@ -684,8 +684,16 @@ static int register_csis_entity(struct fimc_md *fmd,
static int register_fimc_is_entity(struct fimc_md *fmd, struct fimc_is *is) static int register_fimc_is_entity(struct fimc_md *fmd, struct fimc_is *is)
{ {
struct v4l2_subdev *sd = &is->isp.subdev; struct v4l2_subdev *sd = &is->isp.subdev;
struct exynos_media_pipeline *ep;
int ret; int ret;
/* Allocate pipeline object for the ISP capture video node. */
ep = fimc_md_pipeline_create(fmd);
if (!ep)
return -ENOMEM;
v4l2_set_subdev_hostdata(sd, ep);
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
if (ret) { if (ret) {
v4l2_err(&fmd->v4l2_dev, v4l2_err(&fmd->v4l2_dev,
...@@ -959,16 +967,17 @@ static int __fimc_md_create_flite_source_links(struct fimc_md *fmd) ...@@ -959,16 +967,17 @@ static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
/* Create FIMC-IS links */ /* Create FIMC-IS links */
static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd) static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd)
{ {
struct fimc_isp *isp = &fmd->fimc_is->isp;
struct media_entity *source, *sink; struct media_entity *source, *sink;
int i, ret; int i, ret;
source = &fmd->fimc_is->isp.subdev.entity; source = &isp->subdev.entity;
for (i = 0; i < FIMC_MAX_DEVS; i++) { for (i = 0; i < FIMC_MAX_DEVS; i++) {
if (fmd->fimc[i] == NULL) if (fmd->fimc[i] == NULL)
continue; continue;
/* Link from IS-ISP subdev to FIMC */ /* Link from FIMC-IS-ISP subdev to FIMC */
sink = &fmd->fimc[i]->vid_cap.subdev.entity; sink = &fmd->fimc[i]->vid_cap.subdev.entity;
ret = media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_FIFO, ret = media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_FIFO,
sink, FIMC_SD_PAD_SINK_FIFO, 0); sink, FIMC_SD_PAD_SINK_FIFO, 0);
...@@ -976,7 +985,15 @@ static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd) ...@@ -976,7 +985,15 @@ static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd)
return ret; return ret;
} }
return ret; /* Link from FIMC-IS-ISP subdev to fimc-is-isp.capture video node */
sink = &isp->video_capture.ve.vdev.entity;
/* Skip this link if the fimc-is-isp video node driver isn't built-in */
if (sink->num_pads == 0)
return 0;
return media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_DMA,
sink, 0, 0);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment