cbda9ecc101d835db435224e6bf30473efb9d5ec
[openwrt/staging/linusw.git] /
1 From 7d395633947fa6595a117f40e0f27ba87be77d6c Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Mon, 18 Nov 2019 16:51:30 +0100
4 Subject: [PATCH] drm/modes: parse_cmdline: Add support for specifying
5 panel_orientation (v2)
6
7 Commit 4e7a4a6fbdc669c44e6079f9d5eb25673749455f upstream.
8
9 Sometimes we want to override a connector's panel_orientation from the
10 kernel commandline. Either for testing and for special cases, e.g. a kiosk
11 like setup which uses a TV mounted in portrait mode.
12
13 Users can already specify a "rotate" option through a video= kernel cmdline
14 option. But that only supports 0/180 degrees (see drm_client_modeset TODO)
15 and only works for in kernel modeset clients, not for userspace kms users.
16
17 The "panel-orientation" connector property OTOH does support 90/270 degrees
18 as it leaves dealing with the rotation up to userspace and this does work
19 for userspace kms clients (at least those which support this property).
20
21 Changes in v2:
22 -Add missing ':' after @panel_orientation (reported by kbuild test robot)
23
24 BugLink: https://gitlab.freedesktop.org/plymouth/plymouth/merge_requests/83
25 Acked-by: Maxime Ripard <mripard@kernel.org>
26 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
27 Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-9-hdegoede@redhat.com
28 ---
29 Documentation/fb/modedb.rst | 3 ++
30 drivers/gpu/drm/drm_modes.c | 32 +++++++++++++++++++
31 .../gpu/drm/selftests/drm_cmdline_selftests.h | 1 +
32 .../drm/selftests/test-drm_cmdline_parser.c | 22 +++++++++++++
33 include/drm/drm_connector.h | 8 +++++
34 5 files changed, 66 insertions(+)
35
36 --- a/Documentation/fb/modedb.rst
37 +++ b/Documentation/fb/modedb.rst
38 @@ -65,6 +65,9 @@ Valid options are::
39 - reflect_y (boolean): Perform an axial symmetry on the Y axis
40 - rotate (integer): Rotate the initial framebuffer by x
41 degrees. Valid values are 0, 90, 180 and 270.
42 + - panel_orientation, one of "normal", "upside_down", "left_side_up", or
43 + "right_side_up". For KMS drivers only, this sets the "panel orientation"
44 + property on the kms connector as hint for kms users.
45
46
47 -----------------------------------------------------------------------------
48 --- a/drivers/gpu/drm/drm_modes.c
49 +++ b/drivers/gpu/drm/drm_modes.c
50 @@ -1591,6 +1591,33 @@ static int drm_mode_parse_cmdline_int(co
51 return 0;
52 }
53
54 +static int drm_mode_parse_panel_orientation(const char *delim,
55 + struct drm_cmdline_mode *mode)
56 +{
57 + const char *value;
58 +
59 + if (*delim != '=')
60 + return -EINVAL;
61 +
62 + value = delim + 1;
63 + delim = strchr(value, ',');
64 + if (!delim)
65 + delim = value + strlen(value);
66 +
67 + if (!strncmp(value, "normal", delim - value))
68 + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
69 + else if (!strncmp(value, "upside_down", delim - value))
70 + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
71 + else if (!strncmp(value, "left_side_up", delim - value))
72 + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
73 + else if (!strncmp(value, "right_side_up", delim - value))
74 + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
75 + else
76 + return -EINVAL;
77 +
78 + return 0;
79 +}
80 +
81 static int drm_mode_parse_cmdline_options(const char *str,
82 bool freestanding,
83 const struct drm_connector *connector,
84 @@ -1657,6 +1684,9 @@ static int drm_mode_parse_cmdline_option
85 return -EINVAL;
86
87 mode->tv_margins.bottom = margin;
88 + } else if (!strncmp(option, "panel_orientation", delim - option)) {
89 + if (drm_mode_parse_panel_orientation(delim, mode))
90 + return -EINVAL;
91 } else {
92 return -EINVAL;
93 }
94 @@ -1722,6 +1752,8 @@ bool drm_mode_parse_command_line_for_con
95 char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
96 int i, len, ret;
97
98 + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
99 +
100 #ifdef CONFIG_FB
101 if (!mode_option)
102 mode_option = fb_mode_option;
103 --- a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
104 +++ b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
105 @@ -65,3 +65,4 @@ cmdline_test(drm_cmdline_test_bpp_extra_
106 cmdline_test(drm_cmdline_test_extra_and_option)
107 cmdline_test(drm_cmdline_test_freestanding_options)
108 cmdline_test(drm_cmdline_test_freestanding_force_e_and_options)
109 +cmdline_test(drm_cmdline_test_panel_orientation)
110 --- a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
111 +++ b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
112 @@ -1103,6 +1103,28 @@ static int drm_cmdline_test_freestanding
113 return 0;
114 }
115
116 +static int drm_cmdline_test_panel_orientation(void *ignored)
117 +{
118 + struct drm_cmdline_mode mode = { };
119 +
120 + FAIL_ON(!drm_mode_parse_command_line_for_connector("panel_orientation=upside_down",
121 + &no_connector,
122 + &mode));
123 + FAIL_ON(mode.specified);
124 + FAIL_ON(mode.refresh_specified);
125 + FAIL_ON(mode.bpp_specified);
126 +
127 + FAIL_ON(mode.panel_orientation != DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP);
128 +
129 + FAIL_ON(mode.rb);
130 + FAIL_ON(mode.cvt);
131 + FAIL_ON(mode.interlace);
132 + FAIL_ON(mode.margins);
133 + FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
134 +
135 + return 0;
136 +}
137 +
138 #include "drm_selftest.c"
139
140 static int __init test_drm_cmdline_init(void)
141 --- a/include/drm/drm_connector.h
142 +++ b/include/drm/drm_connector.h
143 @@ -1066,6 +1066,14 @@ struct drm_cmdline_mode {
144 unsigned int rotation_reflection;
145
146 /**
147 + * @panel_orientation:
148 + *
149 + * drm-connector "panel orientation" property override value,
150 + * DRM_MODE_PANEL_ORIENTATION_UNKNOWN if not set.
151 + */
152 + enum drm_panel_orientation panel_orientation;
153 +
154 + /**
155 * @tv_margins: TV margins to apply to the mode.
156 */
157 struct drm_connector_tv_margins tv_margins;