From 1794d257fa7bab3ea5162f8abdca749996b65343 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 17 Apr 2011 07:43:32 +0100 Subject: [PATCH] drm: Export the command-line mode parser In the absence of configuration data for providing the fixed mode for a panel, I would like to be able to pass such modes along a separate module paramenter. To do so, I then need to parse a modeline from a string, which drm is already capable of. Export that capability to the drivers. Signed-off-by: Chris Wilson Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 207 ++++++-------------------------- drivers/gpu/drm/drm_modes.c | 154 ++++++++++++++++++++++++ include/drm/drmP.h | 25 ++++ include/drm/drm_fb_helper.h | 16 +-- 4 files changed, 216 insertions(+), 186 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 140b9525b48a..802b61ac3139 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 - * x[M][R][-][@][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; } @@ -901,7 +777,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; @@ -1123,7 +999,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; } @@ -1131,7 +1007,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; @@ -1163,19 +1039,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 25bf87390f53..207b7ebf8150 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 + * x[M][R][-][@][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/include/drm/drmP.h b/include/drm/drmP.h index 4ab866e73f46..738b3a5faa12 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -994,6 +994,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; @@ -1389,6 +1405,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 c99c3d3e7811..6e3076ad646e 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 { -- 2.30.2