Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 366925
b: refs/heads/master
c: 88fa831
h: refs/heads/master
i:
  366923: a562bd9
v: v3
  • Loading branch information
Sylwester Nawrocki authored and Mauro Carvalho Chehab committed Mar 31, 2013
1 parent 5952ad0 commit 43472d1
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 80 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 056f4f3036394892ed591932326c11613b6584c1
refs/heads/master: 88fa8311ee36602362a1d6b61117dc3ac76ff8ad
1 change: 1 addition & 0 deletions trunk/drivers/media/platform/s5p-fimc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
config VIDEO_SAMSUNG_S5P_FIMC
bool "Samsung S5P/EXYNOS SoC camera interface driver (experimental)"
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PLAT_S5P && PM_RUNTIME
depends on MFD_SYSCON
help
Say Y here to enable camera host interface devices for
Samsung S5P and EXYNOS SoC series.
Expand Down
177 changes: 116 additions & 61 deletions trunk/drivers/media/platform/s5p-fimc/fimc-capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,27 @@

static int fimc_capture_hw_init(struct fimc_dev *fimc)
{
struct fimc_source_info *si = &fimc->vid_cap.source_config;
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
struct fimc_pipeline *p = &fimc->pipeline;
struct fimc_sensor_info *sensor;
int ret;
unsigned long flags;
int ret = 0;

if (p->subdevs[IDX_SENSOR] == NULL || ctx == NULL)
return -ENXIO;
if (ctx->s_frame.fmt == NULL)
if (ctx == NULL || ctx->s_frame.fmt == NULL)
return -EINVAL;

sensor = v4l2_get_subdev_hostdata(p->subdevs[IDX_SENSOR]);
if (si->fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) {
ret = fimc_hw_camblk_cfg_writeback(fimc);
if (ret < 0)
return ret;
}

spin_lock_irqsave(&fimc->slock, flags);
fimc_prepare_dma_offset(ctx, &ctx->d_frame);
fimc_set_yuv_order(ctx);

fimc_hw_set_camera_polarity(fimc, &sensor->pdata);
fimc_hw_set_camera_type(fimc, &sensor->pdata);
fimc_hw_set_camera_source(fimc, &sensor->pdata);
fimc_hw_set_camera_polarity(fimc, si);
fimc_hw_set_camera_type(fimc, si);
fimc_hw_set_camera_source(fimc, si);
fimc_hw_set_camera_offset(fimc, &ctx->s_frame);

ret = fimc_set_scaler_info(ctx);
Expand Down Expand Up @@ -606,18 +607,22 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,
fimc_fmt_is_user_defined(ctx->s_frame.fmt->color))
*code = ctx->s_frame.fmt->mbus_code;

if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK)
if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad == FIMC_SD_PAD_SOURCE)
mask |= FMT_FLAGS_M2M;

if (pad == FIMC_SD_PAD_SINK_FIFO)
mask = FMT_FLAGS_WRITEBACK;

ffmt = fimc_find_format(fourcc, code, mask, 0);
if (WARN_ON(!ffmt))
return NULL;

if (code)
*code = ffmt->mbus_code;
if (fourcc)
*fourcc = ffmt->fourcc;

if (pad == FIMC_SD_PAD_SINK) {
if (pad != FIMC_SD_PAD_SOURCE) {
max_w = fimc_fmt_is_user_defined(ffmt->color) ?
pl->scaler_dis_w : pl->scaler_en_w;
/* Apply the camera input interface pixel constraints */
Expand Down Expand Up @@ -851,7 +856,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
tfmt->width = mf->width;
tfmt->height = mf->height;
ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height,
NULL, &fcc, FIMC_SD_PAD_SINK);
NULL, &fcc, FIMC_SD_PAD_SINK_CAM);
ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height,
NULL, &fcc, FIMC_SD_PAD_SOURCE);
if (ffmt && ffmt->mbus_code)
Expand Down Expand Up @@ -938,7 +943,7 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
if (fimc_jpeg_fourcc(pix->pixelformat)) {
fimc_capture_try_format(ctx, &pix->width, &pix->height,
NULL, &pix->pixelformat,
FIMC_SD_PAD_SINK);
FIMC_SD_PAD_SINK_CAM);
ctx->s_frame.f_width = pix->width;
ctx->s_frame.f_height = pix->height;
}
Expand Down Expand Up @@ -992,7 +997,7 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc,
{
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.mf;
struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.ci_fmt;
struct fimc_frame *ff = &ctx->d_frame;
struct fimc_fmt *s_fmt = NULL;
int ret, i;
Expand All @@ -1004,7 +1009,7 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc,
if (fimc_jpeg_fourcc(pix->pixelformat)) {
fimc_capture_try_format(ctx, &pix->width, &pix->height,
NULL, &pix->pixelformat,
FIMC_SD_PAD_SINK);
FIMC_SD_PAD_SINK_CAM);
ctx->s_frame.f_width = pix->width;
ctx->s_frame.f_height = pix->height;
}
Expand Down Expand Up @@ -1121,44 +1126,51 @@ static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i)
static int fimc_pipeline_validate(struct fimc_dev *fimc)
{
struct v4l2_subdev_format sink_fmt, src_fmt;
struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
struct v4l2_subdev *sd;
struct media_pad *pad;
int ret;

/* Start with the video capture node pad */
pad = media_entity_remote_source(&vid_cap->vd_pad);
if (pad == NULL)
return -EPIPE;
/* FIMC.{N} subdevice */
sd = media_entity_to_v4l2_subdev(pad->entity);
struct fimc_vid_cap *vc = &fimc->vid_cap;
struct v4l2_subdev *sd = &vc->subdev;
struct media_pad *sink_pad, *src_pad;
int i, ret;

while (1) {
/* Retrieve format at the sink pad */
pad = &sd->entity.pads[0];
if (!(pad->flags & MEDIA_PAD_FL_SINK))
/*
* Find current entity sink pad and any remote sink pad linked
* to it. We stop if there is no sink pad in current entity or
* it is not linked to any other remote entity.
*/
src_pad = NULL;

for (i = 0; i < sd->entity.num_pads; i++) {
struct media_pad *p = &sd->entity.pads[i];

if (p->flags & MEDIA_PAD_FL_SINK) {
sink_pad = p;
src_pad = media_entity_remote_source(sink_pad);
if (src_pad)
break;
}
}

if (src_pad == NULL ||
media_entity_type(src_pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
break;

/* Don't call FIMC subdev operation to avoid nested locking */
if (sd == &fimc->vid_cap.subdev) {
struct fimc_frame *ff = &vid_cap->ctx->s_frame;
if (sd == &vc->subdev) {
struct fimc_frame *ff = &vc->ctx->s_frame;
sink_fmt.format.width = ff->f_width;
sink_fmt.format.height = ff->f_height;
sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0;
} else {
sink_fmt.pad = pad->index;
sink_fmt.pad = sink_pad->index;
sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD)
return -EPIPE;
}
/* Retrieve format at the source pad */
pad = media_entity_remote_source(pad);
if (pad == NULL ||
media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
break;

sd = media_entity_to_v4l2_subdev(pad->entity);
src_fmt.pad = pad->index;
/* Retrieve format at the source pad */
sd = media_entity_to_v4l2_subdev(src_pad->entity);
src_fmt.pad = src_pad->index;
src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD)
Expand All @@ -1172,7 +1184,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
if (sd == fimc->pipeline.subdevs[IDX_SENSOR] &&
fimc_user_defined_mbus_fmt(src_fmt.format.code)) {
struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES];
struct fimc_frame *frame = &vid_cap->ctx->d_frame;
struct fimc_frame *frame = &vc->ctx->d_frame;
unsigned int i;

ret = fimc_get_sensor_frame_desc(sd, plane_fmt,
Expand All @@ -1196,6 +1208,8 @@ static int fimc_cap_streamon(struct file *file, void *priv,
struct fimc_pipeline *p = &fimc->pipeline;
struct fimc_vid_cap *vc = &fimc->vid_cap;
struct media_entity *entity = &vc->vfd.entity;
struct fimc_source_info *si = NULL;
struct v4l2_subdev *sd;
int ret;

if (fimc_capture_active(fimc))
Expand All @@ -1205,6 +1219,23 @@ static int fimc_cap_streamon(struct file *file, void *priv,
if (ret < 0)
return ret;

sd = p->subdevs[IDX_SENSOR];
if (sd)
si = v4l2_get_subdev_hostdata(sd);

if (si == NULL) {
ret = -EPIPE;
goto err_p_stop;
}
/*
* Save configuration data related to currently attached image
* sensor or other data source, e.g. FIMC-IS.
*/
vc->source_config = *si;

if (vc->input == GRP_ID_FIMC_IS)
vc->source_config.fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK;

if (vc->user_subdev_api) {
ret = fimc_pipeline_validate(fimc);
if (ret < 0)
Expand Down Expand Up @@ -1461,25 +1492,37 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
struct fimc_frame *ff = &ctx->s_frame;
struct v4l2_mbus_framefmt *mf;
struct fimc_frame *ff;

if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
mf = v4l2_subdev_get_try_format(fh, fmt->pad);
fmt->format = *mf;
return 0;
}
mf = &fmt->format;
mf->colorspace = V4L2_COLORSPACE_JPEG;
ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame;

mf = &fmt->format;
mutex_lock(&fimc->lock);
/* The pixel code is same on both input and output pad */
if (!WARN_ON(ctx->s_frame.fmt == NULL))
mf->code = ctx->s_frame.fmt->mbus_code;
mf->width = ff->f_width;
mf->height = ff->f_height;

switch (fmt->pad) {
case FIMC_SD_PAD_SOURCE:
if (!WARN_ON(ff->fmt == NULL))
mf->code = ff->fmt->mbus_code;
/* Sink pads crop rectangle size */
mf->width = ff->width;
mf->height = ff->height;
break;
case FIMC_SD_PAD_SINK_FIFO:
*mf = fimc->vid_cap.wb_fmt;
break;
case FIMC_SD_PAD_SINK_CAM:
default:
*mf = fimc->vid_cap.ci_fmt;
break;
}

mutex_unlock(&fimc->lock);
mf->colorspace = V4L2_COLORSPACE_JPEG;

return 0;
}
Expand All @@ -1490,15 +1533,15 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf = &fmt->format;
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
struct fimc_vid_cap *vc = &fimc->vid_cap;
struct fimc_ctx *ctx = vc->ctx;
struct fimc_frame *ff;
struct fimc_fmt *ffmt;

dbg("pad%d: code: 0x%x, %dx%d",
fmt->pad, mf->code, mf->width, mf->height);

if (fmt->pad == FIMC_SD_PAD_SOURCE &&
vb2_is_busy(&fimc->vid_cap.vbq))
if (fmt->pad == FIMC_SD_PAD_SOURCE && vb2_is_busy(&vc->vbq))
return -EBUSY;

mutex_lock(&fimc->lock);
Expand All @@ -1520,21 +1563,32 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
fimc_alpha_ctrl_update(ctx);

fimc_capture_mark_jpeg_xfer(ctx, ffmt->color);

ff = fmt->pad == FIMC_SD_PAD_SINK ?
&ctx->s_frame : &ctx->d_frame;
if (fmt->pad == FIMC_SD_PAD_SOURCE) {
ff = &ctx->d_frame;
/* Sink pads crop rectangle size */
mf->width = ctx->s_frame.width;
mf->height = ctx->s_frame.height;
} else {
ff = &ctx->s_frame;
}

mutex_lock(&fimc->lock);
set_frame_bounds(ff, mf->width, mf->height);
fimc->vid_cap.mf = *mf;

if (fmt->pad == FIMC_SD_PAD_SINK_FIFO)
vc->wb_fmt = *mf;
else if (fmt->pad == FIMC_SD_PAD_SINK_CAM)
vc->ci_fmt = *mf;

ff->fmt = ffmt;

/* Reset the crop rectangle if required. */
if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_COMPOSE)))
set_frame_crop(ff, 0, 0, mf->width, mf->height);

if (fmt->pad == FIMC_SD_PAD_SINK)
if (fmt->pad != FIMC_SD_PAD_SOURCE)
ctx->state &= ~FIMC_COMPOSE;

mutex_unlock(&fimc->lock);
return 0;
}
Expand All @@ -1549,7 +1603,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
struct v4l2_rect *r = &sel->r;
struct v4l2_rect *try_sel;

if (sel->pad != FIMC_SD_PAD_SINK)
if (sel->pad == FIMC_SD_PAD_SOURCE)
return -EINVAL;

mutex_lock(&fimc->lock);
Expand Down Expand Up @@ -1605,7 +1659,7 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
struct v4l2_rect *try_sel;
unsigned long flags;

if (sel->pad != FIMC_SD_PAD_SINK)
if (sel->pad == FIMC_SD_PAD_SOURCE)
return -EINVAL;

mutex_lock(&fimc->lock);
Expand Down Expand Up @@ -1809,7 +1863,8 @@ int fimc_initialize_capture_subdev(struct fimc_dev *fimc)
sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->id);

fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_CAM].flags = MEDIA_PAD_FL_SINK;
fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_FIFO].flags = MEDIA_PAD_FL_SINK;
fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
fimc->vid_cap.sd_pads, 0);
Expand Down
10 changes: 10 additions & 0 deletions trunk/drivers/media/platform/s5p-fimc/fimc-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/list.h>
#include <linux/mfd/syscon.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
Expand Down Expand Up @@ -78,6 +79,10 @@ static struct fimc_fmt fimc_formats[] = {
.memplanes = 1,
.colplanes = 1,
.flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
}, {
.name = "YUV 4:4:4",
.mbus_code = V4L2_MBUS_FMT_YUV10_1X30,
.flags = FMT_FLAGS_WRITEBACK,
}, {
.name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
Expand Down Expand Up @@ -959,6 +964,11 @@ static int fimc_probe(struct platform_device *pdev)
spin_lock_init(&fimc->slock);
mutex_init(&fimc->lock);

fimc->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
"samsung,sysreg");
if (IS_ERR(fimc->sysreg))
return PTR_ERR(fimc->sysreg);

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
fimc->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(fimc->regs))
Expand Down
Loading

0 comments on commit 43472d1

Please sign in to comment.