aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-4.19/950-0639-drm-modes-Rewrite-the-command-line-parser.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm27xx/patches-4.19/950-0639-drm-modes-Rewrite-the-command-line-parser.patch')
-rw-r--r--target/linux/bcm27xx/patches-4.19/950-0639-drm-modes-Rewrite-the-command-line-parser.patch392
1 files changed, 392 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-4.19/950-0639-drm-modes-Rewrite-the-command-line-parser.patch b/target/linux/bcm27xx/patches-4.19/950-0639-drm-modes-Rewrite-the-command-line-parser.patch
new file mode 100644
index 0000000000..24c25d6944
--- /dev/null
+++ b/target/linux/bcm27xx/patches-4.19/950-0639-drm-modes-Rewrite-the-command-line-parser.patch
@@ -0,0 +1,392 @@
+From 3508a8548f13be68b6d098ad99a7bc1fc1810f76 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@bootlin.com>
+Date: Wed, 19 Jun 2019 12:17:49 +0200
+Subject: [PATCH] drm/modes: Rewrite the command line parser
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit e08ab74bd4c7a5fe311bc05f32dbb4f1e7fa3428 upstream.
+
+Rewrite the command line parser in order to get away from the state machine
+parsing the video mode lines.
+
+Hopefully, this will allow to extend it more easily to support named modes
+and / or properties set directly on the command line.
+
+Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/e32cd4009153b184103554009135c7bf7c9975d7.1560783090.git-series.maxime.ripard@bootlin.com
+---
+ drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++-------------
+ 1 file changed, 210 insertions(+), 115 deletions(-)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -30,6 +30,7 @@
+ * authorization from the copyright holder(s) and author(s).
+ */
+
++#include <linux/ctype.h>
+ #include <linux/list.h>
+ #include <linux/list_sort.h>
+ #include <linux/export.h>
+@@ -1414,6 +1415,151 @@ void drm_connector_list_update(struct dr
+ }
+ EXPORT_SYMBOL(drm_connector_list_update);
+
++static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
++ struct drm_cmdline_mode *mode)
++{
++ unsigned int bpp;
++
++ if (str[0] != '-')
++ return -EINVAL;
++
++ str++;
++ bpp = simple_strtol(str, end_ptr, 10);
++ if (*end_ptr == str)
++ return -EINVAL;
++
++ mode->bpp = bpp;
++ mode->bpp_specified = true;
++
++ return 0;
++}
++
++static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
++ struct drm_cmdline_mode *mode)
++{
++ unsigned int refresh;
++
++ if (str[0] != '@')
++ return -EINVAL;
++
++ str++;
++ refresh = simple_strtol(str, end_ptr, 10);
++ if (*end_ptr == str)
++ return -EINVAL;
++
++ mode->refresh = refresh;
++ mode->refresh_specified = true;
++
++ return 0;
++}
++
++static int drm_mode_parse_cmdline_extra(const char *str, int length,
++ struct drm_connector *connector,
++ struct drm_cmdline_mode *mode)
++{
++ int i;
++
++ for (i = 0; i < length; i++) {
++ switch (str[i]) {
++ case 'i':
++ mode->interlace = true;
++ break;
++ case 'm':
++ mode->margins = true;
++ break;
++ case 'D':
++ if (mode->force != DRM_FORCE_UNSPECIFIED)
++ return -EINVAL;
++
++ if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
++ (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
++ mode->force = DRM_FORCE_ON;
++ else
++ mode->force = DRM_FORCE_ON_DIGITAL;
++ break;
++ case 'd':
++ if (mode->force != DRM_FORCE_UNSPECIFIED)
++ return -EINVAL;
++
++ mode->force = DRM_FORCE_OFF;
++ break;
++ case 'e':
++ if (mode->force != DRM_FORCE_UNSPECIFIED)
++ return -EINVAL;
++
++ mode->force = DRM_FORCE_ON;
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++
++ return 0;
++}
++
++static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
++ bool extras,
++ struct drm_connector *connector,
++ struct drm_cmdline_mode *mode)
++{
++ const char *str_start = str;
++ bool rb = false, cvt = false;
++ int xres = 0, yres = 0;
++ int remaining, i;
++ char *end_ptr;
++
++ xres = simple_strtol(str, &end_ptr, 10);
++ if (end_ptr == str)
++ return -EINVAL;
++
++ if (end_ptr[0] != 'x')
++ return -EINVAL;
++ end_ptr++;
++
++ str = end_ptr;
++ yres = simple_strtol(str, &end_ptr, 10);
++ if (end_ptr == str)
++ return -EINVAL;
++
++ remaining = length - (end_ptr - str_start);
++ if (remaining < 0)
++ return -EINVAL;
++
++ for (i = 0; i < remaining; i++) {
++ switch (end_ptr[i]) {
++ case 'M':
++ cvt = true;
++ break;
++ case 'R':
++ rb = true;
++ break;
++ default:
++ /*
++ * Try to pass that to our extras parsing
++ * function to handle the case where the
++ * extras are directly after the resolution
++ */
++ if (extras) {
++ int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
++ 1,
++ connector,
++ mode);
++ if (ret)
++ return ret;
++ } else {
++ return -EINVAL;
++ }
++ }
++ }
++
++ mode->xres = xres;
++ mode->yres = yres;
++ mode->cvt = cvt;
++ mode->rb = rb;
++
++ return 0;
++}
++
+ /**
+ * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
+ * @mode_option: optional per connector mode option
+@@ -1440,13 +1586,12 @@ bool drm_mode_parse_command_line_for_con
+ struct drm_cmdline_mode *mode)
+ {
+ const char *name;
+- unsigned int namelen;
+- bool res_specified = false, bpp_specified = false, refresh_specified = false;
+- unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
+- bool yres_specified = false, cvt = false, rb = false;
+- bool interlace = false, margins = false, was_digit = false;
+- int i;
+- enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
++ bool parse_extras = false;
++ unsigned int bpp_off = 0, refresh_off = 0;
++ unsigned int mode_end = 0;
++ char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
++ char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
++ int ret;
+
+ #ifdef CONFIG_FB
+ if (!mode_option)
+@@ -1459,127 +1604,77 @@ bool drm_mode_parse_command_line_for_con
+ }
+
+ name = mode_option;
+- namelen = strlen(name);
+- for (i = namelen-1; i >= 0; i--) {
+- switch (name[i]) {
+- case '@':
+- if (!refresh_specified && !bpp_specified &&
+- !yres_specified && !cvt && !rb && was_digit) {
+- refresh = simple_strtol(&name[i+1], NULL, 10);
+- refresh_specified = true;
+- was_digit = false;
+- } else
+- goto done;
+- break;
+- case '-':
+- if (!bpp_specified && !yres_specified && !cvt &&
+- !rb && was_digit) {
+- bpp = simple_strtol(&name[i+1], NULL, 10);
+- bpp_specified = true;
+- was_digit = false;
+- } else
+- goto done;
+- break;
+- case 'x':
+- if (!yres_specified && was_digit) {
+- yres = simple_strtol(&name[i+1], NULL, 10);
+- yres_specified = true;
+- was_digit = false;
+- } else
+- goto done;
+- break;
+- case '0' ... '9':
+- was_digit = true;
+- break;
+- case 'M':
+- if (yres_specified || cvt || was_digit)
+- goto done;
+- cvt = true;
+- break;
+- case 'R':
+- if (yres_specified || cvt || rb || was_digit)
+- goto done;
+- rb = true;
+- break;
+- case 'm':
+- if (cvt || yres_specified || was_digit)
+- goto done;
+- margins = true;
+- break;
+- case 'i':
+- if (cvt || yres_specified || was_digit)
+- goto done;
+- interlace = true;
+- break;
+- case 'e':
+- if (yres_specified || bpp_specified || refresh_specified ||
+- was_digit || (force != DRM_FORCE_UNSPECIFIED))
+- goto done;
+
+- force = DRM_FORCE_ON;
+- break;
+- case 'D':
+- if (yres_specified || bpp_specified || refresh_specified ||
+- was_digit || (force != DRM_FORCE_UNSPECIFIED))
+- goto done;
++ if (!isdigit(name[0]))
++ return false;
+
+- 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':
+- if (yres_specified || bpp_specified || refresh_specified ||
+- was_digit || (force != DRM_FORCE_UNSPECIFIED))
+- goto done;
++ /* Try to locate the bpp and refresh specifiers, if any */
++ bpp_ptr = strchr(name, '-');
++ if (bpp_ptr) {
++ bpp_off = bpp_ptr - name;
++ mode->bpp_specified = true;
++ }
+
+- force = DRM_FORCE_OFF;
+- break;
+- default:
+- goto done;
+- }
++ refresh_ptr = strchr(name, '@');
++ if (refresh_ptr) {
++ refresh_off = refresh_ptr - name;
++ mode->refresh_specified = true;
+ }
+
+- if (i < 0 && yres_specified) {
+- char *ch;
+- xres = simple_strtol(name, &ch, 10);
+- if ((ch != NULL) && (*ch == 'x'))
+- res_specified = true;
+- else
+- i = ch - name;
+- } else if (!yres_specified && was_digit) {
+- /* catch mode that begins with digits but has no 'x' */
+- i = 0;
+- }
+-done:
+- if (i >= 0) {
+- pr_warn("[drm] parse error at position %i in video mode '%s'\n",
+- i, name);
+- mode->specified = false;
+- return false;
++ /* Locate the end of the name / resolution, and parse it */
++ if (bpp_ptr && refresh_ptr) {
++ mode_end = min(bpp_off, refresh_off);
++ } else if (bpp_ptr) {
++ mode_end = bpp_off;
++ } else if (refresh_ptr) {
++ mode_end = refresh_off;
++ } else {
++ mode_end = strlen(name);
++ parse_extras = true;
+ }
+
+- if (res_specified) {
+- mode->specified = true;
+- mode->xres = xres;
+- mode->yres = yres;
++ ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
++ parse_extras,
++ connector,
++ mode);
++ if (ret)
++ return false;
++ mode->specified = true;
++
++ if (bpp_ptr) {
++ ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
++ if (ret)
++ return false;
+ }
+
+- if (refresh_specified) {
+- mode->refresh_specified = true;
+- mode->refresh = refresh;
++ if (refresh_ptr) {
++ ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
++ &refresh_end_ptr, mode);
++ if (ret)
++ return false;
+ }
+
+- if (bpp_specified) {
+- mode->bpp_specified = true;
+- mode->bpp = bpp;
++ /*
++ * Locate the end of the bpp / refresh, and parse the extras
++ * if relevant
++ */
++ if (bpp_ptr && refresh_ptr)
++ extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
++ else if (bpp_ptr)
++ extra_ptr = bpp_end_ptr;
++ else if (refresh_ptr)
++ extra_ptr = refresh_end_ptr;
++
++ if (extra_ptr) {
++ int remaining = strlen(name) - (extra_ptr - name);
++
++ /*
++ * We still have characters to process, while
++ * we shouldn't have any
++ */
++ if (remaining > 0)
++ return false;
+ }
+- mode->rb = rb;
+- mode->cvt = cvt;
+- mode->interlace = interlace;
+- mode->margins = margins;
+- mode->force = force;
+
+ return true;
+ }