intel/display: support force_* and configured mode

Up to now, when using force_*, all other configured modes of a connector
got overwritten and the force_* got enforced. With the commit,
the connector mode is considered (if below max_*) and the resulting
framebuffer may be larger then the dimension of force_*.
This commit is contained in:
Alexander Boettcher 2023-10-09 14:53:11 +02:00 committed by Christian Helmuth
parent ab91750869
commit 9b312054f5
4 changed files with 46 additions and 22 deletions

View File

@ -304,7 +304,7 @@ append_if $use_top boot_modules { top }
build_boot_image $boot_modules
if { [get_cmd_switch --autopilot] } {
run_genode_until {\[init -\> init_dynamic -\> intel_fb_drv\] HDMI-A-2: enable.*} 30
run_genode_until {\[init -\> init_dynamic -\> intel_fb_drv\] HDMI-A-2: enable.*} 30
} else {
run_genode_until forever
}

View File

@ -17,6 +17,8 @@
struct genode_mode {
unsigned width;
unsigned height;
unsigned force_width;
unsigned force_height;
unsigned max_width;
unsigned max_height;
unsigned hz;

View File

@ -59,14 +59,22 @@ static inline bool mode_larger(struct drm_display_mode const * const x,
}
static inline bool conf_smaller_mode(struct genode_mode const * const g,
struct drm_display_mode const * const p)
static inline bool conf_smaller_max_mode(struct genode_mode const * const g,
struct drm_display_mode const * const p)
{
return (uint64_t)g->max_width * (uint64_t)g->max_height <
(uint64_t)p->hdisplay * (uint64_t)p->vdisplay;
}
static inline bool conf_larger_mode(struct genode_mode const * const g,
struct drm_display_mode const * const p)
{
return (uint64_t)g->width * (uint64_t)g->height >
(uint64_t)p->hdisplay * (uint64_t)p->vdisplay;
}
static inline bool fb_smaller_mode(struct fb_info const * const info,
struct drm_display_mode const * const mode)
{
@ -135,18 +143,34 @@ static void preferred_mode(struct drm_device const * const dev,
if (mode_id && mode_larger(&smallest, min_mode))
*min_mode = smallest;
if (conf_mode.force_width && conf_mode.force_height) {
/*
* Even so the force_* mode is selected, a configured mode for
* a connector is considered, effectively the framebuffer content
* will be shown smaller in the upper corner of the monitor
*/
if (conf_larger_mode(&conf_mode, min_mode)) {
min_mode->hdisplay = conf_mode.width;
min_mode->vdisplay = conf_mode.height;
}
/* enforce the force mode */
conf_mode.width = conf_mode.force_width;
conf_mode.height = conf_mode.force_height;
}
/* maximal resolution enforcement */
if (conf_mode.max_width && conf_mode.max_height) {
max_enforcement.hdisplay = conf_mode.max_width;
max_enforcement.vdisplay = conf_mode.max_height;
if (conf_smaller_mode(&conf_mode, prefer))
if (conf_smaller_max_mode(&conf_mode, prefer))
continue;
}
if (!conf_mode.width || !conf_mode.height)
continue;
if (!conf_smaller_mode(&conf_mode, prefer)) {
if (conf_larger_mode(&conf_mode, prefer)) {
prefer->hdisplay = conf_mode.width;
prefer->vdisplay = conf_mode.height;
}
@ -232,7 +256,7 @@ static bool reconfigure(struct drm_client_dev * const dev)
struct drm_display_mode mode_preferred = {};
struct drm_display_mode mode_minimum = {};
struct drm_display_mode mode_real = {};
struct drm_display_mode framebuffer = {};
struct drm_mode_modeinfo user_mode = {};
struct drm_display_mode *mode = NULL;
struct drm_mode_set *mode_set = NULL;
@ -256,22 +280,21 @@ static bool reconfigure(struct drm_client_dev * const dev)
mode_preferred = mode_minimum;
}
if (mode_larger(&mode_preferred, &mode_minimum))
mode_real = mode_preferred;
framebuffer = mode_preferred;
else
mode_real = mode_minimum;
framebuffer = mode_minimum;
{
int const err = check_resize_fb(dev,
&gem_dumb,
&dumb_fb,
mode_real.hdisplay,
mode_real.vdisplay);
framebuffer.hdisplay,
framebuffer.vdisplay);
if (err) {
printk("setting up framebuffer of %ux%u failed - error=%d\n",
mode_real.hdisplay, mode_real.vdisplay, err);
framebuffer.hdisplay, framebuffer.vdisplay, err);
return true;
}
@ -282,8 +305,8 @@ static bool reconfigure(struct drm_client_dev * const dev)
return retry;
/* prepare fb info for register_framebuffer() evaluated by Genode side */
report_fb_info.var.xres = mode_real.hdisplay;
report_fb_info.var.yres = mode_real.vdisplay;
report_fb_info.var.xres = framebuffer.hdisplay;
report_fb_info.var.yres = framebuffer.vdisplay;
report_fb_info.var.xres_virtual = mode_preferred.hdisplay;
report_fb_info.var.yres_virtual = mode_preferred.vdisplay;
@ -397,12 +420,14 @@ static bool reconfigure(struct drm_client_dev * const dev)
}
/* diagnostics */
printk("%s: %s name='%s' id=%u %ux%u@%u%s",
printk("%10s: %s name='%9s' id=%u%s mode=%4ux%4u@%u%s fb=%4ux%4u%s",
connector->name ? connector->name : "unnamed",
conf_mode.enabled ? " enable" : "disable",
mode->name ? mode->name : "noname",
mode_id, mode->hdisplay,
mode_id, mode_id < 10 ? " " : "", mode->hdisplay,
mode->vdisplay, drm_mode_vrefresh(mode),
drm_mode_vrefresh(mode) < 100 ? " ": "",
framebuffer.hdisplay, framebuffer.vdisplay,
(err || no_match) ? "" : "\n");
if (no_match)
@ -512,7 +537,7 @@ void lx_emul_i915_iterate_modes(void * lx_data, void * genode_data)
.preferred = mode->type & (DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DEFAULT),
.hz = drm_mode_vrefresh(mode),
.id = mode_id,
.enabled = !max_mode || !conf_smaller_mode(&conf_max_mode, mode)
.enabled = !max_mode || !conf_smaller_max_mode(&conf_max_mode, mode)
};
static_assert(sizeof(conf_mode.name) == DRM_DISPLAY_MODE_LEN);

View File

@ -256,12 +256,9 @@ void Framebuffer::Driver::lookup_config(char const * const name,
mode.id = node.attribute_value("mode_id", 0U);
});
mode.preferred = false;
with_force([&](unsigned const width, unsigned const height) {
mode.preferred = true;
mode.width = width;
mode.height = height;
mode.id = 0;
mode.force_width = width;
mode.force_height = height;
});
with_max_enforcement([&](unsigned const width, unsigned const height) {