drm: Perform cmdline mode parsing during connector initialisation
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 6 Aug 2014 08:08:32 +0000 (10:08 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 6 Aug 2014 12:50:12 +0000 (14:50 +0200)
i915.ko has a custom fbdev initialisation routine that aims to preserve
the current mode set by the BIOS, unless overruled by the user. The
user's wishes are determined by what, if any, mode is specified on the
command line (via the video= parameter). However, that command line mode
is first parsed by drm_fb_helper_initial_config() which is called after
i915.ko's custom initial_config() as a fallback method. So in order for
us to honour it, we need to move the cmdline parser earlier. If we
perform the connector cmdline parsing as soon as we initialise the
connector, that cmdline mode and forced status is then available even if
the fbdev helper is not compiled in or never called.

We also then expose the cmdline user mode in the connector mode lists.

v2: Rebase after connector->name upheaval.

v3: Adapt mga200 to look for the cmdline mode in the new place. Nicely
simplifies things while at that.

v4: Fix checkpatch.

v5: Select FB_CMDLINE to adapt to the changed fbdev patch.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=73154
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> (v2)
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> (v2)
Cc: dri-devel@lists.freedesktop.org
Cc: Julia Lemire <jlemire@matrox.com>
Cc: Dave Airlie <airlied@redhat.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/Kconfig
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/mgag200/mgag200_mode.c
include/drm/drm_crtc.h
include/drm/drm_fb_helper.h

index 31894c8c1773d6f95684f31731e0e02543e3502e..367f5dd232912bee14b17af30eacba864e0ebbe3 100644 (file)
@@ -8,6 +8,7 @@ menuconfig DRM
        tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
        depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU && HAS_DMA
        select HDMI
+       select FB_CMDLINE
        select I2C
        select I2C_ALGOBIT
        select DMA_SHARED_BUFFER
index 33ff631c8d23f1b98de5ff59f575ec90ef30e73e..66d3bfb8d26442e67366416bcea49b6739be4ab6 100644 (file)
@@ -862,6 +862,59 @@ static void drm_mode_remove(struct drm_connector *connector,
        drm_mode_destroy(connector->dev, mode);
 }
 
+/**
+ * drm_connector_get_cmdline_mode - reads the user's cmdline mode
+ * @connector: connector to quwery
+ * @mode: returned mode
+ *
+ * The kernel supports per-connector configration of its consoles through
+ * use of the video= parameter. This function parses that option and
+ * extracts the user's specified mode (or enable/disable status) for a
+ * particular connector. This is typically only used during the early fbdev
+ * setup.
+ */
+static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
+{
+       struct drm_cmdline_mode *mode = &connector->cmdline_mode;
+       char *option = NULL;
+
+       if (fb_get_options(connector->name, &option))
+               return;
+
+       if (!drm_mode_parse_command_line_for_connector(option,
+                                                      connector,
+                                                      mode))
+               return;
+
+       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", connector->name, s);
+               connector->force = mode->force;
+       }
+
+       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+                     connector->name,
+                     mode->xres, mode->yres,
+                     mode->refresh_specified ? mode->refresh : 60,
+                     mode->rb ? " reduced blanking" : "",
+                     mode->margins ? " with margins" : "",
+                     mode->interlace ?  " interlaced" : "");
+}
+
 /**
  * drm_connector_init - Init a preallocated connector
  * @dev: DRM device
@@ -914,6 +967,8 @@ int drm_connector_init(struct drm_device *dev,
        connector->edid_blob_ptr = NULL;
        connector->status = connector_status_unknown;
 
+       drm_connector_get_cmdline_mode(connector);
+
        list_add_tail(&connector->head, &dev->mode_config.connector_list);
        dev->mode_config.num_connector++;
 
index 3144db9dc0f1f0bf3b0ea7ca8d42665fb47a37f6..3a6b6635e3f5fa2cca00c07fa49d36860e86399f 100644 (file)
@@ -171,60 +171,6 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
 }
 EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
 
-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(connector->name, &option))
-                       continue;
-
-               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",
-                                        connector->name, s);
-                               connector->force = mode->force;
-                       }
-
-                       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
-                                     connector->name,
-                                     mode->xres, mode->yres,
-                                     mode->refresh_specified ? mode->refresh : 60,
-                                     mode->rb ? " reduced blanking" : "",
-                                     mode->margins ? " with margins" : "",
-                                     mode->interlace ?  " interlaced" : "");
-               }
-
-       }
-       return 0;
-}
-
 static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
 {
        uint16_t *r_base, *g_base, *b_base;
@@ -1013,7 +959,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
                struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
                struct drm_cmdline_mode *cmdline_mode;
 
-               cmdline_mode = &fb_helper_conn->cmdline_mode;
+               cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
 
                if (cmdline_mode->bpp_specified) {
                        switch (cmdline_mode->bpp) {
@@ -1260,9 +1206,7 @@ EXPORT_SYMBOL(drm_has_preferred_mode);
 
 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 {
-       struct drm_cmdline_mode *cmdline_mode;
-       cmdline_mode = &fb_connector->cmdline_mode;
-       return cmdline_mode->specified;
+       return fb_connector->connector->cmdline_mode.specified;
 }
 
 struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
@@ -1272,7 +1216,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
        struct drm_display_mode *mode = NULL;
        bool prefer_non_interlace;
 
-       cmdline_mode = &fb_helper_conn->cmdline_mode;
+       cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
        if (cmdline_mode->specified == false)
                return mode;
 
@@ -1657,8 +1601,6 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
        struct drm_device *dev = fb_helper->dev;
        int count = 0;
 
-       drm_fb_helper_parse_command_line(fb_helper);
-
        mutex_lock(&dev->mode_config.mutex);
        count = drm_fb_helper_probe_connector_modes(fb_helper,
                                                    dev->mode_config.max_width,
index bedf1894e17e5fa0f8f6a028a970c976725e1dba..d1b7d20065293338ccf88282369dda6a59c78c7f 100644 (file)
@@ -1259,6 +1259,7 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev,
        if (!mode)
                return NULL;
 
+       mode->type |= DRM_MODE_TYPE_USERDEF;
        drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
        return mode;
 }
index db7d250f7ac753dd244307d49217726e101df51e..6857e9ad6339c7a8ab94aea908be59323985df44 100644 (file)
@@ -82,6 +82,22 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
        return;
 }
 
+static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector)
+{
+       struct drm_display_mode *mode;
+
+       if (!connector->cmdline_mode.specified)
+               return 0;
+
+       mode = drm_mode_create_from_cmdline_mode(connector->dev,
+                                                &connector->cmdline_mode);
+       if (mode == NULL)
+               return 0;
+
+       drm_mode_probed_add(connector, mode);
+       return 1;
+}
+
 static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector,
                                                              uint32_t maxX, uint32_t maxY, bool merge_type_bits)
 {
@@ -141,6 +157,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
 
        if (count == 0 && connector->status == connector_status_connected)
                count = drm_add_modes_noedid(connector, 1024, 768);
+       count += drm_helper_probe_add_cmdline_mode(connector);
        if (count == 0)
                goto prune;
 
index 45f04dea0ac2ad9f3f37847251e15b4fb0d09e80..83485ab81ce8714214c258b537fd1609e12bae2a 100644 (file)
@@ -1483,11 +1483,7 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
 {
        struct drm_device *dev = connector->dev;
        struct mga_device *mdev = (struct mga_device*)dev->dev_private;
-       struct mga_fbdev *mfbdev = mdev->mfbdev;
-       struct drm_fb_helper *fb_helper = &mfbdev->helper;
-       struct drm_fb_helper_connector *fb_helper_conn = NULL;
        int bpp = 32;
-       int i = 0;
 
        if (IS_G200_SE(mdev)) {
                if (mdev->unique_rev_id == 0x01) {
@@ -1537,21 +1533,14 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
        }
 
        /* Validate the mode input by the user */
-       for (i = 0; i < fb_helper->connector_count; i++) {
-               if (fb_helper->connector_info[i]->connector == connector) {
-                       /* Found the helper for this connector */
-                       fb_helper_conn = fb_helper->connector_info[i];
-                       if (fb_helper_conn->cmdline_mode.specified) {
-                               if (fb_helper_conn->cmdline_mode.bpp_specified) {
-                                       bpp = fb_helper_conn->cmdline_mode.bpp;
-                               }
-                       }
-               }
+       if (connector->cmdline_mode.specified) {
+               if (connector->cmdline_mode.bpp_specified)
+                       bpp = connector->cmdline_mode.bpp;
        }
 
        if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->mc.vram_size) {
-               if (fb_helper_conn)
-                       fb_helper_conn->cmdline_mode.specified = false;
+               if (connector->cmdline_mode.specified)
+                       connector->cmdline_mode.specified = false;
                return MODE_BAD;
        }
 
index f1105d0da0598c391a6486531a67188da878c111..c530b4920a095dc638c889ce953b204fa61f189e 100644 (file)
@@ -548,6 +548,7 @@ struct drm_connector {
        void *helper_private;
 
        /* forced on connector */
+       struct drm_cmdline_mode cmdline_mode;
        enum drm_connector_force force;
        bool override_edid;
        uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
index bfd329d613c4541fe1bb311e5e435dbac5c3da1a..f4ad254e3488ea4ebdcf98410757f7e5d01e7cd9 100644 (file)
@@ -77,7 +77,6 @@ struct drm_fb_helper_funcs {
 
 struct drm_fb_helper_connector {
        struct drm_connector *connector;
-       struct drm_cmdline_mode cmdline_mode;
 };
 
 struct drm_fb_helper {