// SPDX-License-Identifier: GPL-2.0-only /* * isppreview.c * * TI OMAP3 ISP driver - Preview module * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2009 Texas Instruments, Inc. * * Contacts: Laurent Pinchart <[email protected]> * Sakari Ailus <[email protected]> */ #include <linux/device.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/uaccess.h> #include "isp.h" #include "ispreg.h" #include "isppreview.h" /* Default values in Office Fluorescent Light for RGBtoRGB Blending */ static const struct omap3isp_prev_rgbtorgb flr_rgb2rgb = …; /* Default values in Office Fluorescent Light for RGB to YUV Conversion*/ static const struct omap3isp_prev_csc flr_prev_csc = …; /* Default values in Office Fluorescent Light for CFA Gradient*/ #define FLR_CFA_GRADTHRS_HORZ … #define FLR_CFA_GRADTHRS_VERT … /* Default values in Office Fluorescent Light for Chroma Suppression*/ #define FLR_CSUP_GAIN … #define FLR_CSUP_THRES … /* Default values in Office Fluorescent Light for Noise Filter*/ #define FLR_NF_STRGTH … /* Default values for White Balance */ #define FLR_WBAL_DGAIN … #define FLR_WBAL_COEF … /* Default values in Office Fluorescent Light for Black Adjustment*/ #define FLR_BLKADJ_BLUE … #define FLR_BLKADJ_GREEN … #define FLR_BLKADJ_RED … #define DEF_DETECT_CORRECT_VAL … /* * Margins and image size limits. * * The preview engine crops several rows and columns internally depending on * which filters are enabled. To avoid format changes when the filters are * enabled or disabled (which would prevent them from being turned on or off * during streaming), the driver assumes all filters that can be configured * during streaming are enabled when computing sink crop and source format * limits. * * If a filter is disabled, additional cropping is automatically added at the * preview engine input by the driver to avoid overflow at line and frame end. * This is completely transparent for applications. * * Median filter 4 pixels * Noise filter, * Faulty pixels correction 4 pixels, 4 lines * Color suppression 2 pixels * or luma enhancement * ------------------------------------------------------------- * Maximum total 10 pixels, 4 lines * * The color suppression and luma enhancement filters are applied after bayer to * YUV conversion. They thus can crop one pixel on the left and one pixel on the * right side of the image without changing the color pattern. When both those * filters are disabled, the driver must crop the two pixels on the same side of * the image to avoid changing the bayer pattern. The left margin is thus set to * 6 pixels and the right margin to 4 pixels. */ #define PREV_MARGIN_LEFT … #define PREV_MARGIN_RIGHT … #define PREV_MARGIN_TOP … #define PREV_MARGIN_BOTTOM … #define PREV_MIN_IN_WIDTH … #define PREV_MIN_IN_HEIGHT … #define PREV_MAX_IN_HEIGHT … #define PREV_MIN_OUT_WIDTH … #define PREV_MIN_OUT_HEIGHT … #define PREV_MAX_OUT_WIDTH_REV_1 … #define PREV_MAX_OUT_WIDTH_REV_2 … #define PREV_MAX_OUT_WIDTH_REV_15 … /* * Coefficient Tables for the submodules in Preview. * Array is initialised with the values from.the tables text file. */ /* * CFA Filter Coefficient Table * */ static u32 cfa_coef_table[4][OMAP3ISP_PREV_CFA_BLK_SIZE] = …; /* * Default Gamma Correction Table - All components */ static u32 gamma_table[] = …; /* * Noise Filter Threshold table */ static u32 noise_filter_table[] = …; /* * Luminance Enhancement Table */ static u32 luma_enhance_table[] = …; /* * preview_config_luma_enhancement - Configure the Luminance Enhancement table */ static void preview_config_luma_enhancement(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_enable_luma_enhancement - Enable/disable Luminance Enhancement */ static void preview_enable_luma_enhancement(struct isp_prev_device *prev, bool enable) { … } /* * preview_enable_invalaw - Enable/disable Inverse A-Law decompression */ static void preview_enable_invalaw(struct isp_prev_device *prev, bool enable) { … } /* * preview_config_hmed - Configure the Horizontal Median Filter */ static void preview_config_hmed(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_enable_hmed - Enable/disable the Horizontal Median Filter */ static void preview_enable_hmed(struct isp_prev_device *prev, bool enable) { … } /* * preview_config_cfa - Configure CFA Interpolation for Bayer formats * * The CFA table is organised in four blocks, one per Bayer component. The * hardware expects blocks to follow the Bayer order of the input data, while * the driver stores the table in GRBG order in memory. The blocks need to be * reordered to support non-GRBG Bayer patterns. */ static void preview_config_cfa(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_config_chroma_suppression - Configure Chroma Suppression */ static void preview_config_chroma_suppression(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_enable_chroma_suppression - Enable/disable Chrominance Suppression */ static void preview_enable_chroma_suppression(struct isp_prev_device *prev, bool enable) { … } /* * preview_config_whitebalance - Configure White Balance parameters * * Coefficient matrix always with default values. */ static void preview_config_whitebalance(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_config_blkadj - Configure Black Adjustment */ static void preview_config_blkadj(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_config_rgb_blending - Configure RGB-RGB Blending */ static void preview_config_rgb_blending(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_config_csc - Configure Color Space Conversion (RGB to YCbYCr) */ static void preview_config_csc(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_config_yc_range - Configure the max and min Y and C values */ static void preview_config_yc_range(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_config_dcor - Configure Couplet Defect Correction */ static void preview_config_dcor(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_enable_dcor - Enable/disable Couplet Defect Correction */ static void preview_enable_dcor(struct isp_prev_device *prev, bool enable) { … } /* * preview_enable_drkframe_capture - Enable/disable Dark Frame Capture */ static void preview_enable_drkframe_capture(struct isp_prev_device *prev, bool enable) { … } /* * preview_enable_drkframe - Enable/disable Dark Frame Subtraction */ static void preview_enable_drkframe(struct isp_prev_device *prev, bool enable) { … } /* * preview_config_noisefilter - Configure the Noise Filter */ static void preview_config_noisefilter(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_enable_noisefilter - Enable/disable the Noise Filter */ static void preview_enable_noisefilter(struct isp_prev_device *prev, bool enable) { … } /* * preview_config_gammacorrn - Configure the Gamma Correction tables */ static void preview_config_gammacorrn(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_enable_gammacorrn - Enable/disable Gamma Correction * * When gamma correction is disabled, the module is bypassed and its output is * the 8 MSB of the 10-bit input . */ static void preview_enable_gammacorrn(struct isp_prev_device *prev, bool enable) { … } /* * preview_config_contrast - Configure the Contrast * * Value should be programmed before enabling the module. */ static void preview_config_contrast(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_config_brightness - Configure the Brightness */ static void preview_config_brightness(struct isp_prev_device *prev, const struct prev_params *params) { … } /* * preview_update_contrast - Updates the contrast. * @contrast: Pointer to hold the current programmed contrast value. * * Value should be programmed before enabling the module. */ static void preview_update_contrast(struct isp_prev_device *prev, u8 contrast) { … } /* * preview_update_brightness - Updates the brightness in preview module. * @brightness: Pointer to hold the current programmed brightness value. * */ static void preview_update_brightness(struct isp_prev_device *prev, u8 brightness) { … } static u32 preview_params_lock(struct isp_prev_device *prev, u32 update, bool shadow) { … } static void preview_params_unlock(struct isp_prev_device *prev, u32 update, bool shadow) { … } static void preview_params_switch(struct isp_prev_device *prev) { … } /* preview parameters update structure */ struct preview_update { … }; /* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */ static const struct preview_update update_attrs[] = …; /* * preview_config - Copy and update local structure with userspace preview * configuration. * @prev: ISP preview engine * @cfg: Configuration * * Return zero if success or -EFAULT if the configuration can't be copied from * userspace. */ static int preview_config(struct isp_prev_device *prev, struct omap3isp_prev_update_config *cfg) { … } /* * preview_setup_hw - Setup preview registers and/or internal memory * @prev: pointer to preview private structure * @update: Bitmask of parameters to setup * @active: Bitmask of parameters active in set 0 * Note: can be called from interrupt context * Return none */ static void preview_setup_hw(struct isp_prev_device *prev, u32 update, u32 active) { … } /* * preview_config_ycpos - Configure byte layout of YUV image. * @prev: pointer to previewer private structure * @pixelcode: pixel code */ static void preview_config_ycpos(struct isp_prev_device *prev, u32 pixelcode) { … } /* * preview_config_averager - Enable / disable / configure averager * @average: Average value to be configured. */ static void preview_config_averager(struct isp_prev_device *prev, u8 average) { … } /* * preview_config_input_format - Configure the input format * @prev: The preview engine * @info: Sink pad format information * * Enable and configure CFA interpolation for Bayer formats and disable it for * greyscale formats. * * The CFA table is organised in four blocks, one per Bayer component. The * hardware expects blocks to follow the Bayer order of the input data, while * the driver stores the table in GRBG order in memory. The blocks need to be * reordered to support non-GRBG Bayer patterns. */ static void preview_config_input_format(struct isp_prev_device *prev, const struct isp_format_info *info) { … } /* * preview_config_input_size - Configure the input frame size * * The preview engine crops several rows and columns internally depending on * which processing blocks are enabled. The driver assumes all those blocks are * enabled when reporting source pad formats to userspace. If this assumption is * not true, rows and columns must be manually cropped at the preview engine * input to avoid overflows at the end of lines and frames. * * See the explanation at the PREV_MARGIN_* definitions for more details. */ static void preview_config_input_size(struct isp_prev_device *prev, u32 active) { … } /* * preview_config_inlineoffset - Configures the Read address line offset. * @prev: Preview module * @offset: Line offset * * According to the TRM, the line offset must be aligned on a 32 bytes boundary. * However, a hardware bug requires the memory start address to be aligned on a * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as * well. */ static void preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset) { … } /* * preview_set_inaddr - Sets memory address of input frame. * @addr: 32bit memory address aligned on 32byte boundary. * * Configures the memory address from which the input frame is to be read. */ static void preview_set_inaddr(struct isp_prev_device *prev, u32 addr) { … } /* * preview_config_outlineoffset - Configures the Write address line offset. * @offset: Line Offset for the preview output. * * The offset must be a multiple of 32 bytes. */ static void preview_config_outlineoffset(struct isp_prev_device *prev, u32 offset) { … } /* * preview_set_outaddr - Sets the memory address to store output frame * @addr: 32bit memory address aligned on 32byte boundary. * * Configures the memory address to which the output frame is written. */ static void preview_set_outaddr(struct isp_prev_device *prev, u32 addr) { … } static void preview_adjust_bandwidth(struct isp_prev_device *prev) { … } /* * omap3isp_preview_busy - Gets busy state of preview module. */ int omap3isp_preview_busy(struct isp_prev_device *prev) { … } /* * omap3isp_preview_restore_context - Restores the values of preview registers */ void omap3isp_preview_restore_context(struct isp_device *isp) { … } /* * preview_print_status - Dump preview module registers to the kernel log */ #define PREV_PRINT_REGISTER(isp, name) … static void preview_print_status(struct isp_prev_device *prev) { … } /* * preview_init_params - init image processing parameters. * @prev: pointer to previewer private structure */ static void preview_init_params(struct isp_prev_device *prev) { … } /* * preview_max_out_width - Handle previewer hardware output limitations * @prev: pointer to previewer private structure * returns maximum width output for current isp revision */ static unsigned int preview_max_out_width(struct isp_prev_device *prev) { … } static void preview_configure(struct isp_prev_device *prev) { … } /* ----------------------------------------------------------------------------- * Interrupt handling */ static void preview_enable_oneshot(struct isp_prev_device *prev) { … } void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev) { … } static void preview_isr_buffer(struct isp_prev_device *prev) { … } /* * omap3isp_preview_isr - ISP preview engine interrupt handler * * Manage the preview engine video buffers and configure shadowed registers. */ void omap3isp_preview_isr(struct isp_prev_device *prev) { … } /* ----------------------------------------------------------------------------- * ISP video operations */ static int preview_video_queue(struct isp_video *video, struct isp_buffer *buffer) { … } static const struct isp_video_operations preview_video_ops = …; /* ----------------------------------------------------------------------------- * V4L2 subdev operations */ /* * preview_s_ctrl - Handle set control subdev method * @ctrl: pointer to v4l2 control structure */ static int preview_s_ctrl(struct v4l2_ctrl *ctrl) { … } static const struct v4l2_ctrl_ops preview_ctrl_ops = …; /* * preview_ioctl - Handle preview module private ioctl's * @sd: pointer to v4l2 subdev structure * @cmd: configuration command * @arg: configuration argument * return -EINVAL or zero on success */ static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { … } /* * preview_set_stream - Enable/Disable streaming on preview subdev * @sd : pointer to v4l2 subdev structure * @enable: 1 == Enable, 0 == Disable * return -EINVAL or zero on success */ static int preview_set_stream(struct v4l2_subdev *sd, int enable) { … } static struct v4l2_mbus_framefmt * __preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_state *sd_state, unsigned int pad, enum v4l2_subdev_format_whence which) { … } static struct v4l2_rect * __preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which) { … } /* previewer format descriptions */ static const unsigned int preview_input_fmts[] = …; static const unsigned int preview_output_fmts[] = …; /* * preview_try_format - Validate a format * @prev: ISP preview engine * @sd_state: V4L2 subdev state * @pad: pad number * @fmt: format to be validated * @which: try/active format selector * * Validate and adjust the given format for the given pad based on the preview * engine limits and the format and crop rectangles on other pads. */ static void preview_try_format(struct isp_prev_device *prev, struct v4l2_subdev_state *sd_state, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { … } /* * preview_try_crop - Validate a crop rectangle * @prev: ISP preview engine * @sink: format on the sink pad * @crop: crop rectangle to be validated * * The preview engine crops lines and columns for its internal operation, * depending on which filters are enabled. Enforce minimum crop margins to * handle that transparently for userspace. * * See the explanation at the PREV_MARGIN_* definitions for more details. */ static void preview_try_crop(struct isp_prev_device *prev, const struct v4l2_mbus_framefmt *sink, struct v4l2_rect *crop) { … } /* * preview_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure * @sd_state: V4L2 subdev state * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int preview_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { … } static int preview_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { … } /* * preview_get_selection - Retrieve a selection rectangle on a pad * @sd: ISP preview V4L2 subdevice * @sd_state: V4L2 subdev state * @sel: Selection rectangle * * The only supported rectangles are the crop rectangles on the sink pad. * * Return 0 on success or a negative error code otherwise. */ static int preview_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { … } /* * preview_set_selection - Set a selection rectangle on a pad * @sd: ISP preview V4L2 subdevice * @sd_state: V4L2 subdev state * @sel: Selection rectangle * * The only supported rectangle is the actual crop rectangle on the sink pad. * * Return 0 on success or a negative error code otherwise. */ static int preview_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { … } /* * preview_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { … } /* * preview_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure * @sd_state: V4L2 subdev state * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { … } /* * preview_init_formats - Initialize formats on all pads * @sd: ISP preview V4L2 subdevice * @fh: V4L2 subdev file handle * * Initialize all pad formats with default values. If fh is not NULL, try * formats are initialized on the file handle. Otherwise active formats are * initialized on the device. */ static int preview_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { … } /* subdev core operations */ static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = …; /* subdev video operations */ static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = …; /* subdev pad operations */ static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = …; /* subdev operations */ static const struct v4l2_subdev_ops preview_v4l2_ops = …; /* subdev internal operations */ static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = …; /* ----------------------------------------------------------------------------- * Media entity operations */ /* * preview_link_setup - Setup previewer connections. * @entity : Pointer to media entity structure * @local : Pointer to local pad array * @remote : Pointer to remote pad array * @flags : Link flags * return -EINVAL or zero on success */ static int preview_link_setup(struct media_entity *entity, const struct media_pad *local, const struct media_pad *remote, u32 flags) { … } /* media operations */ static const struct media_entity_operations preview_media_ops = …; void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) { … } int omap3isp_preview_register_entities(struct isp_prev_device *prev, struct v4l2_device *vdev) { … } /* ----------------------------------------------------------------------------- * ISP previewer initialisation and cleanup */ /* * preview_init_entities - Initialize subdev and media entity. * @prev : Pointer to preview structure * return -ENOMEM or zero on success */ static int preview_init_entities(struct isp_prev_device *prev) { … } /* * omap3isp_preview_init - Previewer initialization. * @isp : Pointer to ISP device * return -ENOMEM or zero on success */ int omap3isp_preview_init(struct isp_device *isp) { … } void omap3isp_preview_cleanup(struct isp_device *isp) { … }