Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/modes: parse_cmdline: Add support for specifying panel_orientation (v2)

Sometimes we want to override a connector's panel_orientation from the
kernel commandline. Either for testing and for special cases, e.g. a kiosk
like setup which uses a TV mounted in portrait mode.

Users can already specify a "rotate" option through a video= kernel cmdline
option. But that only supports 0/180 degrees (see drm_client_modeset TODO)
and only works for in kernel modeset clients, not for userspace kms users.

The "panel-orientation" connector property OTOH does support 90/270 degrees
as it leaves dealing with the rotation up to userspace and this does work
for userspace kms clients (at least those which support this property).

Changes in v2:
-Add missing ':' after @panel_orientation (reported by kbuild test robot)

BugLink: https://gitlab.freedesktop.org/plymouth/plymouth/merge_requests/83
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-9-hdegoede@redhat.com

+66
+3
Documentation/fb/modedb.rst
··· 65 65 - reflect_y (boolean): Perform an axial symmetry on the Y axis 66 66 - rotate (integer): Rotate the initial framebuffer by x 67 67 degrees. Valid values are 0, 90, 180 and 270. 68 + - panel_orientation, one of "normal", "upside_down", "left_side_up", or 69 + "right_side_up". For KMS drivers only, this sets the "panel orientation" 70 + property on the kms connector as hint for kms users. 68 71 69 72 70 73 -----------------------------------------------------------------------------
+32
drivers/gpu/drm/drm_modes.c
··· 1591 1591 return 0; 1592 1592 } 1593 1593 1594 + static int drm_mode_parse_panel_orientation(const char *delim, 1595 + struct drm_cmdline_mode *mode) 1596 + { 1597 + const char *value; 1598 + 1599 + if (*delim != '=') 1600 + return -EINVAL; 1601 + 1602 + value = delim + 1; 1603 + delim = strchr(value, ','); 1604 + if (!delim) 1605 + delim = value + strlen(value); 1606 + 1607 + if (!strncmp(value, "normal", delim - value)) 1608 + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL; 1609 + else if (!strncmp(value, "upside_down", delim - value)) 1610 + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; 1611 + else if (!strncmp(value, "left_side_up", delim - value)) 1612 + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP; 1613 + else if (!strncmp(value, "right_side_up", delim - value)) 1614 + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP; 1615 + else 1616 + return -EINVAL; 1617 + 1618 + return 0; 1619 + } 1620 + 1594 1621 static int drm_mode_parse_cmdline_options(const char *str, 1595 1622 bool freestanding, 1596 1623 const struct drm_connector *connector, ··· 1684 1657 return -EINVAL; 1685 1658 1686 1659 mode->tv_margins.bottom = margin; 1660 + } else if (!strncmp(option, "panel_orientation", delim - option)) { 1661 + if (drm_mode_parse_panel_orientation(delim, mode)) 1662 + return -EINVAL; 1687 1663 } else { 1688 1664 return -EINVAL; 1689 1665 } ··· 1744 1714 const char *options_ptr = NULL; 1745 1715 char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL; 1746 1716 int i, len, ret; 1717 + 1718 + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; 1747 1719 1748 1720 #ifdef CONFIG_FB 1749 1721 if (!mode_option)
+1
drivers/gpu/drm/selftests/drm_cmdline_selftests.h
··· 64 64 cmdline_test(drm_cmdline_test_extra_and_option) 65 65 cmdline_test(drm_cmdline_test_freestanding_options) 66 66 cmdline_test(drm_cmdline_test_freestanding_force_e_and_options) 67 + cmdline_test(drm_cmdline_test_panel_orientation)
+22
drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
··· 1092 1092 return 0; 1093 1093 } 1094 1094 1095 + static int drm_cmdline_test_panel_orientation(void *ignored) 1096 + { 1097 + struct drm_cmdline_mode mode = { }; 1098 + 1099 + FAIL_ON(!drm_mode_parse_command_line_for_connector("panel_orientation=upside_down", 1100 + &no_connector, 1101 + &mode)); 1102 + FAIL_ON(mode.specified); 1103 + FAIL_ON(mode.refresh_specified); 1104 + FAIL_ON(mode.bpp_specified); 1105 + 1106 + FAIL_ON(mode.panel_orientation != DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP); 1107 + 1108 + FAIL_ON(mode.rb); 1109 + FAIL_ON(mode.cvt); 1110 + FAIL_ON(mode.interlace); 1111 + FAIL_ON(mode.margins); 1112 + FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); 1113 + 1114 + return 0; 1115 + } 1116 + 1095 1117 #include "drm_selftest.c" 1096 1118 1097 1119 static int __init test_drm_cmdline_init(void)
+8
include/drm/drm_connector.h
··· 1070 1070 unsigned int rotation_reflection; 1071 1071 1072 1072 /** 1073 + * @panel_orientation: 1074 + * 1075 + * drm-connector "panel orientation" property override value, 1076 + * DRM_MODE_PANEL_ORIENTATION_UNKNOWN if not set. 1077 + */ 1078 + enum drm_panel_orientation panel_orientation; 1079 + 1080 + /** 1073 1081 * @tv_margins: TV margins to apply to the mode. 1074 1082 */ 1075 1083 struct drm_connector_tv_margins tv_margins;