diff options
author | dumbbell <dumbbell@FreeBSD.org> | 2014-11-22 17:37:51 +0000 |
---|---|---|
committer | dumbbell <dumbbell@FreeBSD.org> | 2014-11-22 17:37:51 +0000 |
commit | 2b470c5d7501426073ca250c41c34319c6ce4871 (patch) | |
tree | ef55755e5b4dc8f3c32f73dec74bec1c5944864a /sys/dev/drm2 | |
parent | 395d6697ce00ffaceefdc18e548271866f962418 (diff) | |
download | FreeBSD-src-2b470c5d7501426073ca250c41c34319c6ce4871.zip FreeBSD-src-2b470c5d7501426073ca250c41c34319c6ce4871.tar.gz |
drm: Take vt(4) default mode from loader tunables
By default, vt(4) gets the "preferred mode" from DRM, when using a DRM
video driver as its backend. The preferred mode is usually the native
screen resolution.
Now, if this mode isn't appropriate, a user can use loader tunables to
select a mode. The tunables are read in the following order:
1. kern.vt.fb.modes.$connector_name
2. kern.vt.fb.default_mode
For example, to set a 1024x768 mode, no matter the connector:
kern.vt.fb.default_mode="1024x768"
To set a 800x600 mode only on the laptop builtin screen:
kern.vt.fb.modes.LVDS-1="800x600"
Beside r274031, this MFC includes:
r274049:
drm: When reading connector mode tunables, list connectors
... and their associated tunables. This gives a way to know the list of
available connectors, no matter the driver.
The problem is that xrandr(1) can list connectors but it uses a
different naming.
r274050:
vt(4): Document kern.vt.fb.default_mode and kern.vt.fb.modes.*
Those tunables are used to set a specific mode in vt(4) instead of using
the default mode.
Differential Revision: https://reviews.freebsd.org/D1098
Reviewed by: ak@, emaste@, kwm@
r274051:
vt(4): Improve the description of kern.vt.fb.modes.$connector
Differential Revision: https://reviews.freebsd.org/D1098
Submitted by: emaste@
r274053:
vt(4): Start new sentences on their own lines
Submitted by: brueffer@
MFC of: r274031, r274049, r274050, r274051, r274053
Diffstat (limited to 'sys/dev/drm2')
-rw-r--r-- | sys/dev/drm2/drm_fb_helper.c | 233 | ||||
-rw-r--r-- | sys/dev/drm2/drm_fb_helper.h | 17 |
2 files changed, 68 insertions, 182 deletions
diff --git a/sys/dev/drm2/drm_fb_helper.c b/sys/dev/drm2/drm_fb_helper.c index 05f616e..20ee3fb 100644 --- a/sys/dev/drm2/drm_fb_helper.c +++ b/sys/dev/drm2/drm_fb_helper.c @@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$"); #include <sys/kdb.h> +#include <sys/param.h> +#include <sys/systm.h> struct vt_kms_softc { struct drm_fb_helper *fb_helper; @@ -97,170 +99,34 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) return 0; } -const char *fb_mode_option; - -/** - * 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 = 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 = strtol(&name[i+1], NULL, 10); - bpp_specified = 1; - if (cvt || rb) - cvt = 0; - } else - goto done; - break; - case 'x': - if (!yres_specified) { - yres = 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 = 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 fb_get_options(const char *connector_name, char **option) { + char tunable[64]; /* - * TODO: store mode options pointer in ${option} for connector with - * name ${connector_name} + * A user may use loader tunables to set a specific mode for the + * console. Tunables are read in the following order: + * 1. kern.vt.fb.modes.$connector_name + * 2. kern.vt.fb.default_mode + * + * Example of a mode specific to the LVDS connector: + * kern.vt.fb.modes.LVDS="1024x768" + * + * Example of a mode applied to all connectors not having a + * connector-specific mode: + * kern.vt.fb.default_mode="640x480" */ - return (1); + snprintf(tunable, sizeof(tunable), "kern.vt.fb.modes.%s", + connector_name); + DRM_INFO("Connector %s: get mode from tunables:\n", connector_name); + DRM_INFO(" - %s\n", tunable); + DRM_INFO(" - kern.vt.fb.default_mode\n"); + *option = getenv(tunable); + if (*option == NULL) + *option = getenv("kern.vt.fb.default_mode"); + + return (*option != NULL ? 0 : 1); } static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) @@ -269,15 +135,52 @@ static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) 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_INFO("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" : ""); + } + + freeenv(option); + } return 0; } @@ -956,7 +859,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; @@ -1181,7 +1084,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; } @@ -1192,10 +1095,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne struct drm_cmdline_mode *cmdline_mode; struct drm_display_mode *mode = NULL; - cmdline_mode = &fb_helper_conn->cmdline_mode1; - if (cmdline_mode->specified == false && - !drm_fetch_cmdline_mode_from_kenv(fb_helper_conn->connector, - cmdline_mode)) + cmdline_mode = &fb_helper_conn->cmdline_mode; + if (cmdline_mode->specified == false) return (NULL); /* attempt to find a matching mode in the list of modes diff --git a/sys/dev/drm2/drm_fb_helper.h b/sys/dev/drm2/drm_fb_helper.h index 4b5ef85..16ef7ee 100644 --- a/sys/dev/drm2/drm_fb_helper.h +++ b/sys/dev/drm2/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,9 +60,8 @@ struct drm_fb_helper_funcs { }; struct drm_fb_helper_connector { - struct drm_fb_helper_cmdline_mode cmdline_mode; - struct drm_cmdline_mode cmdline_mode1; struct drm_connector *connector; + struct drm_cmdline_mode cmdline_mode; }; struct drm_fb_helper { |