@@ -2569,6 +2569,51 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
fb_helper->sw_rotations |= DRM_MODE_ROTATE_0;
}
+static void drm_setup_connector_margins(struct drm_connector *connector)
+{
+ struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_state *state;
+ struct drm_device *dev = connector->dev;
+ int ret;
+
+ if (!drm_drv_uses_atomic_modeset(dev))
+ return;
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ state = drm_atomic_state_alloc(dev);
+ state->acquire_ctx = &ctx;
+
+retry:
+ drm_atomic_set_property(state, &connector->base,
+ dev->mode_config.tv_left_margin_property,
+ cmdline->overscan_left);
+
+ drm_atomic_set_property(state, &connector->base,
+ dev->mode_config.tv_right_margin_property,
+ cmdline->overscan_right);
+
+ drm_atomic_set_property(state, &connector->base,
+ dev->mode_config.tv_top_margin_property,
+ cmdline->overscan_top);
+
+ drm_atomic_set_property(state, &connector->base,
+ dev->mode_config.tv_bottom_margin_property,
+ cmdline->overscan_bottom);
+
+ ret = drm_atomic_commit(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_state_clear(state);
+ drm_modeset_backoff(&ctx);
+ goto retry;
+ }
+
+ drm_atomic_state_put(state);
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
u32 width, u32 height)
{
@@ -2682,6 +2727,8 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
struct drm_connector *connector =
fb_helper->connector_info[i]->connector;
+ drm_setup_connector_margins(connector);
+
/* use first connected connector for the physical dimensions */
if (connector->status == connector_status_connected) {
info->var.width = connector->display_info.width_mm;
@@ -1586,6 +1586,50 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
} else if (!strncmp(option, "reflect_y", delim - option)) {
rotation |= DRM_MODE_REFLECT_Y;
sep = delim;
+ } else if (!strncmp(option, "overscan_right", delim - option)) {
+ const char *value = delim + 1;
+ unsigned int margin;
+
+ margin = simple_strtol(value, &sep, 10);
+
+ /* Make sure we have parsed something */
+ if (sep == value)
+ return -EINVAL;
+
+ mode->overscan_right = margin;
+ } else if (!strncmp(option, "overscan_left", delim - option)) {
+ const char *value = delim + 1;
+ unsigned int margin;
+
+ margin = simple_strtol(value, &sep, 10);
+
+ /* Make sure we have parsed something */
+ if (sep == value)
+ return -EINVAL;
+
+ mode->overscan_left = margin;
+ } else if (!strncmp(option, "overscan_top", delim - option)) {
+ const char *value = delim + 1;
+ unsigned int margin;
+
+ margin = simple_strtol(value, &sep, 10);
+
+ /* Make sure we have parsed something */
+ if (sep == value)
+ return -EINVAL;
+
+ mode->overscan_top = margin;
+ } else if (!strncmp(option, "overscan_bottom", delim - option)) {
+ const char *value = delim + 1;
+ unsigned int margin;
+
+ margin = simple_strtol(value, &sep, 10);
+
+ /* Make sure we have parsed something */
+ if (sep == value)
+ return -EINVAL;
+
+ mode->overscan_bottom = margin;
} else {
return -EINVAL;
}
@@ -830,6 +830,7 @@ struct drm_cmdline_mode {
int xres, yres;
int bpp;
int refresh;
+ int overscan_right, overscan_top, overscan_left, overscan_bottom;
bool rb;
bool interlace;
bool cvt;
Properly configuring the overscan properties might be needed for the initial setup of the framebuffer for display that still have overscan. Let's allow for more properties on the kernel command line to setup each margin. Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> --- drivers/gpu/drm/drm_fb_helper.c | 47 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/drm_modes.c | 44 ++++++++++++++++++++++++++++++++- include/drm/drm_connector.h | 1 +- 3 files changed, 92 insertions(+)