ret = fimc_set_scaler_info(ctx); if (!ret) {
fimc_hw_set_input_path(ctx);
fimc_hw_set_prescaler(ctx);
fimc_hw_set_mainscaler(ctx);
fimc_hw_set_target_format(ctx);
fimc_hw_set_rotation(ctx);
fimc_hw_set_effect(ctx);
fimc_hw_set_output_path(ctx);
fimc_hw_set_out_dma(ctx); if (fimc->drv_data->alpha_color)
fimc_hw_set_rgb_alpha(ctx);
clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
}
spin_unlock_irqrestore(&fimc->slock, flags); return ret;
}
/* * 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.
*/ staticint fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)
{ struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *buf; unsignedlong flags; bool streaming;
/** * fimc_capture_config_update - apply the camera interface configuration * @ctx: FIMC capture context * * To be called from within the interrupt handler with fimc.slock * spinlock held. It updates the camera pixel crop, rotation and * image flip in H/W.
*/ staticint fimc_capture_config_update(struct fimc_ctx *ctx)
{ struct fimc_dev *fimc = ctx->fimc_dev; int ret;
fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
ret = fimc_set_scaler_info(ctx); if (ret) return ret;
if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
cap->buf_index = 0;
} /* * Set up a buffer at MIPI-CSIS if current image format * requires the frame embedded data capture.
*/ if (f->fmt->mdataplanes && !list_empty(&cap->active_buf_q)) { unsignedint plane = ffs(f->fmt->mdataplanes) - 1; unsignedint size = f->payload[plane];
s32 index = fimc_hw_get_frame_index(fimc); void *vaddr;
for (i = 0; i < vid_cap->reqbufs_count; i++) { if (list_empty(&vid_cap->pending_buf_q)) break;
buf = fimc_pending_queue_pop(vid_cap);
buffer_queue(&buf->vb.vb2_buf);
} return 0;
if (*num_planes) { if (*num_planes != fmt->memplanes) return -EINVAL; for (i = 0; i < *num_planes; i++) if (sizes[i] < (wh * fmt->depth[i]) / 8) return -EINVAL; return 0;
}
*num_planes = fmt->memplanes;
for (i = 0; i < fmt->memplanes; i++) { unsignedint size = (wh * fmt->depth[i]) / 8;
/* Conversion from/to JPEG or User Defined format is not supported */ if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE &&
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_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_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 */
v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4,
height, max_t(u32, *height, 32),
FIMC_CAMIF_MAX_HEIGHT,
fimc_fmt_is_user_defined(ffmt->color) ?
3 : 1,
0); return ffmt;
} /* Can't scale or crop in transparent (JPEG) transfer mode */ if (fimc_fmt_is_user_defined(ffmt->color)) {
*width = ctx->s_frame.f_width;
*height = ctx->s_frame.f_height; return ffmt;
} /* Apply the scaler and the output DMA constraints */
max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w; if (ctx->state & FIMC_COMPOSE) {
min_w = dst->offs_h + dst->width;
min_h = dst->offs_v + dst->height;
} else {
min_w = var->min_out_pixsize;
min_h = var->min_out_pixsize;
} if (var->min_vsize_align == 1 && !rotation)
align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1;
/* In JPEG transparent transfer mode cropping is not supported */ if (fimc_fmt_is_user_defined(ctx->d_frame.fmt->color)) {
r->width = sink->f_width;
r->height = sink->f_height;
r->left = r->top = 0; return;
} if (target == V4L2_SEL_TGT_COMPOSE) {
u32 tmp_min_h = ffs(sink->width) - 3;
u32 tmp_min_v = ffs(sink->height) - 1;
if (ctx->rotation != 90 && ctx->rotation != 270)
align_h = 1;
max_sc_h = min(SCALER_MAX_HRATIO, 1 << tmp_min_h);
max_sc_v = min(SCALER_MAX_VRATIO, 1 << tmp_min_v);
min_sz = var->min_out_pixsize;
} else {
u32 depth = fimc_get_format_depth(sink->fmt);
align_sz = 64/ALIGN(depth, 8);
min_sz = var->min_inp_pixsize;
min_w = min_h = min_sz;
max_sc_h = max_sc_v = 1;
} /* * For the compose rectangle the following constraints must be met: * - it must fit in the sink pad format rectangle (f_width/f_height); * - maximum downscaling ratio is 64; * - maximum crop size depends if the rotator is used or not; * - the sink pad format width/height must be 4 multiple of the * prescaler ratios determined by sink pad size and source pad crop, * the prescaler ratio is returned by fimc_get_scaler_factor().
*/
max_w = min_t(u32,
rotate ? pl->out_rot_en_w : pl->out_rot_dis_w,
rotate ? sink->f_height : sink->f_width);
max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height);
/** * fimc_get_sensor_frame_desc - query the sensor for media bus frame parameters * @sensor: pointer to the sensor subdev * @plane_fmt: provides plane sizes corresponding to the frame layout entries * @num_planes: number of planes * @try: true to set the frame parameters, false to query only * * This function is used by this driver only for compressed/blob data formats.
*/ staticint fimc_get_sensor_frame_desc(struct v4l2_subdev *sensor, struct v4l2_plane_pix_format *plane_fmt, unsignedint num_planes, booltry)
{ struct v4l2_mbus_frame_desc fd = { }; int i, ret; int pad;
for (i = 0; i < num_planes; i++)
fd.entry[i].length = plane_fmt[i].sizeimage;
pad = sensor->entity.num_pads - 1; if (try)
ret = v4l2_subdev_call(sensor, pad, set_frame_desc, pad, &fd); else
ret = v4l2_subdev_call(sensor, pad, get_frame_desc, pad, &fd);
if (ret < 0) return ret;
if (num_planes != fd.num_entries) return -EINVAL;
for (i = 0; i < num_planes; i++)
plane_fmt[i].sizeimage = fd.entry[i].length;
/* * Try or set format on the fimc.X.capture video node and additionally * on the whole pipeline if @try is false. * Locking: the caller must _not_ hold the graph mutex.
*/ staticint __video_try_or_set_format(struct fimc_dev *fimc, struct v4l2_format *f, booltry, conststruct fimc_fmt **inp_fmt, conststruct fimc_fmt **out_fmt)
{ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; struct fimc_vid_cap *vc = &fimc->vid_cap; struct exynos_video_entity *ve = &vc->ve; struct fimc_ctx *ctx = vc->ctx; unsignedint width = 0, height = 0; int ret = 0;
/* Pre-configure format at the camera input interface, for JPEG only */ if (fimc_jpeg_fourcc(pix->pixelformat)) {
fimc_capture_try_format(ctx, &pix->width, &pix->height,
NULL, &pix->pixelformat,
FIMC_SD_PAD_SINK_CAM); if (try) {
width = pix->width;
height = pix->height;
} else {
ctx->s_frame.f_width = pix->width;
ctx->s_frame.f_height = pix->height;
}
}
/* Try the format at the scaler and the DMA output */
*out_fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,
NULL, &pix->pixelformat,
FIMC_SD_PAD_SOURCE); if (*out_fmt == NULL) return -EINVAL;
/* Restore image width/height for JPEG (no resizing supported). */ if (try && fimc_jpeg_fourcc(pix->pixelformat)) {
pix->width = width;
pix->height = height;
}
/* Try to match format at the host and the sensor */ if (!vc->user_subdev_api) { struct v4l2_mbus_framefmt mbus_fmt; struct v4l2_mbus_framefmt *mf;
if (vb2_is_busy(&fimc->vid_cap.vbq)) return -EBUSY;
ret = __video_try_or_set_format(fimc, f, false, &inp_fmt, &ff->fmt); if (ret < 0) return ret;
/* Update RGB Alpha control state and value range */
fimc_alpha_ctrl_update(ctx);
for (i = 0; i < ff->fmt->memplanes; i++) {
ff->bytesperline[i] = pix->plane_fmt[i].bytesperline;
ff->payload[i] = pix->plane_fmt[i].sizeimage;
}
set_frame_bounds(ff, pix->width, pix->height); /* Reset the composition rectangle if not yet configured */ if (!(ctx->state & FIMC_COMPOSE))
set_frame_crop(ff, 0, 0, pix->width, pix->height);
fimc_capture_mark_jpeg_xfer(ctx, ff->fmt->color);
/* Reset cropping and set format at the camera interface input */ if (!vc->user_subdev_api) {
ctx->s_frame.fmt = inp_fmt;
set_frame_bounds(&ctx->s_frame, pix->width, pix->height);
set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height);
}
/** * fimc_pipeline_validate - check for formats inconsistencies * between source and sink pad of each link * @fimc: the FIMC device this context applies to * * Return 0 if all formats match or -EPIPE otherwise.
*/ staticint fimc_pipeline_validate(struct fimc_dev *fimc)
{ struct v4l2_subdev_format sink_fmt = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
}; struct v4l2_subdev_format src_fmt = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
}; struct fimc_vid_cap *vc = &fimc->vid_cap; struct v4l2_subdev *sd = &vc->subdev; struct fimc_pipeline *p = to_fimc_pipeline(vc->ve.pipe); struct media_pad *sink_pad, *src_pad; int i, ret;
while (1) { /* * 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_pad_remote_pad_first(sink_pad); if (src_pad) break;
}
}
if (!src_pad || !is_media_entity_v4l2_subdev(src_pad->entity)) break;
/* Retrieve format at the source pad */
sd = media_entity_to_v4l2_subdev(src_pad->entity);
src_fmt.pad = src_pad->index;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt); if (ret < 0 && ret != -ENOIOCTLCMD) return -EPIPE;
ret = video_device_pipeline_start(&vc->ve.vdev, &vc->ve.pipe->mp); if (ret < 0) return ret;
sd = __fimc_md_get_subdev(vc->ve.pipe, 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) goto err_p_stop;
}
ret = vb2_ioctl_streamon(file, priv, type); if (!ret) {
vc->streaming = true; return ret;
}
/** * fimc_sensor_notify - v4l2_device notification from a sensor subdev * @sd: pointer to a subdev generating the notification * @notification: the notification type, must be S5P_FIMC_TX_END_NOTIFY * @arg: pointer to an u32 type integer that stores the frame payload value * * The End Of Frame notification sent by sensor subdev in its still capture * mode. If there is only a single VSYNC generated by the sensor at the * beginning of a frame transmission, FIMC does not issue the LastIrq * (end of frame) interrupt. And this notification is used to complete the * frame capture and returning a buffer to user-space. Subdev drivers should * call this notification from their last 'End of frame capture' interrupt.
*/ void fimc_sensor_notify(struct v4l2_subdev *sd, unsignedint notification, void *arg)
{ struct fimc_source_info *si; struct fimc_vid_buffer *buf; struct fimc_md *fmd; struct fimc_dev *fimc; unsignedlong flags;
if (sd == NULL) return;
si = v4l2_get_subdev_hostdata(sd);
fmd = entity_to_fimc_mdev(&sd->entity);
spin_lock_irqsave(&fmd->slock, flags);
fimc = si ? source_to_sensor_info(si)->host : NULL;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*mf = fmt->format; return 0;
} /* There must be a bug in the driver if this happens */ if (WARN_ON(ffmt == NULL)) return -EINVAL;
/* Update RGB Alpha control state and value range */
fimc_alpha_ctrl_update(ctx);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.