return sink_code;
} break; case CAMSS_660: case CAMSS_7280: case CAMSS_8x96: case CAMSS_8250: case CAMSS_8280XP: case CAMSS_845: case CAMSS_8550: case CAMSS_X1E80100: switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_1X16:
{
u32 src_code[] = {
MEDIA_BUS_FMT_YUYV8_1X16,
MEDIA_BUS_FMT_YVYU8_1X16,
MEDIA_BUS_FMT_UYVY8_1X16,
MEDIA_BUS_FMT_VYUY8_1X16,
MEDIA_BUS_FMT_YUYV8_1_5X8,
};
v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip); /* Max frame skip is 29 frames */ if (frame_skip > VFE_FRAME_DROP_VAL - 1)
frame_skip = VFE_FRAME_DROP_VAL - 1;
}
spin_lock_irqsave(&vfe->output_lock, flags);
ops->reg_update_clear(vfe, line->id);
if (output->state > VFE_OUTPUT_RESERVED) {
dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
output->state);
spin_unlock_irqrestore(&vfe->output_lock, flags); return -EINVAL;
}
for (i = 0; i < 2; i++) {
output->buf[i] = vfe_buf_get_pending(output); if (!output->buf[i]) break;
output->gen2.active_num++;
ops->vfe_wm_update(vfe, output->wm_idx[0],
output->buf[i]->addr[0], line);
ops->reg_update(vfe, line->id);
}
spin_unlock_irqrestore(&vfe->output_lock, flags);
return 0;
}
/* * vfe_queue_buffer_v2 - Add empty buffer * @vid: Video device structure * @buf: Buffer to be enqueued * * Add an empty buffer - depending on the current number of buffers it will be * put in pending buffer queue or directly given to the hardware to be filled. * * Return 0 on success or a negative error code otherwise
*/ int vfe_queue_buffer_v2(struct camss_video *vid, struct camss_buffer *buf)
{ struct vfe_line *line = container_of(vid, struct vfe_line, video_out); struct vfe_device *vfe = to_vfe(line); conststruct vfe_hw_ops *ops = vfe->res->hw_ops; struct vfe_output *output; unsignedlong flags;
/* * vfe_enable_v2 - Enable streaming on VFE line * @line: VFE line * * Return 0 on success or a negative error code otherwise
*/ int vfe_enable_v2(struct vfe_line *line)
{ struct vfe_device *vfe = to_vfe(line); conststruct vfe_hw_ops *ops = vfe->res->hw_ops; int ret;
mutex_lock(&vfe->stream_lock);
if (vfe->res->hw_ops->enable_irq)
ops->enable_irq(vfe);
vfe->stream_count++;
mutex_unlock(&vfe->stream_lock);
ret = vfe_get_output_v2(line); if (ret < 0) goto error_get_output;
ret = vfe_enable_output_v2(line); if (ret < 0) goto error_enable_output;
vfe->was_streaming = 1;
return 0;
error_enable_output:
vfe_put_output(line);
error_get_output:
mutex_lock(&vfe->stream_lock);
vfe->stream_count--;
mutex_unlock(&vfe->stream_lock);
return ret;
}
/* * vfe_get_output_v2 - Get vfe output port for corresponding VFE line * @line: VFE line * * Return 0 on success or a negative error code otherwise
*/ int vfe_get_output_v2(struct vfe_line *line)
{ struct vfe_device *vfe = to_vfe(line); struct vfe_output *output; unsignedlong flags;
spin_lock_irqsave(&vfe->output_lock, flags);
output = &line->output; if (output->state > VFE_OUTPUT_RESERVED) {
dev_err(vfe->camss->dev, "Output is running\n"); goto error;
}
output->wm_num = 1;
/* Correspondence between VFE line number and WM number. * line 0 -> RDI 0, line 1 -> RDI1, line 2 -> RDI2, line 3 -> PIX/RDI3 * Note this 1:1 mapping will not work for PIX streams.
*/
output->wm_idx[0] = line->id;
vfe->wm_output_map[line->id] = line->id;
staticvoid vfe_reset_output_maps(struct vfe_device *vfe)
{ int i;
for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++)
vfe->wm_output_map[i] = VFE_LINE_NONE;
}
int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
{ int ret = -EBUSY; int i;
for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++) { if (vfe->wm_output_map[i] == VFE_LINE_NONE) {
vfe->wm_output_map[i] = line_id;
ret = i; break;
}
}
return ret;
}
int vfe_release_wm(struct vfe_device *vfe, u8 wm)
{ if (wm >= ARRAY_SIZE(vfe->wm_output_map)) return -EINVAL;
spin_lock_irqsave(&vfe->output_lock, flags); for (i = 0; i < output->wm_num; i++)
vfe->res->hw_ops->vfe_wm_stop(vfe, output->wm_idx[i]);
output->gen2.active_num = 0;
spin_unlock_irqrestore(&vfe->output_lock, flags);
return vfe_reset(vfe);
}
/* * vfe_disable - Disable streaming on VFE line * @line: VFE line * * Return 0 on success or a negative error code otherwise
*/ int vfe_disable(struct vfe_line *line)
{ struct vfe_device *vfe = to_vfe(line); int ret;
ret = vfe_disable_output(line); if (ret) goto error;
/* * vfe_pm_domain_off - Disable power domains specific to this VFE. * @vfe: VFE Device
*/ void vfe_pm_domain_off(struct vfe_device *vfe)
{ if (!vfe->genpd) return;
/* * vfe_set_clock_rates - Calculate and set clock rates on VFE module * @vfe: VFE device * * Return 0 on success or a negative error code otherwise
*/ staticint vfe_set_clock_rates(struct vfe_device *vfe)
{ struct device *dev = vfe->camss->dev;
u64 pixel_clock[VFE_LINE_NUM_MAX]; int i, j; int ret;
for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {
ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity,
&pixel_clock[i]); if (ret)
pixel_clock[i] = 0;
}
for (i = 0; i < vfe->nclocks; i++) { struct camss_clock *clock = &vfe->clock[i];
if (vfe_match_clock_names(vfe, clock)) {
u64 min_rate = 0; long rate;
ret = clk_set_rate(clock->clk, rate); if (ret < 0) {
dev_err(dev, "clk set rate failed: %d\n", ret); return ret;
}
}
}
return 0;
}
/* * vfe_check_clock_rates - Check current clock rates on VFE module * @vfe: VFE device * * Return 0 if current clock rates are suitable for a new pipeline * or a negative error code otherwise
*/ staticint vfe_check_clock_rates(struct vfe_device *vfe)
{
u64 pixel_clock[VFE_LINE_NUM_MAX]; int i, j; int ret;
for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {
ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity,
&pixel_clock[i]); if (ret)
pixel_clock[i] = 0;
}
for (i = 0; i < vfe->nclocks; i++) { struct camss_clock *clock = &vfe->clock[i];
if (vfe_match_clock_names(vfe, clock)) {
u64 min_rate = 0; unsignedlong rate;
/* * vfe_get - Power up and reset VFE module * @vfe: VFE Device * * Return 0 on success or a negative error code otherwise
*/ int vfe_get(struct vfe_device *vfe)
{ int ret;
mutex_lock(&vfe->power_lock);
if (vfe->power_count == 0) {
ret = vfe->res->hw_ops->pm_domain_on(vfe); if (ret < 0) goto error_pm_domain;
ret = pm_runtime_resume_and_get(vfe->camss->dev); if (ret < 0) goto error_domain_off;
ret = vfe_set_clock_rates(vfe); if (ret < 0) goto error_pm_runtime_get;
ret = camss_enable_clocks(vfe->nclocks, vfe->clock,
vfe->camss->dev); if (ret < 0) goto error_pm_runtime_get;
ret = vfe_reset(vfe); if (ret < 0) goto error_reset;
vfe_reset_output_maps(vfe);
vfe_init_outputs(vfe);
vfe->res->hw_ops->hw_version(vfe);
} else {
ret = vfe_check_clock_rates(vfe); if (ret < 0) goto error_pm_domain;
}
vfe->power_count++;
/* * vfe_put - Power down VFE module * @vfe: VFE Device
*/ void vfe_put(struct vfe_device *vfe)
{
mutex_lock(&vfe->power_lock);
if (vfe->power_count == 0) {
dev_err(vfe->camss->dev, "vfe power off on power_count == 0\n"); gotoexit;
} elseif (vfe->power_count == 1) { if (vfe->was_streaming) {
vfe->was_streaming = 0;
vfe->res->hw_ops->vfe_halt(vfe);
}
camss_disable_clocks(vfe->nclocks, vfe->clock);
pm_runtime_put_sync(vfe->camss->dev);
vfe->res->hw_ops->pm_domain_off(vfe);
}
vfe->power_count--;
exit:
mutex_unlock(&vfe->power_lock);
}
/* * vfe_flush_buffers - Return all vb2 buffers * @vid: Video device structure * @state: vb2 buffer state of the returned buffers * * Return all buffers to vb2. This includes queued pending buffers (still * unused) and any buffers given to the hardware but again still not used. * * Return 0 on success or a negative error code otherwise
*/ int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state)
{ struct vfe_line *line = container_of(vid, struct vfe_line, video_out); struct vfe_device *vfe = to_vfe(line); struct vfe_output *output; unsignedlong flags;
output = &line->output;
spin_lock_irqsave(&vfe->output_lock, flags);
vfe_buf_flush_pending(output, state);
if (output->buf[0])
vb2_buffer_done(&output->buf[0]->vb.vb2_buf, state);
if (output->buf[1])
vb2_buffer_done(&output->buf[1]->vb.vb2_buf, state);
if (output->last_buffer) {
vb2_buffer_done(&output->last_buffer->vb.vb2_buf, state);
output->last_buffer = NULL;
}
spin_unlock_irqrestore(&vfe->output_lock, flags);
return 0;
}
/* * vfe_set_power - Power on/off VFE module * @sd: VFE V4L2 subdevice * @on: Requested power state * * Return 0 on success or a negative error code otherwise
*/ staticint vfe_set_power(struct v4l2_subdev *sd, int on)
{ struct vfe_line *line = v4l2_get_subdevdata(sd); struct vfe_device *vfe = to_vfe(line); int ret;
if (on) {
ret = vfe_get(vfe); if (ret < 0) return ret;
} else {
vfe_put(vfe);
}
return 0;
}
/* * vfe_set_stream - Enable/disable streaming on VFE module * @sd: VFE V4L2 subdevice * @enable: Requested streaming state * * Main configuration of VFE module is triggered here. * * Return 0 on success or a negative error code otherwise
*/ staticint vfe_set_stream(struct v4l2_subdev *sd, int enable)
{ struct vfe_line *line = v4l2_get_subdevdata(sd); struct vfe_device *vfe = to_vfe(line); int ret;
if (enable) {
line->output.state = VFE_OUTPUT_RESERVED;
ret = vfe->res->hw_ops->vfe_enable(line); if (ret < 0)
dev_err(vfe->camss->dev, "Failed to enable vfe outputs\n");
} else {
ret = vfe->res->hw_ops->vfe_disable(line); if (ret < 0)
dev_err(vfe->camss->dev, "Failed to disable vfe outputs\n");
}
return ret;
}
/* * __vfe_get_format - Get pointer to format structure * @line: VFE line * @sd_state: V4L2 subdev state * @pad: pad from which format is requested * @which: TRY or ACTIVE format * * Return pointer to TRY or ACTIVE format structure
*/ staticstruct v4l2_mbus_framefmt *
__vfe_get_format(struct vfe_line *line, struct v4l2_subdev_state *sd_state, unsignedint pad, enum v4l2_subdev_format_whence which)
{ if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_state_get_format(sd_state, pad);
return &line->fmt[pad];
}
/* * __vfe_get_compose - Get pointer to compose selection structure * @line: VFE line * @sd_state: V4L2 subdev state * @which: TRY or ACTIVE format * * Return pointer to TRY or ACTIVE compose rectangle structure
*/ staticstruct v4l2_rect *
__vfe_get_compose(struct vfe_line *line, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which)
{ if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_state_get_compose(sd_state,
MSM_VFE_PAD_SINK);
return &line->compose;
}
/* * __vfe_get_crop - Get pointer to crop selection structure * @line: VFE line * @sd_state: V4L2 subdev state * @which: TRY or ACTIVE format * * Return pointer to TRY or ACTIVE crop rectangle structure
*/ staticstruct v4l2_rect *
__vfe_get_crop(struct vfe_line *line, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which)
{ if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_state_get_crop(sd_state, MSM_VFE_PAD_SRC);
return &line->crop;
}
/* * vfe_try_format - Handle try format by pad subdev method * @line: VFE line * @sd_state: V4L2 subdev state * @pad: pad on which format is requested * @fmt: pointer to v4l2 format structure * @which: wanted subdev format
*/ staticvoid vfe_try_format(struct vfe_line *line, struct v4l2_subdev_state *sd_state, unsignedint pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which)
{ unsignedint i;
u32 code;
switch (pad) { case MSM_VFE_PAD_SINK: /* Set format on sink pad */
for (i = 0; i < line->nformats; i++) if (fmt->code == line->formats[i].code) break;
/* If not found, use UYVY as default */ if (i >= line->nformats)
fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
if (res->vfe.pd_name) {
vfe->genpd = dev_pm_domain_attach_by_name(camss->dev,
res->vfe.pd_name); if (IS_ERR(vfe->genpd)) {
ret = PTR_ERR(vfe->genpd); return ret;
}
}
if (!vfe->genpd && res->vfe.has_pd) { /* * Legacy magic index. * Requires * power-domain = <VFE_X>, * <VFE_Y>, * <TITAN_TOP> * id must correspondng to the index of the VFE which must * come before the TOP GDSC. VFE Lite has no individually * collapasible domain which is why id < vfe_num is a valid * check.
*/
vfe->genpd = dev_pm_domain_attach_by_id(camss->dev, id); if (IS_ERR(vfe->genpd)) return PTR_ERR(vfe->genpd);
}
/* Memory */
vfe->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]); if (IS_ERR(vfe->base)) {
dev_err(dev, "could not map memory\n"); return PTR_ERR(vfe->base);
}
/* Interrupt */
ret = platform_get_irq_byname(pdev, res->interrupt[0]); if (ret < 0) return ret;
staticint vfe_bpl_align(struct vfe_device *vfe)
{ int ret = 8;
switch (vfe->camss->res->version) { case CAMSS_7280: case CAMSS_8250: case CAMSS_8280XP: case CAMSS_845: case CAMSS_8550: case CAMSS_X1E80100:
ret = 16; break; default: break;
}
return ret;
}
/* * msm_vfe_register_entities - Register subdev node for VFE module * @vfe: VFE device * @v4l2_dev: V4L2 device * * Initialize and register a subdev node for the VFE module. Then * call msm_video_register() to register the video device node which * will be connected to this subdev node. Then actually create the * media link between them. * * Return 0 on success or a negative error code otherwise
*/ int msm_vfe_register_entities(struct vfe_device *vfe, struct v4l2_device *v4l2_dev)
{ struct device *dev = vfe->camss->dev; struct v4l2_subdev *sd; struct media_pad *pads; struct camss_video *video_out; int ret; int i;
for (i = 0; i < vfe->res->line_num; i++) { char name[32];
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.