/* * Removed VCXFE mask as it doesn't exist in IER * Removed STOP state irq as this will keep driver in irq handler only
*/ #define XCSI_IER_INTR_MASK (XCSI_ISR_ALLINTR_MASK &\
~(XCSI_ISR_STOP | XCSI_ISR_VCXFE))
/* * Sink pad connected to sensor source pad. * Source pad connected to next module like demosaic.
*/ #define XCSI_MEDIA_PADS 2 #define XCSI_DEFAULT_WIDTH 1920 #define XCSI_DEFAULT_HEIGHT 1080
/** * struct xcsi2rxss_state - CSI-2 Rx Subsystem device structure * @subdev: The v4l2 subdev structure * @format: Active V4L2 formats on each pad * @default_format: Default V4L2 format * @events: counter for events * @vcx_events: counter for vcx_events * @dev: Platform structure * @rsubdev: Remote subdev connected to sink pad * @rst_gpio: reset to video_aresetn * @clks: array of clocks * @iomem: Base address of subsystem * @max_num_lanes: Maximum number of lanes present * @datatype: Data type filter * @lock: mutex for accessing this structure * @pads: media pads * @streaming: Flag for storing streaming state * @enable_active_lanes: If number of active lanes can be modified * @en_vcx: If more than 4 VC are enabled * * This structure contains the device driver related parameters
*/ struct xcsi2rxss_state { struct v4l2_subdev subdev; struct v4l2_mbus_framefmt format; struct v4l2_mbus_framefmt default_format;
u32 events[XCSI_NUM_EVENTS];
u32 vcx_events[XCSI_VCX_NUM_EVENTS]; struct device *dev; struct v4l2_subdev *rsubdev; struct gpio_desc *rst_gpio; struct clk_bulk_data *clks; void __iomem *iomem;
u32 max_num_lanes;
u32 datatype; /* used to protect access to this struct */ struct mutex lock; struct media_pad pads[XCSI_MEDIA_PADS]; bool streaming; bool enable_active_lanes; bool en_vcx;
};
/* * This function returns the nth mbus for a data type. * In case of error, mbus code returned is 0.
*/ static u32 xcsi2rxss_get_nth_mbus(u32 dt, u32 n)
{ unsignedint i;
for (i = 0; i < ARRAY_SIZE(xcsi2dt_mbus_lut); i++) { if (xcsi2dt_mbus_lut[i][0] == dt) { if (n-- == 0) return xcsi2dt_mbus_lut[i][1];
}
}
return 0;
}
/* This returns the data type for a media bus format else 0 */ static u32 xcsi2rxss_get_dt(u32 mbus)
{ unsignedint i;
for (i = 0; i < ARRAY_SIZE(xcsi2dt_mbus_lut); i++) { if (xcsi2dt_mbus_lut[i][1] == mbus) return xcsi2dt_mbus_lut[i][0];
}
return 0;
}
/** * xcsi2rxss_soft_reset - Does a soft reset of the MIPI CSI-2 Rx Subsystem * @state: Xilinx CSI-2 Rx Subsystem structure pointer * * Core takes less than 100 video clock cycles to reset. * So a larger timeout value is chosen for margin. * * Return: 0 - on success OR -ETIME if reset times out
*/ staticint xcsi2rxss_soft_reset(struct xcsi2rxss_state *state)
{
u32 timeout = 1000; /* us */
dev_info(dev, "***** Core Status *****\n");
data = xcsi2rxss_read(xcsi2rxss, XCSI_CSR_OFFSET);
dev_info(dev, "Short Packet FIFO Full = %s\n",
data & XCSI_CSR_SPFIFOFULL ? "true" : "false");
dev_info(dev, "Short Packet FIFO Not Empty = %s\n",
data & XCSI_CSR_SPFIFONE ? "true" : "false");
dev_info(dev, "Stream line buffer full = %s\n",
data & XCSI_CSR_SLBF ? "true" : "false");
dev_info(dev, "Soft reset/Core disable in progress = %s\n",
data & XCSI_CSR_RIPCD ? "true" : "false");
/* Clk & Lane Info */
dev_info(dev, "******** Clock Lane Info *********\n");
data = xcsi2rxss_read(xcsi2rxss, XCSI_CLKINFR_OFFSET);
dev_info(dev, "Clock Lane in Stop State = %s\n",
data & XCSI_CLKINFR_STOP ? "true" : "false");
dev_info(dev, "******** Data Lane Info *********\n");
dev_info(dev, "Lane\tSoT Error\tSoT Sync Error\tStop State\n");
reg = XCSI_DLXINFR_OFFSET; for (i = 0; i < XCSI_MAXDL_COUNT; i++) {
data = xcsi2rxss_read(xcsi2rxss, reg);
dev_info(dev, "%d\t%s\t\t%s\t\t%s\n", i,
data & XCSI_DLXINFR_SOTERR ? "true" : "false",
data & XCSI_DLXINFR_SOTSYNCERR ? "true" : "false",
data & XCSI_DLXINFR_STOP ? "true" : "false");
reg += XCSI_NEXTREG_OFFSET;
}
/* Virtual Channel Image Information */
dev_info(dev, "********** Virtual Channel Info ************\n");
dev_info(dev, "VC\tLine Count\tByte Count\tData Type\n"); if (xcsi2rxss->en_vcx)
max_vc = XCSI_MAX_VCX; else
max_vc = XCSI_MAX_VC;
reg = XCSI_VCXINF1R_OFFSET; for (i = 0; i < max_vc; i++) {
u32 line_count, byte_count, data_type;
/* Get line and byte count from VCXINFR1 Register */
data = xcsi2rxss_read(xcsi2rxss, reg);
byte_count = data & XCSI_VCXINF1R_BYTECOUNT;
line_count = data & XCSI_VCXINF1R_LINECOUNT;
line_count >>= XCSI_VCXINF1R_LINECOUNT_SHIFT;
/* Get data type from VCXINFR2 Register */
reg += XCSI_NEXTREG_OFFSET;
data = xcsi2rxss_read(xcsi2rxss, reg);
data_type = data & XCSI_VCXINF2R_DT;
dev_info(dev, "%d\t%d\t\t%d\t\t0x%x\n", i, line_count,
byte_count, data_type);
/* Move to next pair of VC Info registers */
reg += XCSI_NEXTREG_OFFSET;
}
/** * xcsi2rxss_irq_handler - Interrupt handler for CSI-2 * @irq: IRQ number * @data: Pointer to device state * * In the interrupt handler, a list of event counters are updated for * corresponding interrupts. This is useful to get status / debug. * * Return: IRQ_HANDLED after handling interrupts
*/ static irqreturn_t xcsi2rxss_irq_handler(int irq, void *data)
{ struct xcsi2rxss_state *state = (struct xcsi2rxss_state *)data; struct device *dev = state->dev;
u32 status;
status = xcsi2rxss_read(state, XCSI_ISR_OFFSET) & XCSI_ISR_ALLINTR_MASK;
xcsi2rxss_write(state, XCSI_ISR_OFFSET, status);
/* Received a short packet */ if (status & XCSI_ISR_SPFIFONE) {
u32 count = 0;
/* * Drain generic short packet FIFO by reading max 31 * (fifo depth) short packets from fifo or till fifo is empty.
*/ for (count = 0; count < XCSI_SPKT_FIFO_DEPTH; ++count) {
u32 spfifostat, spkt;
/* Short packet FIFO overflow */ if (status & XCSI_ISR_SPFIFOF)
dev_dbg_ratelimited(dev, "Short packet FIFO overflowed\n");
/* * Stream line buffer full * This means there is a backpressure from downstream IP
*/ if (status & XCSI_ISR_SLBF) {
dev_alert_ratelimited(dev, "Stream Line Buffer Full!\n");
mutex_lock(&xcsi2rxss->lock); for (i = 0; i < XCSI_MEDIA_PADS; i++) {
format = v4l2_subdev_state_get_format(sd_state, i);
*format = xcsi2rxss->default_format;
}
mutex_unlock(&xcsi2rxss->lock);
/* * Only the format->code parameter matters for CSI as the * CSI format cannot be changed at runtime. * Ensure that format to set is copied to over to CSI pad format
*/
__format = __xcsi2rxss_get_pad_format(xcsi2rxss, sd_state,
fmt->pad, fmt->which);
/* only sink pad format can be updated */ if (fmt->pad == XVIP_PAD_SOURCE) {
fmt->format = *__format;
mutex_unlock(&xcsi2rxss->lock); return 0;
}
/* * RAW8 is supported in all datatypes. So if requested media bus format * is of RAW8 type, then allow to be set. In case core is configured to * other RAW, YUV422 8/10 or RGB888, set appropriate media bus format.
*/
dt = xcsi2rxss_get_dt(fmt->format.code); if (dt != xcsi2rxss->datatype && dt != MIPI_CSI2_DT_RAW8) {
dev_dbg(xcsi2rxss->dev, "Unsupported media bus format"); /* set the default format for the data type */
fmt->format.code = xcsi2rxss_get_nth_mbus(xcsi2rxss->datatype,
0);
}
ret = of_property_read_u32(node, "xlnx,csi-pxl-format",
&xcsi2rxss->datatype); if (ret < 0) {
dev_err(dev, "missing xlnx,csi-pxl-format property\n"); return ret;
}
switch (xcsi2rxss->datatype) { case MIPI_CSI2_DT_YUV422_8B: case MIPI_CSI2_DT_RGB444: case MIPI_CSI2_DT_RGB555: case MIPI_CSI2_DT_RGB565: case MIPI_CSI2_DT_RGB666: case MIPI_CSI2_DT_RGB888: case MIPI_CSI2_DT_RAW6: case MIPI_CSI2_DT_RAW7: case MIPI_CSI2_DT_RAW8: case MIPI_CSI2_DT_RAW10: case MIPI_CSI2_DT_RAW12: case MIPI_CSI2_DT_RAW14: break; case MIPI_CSI2_DT_YUV422_10B: case MIPI_CSI2_DT_RAW16: case MIPI_CSI2_DT_RAW20: if (!en_csi_v20) {
ret = -EINVAL;
dev_dbg(dev, "enable csi v2 for this pixel format");
} break; default:
ret = -EINVAL;
} if (ret < 0) {
dev_err(dev, "invalid csi-pxl-format property!\n"); return ret;
}
vfb = of_property_read_bool(node, "xlnx,vfb"); if (!vfb) {
dev_err(dev, "operation without VFB is not supported\n"); return -EINVAL;
}
ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
XVIP_PAD_SINK, 0,
FWNODE_GRAPH_ENDPOINT_NEXT); if (!ep) {
dev_err(dev, "no sink port found"); return -EINVAL;
}
ret = v4l2_fwnode_endpoint_parse(ep, &vep);
fwnode_handle_put(ep); if (ret) {
dev_err(dev, "error parsing sink port"); return ret;
}
dev_dbg(dev, "mipi number lanes = %d\n",
vep.bus.mipi_csi2.num_data_lanes);
ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
XVIP_PAD_SOURCE, 0,
FWNODE_GRAPH_ENDPOINT_NEXT); if (!ep) {
dev_err(dev, "no source port found"); return -EINVAL;
}
fwnode_handle_put(ep);
dev_dbg(dev, "vcx %s, %u data lanes (%s), data type 0x%02x\n",
xcsi2rxss->en_vcx ? "enabled" : "disabled",
xcsi2rxss->max_num_lanes,
xcsi2rxss->enable_active_lanes ? "dynamic" : "static",
xcsi2rxss->datatype);
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.