@@ -691,6 +691,65 @@ static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
.atomic_disable = rcar_du_crtc_atomic_disable,
};
+static void rcar_du_crtc_crc_init(struct rcar_du_crtc *rcrtc)
+{
+ struct rcar_du_device *rcdu = rcrtc->group->dev;
+ const char **sources;
+ unsigned int count;
+ int i = -1;
+
+ /* CRC available only on Gen3 HW. */
+ if (rcdu->info->gen < 3)
+ return;
+
+ /* Reserve 1 for "auto" source. */
+ count = rcrtc->vsp->num_planes + 1;
+
+ sources = kmalloc_array(count, sizeof(*sources), GFP_KERNEL);
+ if (!sources)
+ return;
+
+ sources[0] = kstrdup("auto", GFP_KERNEL);
+ if (!sources[0])
+ goto error;
+
+ for (i = 0; i < rcrtc->vsp->num_planes; ++i) {
+ struct drm_plane *plane = &rcrtc->vsp->planes[i].plane;
+ char name[16];
+
+ sprintf(name, "plane%u", plane->base.id);
+ sources[i + 1] = kstrdup(name, GFP_KERNEL);
+ if (!sources[i + 1])
+ goto error;
+ }
+
+ rcrtc->sources = sources;
+ rcrtc->sources_count = count;
+ return;
+
+error:
+ while (i >= 0) {
+ kfree(sources[i]);
+ i--;
+ }
+ kfree(sources);
+}
+
+static void rcar_du_crtc_crc_cleanup(struct rcar_du_crtc *rcrtc)
+{
+ unsigned int i;
+
+ if (!rcrtc->sources)
+ return;
+
+ for (i = 0; i < rcrtc->sources_count; i++)
+ kfree(rcrtc->sources[i]);
+ kfree(rcrtc->sources);
+
+ rcrtc->sources = NULL;
+ rcrtc->sources_count = 0;
+}
+
static struct drm_crtc_state *
rcar_du_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
{
@@ -717,6 +776,15 @@ static void rcar_du_crtc_atomic_destroy_state(struct drm_crtc *crtc,
kfree(to_rcar_crtc_state(state));
}
+static void rcar_du_crtc_cleanup(struct drm_crtc *crtc)
+{
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+ rcar_du_crtc_crc_cleanup(rcrtc);
+
+ return drm_crtc_cleanup(crtc);
+}
+
static void rcar_du_crtc_reset(struct drm_crtc *crtc)
{
struct rcar_du_crtc_state *state;
@@ -809,6 +877,15 @@ static int rcar_du_crtc_verify_crc_source(struct drm_crtc *crtc,
return 0;
}
+const char *const *rcar_du_crtc_get_crc_sources(struct drm_crtc *crtc,
+ size_t *count)
+{
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+ *count = rcrtc->sources_count;
+ return rcrtc->sources;
+}
+
static int rcar_du_crtc_set_crc_source(struct drm_crtc *crtc,
const char *source_name)
{
@@ -879,7 +956,7 @@ static const struct drm_crtc_funcs crtc_funcs_gen2 = {
static const struct drm_crtc_funcs crtc_funcs_gen3 = {
.reset = rcar_du_crtc_reset,
- .destroy = drm_crtc_cleanup,
+ .destroy = rcar_du_crtc_cleanup,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.atomic_duplicate_state = rcar_du_crtc_atomic_duplicate_state,
@@ -888,6 +965,7 @@ static const struct drm_crtc_funcs crtc_funcs_gen3 = {
.disable_vblank = rcar_du_crtc_disable_vblank,
.set_crc_source = rcar_du_crtc_set_crc_source,
.verify_crc_source = rcar_du_crtc_verify_crc_source,
+ .get_crc_sources = rcar_du_crtc_get_crc_sources,
};
/* -----------------------------------------------------------------------------
@@ -1026,5 +1104,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
return ret;
}
+ rcar_du_crtc_crc_init(rcrtc);
+
return 0;
}
@@ -67,6 +67,9 @@ struct rcar_du_crtc {
struct rcar_du_group *group;
struct rcar_du_vsp *vsp;
unsigned int vsp_pipe;
+
+ const char *const *sources;
+ unsigned int sources_count;
};
#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc)