Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 237e0265 authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab
Browse files

[media] s5p-fimc: Add subdev for the FIMC processing block



Add a subdev to expose the host's scaling and composition functions.
The camera frame composition onto an output buffer may be configured
through set/get_crop at FIMC.{n} source pad.
Additionally allow crop, composition and controls to be modified
during streaming. Make sure the default format is set when opening
the video capture node.
Rename struct fimc_vid_cap::fmt to more relevant 'mf' to avoid
confusion.

Signed-off-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 4db5e27e
Loading
Loading
Loading
Loading
+657 −77

File changed.

Preview size limit exceeded, changes collapsed.

+11 −19
Original line number Diff line number Diff line
@@ -372,6 +372,8 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc)
		set_bit(ST_CAPT_RUN, &fimc->state);
	}

	fimc_capture_config_update(cap->ctx);

	dbg("frame: %d, active_buf_cnt: %d",
	    fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
}
@@ -1198,12 +1200,11 @@ static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
	return 0;
}

int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
{
	struct fimc_dev *fimc = ctx->fimc_dev;
	struct fimc_frame *f;
	u32 min_size, halign, depth = 0;
	bool is_capture_ctx;
	int i;

	if (cr->c.top < 0 || cr->c.left < 0) {
@@ -1211,13 +1212,9 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
			"doesn't support negative values for top & left\n");
		return -EINVAL;
	}

	is_capture_ctx = fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx);

	if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
		f = is_capture_ctx ? &ctx->s_frame : &ctx->d_frame;
	else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
		 !is_capture_ctx)
		f = &ctx->d_frame;
	else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
		f = &ctx->s_frame;
	else
		return -EINVAL;
@@ -1226,15 +1223,10 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
		fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;

	/* Get pixel alignment constraints. */
	if (is_capture_ctx) {
		min_size = 16;
		halign = 4;
	} else {
	if (fimc->id == 1 && fimc->variant->pix_hoff)
		halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
	else
		halign = ffs(min_size) - 1;
	}

	for (i = 0; i < f->fmt->colplanes; i++)
		depth += f->fmt->depth[i];
@@ -1251,7 +1243,7 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
		cr->c.top = f->o_height - cr->c.height;

	cr->c.left = round_down(cr->c.left, min_size);
	cr->c.top  = round_down(cr->c.top, is_capture_ctx ? 16 : 8);
	cr->c.top  = round_down(cr->c.top, fimc->variant->hor_offs_align);

	dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
	    cr->c.left, cr->c.top, cr->c.width, cr->c.height,
@@ -1267,7 +1259,7 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
	struct fimc_frame *f;
	int ret;

	ret = fimc_try_crop(ctx, cr);
	ret = fimc_m2m_try_crop(ctx, cr);
	if (ret)
		return ret;

+46 −7
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#define SCALER_MAX_HRATIO	64
#define SCALER_MAX_VRATIO	64
#define DMA_MIN_SIZE		8
#define FIMC_CAMIF_MAX_HEIGHT	0x2000

/* indices to the clocks array */
enum {
@@ -92,9 +93,11 @@ enum fimc_color_fmt {
	S5P_FIMC_CBYCRY422,
	S5P_FIMC_CRYCBY422,
	S5P_FIMC_YCBCR444_LOCAL,
	S5P_FIMC_JPEG = 0x40,
};

#define fimc_fmt_is_rgb(x) ((x) & 0x10)
#define fimc_fmt_is_rgb(x) (!!((x) & 0x10))
#define fimc_fmt_is_jpeg(x) (!!((x) & 0x40))

#define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \
			__strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
@@ -116,9 +119,10 @@ enum fimc_color_fmt {
#define	FIMC_DST_ADDR		(1 << 2)
#define	FIMC_SRC_FMT		(1 << 3)
#define	FIMC_DST_FMT		(1 << 4)
#define	FIMC_CTX_M2M		(1 << 5)
#define	FIMC_CTX_CAP		(1 << 6)
#define	FIMC_CTX_SHUT		(1 << 7)
#define	FIMC_DST_CROP		(1 << 5)
#define	FIMC_CTX_M2M		(1 << 16)
#define	FIMC_CTX_CAP		(1 << 17)
#define	FIMC_CTX_SHUT		(1 << 18)

/* Image conversion flags */
#define	FIMC_IN_DMA_ACCESS_TILED	(1 << 0)
@@ -293,12 +297,18 @@ struct fimc_m2m_device {
	int			refcnt;
};

#define FIMC_SD_PAD_SINK	0
#define FIMC_SD_PAD_SOURCE	1
#define FIMC_SD_PADS_NUM	2

/**
 * struct fimc_vid_cap - camera capture device information
 * @ctx: hardware context data
 * @vfd: video device node for camera capture mode
 * @subdev: subdev exposing the FIMC processing block
 * @vd_pad: fimc video capture node pad
 * @fmt: Media Bus format configured at selected image sensor
 * @sd_pads: fimc video processing block pads
 * @mf: media bus format at the FIMC camera input (and the scaler output) pad
 * @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
@@ -315,8 +325,10 @@ struct fimc_vid_cap {
	struct fimc_ctx			*ctx;
	struct vb2_alloc_ctx		*alloc_ctx;
	struct video_device		*vfd;
	struct v4l2_subdev		*subdev;
	struct media_pad		vd_pad;
	struct v4l2_mbus_framefmt	fmt;
	struct v4l2_mbus_framefmt	mf;
	struct media_pad		sd_pads[FIMC_SD_PADS_NUM];
	struct list_head		pending_buf_q;
	struct list_head		active_buf_q;
	struct vb2_queue		vbq;
@@ -498,6 +510,33 @@ struct fimc_ctx {

#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh)

static inline void set_frame_bounds(struct fimc_frame *f, u32 width, u32 height)
{
	f->o_width  = width;
	f->o_height = height;
	f->f_width  = width;
	f->f_height = height;
}

static inline void set_frame_crop(struct fimc_frame *f,
				  u32 left, u32 top, u32 width, u32 height)
{
	f->offs_h = left;
	f->offs_v = top;
	f->width  = width;
	f->height = height;
}

static inline u32 fimc_get_format_depth(struct fimc_fmt *ff)
{
	u32 i, depth = 0;

	if (ff != NULL)
		for (i = 0; i < ff->colplanes; i++)
			depth += ff->depth[i];
	return depth;
}

static inline bool fimc_capture_active(struct fimc_dev *fimc)
{
	unsigned long flags;
@@ -649,7 +688,6 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
/* fimc-core.c */
int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
				struct v4l2_fmtdesc *f);
int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr);
int fimc_ctrls_create(struct fimc_ctx *ctx);
void fimc_ctrls_delete(struct fimc_ctx *ctx);
void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
@@ -684,6 +722,7 @@ int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
			     struct fimc_vid_buffer *fimc_vb);
int fimc_capture_suspend(struct fimc_dev *fimc);
int fimc_capture_resume(struct fimc_dev *fimc);
int fimc_capture_config_update(struct fimc_ctx *ctx);

/* Locking: the caller holds fimc->slock */
static inline void fimc_activate_capture(struct fimc_ctx *ctx)
+33 −14
Original line number Diff line number Diff line
@@ -416,7 +416,7 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
	struct fimc_sensor_info *s_info;
	struct media_entity *sink;
	unsigned int flags;
	int ret, i, src_pad;
	int ret, i;

	for (i = 0; i < FIMC_MAX_DEVS; i++) {
		if (!fmd->fimc[i])
@@ -425,20 +425,27 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
		 * Some FIMC variants are not fitted with camera capture
		 * interface. Skip creating a link from sensor for those.
		 */
		if (sensor && sensor->grp_id == SENSOR_GROUP_ID &&
		if (sensor->grp_id == SENSOR_GROUP_ID &&
		    !fmd->fimc[i]->variant->has_cam_if)
			continue;

		flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
		sink = &fmd->fimc[i]->vid_cap.vfd->entity;
		ret = media_entity_create_link(source, 0, sink, 0, flags);
		sink = &fmd->fimc[i]->vid_cap.subdev->entity;
		ret = media_entity_create_link(source, pad, sink,
					      FIMC_SD_PAD_SINK, flags);
		if (ret)
			return ret;

		/* Notify FIMC capture subdev entity */
		ret = media_entity_call(sink, link_setup, &sink->pads[0],
					&source->pads[pad], flags);
		if (ret)
			break;

		v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
			  source->name, flags ? '=' : '-', sink->name);

		if (flags == 0 || sensor == NULL)
		if (flags == 0)
			continue;
		s_info = v4l2_get_subdev_hostdata(sensor);
		if (!WARN_ON(s_info == NULL)) {
@@ -468,10 +475,10 @@ static int fimc_md_create_links(struct fimc_md *fmd)
	struct v4l2_subdev *sensor, *csis;
	struct s5p_fimc_isp_info *pdata;
	struct fimc_sensor_info *s_info;
	struct media_entity *source;
	int fimc_id = 0;
	int i, pad;
	struct media_entity *source, *sink;
	int i, pad, fimc_id = 0;
	int ret = 0;
	u32 flags;

	for (i = 0; i < fmd->num_sensors; i++) {
		if (fmd->sensor[i].subdev == NULL)
@@ -507,7 +514,6 @@ static int fimc_md_create_links(struct fimc_md *fmd)
			v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]",
				  sensor->entity.name, csis->entity.name);

			sensor = NULL;
			source = &csis->entity;
			pad = CSIS_PAD_SOURCE;
			break;
@@ -528,6 +534,19 @@ static int fimc_md_create_links(struct fimc_md *fmd)
		ret = __fimc_md_create_fimc_links(fmd, source, sensor, pad,
						  fimc_id++);
	}
	/* Create immutable links between each FIMC's subdev and video node */
	flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
	for (i = 0; i < FIMC_MAX_DEVS; i++) {
		if (!fmd->fimc[i])
			continue;
		source = &fmd->fimc[i]->vid_cap.subdev->entity;
		sink = &fmd->fimc[i]->vid_cap.vfd->entity;
		ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
					      sink, 0, flags);
		if (ret)
			break;
	}

	return ret;
}

@@ -636,15 +655,15 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
static int fimc_md_link_notify(struct media_pad *source,
			       struct media_pad *sink, u32 flags)
{
	struct video_device *vid_dev;
	struct v4l2_subdev *sd;
	struct fimc_dev *fimc;
	int ret = 0;

	if (WARN_ON(media_entity_type(sink->entity) != MEDIA_ENT_T_DEVNODE))
	if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
		return 0;

	vid_dev = media_entity_to_video_device(sink->entity);
	fimc = video_get_drvdata(vid_dev);
	sd = media_entity_to_v4l2_subdev(sink->entity);
	fimc = v4l2_get_subdevdata(sd);

	if (!(flags & MEDIA_LNK_FL_ENABLED)) {
		ret = __fimc_pipeline_shutdown(fimc);
+4 −4
Original line number Diff line number Diff line
@@ -572,7 +572,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,

	if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
		for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
			if (fimc->vid_cap.fmt.code == pix_desc[i].pixelcode) {
			if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
				cfg = pix_desc[i].cisrcfmt;
				bus_width = pix_desc[i].bus_width;
				break;
@@ -582,7 +582,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
		if (i == ARRAY_SIZE(pix_desc)) {
			v4l2_err(fimc->vid_cap.vfd,
				 "Camera color format not supported: %d\n",
				 fimc->vid_cap.fmt.code);
				 fimc->vid_cap.mf.code);
			return -EINVAL;
		}

@@ -642,12 +642,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
			cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;

		/* TODO: add remaining supported formats. */
		if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) {
		if (vid_cap->mf.code == V4L2_MBUS_FMT_VYUY8_2X8) {
			tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
		} else {
			v4l2_err(fimc->vid_cap.vfd,
				 "Not supported camera pixel format: %d",
				 vid_cap->fmt.code);
				 vid_cap->mf.code);
			return -EINVAL;
		}
		tmp |= (cam->csi_data_align == 32) << 8;