/* * Find the CSI data format and data width for the given V4L2 media * bus pixel format code.
*/ staticint mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code, enum v4l2_mbus_type mbus_type)
{ switch (mbus_code) { case MEDIA_BUS_FMT_BGR565_2X8_BE: case MEDIA_BUS_FMT_BGR565_2X8_LE: case MEDIA_BUS_FMT_RGB565_2X8_BE: case MEDIA_BUS_FMT_RGB565_2X8_LE: if (mbus_type == V4L2_MBUS_CSI2_DPHY)
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565; else
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_RGB565;
cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE: case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
cfg->mipi_dt = MIPI_DT_RGB444;
cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE: case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
cfg->mipi_dt = MIPI_DT_RGB555;
cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; case MEDIA_BUS_FMT_RGB888_1X24: case MEDIA_BUS_FMT_BGR888_1X24:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
cfg->mipi_dt = MIPI_DT_RGB888;
cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; case MEDIA_BUS_FMT_UYVY8_2X8:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
cfg->mipi_dt = MIPI_DT_YUV422;
cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; case MEDIA_BUS_FMT_YUYV8_2X8:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
cfg->mipi_dt = MIPI_DT_YUV422;
cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; case MEDIA_BUS_FMT_UYVY8_1X16: if (mbus_type == V4L2_MBUS_BT656) {
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
} else {
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->data_width = IPU_CSI_DATA_WIDTH_16;
}
cfg->mipi_dt = MIPI_DT_YUV422; break; case MEDIA_BUS_FMT_YUYV8_1X16: if (mbus_type == V4L2_MBUS_BT656) {
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
} else {
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->data_width = IPU_CSI_DATA_WIDTH_16;
}
cfg->mipi_dt = MIPI_DT_YUV422; break; case MEDIA_BUS_FMT_SBGGR8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SRGGB8_1X8: case MEDIA_BUS_FMT_Y8_1X8:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_RAW8;
cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8: case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8: case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8: case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE: case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE: case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE: case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_RAW10;
cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; case MEDIA_BUS_FMT_SBGGR10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10: case MEDIA_BUS_FMT_Y10_1X10:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_RAW10;
cfg->data_width = IPU_CSI_DATA_WIDTH_10; break; case MEDIA_BUS_FMT_SBGGR12_1X12: case MEDIA_BUS_FMT_SGBRG12_1X12: case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12: case MEDIA_BUS_FMT_Y12_1X12:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_RAW12;
cfg->data_width = IPU_CSI_DATA_WIDTH_12; break; case MEDIA_BUS_FMT_JPEG_1X8: /* TODO */
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
cfg->mipi_dt = MIPI_DT_RAW8;
cfg->data_width = IPU_CSI_DATA_WIDTH_8; break; default: return -EINVAL;
}
return 0;
}
/* translate alternate field mode based on given standard */ staticinlineenum v4l2_field
ipu_csi_translate_field(enum v4l2_field field, v4l2_std_id std)
{ return (field != V4L2_FIELD_ALTERNATE) ? field :
((std & V4L2_STD_525_60) ?
V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_TB);
}
/* * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
*/ staticint fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, conststruct v4l2_mbus_config *mbus_cfg, conststruct v4l2_mbus_framefmt *mbus_fmt)
{ int ret, is_bt1120;
memset(csicfg, 0, sizeof(*csicfg));
ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type); if (ret < 0) return ret;
switch (mbus_cfg->type) { case V4L2_MBUS_PARALLEL:
csicfg->ext_vsync = 1;
csicfg->vsync_pol = (mbus_cfg->bus.parallel.flags &
V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
csicfg->hsync_pol = (mbus_cfg->bus.parallel.flags &
V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
csicfg->pixclk_pol = (mbus_cfg->bus.parallel.flags &
V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; break; case V4L2_MBUS_BT656:
csicfg->ext_vsync = 0; /* UYVY10_1X20 etc. should be supported as well */
is_bt1120 = mbus_fmt->code == MEDIA_BUS_FMT_UYVY8_1X16 ||
mbus_fmt->code == MEDIA_BUS_FMT_YUYV8_1X16; if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) ||
mbus_fmt->field == V4L2_FIELD_ALTERNATE)
csicfg->clk_mode = is_bt1120 ?
IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR :
IPU_CSI_CLK_MODE_CCIR656_INTERLACED; else
csicfg->clk_mode = is_bt1120 ?
IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR :
IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; break; case V4L2_MBUS_CSI2_DPHY: /* * MIPI CSI-2 requires non gated clock mode, all other * parameters are not applicable for MIPI CSI-2 bus.
*/
csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK; break; default: /* will never get here, keep compiler quiet */ break;
}
/* get translated field type of input and output */
infield = ipu_csi_translate_field(infmt->field, std);
outfield = ipu_csi_translate_field(outfmt->field, std);
/* * Write the H-V-F codes the CSI will match against the * incoming data for start/end of active and blanking * field intervals. If input and output field types are * sequential but not the same (one is SEQ_BT and the other * is SEQ_TB), swap the F-bit so that the CSI will capture * field 1 lines before field 0 lines.
*/
swap_fields = (V4L2_FIELD_IS_SEQUENTIAL(infield) &&
V4L2_FIELD_IS_SEQUENTIAL(outfield) &&
infield != outfield);
/* same as above but with F-bit inverted */
ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN,
CSI_CCIR_CODE_1);
ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
}
ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
return 0;
}
int ipu_csi_init_interface(struct ipu_csi *csi, conststruct v4l2_mbus_config *mbus_cfg, conststruct v4l2_mbus_framefmt *infmt, conststruct v4l2_mbus_framefmt *outfmt)
{ struct ipu_csi_bus_config cfg; unsignedlong flags;
u32 width, height, data = 0;
v4l2_std_id std; int ret;
ret = fill_csi_bus_cfg(&cfg, mbus_cfg, infmt); if (ret < 0) return ret;
/* set default sensor frame width and height */
width = infmt->width;
height = infmt->height; if (infmt->field == V4L2_FIELD_ALTERNATE)
height *= 2;
ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std); if (ret) goto out_unlock; break; case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN,
CSI_CCIR_CODE_1);
ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); break; case IPU_CSI_CLK_MODE_GATED_CLK: case IPU_CSI_CLK_MODE_NONGATED_CLK:
ipu_csi_write(csi, 0, CSI_CCIR_CODE_1); break;
}
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.