/* Default values in Office Fluorescent Light for CFA Gradient*/ #define FLR_CFA_GRADTHRS_HORZ 0x28 #define FLR_CFA_GRADTHRS_VERT 0x28
/* Default values in Office Fluorescent Light for Chroma Suppression*/ #define FLR_CSUP_GAIN 0x0D #define FLR_CSUP_THRES 0xEB
/* Default values in Office Fluorescent Light for Noise Filter*/ #define FLR_NF_STRGTH 0x03
/* Default values for White Balance */ #define FLR_WBAL_DGAIN 0x100 #define FLR_WBAL_COEF 0x20
/* Default values in Office Fluorescent Light for Black Adjustment*/ #define FLR_BLKADJ_BLUE 0x0 #define FLR_BLKADJ_GREEN 0x0 #define FLR_BLKADJ_RED 0x0
#define DEF_DETECT_CORRECT_VAL 0xe
/* * 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.
*/
/* * 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.
*/ staticvoid preview_config_cfa(struct isp_prev_device *prev, conststruct prev_params *params)
{ staticconstunsignedint cfa_coef_order[4][4] = {
{ 0, 1, 2, 3 }, /* GRBG */
{ 1, 0, 3, 2 }, /* RGGB */
{ 2, 3, 0, 1 }, /* BGGR */
{ 3, 2, 1, 0 }, /* GBRG */
}; constunsignedint *order = cfa_coef_order[prev->params.cfa_order]; conststruct omap3isp_prev_cfa *cfa = ¶ms->cfa; struct isp_device *isp = to_isp_device(prev); unsignedint i; unsignedint j;
val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
}
/* * preview_config_yc_range - Configure the max and min Y and C values
*/ staticvoid
preview_config_yc_range(struct isp_prev_device *prev, conststruct prev_params *params)
{ struct isp_device *isp = to_isp_device(prev); conststruct omap3isp_prev_yclimit *yc = ¶ms->yclimit;
isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
ISPPRV_SET_TBL_DATA);
isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
ISPPRV_SET_TBL_DATA);
isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
ISPPRV_SET_TBL_DATA);
}
/* * 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 .
*/ staticvoid
preview_enable_gammacorrn(struct isp_prev_device *prev, bool enable)
{ struct isp_device *isp = to_isp_device(prev);
/* * preview_update_contrast - Updates the contrast. * @contrast: Pointer to hold the current programmed contrast value. * * Value should be programmed before enabling the module.
*/ staticvoid
preview_update_contrast(struct isp_prev_device *prev, u8 contrast)
{ struct prev_params *params; unsignedlong flags;
if (shadow) { /* Mark all shadow parameters we are going to touch as busy. */
prev->params.params[0].busy |= ~active & update;
prev->params.params[1].busy |= active & update;
} else { /* Mark all active parameters we are going to touch as busy. */
update = (prev->params.params[0].update & active)
| (prev->params.params[1].update & ~active);
if (shadow) { /* Set the update flag for shadow parameters that have been * updated and clear the busy flag for all shadow parameters.
*/
prev->params.params[0].update |= (~active & update);
prev->params.params[1].update |= (active & update);
prev->params.params[0].busy &= active;
prev->params.params[1].busy &= ~active;
} else { /* Clear the update flag for active parameters that have been * applied and the busy flag for all active parameters.
*/
prev->params.params[0].update &= ~(active & update);
prev->params.params[1].update &= ~(~active & update);
prev->params.params[0].busy &= ~active;
prev->params.params[1].busy &= active;
}
}
/* Switch active parameters with updated shadow parameters when the * shadow parameter has been updated and neither the active not the * shadow parameter is busy.
*/
to_switch = (prev->params.params[0].update & ~prev->params.active)
| (prev->params.params[1].update & prev->params.active);
to_switch &= ~(prev->params.params[0].busy |
prev->params.params[1].busy); if (to_switch == 0) return;
prev->params.active ^= to_switch;
/* Remove the update flag for the shadow copy of parameters we have * switched.
*/
prev->params.params[0].update &= ~(~prev->params.active & to_switch);
prev->params.params[1].update &= ~(prev->params.active & to_switch);
}
/* * 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.
*/ staticint preview_config(struct isp_prev_device *prev, struct omap3isp_prev_update_config *cfg)
{ unsignedlong flags; unsignedint i; int rval = 0;
u32 update;
u32 active;
if (cfg->update == 0) return 0;
/* Mark the shadow parameters we're going to update as busy. */
spin_lock_irqsave(&prev->params.lock, flags);
preview_params_lock(prev, cfg->update, true);
active = prev->params.active;
spin_unlock_irqrestore(&prev->params.lock, flags);
update = 0;
for (i = 0; i < ARRAY_SIZE(update_attrs); i++) { conststruct preview_update *attr = &update_attrs[i]; struct prev_params *params; unsignedint bit = 1 << i;
/* * 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.
*/ staticvoid preview_config_input_format(struct isp_prev_device *prev, conststruct isp_format_info *info)
{ struct isp_device *isp = to_isp_device(prev); struct prev_params *params;
/* * 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.
*/ staticvoid preview_config_input_size(struct isp_prev_device *prev, u32 active)
{ conststruct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK]; struct isp_device *isp = to_isp_device(prev); unsignedint sph = prev->crop.left; unsignedint eph = prev->crop.left + prev->crop.width - 1; unsignedint slv = prev->crop.top; unsignedint elv = prev->crop.top + prev->crop.height - 1;
u32 features;
/* * 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.
*/ staticvoid
preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset)
{ struct isp_device *isp = to_isp_device(prev);
/* * 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.
*/ staticvoid preview_config_outlineoffset(struct isp_prev_device *prev,
u32 offset)
{ struct isp_device *isp = to_isp_device(prev);
/* Compute the minimum number of cycles per request, based on the * pipeline maximum data rate. This is an absolute lower bound if we * don't want SBL overflows, so round the value up.
*/
cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
pipe->max_rate);
minimum = DIV_ROUND_UP(cycles_per_request, 32);
/* Compute the maximum number of cycles per request, based on the * requested frame rate. This is a soft upper bound to achieve a frame * rate equal or higher than the requested value, so round the value * down.
*/
timeperframe = &pipe->max_timeperframe;
spin_lock_irqsave(&prev->params.lock, flags); /* Mark all active parameters we are going to touch as busy. */
update = preview_params_lock(prev, 0, false);
active = prev->params.active;
spin_unlock_irqrestore(&prev->params.lock, flags);
/* PREV_PAD_SINK */
format = &prev->formats[PREV_PAD_SINK];
info = omap3isp_video_format_info(format->code);
/* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE * bit is set. As the preview engine is used in single-shot mode, we * need to set PCR.SOURCE before enabling the preview engine.
*/ if (prev->input == PREVIEW_INPUT_MEMORY)
isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
ISPPRV_PCR_SOURCE);
void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev)
{ /* * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun * condition, the module was paused and now we have a buffer queued * on the output again. Restart the pipeline if running in continuous * mode.
*/ if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
preview_enable_oneshot(prev);
isp_video_dmaqueue_flags_clr(&prev->video_out);
}
}
if (prev->input == PREVIEW_INPUT_MEMORY) {
buffer = omap3isp_video_buffer_next(&prev->video_in); if (buffer != NULL)
preview_set_inaddr(prev, buffer->dma);
pipe->state |= ISP_PIPELINE_IDLE_INPUT;
}
switch (prev->state) { case ISP_PIPELINE_STREAM_SINGLESHOT: if (isp_pipeline_ready(pipe))
omap3isp_pipeline_set_stream(pipe,
ISP_PIPELINE_STREAM_SINGLESHOT); break;
case ISP_PIPELINE_STREAM_CONTINUOUS: /* If an underrun occurs, the video queue operation handler will * restart the preview engine. Otherwise restart it immediately.
*/ if (restart)
preview_enable_oneshot(prev); break;
case ISP_PIPELINE_STREAM_STOPPED: default: return;
}
}
switch (enable) { case ISP_PIPELINE_STREAM_CONTINUOUS: if (prev->output & PREVIEW_OUTPUT_MEMORY)
omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED ||
!(prev->output & PREVIEW_OUTPUT_MEMORY))
preview_enable_oneshot(prev);
isp_video_dmaqueue_flags_clr(video_out); break;
case ISP_PIPELINE_STREAM_SINGLESHOT: if (prev->input == PREVIEW_INPUT_MEMORY)
omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ); if (prev->output & PREVIEW_OUTPUT_MEMORY)
omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
preview_enable_oneshot(prev); break;
case ISP_PIPELINE_STREAM_STOPPED: if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
&prev->stopping))
dev_dbg(dev, "%s: stop timeout.\n", sd->name);
omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
isp_video_dmaqueue_flags_clr(video_out); break;
}
/* * 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.
*/ staticvoid preview_try_format(struct isp_prev_device *prev, struct v4l2_subdev_state *sd_state, unsignedint pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which)
{
u32 pixelcode; struct v4l2_rect *crop; unsignedint i;
switch (pad) { case PREV_PAD_SINK: /* When reading data from the CCDC, the input size has already * been mangled by the CCDC output pad so it can be accepted * as-is. * * When reading data from memory, clamp the requested width and * height. The TRM doesn't specify a minimum input height, make * sure we got enough lines to enable the noise filter and color * filter array interpolation.
*/ if (prev->input == PREVIEW_INPUT_MEMORY) {
fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH,
preview_max_out_width(prev));
fmt->height = clamp_t(u32, fmt->height,
PREV_MIN_IN_HEIGHT,
PREV_MAX_IN_HEIGHT);
}
fmt->colorspace = V4L2_COLORSPACE_SRGB;
for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) { if (fmt->code == preview_input_fmts[i]) break;
}
/* If not found, use SGRBG10 as default */ if (i >= ARRAY_SIZE(preview_input_fmts))
fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; break;
/* The preview module output size is configurable through the * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This * is not supported yet, hardcode the output size to the crop * rectangle size.
*/
crop = __preview_get_crop(prev, sd_state, which);
fmt->width = crop->width;
fmt->height = crop->height;
fmt->colorspace = V4L2_COLORSPACE_JPEG; break;
}
fmt->field = V4L2_FIELD_NONE;
}
/* * 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.
*/ staticvoid preview_try_crop(struct isp_prev_device *prev, conststruct v4l2_mbus_framefmt *sink, struct v4l2_rect *crop)
{ unsignedint left = PREV_MARGIN_LEFT; unsignedint right = sink->width - PREV_MARGIN_RIGHT; unsignedint top = PREV_MARGIN_TOP; unsignedint bottom = sink->height - PREV_MARGIN_BOTTOM;
/* When processing data on-the-fly from the CCDC, at least 2 pixels must * be cropped from the left and right sides of the image. As we don't * know which filters will be enabled, increase the left and right * margins by two.
*/ if (prev->input == PREVIEW_INPUT_CCDC) {
left += 2;
right -= 2;
}
/* The CFA filter crops 4 lines and 4 columns in Bayer mode, and 2 lines * and no columns in other modes. Increase the margins based on the sink * format.
*/ if (sink->code != MEDIA_BUS_FMT_Y8_1X8 &&
sink->code != MEDIA_BUS_FMT_Y10_1X10) {
left += 2;
right -= 2;
top += 2;
bottom -= 2;
}
/* Restrict left/top to even values to keep the Bayer pattern. */
crop->left &= ~1;
crop->top &= ~1;
format = __preview_get_format(prev, sd_state, PREV_PAD_SINK,
sel->which);
preview_try_crop(prev, format, &sel->r); break;
case V4L2_SEL_TGT_CROP:
sel->r = *__preview_get_crop(prev, sd_state, sel->which); break;
default: return -EINVAL;
}
return 0;
}
/* * 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.
*/ staticint preview_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel)
{ struct isp_prev_device *prev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format;
if (sel->target != V4L2_SEL_TGT_CROP ||
sel->pad != PREV_PAD_SINK) return -EINVAL;
/* The crop rectangle can't be changed while streaming. */ if (prev->state != ISP_PIPELINE_STREAM_STOPPED) return -EBUSY;
/* Modifying the crop rectangle always changes the format on the source * pad. If the KEEP_CONFIG flag is set, just return the current crop * rectangle.
*/ if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {
sel->r = *__preview_get_crop(prev, sd_state, sel->which); return 0;
}
format = __preview_get_format(prev, sd_state, PREV_PAD_SINK,
sel->which);
preview_try_crop(prev, format, &sel->r);
*__preview_get_crop(prev, sd_state, sel->which) = sel->r;
/* Update the source format. */
format = __preview_get_format(prev, sd_state, PREV_PAD_SOURCE,
sel->which);
preview_try_format(prev, sd_state, PREV_PAD_SOURCE, format,
sel->which);
return 0;
}
/* * 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
*/ staticint preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt)
{ struct isp_prev_device *prev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format;
format = __preview_get_format(prev, sd_state, fmt->pad, fmt->which); if (format == NULL) return -EINVAL;
fmt->format = *format; return 0;
}
/* * 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
*/ staticint preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt)
{ struct isp_prev_device *prev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop;
format = __preview_get_format(prev, sd_state, fmt->pad, fmt->which); if (format == NULL) return -EINVAL;
/* Propagate the format from sink to source */ if (fmt->pad == PREV_PAD_SINK) { /* Reset the crop rectangle. */
crop = __preview_get_crop(prev, sd_state, fmt->which);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
crop->height = fmt->format.height;
preview_try_crop(prev, &fmt->format, crop);
/* Update the source format. */
format = __preview_get_format(prev, sd_state, PREV_PAD_SOURCE,
fmt->which);
preview_try_format(prev, sd_state, PREV_PAD_SOURCE, format,
fmt->which);
}
return 0;
}
/* * 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.
*/ staticint preview_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{ struct v4l2_subdev_format format;
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.