// SPDX-License-Identifier: GPL-2.0 /* * camss-vfe.c * * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module * * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (C) 2015-2018 Linaro Ltd. */ #include <linux/clk.h> #include <linux/completion.h> #include <linux/interrupt.h> #include <linux/iommu.h> #include <linux/mutex.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> #include <linux/spinlock_types.h> #include <linux/spinlock.h> #include <media/media-entity.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> #include "camss-vfe.h" #include "camss.h" #define MSM_VFE_NAME … /* VFE reset timeout */ #define VFE_RESET_TIMEOUT_MS … #define SCALER_RATIO_MAX … static const struct camss_format_info formats_rdi_8x16[] = …; static const struct camss_format_info formats_rdi_8x96[] = …; static const struct camss_format_info formats_rdi_845[] = …; static const struct camss_format_info formats_pix_8x16[] = …; static const struct camss_format_info formats_pix_8x96[] = …; const struct camss_formats vfe_formats_rdi_8x16 = …; const struct camss_formats vfe_formats_pix_8x16 = …; const struct camss_formats vfe_formats_rdi_8x96 = …; const struct camss_formats vfe_formats_pix_8x96 = …; const struct camss_formats vfe_formats_rdi_845 = …; /* TODO: Replace with pix formats */ const struct camss_formats vfe_formats_pix_845 = …; static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, unsigned int index, u32 src_req_code) { … } int vfe_reset(struct vfe_device *vfe) { … } static void vfe_init_outputs(struct vfe_device *vfe) { … } static void vfe_reset_output_maps(struct vfe_device *vfe) { … } int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id) { … } int vfe_release_wm(struct vfe_device *vfe, u8 wm) { … } struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output) { … } void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer) { … } /* * vfe_buf_flush_pending - Flush all pending buffers. * @output: VFE output * @state: vb2 buffer state */ static void vfe_buf_flush_pending(struct vfe_output *output, enum vb2_buffer_state state) { … } int vfe_put_output(struct vfe_line *line) { … } static int vfe_disable_output(struct vfe_line *line) { … } /* * 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) { … } /** * vfe_isr_comp_done() - Process composite image done interrupt * @vfe: VFE Device * @comp: Composite image id */ void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp) { … } void vfe_isr_reset_ack(struct vfe_device *vfe) { … } /* * vfe_pm_domain_off - Disable power domains specific to this VFE. * @vfe: VFE Device */ void vfe_pm_domain_off(struct vfe_device *vfe) { … } /* * vfe_pm_domain_on - Enable power domains specific to this VFE. * @vfe: VFE Device */ int vfe_pm_domain_on(struct vfe_device *vfe) { … } static int vfe_match_clock_names(struct vfe_device *vfe, struct camss_clock *clock) { … } /* * 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 */ static int vfe_set_clock_rates(struct vfe_device *vfe) { … } /* * 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 */ static int vfe_check_clock_rates(struct vfe_device *vfe) { … } /* * 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) { … } /* * vfe_put - Power down VFE module * @vfe: VFE Device */ void vfe_put(struct vfe_device *vfe) { … } /* * 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) { … } /* * 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 */ static int vfe_set_power(struct v4l2_subdev *sd, int on) { … } /* * 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 */ static int vfe_set_stream(struct v4l2_subdev *sd, int enable) { … } /* * __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 */ static struct v4l2_mbus_framefmt * __vfe_get_format(struct vfe_line *line, struct v4l2_subdev_state *sd_state, unsigned int pad, enum v4l2_subdev_format_whence which) { … } /* * __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 */ static struct v4l2_rect * __vfe_get_compose(struct vfe_line *line, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which) { … } /* * __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 */ static struct v4l2_rect * __vfe_get_crop(struct vfe_line *line, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which) { … } /* * 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 */ static void vfe_try_format(struct vfe_line *line, struct v4l2_subdev_state *sd_state, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { … } /* * vfe_try_compose - Handle try compose selection by pad subdev method * @line: VFE line * @sd_state: V4L2 subdev state * @rect: pointer to v4l2 rect structure * @which: wanted subdev format */ static void vfe_try_compose(struct vfe_line *line, struct v4l2_subdev_state *sd_state, struct v4l2_rect *rect, enum v4l2_subdev_format_whence which) { … } /* * vfe_try_crop - Handle try crop selection by pad subdev method * @line: VFE line * @sd_state: V4L2 subdev state * @rect: pointer to v4l2 rect structure * @which: wanted subdev format */ static void vfe_try_crop(struct vfe_line *line, struct v4l2_subdev_state *sd_state, struct v4l2_rect *rect, enum v4l2_subdev_format_whence which) { … } /* * vfe_enum_mbus_code - Handle pixel format enumeration * @sd: VFE V4L2 subdevice * @sd_state: V4L2 subdev state * @code: pointer to v4l2_subdev_mbus_code_enum structure * * return -EINVAL or zero on success */ static int vfe_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { … } /* * vfe_enum_frame_size - Handle frame size enumeration * @sd: VFE V4L2 subdevice * @sd_state: V4L2 subdev state * @fse: pointer to v4l2_subdev_frame_size_enum structure * * Return -EINVAL or zero on success */ static int vfe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { … } /* * vfe_get_format - Handle get format by pads subdev method * @sd: VFE V4L2 subdevice * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * * Return -EINVAL or zero on success */ static int vfe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { … } static int vfe_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel); /* * vfe_set_format - Handle set format by pads subdev method * @sd: VFE V4L2 subdevice * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * * Return -EINVAL or zero on success */ static int vfe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { … } /* * vfe_get_selection - Handle get selection by pads subdev method * @sd: VFE V4L2 subdevice * @sd_state: V4L2 subdev state * @sel: pointer to v4l2 subdev selection structure * * Return -EINVAL or zero on success */ static int vfe_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { … } /* * vfe_set_selection - Handle set selection by pads subdev method * @sd: VFE V4L2 subdevice * @sd_state: V4L2 subdev state * @sel: pointer to v4l2 subdev selection structure * * Return -EINVAL or zero on success */ static int vfe_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { … } /* * vfe_init_formats - Initialize formats on all pads * @sd: VFE V4L2 subdevice * @fh: V4L2 subdev file handle * * Initialize all pad formats with default values. * * Return 0 on success or a negative error code otherwise */ static int vfe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { … } /* * msm_vfe_subdev_init - Initialize VFE device structure and resources * @vfe: VFE device * @res: VFE module resources table * * Return 0 on success or a negative error code otherwise */ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, const struct camss_subdev_resources *res, u8 id) { … } /* * msm_vfe_genpd_cleanup - Cleanup VFE genpd linkages * @vfe: VFE device */ void msm_vfe_genpd_cleanup(struct vfe_device *vfe) { … } /* * vfe_link_setup - Setup VFE connections * @entity: Pointer to media entity structure * @local: Pointer to local pad * @remote: Pointer to remote pad * @flags: Link flags * * Return 0 on success */ static int vfe_link_setup(struct media_entity *entity, const struct media_pad *local, const struct media_pad *remote, u32 flags) { … } static const struct v4l2_subdev_core_ops vfe_core_ops = …; static const struct v4l2_subdev_video_ops vfe_video_ops = …; static const struct v4l2_subdev_pad_ops vfe_pad_ops = …; static const struct v4l2_subdev_ops vfe_v4l2_ops = …; static const struct v4l2_subdev_internal_ops vfe_v4l2_internal_ops = …; static const struct media_entity_operations vfe_media_ops = …; static int vfe_bpl_align(struct vfe_device *vfe) { … } /* * 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) { … } /* * msm_vfe_unregister_entities - Unregister VFE module subdev node * @vfe: VFE device */ void msm_vfe_unregister_entities(struct vfe_device *vfe) { … } bool vfe_is_lite(struct vfe_device *vfe) { … }