Skip to content

Commit

Permalink
drm/kms: start adding command line interface using fb.
Browse files Browse the repository at this point in the history
[note this requires an fb patch posted to linux-fbdev-devel already]

This uses the normal video= command line option to control the kms
output setup at boot time. It is used to override the autodetection
done by kms.

video= normally takes a framebuffer as the first parameter, in kms
it will take a connector name, DVI-I-1, or LVDS-1 etc. If no output
connector is specified the mode string will apply to all connectors.

The mode specification used will match down the probed modes, and if
no mode is found it will add a CVT mode that matches.

video=1024x768 - all connectors match a 1024x768 mode or add a CVT on
video=VGA-1:1024x768, VGA-1 connector gets mode only.

The same strings as used in current fb modedb.c are used, except I've
added three more letters, e, D, d, e = enable, D = enable Digital,
d = disable, which allow a connector to be forced into a certain state.

Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Dave Airlie committed Sep 25, 2009
1 parent f803303 commit d50ba25
Show file tree
Hide file tree
Showing 10 changed files with 386 additions and 21 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/drm_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ void drm_connector_cleanup(struct drm_connector *connector)
list_for_each_entry_safe(mode, t, &connector->user_modes, head)
drm_mode_remove(connector, mode);

kfree(connector->fb_helper_private);
mutex_lock(&dev->mode_config.mutex);
drm_mode_object_put(dev, &connector->base);
list_del(&connector->head);
Expand Down
79 changes: 74 additions & 5 deletions drivers/gpu/drm/drm_crtc_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "drmP.h"
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
#include "drm_fb_helper.h"

static void drm_mode_validate_flag(struct drm_connector *connector,
int flags)
Expand Down Expand Up @@ -90,7 +91,15 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
list_for_each_entry_safe(mode, t, &connector->modes, head)
mode->status = MODE_UNVERIFIED;

connector->status = connector->funcs->detect(connector);
if (connector->force) {
if (connector->force == DRM_FORCE_ON)
connector->status = connector_status_connected;
else
connector->status = connector_status_disconnected;
if (connector->funcs->force)
connector->funcs->force(connector);
} else
connector->status = connector->funcs->detect(connector);

if (connector->status == connector_status_disconnected) {
DRM_DEBUG_KMS("%s is disconnected\n",
Expand Down Expand Up @@ -267,6 +276,56 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *con
return NULL;
}

static bool drm_has_cmdline_mode(struct drm_connector *connector)
{
struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
struct drm_fb_helper_cmdline_mode *cmdline_mode = &fb_help_conn->cmdline_mode;
return cmdline_mode->specified;
}

static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height)
{
struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
struct drm_fb_helper_cmdline_mode *cmdline_mode = &fb_help_conn->cmdline_mode;
struct drm_display_mode *mode = NULL;

if (cmdline_mode->specified == false)
return mode;

/* attempt to find a matching mode in the list of modes
* we have gotten so far, if not add a CVT mode that conforms
*/
if (cmdline_mode->rb || cmdline_mode->margins)
goto create_mode;

list_for_each_entry(mode, &connector->modes, head) {
/* check width/height */
if (mode->hdisplay != cmdline_mode->xres ||
mode->vdisplay != cmdline_mode->yres)
continue;

if (cmdline_mode->refresh_specified) {
if (mode->vrefresh != cmdline_mode->refresh)
continue;
}

if (cmdline_mode->interlace) {
if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
continue;
}
return mode;
}

create_mode:
mode = drm_cvt_mode(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);
list_add(&mode->head, &connector->modes);
return mode;
}

static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
{
bool enable;
Expand Down Expand Up @@ -317,10 +376,16 @@ static bool drm_target_preferred(struct drm_device *dev,
continue;
}

DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
connector->base.id);
DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
connector->base.id);

modes[i] = drm_has_preferred_mode(connector, width, height);
/* got for command line mode first */
modes[i] = drm_pick_cmdline_mode(connector, width, height);
if (!modes[i]) {
DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
connector->base.id);
modes[i] = drm_has_preferred_mode(connector, width, height);
}
/* No preferred modes, pick one off the list */
if (!modes[i] && !list_empty(&connector->modes)) {
list_for_each_entry(modes[i], &connector->modes, head)
Expand Down Expand Up @@ -369,6 +434,8 @@ static int drm_pick_crtcs(struct drm_device *dev,
my_score = 1;
if (connector->status == connector_status_connected)
my_score++;
if (drm_has_cmdline_mode(connector))
my_score++;
if (drm_has_preferred_mode(connector, width, height))
my_score++;

Expand Down Expand Up @@ -943,14 +1010,16 @@ bool drm_helper_initial_config(struct drm_device *dev)
{
int count = 0;

drm_fb_helper_parse_command_line(dev);

count = drm_helper_probe_connector_modes(dev,
dev->mode_config.max_width,
dev->mode_config.max_height);

/*
* we shouldn't end up with no modes here.
*/
WARN(!count, "Connected connector with 0 modes\n");
WARN(!count, "No connectors reported connected with modes\n");

drm_setup_crtcs(dev);

Expand Down
6 changes: 4 additions & 2 deletions drivers/gpu/drm/drm_edid.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,8 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
vsize = (hsize * 9) / 16;
/* HDTV hack */
if (hsize == 1360 && vsize == 765 && vrefresh_rate == 60) {
mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0,
false);
mode->hdisplay = 1366;
mode->vsync_start = mode->vsync_start - 1;
mode->vsync_end = mode->vsync_end - 1;
Expand All @@ -579,7 +580,8 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
break;
case LEVEL_CVT:
mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0,
false);
break;
}
return mode;
Expand Down
Loading

0 comments on commit d50ba25

Please sign in to comment.