On Tue, Mar 26, 2019 at 10:17:44AM +0100, Thomas Zimmermann wrote: > Mode detection currently reports the modes listed in fb_info::modelist. > The list is either build from EDID information or, more often, a list of > previously set modes. A later update to the mode detection could also > take into account the modes in fb_monspecs::modedb or test pre-defined > VESA modes. > > Signed-off-by: Thomas Zimmermann <tzimmermann@xxxxxxx> > --- > drivers/gpu/drm/fbdevdrm/fbdevdrm_modeset.c | 163 +++++++++++++++++++- > 1 file changed, 162 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/fbdevdrm/fbdevdrm_modeset.c b/drivers/gpu/drm/fbdevdrm/fbdevdrm_modeset.c > index 87f56ec76edf..e89eca4b58df 100644 > --- a/drivers/gpu/drm/fbdevdrm/fbdevdrm_modeset.c > +++ b/drivers/gpu/drm/fbdevdrm/fbdevdrm_modeset.c > @@ -21,9 +21,16 @@ > #include <drm/drm_print.h> > #include <drm/drm_probe_helper.h> > #include <linux/fb.h> > +#include "fbdevdrm_device.h" > #include "fbdevdrm_modes.h" > #include "fbdevdrm_primary.h" > > +static struct fbdevdrm_modeset* fbdevdrm_modeset_of_connector( > + struct drm_connector *connector) > +{ > + return container_of(connector, struct fbdevdrm_modeset, connector); > +} > + > static struct fbdevdrm_modeset* fbdevdrm_modeset_of_crtc( > struct drm_crtc *crtc) > { > @@ -353,11 +360,130 @@ static const struct drm_encoder_funcs fbdevdrm_encoder_funcs = { > * Connector > */ > > -static int connector_helper_get_modes(struct drm_connector *connector) > +static int update_display_info(struct drm_display_info *info, struct fb_info *fb_info) > +{ > + int num_pixel; > + > + if (fb_info->fix.type != FB_TYPE_PACKED_PIXELS) > + return -EINVAL; /* rule out text mode, etc. */ > + > + if (fb_info->fix.id[0]) { > + strncpy(info->name, fb_info->fix.id, sizeof(info->name) - 1); > + info->name[sizeof(info->name) - 1] = '\0'; > + } else { > + memset(info->name, '\0', sizeof(info->name)); > + } > + > + info->width_mm = fb_info->var.width; > + info->height_mm = fb_info->var.height; > + info->pixel_clock = PICOS2KHZ(fb_info->var.pixclock); > + > + num_pixel = 0; > + if (fb_info->var.red.length) > + ++num_pixel; > + if (fb_info->var.green.length) > + ++num_pixel; > + if (fb_info->var.blue.length) > + ++num_pixel; > + if (fb_info->var.transp.length) > + ++num_pixel; > + > + if (num_pixel) > + info->bpc = fb_info->var.bits_per_pixel; > + else > + info->bpc = 0; > + > + info->subpixel_order = SubPixelUnknown; > + info->color_formats = DRM_COLOR_FORMAT_RGB444; > + info->bus_formats = &info->color_formats; > + info->num_bus_formats = 1; > + info->bus_flags = 0; > + info->max_tmds_clock = 0; > + info->dvi_dual = false; > + info->has_hdmi_infoframe = false; > + info->edid_hdmi_dc_modes = 0; > + info->cea_rev = 0; > + memset(&info->hdmi, 0, sizeof(info->hdmi)); > + info->non_desktop = 0; I think the only things here you may want to set are width_mm and height_mm. The rest should not matter. > + > + return 0; > +} > + > +static int drm_mode_probed_add_from_fb_videomode( > + struct drm_connector *connector, const struct fb_videomode *fb_mode, > + struct fb_info *fb_info) > { > + struct drm_display_mode *mode; > + > + mode = drm_mode_create_from_fb_videomode(connector->dev, fb_mode); > + if (!mode) > + return -ENOMEM; > + > + mode->width_mm = fb_info->var.width; > + mode->height_mm = fb_info->var.height; > + > + drm_mode_probed_add(connector, mode); > + > + /* update connector properties from display mode */ > + if (mode->flags & DRM_MODE_FLAG_INTERLACE) > + connector->interlace_allowed = true; > + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) > + connector->doublescan_allowed = true; > + if (mode->flags & DRM_MODE_FLAG_3D_MASK) > + connector->stereo_allowed = true; > + > return 0; > } > > +static int connector_helper_get_modes(struct drm_connector *connector) > +{ > + struct fbdevdrm_modeset *modeset; > + struct list_head *pos; > + int ret, num_modes = 0; > + > + modeset = fbdevdrm_modeset_of_connector(connector); > + > + ret = update_display_info(&connector->display_info, modeset->fb_info); > + if (ret) > + return 0; > + > + /* update connector properties from video modes */ > + connector->interlace_allowed = 0; > + connector->doublescan_allowed = 0; > + connector->stereo_allowed = 0; > + > + if (!num_modes && modeset->fb_info->mode) { > + ret = drm_mode_probed_add_from_fb_videomode( > + connector, modeset->fb_info->mode, modeset->fb_info); > + if (!ret) > + ++num_modes; > + } > + > + if (!num_modes) { > + > + /* DRM backporting notes: we go through all modes in the > + * fb_info's mode list and convert each to a DRM modes. If > + * you convert an fbdev driver to DRM, replace this code > + * with an actual hardware query. This will usually involve > + * reading the monitor EDID via DDC. > + */ > + > + list_for_each(pos, &modeset->fb_info->modelist) { fbdev has a modelist? I guess it does. But not exposed to userspace, which is probably the reason I never realized this. -- Ville Syrjälä Intel