* Pipeline Configuration
*/
+/* Setup one RPF and the connected BRU sink pad. */
+static int vsp1_du_pipeline_setup_rpf(struct vsp1_device *vsp1,
+ struct vsp1_pipeline *pipe,
+ struct vsp1_rwpf *rpf,
+ unsigned int bru_input)
+{
+ struct v4l2_subdev_selection sel;
+ struct v4l2_subdev_format format;
+ const struct v4l2_rect *crop;
+ int ret;
+
+ /*
+ * Configure the format on the RPF sink pad and propagate it up to the
+ * BRU sink pad.
+ */
+ crop = &vsp1->drm->inputs[rpf->entity.index].crop;
+
+ memset(&format, 0, sizeof(format));
+ format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.pad = RWPF_PAD_SINK;
+ format.format.width = crop->width + crop->left;
+ format.format.height = crop->height + crop->top;
+ format.format.code = rpf->fmtinfo->mbus;
+ format.format.field = V4L2_FIELD_NONE;
+
+ ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev,
+ "%s: set format %ux%u (%x) on RPF%u sink\n",
+ __func__, format.format.width, format.format.height,
+ format.format.code, rpf->entity.index);
+
+ memset(&sel, 0, sizeof(sel));
+ sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ sel.pad = RWPF_PAD_SINK;
+ sel.target = V4L2_SEL_TGT_CROP;
+ sel.r = *crop;
+
+ ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL,
+ &sel);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev,
+ "%s: set selection (%u,%u)/%ux%u on RPF%u sink\n",
+ __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
+ rpf->entity.index);
+
+ /*
+ * RPF source, hardcode the format to ARGB8888 to turn on format
+ * conversion if needed.
+ */
+ format.pad = RWPF_PAD_SOURCE;
+
+ ret = v4l2_subdev_call(&rpf->entity.subdev, pad, get_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev,
+ "%s: got format %ux%u (%x) on RPF%u source\n",
+ __func__, format.format.width, format.format.height,
+ format.format.code, rpf->entity.index);
+
+ format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
+
+ ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ /* BRU sink, propagate the format from the RPF source. */
+ format.pad = bru_input;
+
+ ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_fmt, NULL,
+ &format);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
+ __func__, format.format.width, format.format.height,
+ format.format.code, BRU_NAME(pipe->bru), format.pad);
+
+ sel.pad = bru_input;
+ sel.target = V4L2_SEL_TGT_COMPOSE;
+ sel.r = vsp1->drm->inputs[rpf->entity.index].compose;
+
+ ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_selection, NULL,
+ &sel);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(vsp1->dev, "%s: set selection (%u,%u)/%ux%u on %s pad %u\n",
+ __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
+ BRU_NAME(pipe->bru), sel.pad);
+
+ return 0;
+}
+
+static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf)
+{
+ return vsp1->drm->inputs[rpf->entity.index].zpos;
+}
+
+/* Setup the input side of the pipeline (RPFs and BRU sink pads). */
+static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1,
+ struct vsp1_pipeline *pipe)
+{
+ struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
+ struct vsp1_bru *bru = to_bru(&pipe->bru->subdev);
+ unsigned int i;
+ int ret;
+
+ /* Count the number of enabled inputs and sort them by Z-order. */
+ pipe->num_inputs = 0;
+
+ for (i = 0; i < vsp1->info->rpf_count; ++i) {
+ struct vsp1_rwpf *rpf = vsp1->rpf[i];
+ unsigned int j;
+
+ /*
+ * Make sure we don't accept more inputs than the hardware can
+ * handle. This is a temporary fix to avoid display stall, we
+ * need to instead allocate the BRU or BRS to display pipelines
+ * dynamically based on the number of planes they each use.
+ */
+ if (pipe->num_inputs >= pipe->bru->source_pad)
+ pipe->inputs[i] = NULL;
+
+ if (!pipe->inputs[i])
+ continue;
+
+ /* Insert the RPF in the sorted RPFs array. */
+ for (j = pipe->num_inputs++; j > 0; --j) {
+ if (rpf_zpos(vsp1, inputs[j-1]) <= rpf_zpos(vsp1, rpf))
+ break;
+ inputs[j] = inputs[j-1];
+ }
+
+ inputs[j] = rpf;
+ }
+
+ /* Setup the RPF input pipeline for every enabled input. */
+ for (i = 0; i < pipe->bru->source_pad; ++i) {
+ struct vsp1_rwpf *rpf = inputs[i];
+
+ if (!rpf) {
+ bru->inputs[i].rpf = NULL;
+ continue;
+ }
+
+ if (!rpf->entity.pipe) {
+ rpf->entity.pipe = pipe;
+ list_add_tail(&rpf->entity.list_pipe, &pipe->entities);
+ }
+
+ bru->inputs[i].rpf = rpf;
+ rpf->bru_input = i;
+ rpf->entity.sink = pipe->bru;
+ rpf->entity.sink_pad = i;
+
+ dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n",
+ __func__, rpf->entity.index, BRU_NAME(pipe->bru), i);
+
+ ret = vsp1_du_pipeline_setup_rpf(vsp1, pipe, rpf, i);
+ if (ret < 0) {
+ dev_err(vsp1->dev,
+ "%s: failed to setup RPF.%u\n",
+ __func__, rpf->entity.index);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
/* Configure all entities in the pipeline. */
static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
{
}
EXPORT_SYMBOL_GPL(vsp1_du_atomic_update);
-static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1,
- struct vsp1_pipeline *pipe,
- struct vsp1_rwpf *rpf, unsigned int bru_input)
-{
- struct v4l2_subdev_selection sel;
- struct v4l2_subdev_format format;
- const struct v4l2_rect *crop;
- int ret;
-
- /*
- * Configure the format on the RPF sink pad and propagate it up to the
- * BRU sink pad.
- */
- crop = &vsp1->drm->inputs[rpf->entity.index].crop;
-
- memset(&format, 0, sizeof(format));
- format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- format.pad = RWPF_PAD_SINK;
- format.format.width = crop->width + crop->left;
- format.format.height = crop->height + crop->top;
- format.format.code = rpf->fmtinfo->mbus;
- format.format.field = V4L2_FIELD_NONE;
-
- ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
- &format);
- if (ret < 0)
- return ret;
-
- dev_dbg(vsp1->dev,
- "%s: set format %ux%u (%x) on RPF%u sink\n",
- __func__, format.format.width, format.format.height,
- format.format.code, rpf->entity.index);
-
- memset(&sel, 0, sizeof(sel));
- sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- sel.pad = RWPF_PAD_SINK;
- sel.target = V4L2_SEL_TGT_CROP;
- sel.r = *crop;
-
- ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL,
- &sel);
- if (ret < 0)
- return ret;
-
- dev_dbg(vsp1->dev,
- "%s: set selection (%u,%u)/%ux%u on RPF%u sink\n",
- __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
- rpf->entity.index);
-
- /*
- * RPF source, hardcode the format to ARGB8888 to turn on format
- * conversion if needed.
- */
- format.pad = RWPF_PAD_SOURCE;
-
- ret = v4l2_subdev_call(&rpf->entity.subdev, pad, get_fmt, NULL,
- &format);
- if (ret < 0)
- return ret;
-
- dev_dbg(vsp1->dev,
- "%s: got format %ux%u (%x) on RPF%u source\n",
- __func__, format.format.width, format.format.height,
- format.format.code, rpf->entity.index);
-
- format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
-
- ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
- &format);
- if (ret < 0)
- return ret;
-
- /* BRU sink, propagate the format from the RPF source. */
- format.pad = bru_input;
-
- ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_fmt, NULL,
- &format);
- if (ret < 0)
- return ret;
-
- dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n",
- __func__, format.format.width, format.format.height,
- format.format.code, BRU_NAME(pipe->bru), format.pad);
-
- sel.pad = bru_input;
- sel.target = V4L2_SEL_TGT_COMPOSE;
- sel.r = vsp1->drm->inputs[rpf->entity.index].compose;
-
- ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_selection, NULL,
- &sel);
- if (ret < 0)
- return ret;
-
- dev_dbg(vsp1->dev, "%s: set selection (%u,%u)/%ux%u on %s pad %u\n",
- __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
- BRU_NAME(pipe->bru), sel.pad);
-
- return 0;
-}
-
-static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf)
-{
- return vsp1->drm->inputs[rpf->entity.index].zpos;
-}
-
/**
* vsp1_du_atomic_flush - Commit an atomic update
* @dev: the VSP device
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
struct vsp1_pipeline *pipe = &drm_pipe->pipe;
- struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
- struct vsp1_bru *bru = to_bru(&pipe->bru->subdev);
- unsigned int i;
- int ret;
-
- /* Count the number of enabled inputs and sort them by Z-order. */
- pipe->num_inputs = 0;
-
- for (i = 0; i < vsp1->info->rpf_count; ++i) {
- struct vsp1_rwpf *rpf = vsp1->rpf[i];
- unsigned int j;
-
- /*
- * Make sure we don't accept more inputs than the hardware can
- * handle. This is a temporary fix to avoid display stall, we
- * need to instead allocate the BRU or BRS to display pipelines
- * dynamically based on the number of planes they each use.
- */
- if (pipe->num_inputs >= pipe->bru->source_pad)
- pipe->inputs[i] = NULL;
-
- if (!pipe->inputs[i])
- continue;
-
- /* Insert the RPF in the sorted RPFs array. */
- for (j = pipe->num_inputs++; j > 0; --j) {
- if (rpf_zpos(vsp1, inputs[j-1]) <= rpf_zpos(vsp1, rpf))
- break;
- inputs[j] = inputs[j-1];
- }
-
- inputs[j] = rpf;
- }
-
- /* Setup the RPF input pipeline for every enabled input. */
- for (i = 0; i < pipe->bru->source_pad; ++i) {
- struct vsp1_rwpf *rpf = inputs[i];
-
- if (!rpf) {
- bru->inputs[i].rpf = NULL;
- continue;
- }
-
- if (!rpf->entity.pipe) {
- rpf->entity.pipe = pipe;
- list_add_tail(&rpf->entity.list_pipe, &pipe->entities);
- }
-
- bru->inputs[i].rpf = rpf;
- rpf->bru_input = i;
- rpf->entity.sink = pipe->bru;
- rpf->entity.sink_pad = i;
-
- dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n",
- __func__, rpf->entity.index, BRU_NAME(pipe->bru), i);
-
- ret = vsp1_du_setup_rpf_pipe(vsp1, pipe, rpf, i);
- if (ret < 0)
- dev_err(vsp1->dev,
- "%s: failed to setup RPF.%u\n",
- __func__, rpf->entity.index);
- }
+ vsp1_du_pipeline_setup_inputs(vsp1, pipe);
vsp1_du_pipeline_configure(pipe);
}
EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);