aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-4.19/950-0625-drm-vc4-Add-support-for-margins-to-fkms.patch
diff options
context:
space:
mode:
authorAdrian Schmutzler <freifunk@adrianschmutzler.de>2020-02-08 21:58:55 +0100
committerAdrian Schmutzler <freifunk@adrianschmutzler.de>2020-02-14 14:10:51 +0100
commit7d7aa2fd924c27829ec25f825481554dd81bce97 (patch)
tree658b87b89331670266163e522ea5fb52535633cb /target/linux/bcm27xx/patches-4.19/950-0625-drm-vc4-Add-support-for-margins-to-fkms.patch
parente7bfda2c243e66a75ff966ba04c28b1590b5d24c (diff)
downloadupstream-7d7aa2fd924c27829ec25f825481554dd81bce97.tar.gz
upstream-7d7aa2fd924c27829ec25f825481554dd81bce97.tar.bz2
upstream-7d7aa2fd924c27829ec25f825481554dd81bce97.zip
brcm2708: rename target to bcm27xx
This change makes the names of Broadcom targets consistent by using the common notation based on SoC/CPU ID (which is used internally anyway), bcmXXXX instead of brcmXXXX. This is even used for target TITLE in make menuconfig already, only the short target name used brcm so far. Despite, since subtargets range from bcm2708 to bcm2711, it seems appropriate to use bcm27xx instead of bcm2708 (again, as already done for BOARDNAME). This also renames the packages brcm2708-userland and brcm2708-gpu-fw. Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de> Acked-by: Álvaro Fernández Rojas <noltari@gmail.com>
Diffstat (limited to 'target/linux/bcm27xx/patches-4.19/950-0625-drm-vc4-Add-support-for-margins-to-fkms.patch')
-rw-r--r--target/linux/bcm27xx/patches-4.19/950-0625-drm-vc4-Add-support-for-margins-to-fkms.patch328
1 files changed, 328 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-4.19/950-0625-drm-vc4-Add-support-for-margins-to-fkms.patch b/target/linux/bcm27xx/patches-4.19/950-0625-drm-vc4-Add-support-for-margins-to-fkms.patch
new file mode 100644
index 0000000000..12f1606db0
--- /dev/null
+++ b/target/linux/bcm27xx/patches-4.19/950-0625-drm-vc4-Add-support-for-margins-to-fkms.patch
@@ -0,0 +1,328 @@
+From a4e8051901a5d858a69732a3f9734835afc00af5 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.org>
+Date: Fri, 19 Jul 2019 15:35:13 +0100
+Subject: [PATCH] drm/vc4: Add support for margins to fkms
+
+Allows for overscan to be configured under FKMS.
+NB This is rescaling the planes, not reducing the size of the
+display mode.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+---
+ drivers/gpu/drm/vc4/vc4_firmware_kms.c | 241 +++++++++++++++++++------
+ 1 file changed, 190 insertions(+), 51 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
+@@ -256,6 +256,23 @@ static inline struct vc4_crtc *to_vc4_cr
+ return container_of(crtc, struct vc4_crtc, base);
+ }
+
++struct vc4_crtc_state {
++ struct drm_crtc_state base;
++
++ struct {
++ unsigned int left;
++ unsigned int right;
++ unsigned int top;
++ unsigned int bottom;
++ } margins;
++};
++
++static inline struct vc4_crtc_state *
++to_vc4_crtc_state(struct drm_crtc_state *crtc_state)
++{
++ return (struct vc4_crtc_state *)crtc_state;
++}
++
+ struct vc4_fkms_encoder {
+ struct drm_encoder base;
+ bool hdmi_monitor;
+@@ -365,17 +382,127 @@ static int vc4_plane_set_blank(struct dr
+ return ret;
+ }
+
++static void vc4_fkms_crtc_get_margins(struct drm_crtc_state *state,
++ unsigned int *left, unsigned int *right,
++ unsigned int *top, unsigned int *bottom)
++{
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++ struct drm_connector_state *conn_state;
++ struct drm_connector *conn;
++ int i;
++
++ *left = vc4_state->margins.left;
++ *right = vc4_state->margins.right;
++ *top = vc4_state->margins.top;
++ *bottom = vc4_state->margins.bottom;
++
++ /* We have to interate over all new connector states because
++ * vc4_fkms_crtc_get_margins() might be called before
++ * vc4_fkms_crtc_atomic_check() which means margins info in
++ * vc4_crtc_state might be outdated.
++ */
++ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
++ if (conn_state->crtc != state->crtc)
++ continue;
++
++ *left = conn_state->tv.margins.left;
++ *right = conn_state->tv.margins.right;
++ *top = conn_state->tv.margins.top;
++ *bottom = conn_state->tv.margins.bottom;
++ break;
++ }
++}
++
++static int vc4_fkms_margins_adj(struct drm_plane_state *pstate,
++ struct set_plane *plane)
++{
++ unsigned int left, right, top, bottom;
++ int adjhdisplay, adjvdisplay;
++ struct drm_crtc_state *crtc_state;
++
++ crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
++ pstate->crtc);
++
++ vc4_fkms_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
++
++ if (!left && !right && !top && !bottom)
++ return 0;
++
++ if (left + right >= crtc_state->mode.hdisplay ||
++ top + bottom >= crtc_state->mode.vdisplay)
++ return -EINVAL;
++
++ adjhdisplay = crtc_state->mode.hdisplay - (left + right);
++ plane->dst_x = DIV_ROUND_CLOSEST(plane->dst_x * adjhdisplay,
++ (int)crtc_state->mode.hdisplay);
++ plane->dst_x += left;
++ if (plane->dst_x > (int)(crtc_state->mode.hdisplay - left))
++ plane->dst_x = crtc_state->mode.hdisplay - left;
++
++ adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
++ plane->dst_y = DIV_ROUND_CLOSEST(plane->dst_y * adjvdisplay,
++ (int)crtc_state->mode.vdisplay);
++ plane->dst_y += top;
++ if (plane->dst_y > (int)(crtc_state->mode.vdisplay - top))
++ plane->dst_y = crtc_state->mode.vdisplay - top;
++
++ plane->dst_w = DIV_ROUND_CLOSEST(plane->dst_w * adjhdisplay,
++ crtc_state->mode.hdisplay);
++ plane->dst_h = DIV_ROUND_CLOSEST(plane->dst_h * adjvdisplay,
++ crtc_state->mode.vdisplay);
++
++ if (!plane->dst_w || !plane->dst_h)
++ return -EINVAL;
++
++ return 0;
++}
++
+ static void vc4_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+ {
+ struct drm_plane_state *state = plane->state;
++
++ /*
++ * Do NOT set now, as we haven't checked if the crtc is active or not.
++ * Set from vc4_plane_set_blank instead.
++ *
++ * If the CRTC is on (or going to be on) and we're enabled,
++ * then unblank. Otherwise, stay blank until CRTC enable.
++ */
++ if (state->crtc->state->active)
++ vc4_plane_set_blank(plane, false);
++}
++
++static void vc4_plane_atomic_disable(struct drm_plane *plane,
++ struct drm_plane_state *old_state)
++{
++ struct drm_plane_state *state = plane->state;
++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
++
++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
++ plane->base.id, plane->name,
++ state->crtc_w,
++ state->crtc_h,
++ vc4_plane->mb.plane.vc_image_type,
++ state->crtc_x,
++ state->crtc_y);
++ vc4_plane_set_blank(plane, true);
++}
++
++static bool plane_enabled(struct drm_plane_state *state)
++{
++ return state->fb && state->crtc;
++}
++
++static int vc4_plane_to_mb(struct drm_plane *plane,
++ struct mailbox_set_plane *mb,
++ struct drm_plane_state *state)
++{
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
+ const struct drm_format_info *drm_fmt = fb->format;
+ const struct vc_image_format *vc_fmt =
+ vc4_get_vc_image_fmt(drm_fmt->format);
+- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+- struct mailbox_set_plane *mb = &vc4_plane->mb;
+ int num_planes = fb->format->num_planes;
+ struct drm_display_mode *mode = &state->crtc->mode;
+ unsigned int rotation = SUPPORTED_ROTATIONS;
+@@ -417,25 +544,7 @@ static void vc4_plane_atomic_update(stru
+ break;
+ }
+
+- /* FIXME: If the dest rect goes off screen then clip the src rect so we
+- * don't have off-screen pixels.
+- */
+- if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+- /* There is no scaling on the cursor plane, therefore the calcs
+- * to alter the source crop as the cursor goes off the screen
+- * are simple.
+- */
+- if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) {
+- mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x;
+- mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x)
+- << 16;
+- }
+- if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) {
+- mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y;
+- mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y)
+- << 16;
+- }
+- }
++ vc4_fkms_margins_adj(state, &mb->plane);
+
+ if (num_planes > 1) {
+ /* Assume this must be YUV */
+@@ -525,38 +634,19 @@ static void vc4_plane_atomic_update(stru
+ state->alpha,
+ state->normalized_zpos);
+
+- /*
+- * Do NOT set now, as we haven't checked if the crtc is active or not.
+- * Set from vc4_plane_set_blank instead.
+- *
+- * If the CRTC is on (or going to be on) and we're enabled,
+- * then unblank. Otherwise, stay blank until CRTC enable.
+- */
+- if (state->crtc->state->active)
+- vc4_plane_set_blank(plane, false);
++ return 0;
+ }
+
+-static void vc4_plane_atomic_disable(struct drm_plane *plane,
+- struct drm_plane_state *old_state)
++static int vc4_plane_atomic_check(struct drm_plane *plane,
++ struct drm_plane_state *state)
+ {
+- //struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
+- struct drm_plane_state *state = plane->state;
+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
+
+- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n",
+- plane->base.id, plane->name,
+- state->crtc_w,
+- state->crtc_h,
+- vc4_plane->mb.plane.vc_image_type,
+- state->crtc_x,
+- state->crtc_y);
+- vc4_plane_set_blank(plane, true);
+-}
++ if (!plane_enabled(state))
++ return 0;
++
++ return vc4_plane_to_mb(plane, &vc4_plane->mb, state);
+
+-static int vc4_plane_atomic_check(struct drm_plane *plane,
+- struct drm_plane_state *state)
+-{
+- return 0;
+ }
+
+ static void vc4_plane_destroy(struct drm_plane *plane)
+@@ -878,8 +968,23 @@ vc4_crtc_mode_valid(struct drm_crtc *crt
+ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+ {
+- DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n",
+- crtc->base.id);
++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
++ struct drm_connector *conn;
++ struct drm_connector_state *conn_state;
++ int i;
++
++ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", crtc->base.id);
++
++ for_each_new_connector_in_state(state->state, conn, conn_state, i) {
++ if (conn_state->crtc != crtc)
++ continue;
++
++ vc4_state->margins.left = conn_state->tv.margins.left;
++ vc4_state->margins.right = conn_state->tv.margins.right;
++ vc4_state->margins.top = conn_state->tv.margins.top;
++ vc4_state->margins.bottom = conn_state->tv.margins.bottom;
++ break;
++ }
+ return 0;
+ }
+
+@@ -980,6 +1085,33 @@ static int vc4_page_flip(struct drm_crtc
+ return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
+ }
+
++static struct drm_crtc_state *
++vc4_crtc_duplicate_state(struct drm_crtc *crtc)
++{
++ struct vc4_crtc_state *vc4_state, *old_vc4_state;
++
++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
++ if (!vc4_state)
++ return NULL;
++
++ old_vc4_state = to_vc4_crtc_state(crtc->state);
++ vc4_state->margins = old_vc4_state->margins;
++
++ __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
++ return &vc4_state->base;
++}
++
++static void
++vc4_crtc_reset(struct drm_crtc *crtc)
++{
++ if (crtc->state)
++ __drm_atomic_helper_crtc_destroy_state(crtc->state);
++
++ crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
++ if (crtc->state)
++ crtc->state->crtc = crtc;
++}
++
+ static int vc4_fkms_enable_vblank(struct drm_crtc *crtc)
+ {
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+@@ -1007,8 +1139,8 @@ static const struct drm_crtc_funcs vc4_c
+ .set_property = NULL,
+ .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
+ .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
+- .reset = drm_atomic_helper_crtc_reset,
+- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
++ .reset = vc4_crtc_reset,
++ .atomic_duplicate_state = vc4_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = vc4_fkms_enable_vblank,
+ .disable_vblank = vc4_fkms_disable_vblank,
+@@ -1267,6 +1399,13 @@ vc4_fkms_connector_init(struct drm_devic
+ connector->interlace_allowed = 0;
+ }
+
++ /* Create and attach TV margin props to this connector. */
++ ret = drm_mode_create_tv_margin_properties(dev);
++ if (ret)
++ return ERR_PTR(ret);
++
++ drm_connector_attach_tv_margin_properties(connector);
++
+ connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT);
+