From: Dave Airlie <airlied@redhat.com>
To: Chris Wilson <chris@chris-wilson.co.uk>
Cc: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org,
Oliver Seitz <info@vtnd.de>
Subject: Re: [PATCH] drm, drm/i915/lvds: Honour video= parameter to override LVDS fixed mode
Date: Thu, 10 Feb 2011 09:41:46 +1000 [thread overview]
Message-ID: <1297294906.23505.7.camel@clockmaker-el6> (raw)
In-Reply-To: <1297263708-24392-1-git-send-email-chris@chris-wilson.co.uk>
On Wed, 2011-02-09 at 15:01 +0000, Chris Wilson wrote:
> The LVDS code ignores any connector for which it cannot find a fixed
> mode (through an EDID, vBIOS tables or the current active mode). Some
> platforms may include an LVDS header on the board and this may then be
> partnered with a panel without an EDID. This results in us ignoring the
> connector and not lighting up the panel.
Yeah not like this.
you want to make the command line the *last* option we use, the final
fallback. LVDS panels have EDID and VBT hardcoded modes for a good
reason, they don't work with other modes that well. You always want to
use a scaler on the LVDS panel to do modes not the native mode. So if I
have a VBT or EDID and you set video= I should get a scaled mode, not
garbage.
So what I suspect you really want is to leave video= alone or enhance it
somehow, or maybe add i915.lvds_native_mode= parameter.
Dave.
>
> Under UMS, it was possible to override this by specifying the mode
> through the Xorg.conf. For KMS, one specifies the modeline through the
> video= parameter. So we need to include this user modeline when checking
> for panel fixed modes.
>
> The machinery to parse the video= modes and generate the appropriate
> drm_mode is already built into drm_fb_herlper and so we can just
> extract, move it to the core and also use it from intel_lvds.c
>
> Reported-by: Oliver Seitz <info@vtnd.de>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Dave Airlie <airlied@redhat.com>
> ---
> drivers/gpu/drm/drm_fb_helper.c | 207 +++++++------------------------------
> drivers/gpu/drm/drm_modes.c | 154 +++++++++++++++++++++++++++
> drivers/gpu/drm/i915/intel_lvds.c | 17 +++
> include/drm/drmP.h | 25 +++++
> include/drm/drm_fb_helper.h | 16 +---
> 5 files changed, 233 insertions(+), 186 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 6977a1c..5a80412 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -70,174 +70,50 @@ fail:
> }
> EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
>
> -/**
> - * drm_fb_helper_connector_parse_command_line - parse command line for connector
> - * @connector - connector to parse line for
> - * @mode_option - per connector mode option
> - *
> - * This parses the connector specific then generic command lines for
> - * modes and options to configure the connector.
> - *
> - * This uses the same parameters as the fb modedb.c, except for extra
> - * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
> - *
> - * enable/enable Digital/disable bit at the end
> - */
> -static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
> - const char *mode_option)
> -{
> - const char *name;
> - unsigned int namelen;
> - int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
> - unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
> - int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
> - int i;
> - enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
> - struct drm_fb_helper_cmdline_mode *cmdline_mode;
> - struct drm_connector *connector;
> -
> - if (!fb_helper_conn)
> - return false;
> - connector = fb_helper_conn->connector;
> -
> - cmdline_mode = &fb_helper_conn->cmdline_mode;
> - if (!mode_option)
> - mode_option = fb_mode_option;
> -
> - if (!mode_option) {
> - cmdline_mode->specified = false;
> - return false;
> - }
> -
> - name = mode_option;
> - namelen = strlen(name);
> - for (i = namelen-1; i >= 0; i--) {
> - switch (name[i]) {
> - case '@':
> - namelen = i;
> - if (!refresh_specified && !bpp_specified &&
> - !yres_specified) {
> - refresh = simple_strtol(&name[i+1], NULL, 10);
> - refresh_specified = 1;
> - if (cvt || rb)
> - cvt = 0;
> - } else
> - goto done;
> - break;
> - case '-':
> - namelen = i;
> - if (!bpp_specified && !yres_specified) {
> - bpp = simple_strtol(&name[i+1], NULL, 10);
> - bpp_specified = 1;
> - if (cvt || rb)
> - cvt = 0;
> - } else
> - goto done;
> - break;
> - case 'x':
> - if (!yres_specified) {
> - yres = simple_strtol(&name[i+1], NULL, 10);
> - yres_specified = 1;
> - } else
> - goto done;
> - case '0' ... '9':
> - break;
> - case 'M':
> - if (!yres_specified)
> - cvt = 1;
> - break;
> - case 'R':
> - if (cvt)
> - rb = 1;
> - break;
> - case 'm':
> - if (!cvt)
> - margins = 1;
> - break;
> - case 'i':
> - if (!cvt)
> - interlace = 1;
> - break;
> - case 'e':
> - force = DRM_FORCE_ON;
> - break;
> - case 'D':
> - if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
> - (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
> - force = DRM_FORCE_ON;
> - else
> - force = DRM_FORCE_ON_DIGITAL;
> - break;
> - case 'd':
> - force = DRM_FORCE_OFF;
> - break;
> - default:
> - goto done;
> - }
> - }
> - if (i < 0 && yres_specified) {
> - xres = simple_strtol(name, NULL, 10);
> - res_specified = 1;
> - }
> -done:
> -
> - DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
> - drm_get_connector_name(connector), xres, yres,
> - (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
> - "", (margins) ? " with margins" : "", (interlace) ?
> - " interlaced" : "");
> -
> - if (force) {
> - const char *s;
> - switch (force) {
> - case DRM_FORCE_OFF: s = "OFF"; break;
> - case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
> - default:
> - case DRM_FORCE_ON: s = "ON"; break;
> - }
> -
> - DRM_INFO("forcing %s connector %s\n",
> - drm_get_connector_name(connector), s);
> - connector->force = force;
> - }
> -
> - if (res_specified) {
> - cmdline_mode->specified = true;
> - cmdline_mode->xres = xres;
> - cmdline_mode->yres = yres;
> - }
> -
> - if (refresh_specified) {
> - cmdline_mode->refresh_specified = true;
> - cmdline_mode->refresh = refresh;
> - }
> -
> - if (bpp_specified) {
> - cmdline_mode->bpp_specified = true;
> - cmdline_mode->bpp = bpp;
> - }
> - cmdline_mode->rb = rb ? true : false;
> - cmdline_mode->cvt = cvt ? true : false;
> - cmdline_mode->interlace = interlace ? true : false;
> -
> - return true;
> -}
> -
> static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
> {
> struct drm_fb_helper_connector *fb_helper_conn;
> int i;
>
> for (i = 0; i < fb_helper->connector_count; i++) {
> + struct drm_cmdline_mode *mode;
> + struct drm_connector *connector;
> char *option = NULL;
>
> fb_helper_conn = fb_helper->connector_info[i];
> + connector = fb_helper_conn->connector;
> + mode = &fb_helper_conn->cmdline_mode;
>
> /* do something on return - turn off connector maybe */
> - if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option))
> + if (fb_get_options(drm_get_connector_name(connector), &option))
> continue;
>
> - drm_fb_helper_connector_parse_command_line(fb_helper_conn, option);
> + if (drm_mode_parse_command_line_for_connector(option,
> + connector,
> + mode)) {
> + if (mode->force) {
> + const char *s;
> + switch (mode->force) {
> + case DRM_FORCE_OFF: s = "OFF"; break;
> + case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
> + default:
> + case DRM_FORCE_ON: s = "ON"; break;
> + }
> +
> + DRM_INFO("forcing %s connector %s\n",
> + drm_get_connector_name(connector), s);
> + connector->force = mode->force;
> + }
> +
> + DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
> + drm_get_connector_name(connector),
> + mode->xres, mode->yres,
> + mode->refresh_specified ? mode->refresh : 60,
> + mode->rb ? " reduced blanking" : "",
> + mode->margins ? " with margins" : "",
> + mode->interlace ? " interlaced" : "");
> + }
> +
> }
> return 0;
> }
> @@ -883,7 +759,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
> /* first up get a count of crtcs now in use and new min/maxes width/heights */
> for (i = 0; i < fb_helper->connector_count; i++) {
> struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
> - struct drm_fb_helper_cmdline_mode *cmdline_mode;
> + struct drm_cmdline_mode *cmdline_mode;
>
> cmdline_mode = &fb_helper_conn->cmdline_mode;
>
> @@ -1105,7 +981,7 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_conn
>
> static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
> {
> - struct drm_fb_helper_cmdline_mode *cmdline_mode;
> + struct drm_cmdline_mode *cmdline_mode;
> cmdline_mode = &fb_connector->cmdline_mode;
> return cmdline_mode->specified;
> }
> @@ -1113,7 +989,7 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
> static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
> int width, int height)
> {
> - struct drm_fb_helper_cmdline_mode *cmdline_mode;
> + struct drm_cmdline_mode *cmdline_mode;
> struct drm_display_mode *mode = NULL;
>
> cmdline_mode = &fb_helper_conn->cmdline_mode;
> @@ -1145,19 +1021,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
> }
>
> create_mode:
> - if (cmdline_mode->cvt)
> - mode = drm_cvt_mode(fb_helper_conn->connector->dev,
> - cmdline_mode->xres, cmdline_mode->yres,
> - cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
> - cmdline_mode->rb, cmdline_mode->interlace,
> - cmdline_mode->margins);
> - else
> - mode = drm_gtf_mode(fb_helper_conn->connector->dev,
> - cmdline_mode->xres, cmdline_mode->yres,
> - cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
> - cmdline_mode->interlace,
> - cmdline_mode->margins);
> - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
> + mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
> + cmdline_mode);
> list_add(&mode->head, &fb_helper_conn->connector->modes);
> return mode;
> }
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index 58e65f9..f9da47e 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -974,3 +974,157 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
> }
> }
> EXPORT_SYMBOL(drm_mode_connector_list_update);
> +
> +/**
> + * drm_mode_parse_command_line_for_connector - parse command line for connector
> + * @mode_option - per connector mode option
> + * @connector - connector to parse line for
> + *
> + * This parses the connector specific then generic command lines for
> + * modes and options to configure the connector.
> + *
> + * This uses the same parameters as the fb modedb.c, except for extra
> + * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
> + *
> + * enable/enable Digital/disable bit at the end
> + */
> +bool drm_mode_parse_command_line_for_connector(const char *mode_option,
> + struct drm_connector *connector,
> + struct drm_cmdline_mode *mode)
> +{
> + const char *name;
> + unsigned int namelen;
> + int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
> + unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
> + int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
> + int i;
> + enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
> +
> + if (!mode_option)
> + mode_option = fb_mode_option;
> +
> + if (!mode_option) {
> + mode->specified = false;
> + return false;
> + }
> +
> + name = mode_option;
> + namelen = strlen(name);
> + for (i = namelen-1; i >= 0; i--) {
> + switch (name[i]) {
> + case '@':
> + namelen = i;
> + if (!refresh_specified && !bpp_specified &&
> + !yres_specified) {
> + refresh = simple_strtol(&name[i+1], NULL, 10);
> + refresh_specified = 1;
> + if (cvt || rb)
> + cvt = 0;
> + } else
> + goto done;
> + break;
> + case '-':
> + namelen = i;
> + if (!bpp_specified && !yres_specified) {
> + bpp = simple_strtol(&name[i+1], NULL, 10);
> + bpp_specified = 1;
> + if (cvt || rb)
> + cvt = 0;
> + } else
> + goto done;
> + break;
> + case 'x':
> + if (!yres_specified) {
> + yres = simple_strtol(&name[i+1], NULL, 10);
> + yres_specified = 1;
> + } else
> + goto done;
> + case '0' ... '9':
> + break;
> + case 'M':
> + if (!yres_specified)
> + cvt = 1;
> + break;
> + case 'R':
> + if (cvt)
> + rb = 1;
> + break;
> + case 'm':
> + if (!cvt)
> + margins = 1;
> + break;
> + case 'i':
> + if (!cvt)
> + interlace = 1;
> + break;
> + case 'e':
> + force = DRM_FORCE_ON;
> + break;
> + case 'D':
> + if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
> + (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
> + force = DRM_FORCE_ON;
> + else
> + force = DRM_FORCE_ON_DIGITAL;
> + break;
> + case 'd':
> + force = DRM_FORCE_OFF;
> + break;
> + default:
> + goto done;
> + }
> + }
> + if (i < 0 && yres_specified) {
> + xres = simple_strtol(name, NULL, 10);
> + res_specified = 1;
> + }
> +done:
> + if (res_specified) {
> + mode->specified = true;
> + mode->xres = xres;
> + mode->yres = yres;
> + }
> +
> + if (refresh_specified) {
> + mode->refresh_specified = true;
> + mode->refresh = refresh;
> + }
> +
> + if (bpp_specified) {
> + mode->bpp_specified = true;
> + mode->bpp = bpp;
> + }
> + mode->rb = rb ? true : false;
> + mode->cvt = cvt ? true : false;
> + mode->interlace = interlace ? true : false;
> + mode->force = force;
> +
> + return true;
> +}
> +EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
> +
> +struct drm_display_mode *
> +drm_mode_create_from_cmdline_mode(struct drm_device *dev,
> + struct drm_cmdline_mode *cmd)
> +{
> + struct drm_display_mode *mode;
> +
> + if (cmd->cvt)
> + mode = drm_cvt_mode(dev,
> + cmd->xres, cmd->yres,
> + cmd->refresh_specified ? cmd->refresh : 60,
> + cmd->rb, cmd->interlace,
> + cmd->margins);
> + else
> + mode = drm_gtf_mode(dev,
> + cmd->xres, cmd->yres,
> + cmd->refresh_specified ? cmd->refresh : 60,
> + cmd->interlace,
> + cmd->margins);
> + if (!mode)
> + return NULL;
> +
> + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
> + return mode;
> +}
> +EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
> diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
> index cd08960..af4ef17 100644
> --- a/drivers/gpu/drm/i915/intel_lvds.c
> +++ b/drivers/gpu/drm/i915/intel_lvds.c
> @@ -874,6 +874,8 @@ bool intel_lvds_init(struct drm_device *dev)
> struct drm_encoder *encoder;
> struct drm_display_mode *scan; /* *modes, *bios_mode; */
> struct drm_crtc *crtc;
> + char *cmdline_option = NULL;
> + struct drm_cmdline_mode cmdline_mode;
> u32 lvds;
> int pipe;
> u8 pin;
> @@ -951,6 +953,7 @@ bool intel_lvds_init(struct drm_device *dev)
> intel_lvds->fitting_mode = DRM_MODE_SCALE_ASPECT;
> /*
> * LVDS discovery:
> + * 0) user override
> * 1) check for EDID on DDC
> * 2) check for VBT data
> * 3) check to see if LVDS is already on
> @@ -959,6 +962,20 @@ bool intel_lvds_init(struct drm_device *dev)
> * if closed, act like it's not there for now
> */
>
> + if (fb_get_options(drm_get_connector_name(connector),
> + &cmdline_option) == 0 &&
> + drm_mode_parse_command_line_for_connector(cmdline_option,
> + connector,
> + &cmdline_mode)) {
> + intel_lvds->fixed_mode =
> + drm_mode_create_from_cmdline_mode(dev, &cmdline_mode);
> + if (intel_lvds->fixed_mode) {
> + intel_lvds->fixed_mode->type |=
> + DRM_MODE_TYPE_PREFERRED;
> + goto out;
> + }
> + }
> +
> /*
> * Attempt to get the fixed panel mode from DDC. Assume that the
> * preferred mode is the right one.
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index fe29aad..bf01108 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -968,6 +968,22 @@ struct drm_minor {
> struct drm_mode_group mode_group;
> };
>
> +/* mode specified on the command line */
> +struct drm_cmdline_mode {
> + bool specified;
> + bool refresh_specified;
> + bool bpp_specified;
> + int xres, yres;
> + int bpp;
> + int refresh;
> + bool rb;
> + bool interlace;
> + bool cvt;
> + bool margins;
> + enum drm_connector_force force;
> +};
> +
> +
> struct drm_pending_vblank_event {
> struct drm_pending_event base;
> int pipe;
> @@ -1381,6 +1397,15 @@ extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
> struct drm_crtc *refcrtc);
> extern void drm_calc_timestamping_constants(struct drm_crtc *crtc);
>
> +extern bool
> +drm_mode_parse_command_line_for_connector(const char *mode_option,
> + struct drm_connector *connector,
> + struct drm_cmdline_mode *mode);
> +
> +extern struct drm_display_mode *
> +drm_mode_create_from_cmdline_mode(struct drm_device *dev,
> + struct drm_cmdline_mode *cmd);
> +
> /* Modesetting support */
> extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
> extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc);
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index f22e7fe..4e66488 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -40,20 +40,6 @@ struct drm_fb_helper_crtc {
> struct drm_display_mode *desired_mode;
> };
>
> -/* mode specified on the command line */
> -struct drm_fb_helper_cmdline_mode {
> - bool specified;
> - bool refresh_specified;
> - bool bpp_specified;
> - int xres, yres;
> - int bpp;
> - int refresh;
> - bool rb;
> - bool interlace;
> - bool cvt;
> - bool margins;
> -};
> -
> struct drm_fb_helper_surface_size {
> u32 fb_width;
> u32 fb_height;
> @@ -74,8 +60,8 @@ struct drm_fb_helper_funcs {
> };
>
> struct drm_fb_helper_connector {
> - struct drm_fb_helper_cmdline_mode cmdline_mode;
> struct drm_connector *connector;
> + struct drm_cmdline_mode cmdline_mode;
> };
>
> struct drm_fb_helper {
next prev parent reply other threads:[~2011-02-09 23:41 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-02-09 7:52 LVDS output not working (anymore) Oliver Seitz
2011-02-09 9:16 ` Chris Wilson
2011-02-09 13:40 ` Oliver Seitz
2011-02-09 13:59 ` Chris Wilson
2011-02-09 15:01 ` [PATCH] drm, drm/i915/lvds: Honour video= parameter to override LVDS fixed mode Chris Wilson
2011-02-09 23:41 ` Dave Airlie [this message]
2011-03-28 21:33 ` Steven Newbury
2011-03-28 21:46 ` Steven Newbury
2011-03-29 6:18 ` Oliver Seitz
2011-03-29 6:49 ` Chris Wilson
2011-03-29 6:57 ` Keith Packard
2011-03-29 7:21 ` Mike Isely
2011-03-29 7:29 ` Chris Wilson
2011-03-29 7:49 ` Dave Airlie
2011-03-29 8:02 ` Dave Airlie
2011-03-29 10:55 ` Steven Newbury
2011-03-29 11:41 ` [Intel-gfx] " Steven Newbury
2011-03-29 11:50 ` Steven Newbury
2011-03-29 12:37 ` Steven Newbury
2011-03-29 14:52 ` Steven Newbury
2011-04-03 23:36 ` Steven Newbury
2011-03-29 10:50 ` Steven Newbury
2011-02-10 11:39 ` Oliver Seitz
2011-02-13 16:46 ` Oliver Seitz
2011-02-16 6:18 ` Oliver Seitz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1297294906.23505.7.camel@clockmaker-el6 \
--to=airlied@redhat.com \
--cc=chris@chris-wilson.co.uk \
--cc=dri-devel@lists.freedesktop.org \
--cc=info@vtnd.de \
--cc=intel-gfx@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.