kernel: bump 5.4 to 5.4.28
[oweals/openwrt.git] / target / linux / bcm27xx / patches-5.4 / 950-0487-drm-modes-parse_cmdline-Allow-specifying-stand-alone.patch
1 From b3212eba63b541206e12c8dc31fc0d99d916b210 Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Mon, 18 Nov 2019 16:51:29 +0100
4 Subject: [PATCH] drm/modes: parse_cmdline: Allow specifying
5  stand-alone options
6
7 Commit 7b1cce760afe38b40f0989cdf10b2190dccf9815 upstream.
8
9 Some options which can be specified on the commandline, such as
10 margin_right=..., margin_left=..., etc. are applied not only to the
11 specified mode, but to all modes. As such it would be nice if the user
12 can simply say e.g.
13 video=HDMI-1:margin_right=14,margin_left=24,margin_bottom=36,margin_top=42
14
15 This commit refactors drm_mode_parse_command_line_for_connector() to
16 add support for this, and as a nice side effect also cleans up the
17 function a bit.
18
19 Acked-by: Maxime Ripard <mripard@kernel.org>
20 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
21 Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-8-hdegoede@redhat.com
22 ---
23  drivers/gpu/drm/drm_modes.c                   | 92 +++++++------------
24  .../gpu/drm/selftests/drm_cmdline_selftests.h |  2 +
25  .../drm/selftests/test-drm_cmdline_parser.c   | 50 ++++++++++
26  3 files changed, 86 insertions(+), 58 deletions(-)
27
28 --- a/drivers/gpu/drm/drm_modes.c
29 +++ b/drivers/gpu/drm/drm_modes.c
30 @@ -1684,17 +1684,6 @@ static const char * const drm_named_mode
31         "PAL",
32  };
33  
34 -static bool drm_named_mode_is_in_whitelist(const char *mode, unsigned int size)
35 -{
36 -       int i;
37 -
38 -       for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++)
39 -               if (!strncmp(mode, drm_named_modes_whitelist[i], size))
40 -                       return true;
41 -
42 -       return false;
43 -}
44 -
45  /**
46   * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
47   * @mode_option: optional per connector mode option
48 @@ -1725,7 +1714,7 @@ bool drm_mode_parse_command_line_for_con
49                                                struct drm_cmdline_mode *mode)
50  {
51         const char *name;
52 -       bool named_mode = false, parse_extras = false;
53 +       bool freestanding = false, parse_extras = false;
54         unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
55         unsigned int mode_end = 0;
56         const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
57 @@ -1745,49 +1734,14 @@ bool drm_mode_parse_command_line_for_con
58  
59         name = mode_option;
60  
61 -       /*
62 -        * This is a bit convoluted. To differentiate between the
63 -        * named modes and poorly formatted resolutions, we need a
64 -        * bunch of things:
65 -        *   - We need to make sure that the first character (which
66 -        *     would be our resolution in X) is a digit.
67 -        *   - If not, then it's either a named mode or a force on/off.
68 -        *     To distinguish between the two, we need to run the
69 -        *     extra parsing function, and if not, then we consider it
70 -        *     a named mode.
71 -        *
72 -        * If this isn't enough, we should add more heuristics here,
73 -        * and matching unit-tests.
74 -        */
75 -       if (!isdigit(name[0]) && name[0] != 'x') {
76 -               unsigned int namelen = strlen(name);
77 -
78 -               /*
79 -                * Only the force on/off options can be in that case,
80 -                * and they all take a single character.
81 -                */
82 -               if (namelen == 1) {
83 -                       ret = drm_mode_parse_cmdline_extra(name, namelen, true,
84 -                                                          connector, mode);
85 -                       if (!ret)
86 -                               return true;
87 -               }
88 -
89 -               named_mode = true;
90 -       }
91 -
92         /* Try to locate the bpp and refresh specifiers, if any */
93         bpp_ptr = strchr(name, '-');
94         if (bpp_ptr)
95                 bpp_off = bpp_ptr - name;
96  
97         refresh_ptr = strchr(name, '@');
98 -       if (refresh_ptr) {
99 -               if (named_mode)
100 -                       return false;
101 -
102 +       if (refresh_ptr)
103                 refresh_off = refresh_ptr - name;
104 -       }
105  
106         /* Locate the start of named options */
107         options_ptr = strchr(name, ',');
108 @@ -1807,23 +1761,45 @@ bool drm_mode_parse_command_line_for_con
109                 parse_extras = true;
110         }
111  
112 -       if (named_mode) {
113 -               if (mode_end + 1 > DRM_DISPLAY_MODE_LEN)
114 -                       return false;
115 -
116 -               if (!drm_named_mode_is_in_whitelist(name, mode_end))
117 -                       return false;
118 +       /* First check for a named mode */
119 +       for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
120 +               ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
121 +               if (ret == mode_end) {
122 +                       if (refresh_ptr)
123 +                               return false; /* named + refresh is invalid */
124 +
125 +                       strcpy(mode->name, drm_named_modes_whitelist[i]);
126 +                       mode->specified = true;
127 +                       break;
128 +               }
129 +       }
130  
131 -               strscpy(mode->name, name, mode_end + 1);
132 -       } else {
133 +       /* No named mode? Check for a normal mode argument, e.g. 1024x768 */
134 +       if (!mode->specified && isdigit(name[0])) {
135                 ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
136                                                       parse_extras,
137                                                       connector,
138                                                       mode);
139                 if (ret)
140                         return false;
141 +
142 +               mode->specified = true;
143 +       }
144 +
145 +       /* No mode? Check for freestanding extras and/or options */
146 +       if (!mode->specified) {
147 +               unsigned int len = strlen(mode_option);
148 +
149 +               if (bpp_ptr || refresh_ptr)
150 +                       return false; /* syntax error */
151 +
152 +               if (len == 1 || (len >= 2 && mode_option[1] == ','))
153 +                       extra_ptr = mode_option;
154 +               else
155 +                       options_ptr = mode_option - 1;
156 +
157 +               freestanding = true;
158         }
159 -       mode->specified = true;
160  
161         if (bpp_ptr) {
162                 ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
163 @@ -1859,7 +1835,7 @@ bool drm_mode_parse_command_line_for_con
164                 else
165                         len = strlen(extra_ptr);
166  
167 -               ret = drm_mode_parse_cmdline_extra(extra_ptr, len, false,
168 +               ret = drm_mode_parse_cmdline_extra(extra_ptr, len, freestanding,
169                                                    connector, mode);
170                 if (ret)
171                         return false;
172 @@ -1867,7 +1843,7 @@ bool drm_mode_parse_command_line_for_con
173  
174         if (options_ptr) {
175                 ret = drm_mode_parse_cmdline_options(options_ptr + 1,
176 -                                                    false,
177 +                                                    freestanding,
178                                                      connector, mode);
179                 if (ret)
180                         return false;
181 --- a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
182 +++ b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
183 @@ -63,3 +63,5 @@ cmdline_test(drm_cmdline_test_multiple_o
184  cmdline_test(drm_cmdline_test_invalid_option)
185  cmdline_test(drm_cmdline_test_bpp_extra_and_option)
186  cmdline_test(drm_cmdline_test_extra_and_option)
187 +cmdline_test(drm_cmdline_test_freestanding_options)
188 +cmdline_test(drm_cmdline_test_freestanding_force_e_and_options)
189 --- a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
190 +++ b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
191 @@ -1053,6 +1053,56 @@ static int drm_cmdline_test_extra_and_op
192         return 0;
193  }
194  
195 +static int drm_cmdline_test_freestanding_options(void *ignored)
196 +{
197 +       struct drm_cmdline_mode mode = { };
198 +
199 +       FAIL_ON(!drm_mode_parse_command_line_for_connector("margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
200 +                                                          &no_connector,
201 +                                                          &mode));
202 +       FAIL_ON(mode.specified);
203 +       FAIL_ON(mode.refresh_specified);
204 +       FAIL_ON(mode.bpp_specified);
205 +
206 +       FAIL_ON(mode.tv_margins.right != 14);
207 +       FAIL_ON(mode.tv_margins.left != 24);
208 +       FAIL_ON(mode.tv_margins.bottom != 36);
209 +       FAIL_ON(mode.tv_margins.top != 42);
210 +
211 +       FAIL_ON(mode.rb);
212 +       FAIL_ON(mode.cvt);
213 +       FAIL_ON(mode.interlace);
214 +       FAIL_ON(mode.margins);
215 +       FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
216 +
217 +       return 0;
218 +}
219 +
220 +static int drm_cmdline_test_freestanding_force_e_and_options(void *ignored)
221 +{
222 +       struct drm_cmdline_mode mode = { };
223 +
224 +       FAIL_ON(!drm_mode_parse_command_line_for_connector("e,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
225 +                                                          &no_connector,
226 +                                                          &mode));
227 +       FAIL_ON(mode.specified);
228 +       FAIL_ON(mode.refresh_specified);
229 +       FAIL_ON(mode.bpp_specified);
230 +
231 +       FAIL_ON(mode.tv_margins.right != 14);
232 +       FAIL_ON(mode.tv_margins.left != 24);
233 +       FAIL_ON(mode.tv_margins.bottom != 36);
234 +       FAIL_ON(mode.tv_margins.top != 42);
235 +
236 +       FAIL_ON(mode.rb);
237 +       FAIL_ON(mode.cvt);
238 +       FAIL_ON(mode.interlace);
239 +       FAIL_ON(mode.margins);
240 +       FAIL_ON(mode.force != DRM_FORCE_ON);
241 +
242 +       return 0;
243 +}
244 +
245  #include "drm_selftest.c"
246  
247  static int __init test_drm_cmdline_init(void)