linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration
@ 2019-06-17 14:51 Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 01/12] drm/connector: Add documentation for drm_cmdline_mode Maxime Ripard
                   ` (11 more replies)
  0 siblings, 12 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, linux-arm-kernel

Hi,

The proprietary stack for the RaspberryPi allows for a number of video
parameters widely used by their users, but yet don't have any equivalents
in the mainline kernel.

Those options are detailed here:
https://www.raspberrypi.org/documentation/configuration/config-txt/video.md

While not all of them are desirable to have in the mainline kernel, some of
them still have value, such as properties to initialise the overscan or
rotation parameters.

This series is an attempt to support those, and is based on a rewrite of
the command line parser I did a couple of years ago that never reached
upstream (due to a lack of time on my side). While this parser was
initially made to deal with named modes (in order to support TV modes), it
also allowed to extend it more easily, which is why it's resurrected.

It relies on the series "drm/fb-helper: Move modesetting code to
drm_client" by Noralf Trønnes found here:
https://patchwork.freedesktop.org/series/58598/

Let me know what you think,
Maxime

Changes from v4:
  - Change the name of the variable to make it clear it's about reflection
    and rotation.
  - Fix the reflection case in drm_client_rotation
  - Fix the documentation accordingly
  - Added missing modedb.rst documentation
  - Fix a chunk not in the proper commit
  - Fix a few typos
  - Rebased on top of current next

Changes from v3:
  - Add documentation for drm_cmdline_mode and the new variables
  - Move the TV properties reset to a helper
  - Fix a missing X resolution or a missing Y resolution
  - Add more tests
  - Add the rotation to the orientation
  - Fix the reflection
  - Change the name of the drm_client_panel_rotation function
  - Rebased on top of current next

Changes from v2:
  - Fixed some sparse warnings
  - Rebased on top of next and Noralf series
  - Moved the property initialisation to vc4 reset hook
  - Added documentation for the new drm_cmdline_mode
  - Renamed overscan to tv_margins to be consistent with the APIs

Changes from v1:
  - Dropped the patches to deal with EDID
  - Added the unit test as selftest
  - Rebased on next

Maxime Ripard (12):
  drm/connector: Add documentation for drm_cmdline_mode
  drm/client: Restrict the plane_state scope
  drm/client: Restrict the rotation check to the rotation itself
  drm/client: Change drm_client_panel_rotation name
  drm/modes: Rewrite the command line parser
  drm/modes: Support modes names on the command line
  drm/modes: Allow to specify rotation and reflection on the commandline
  drm/connector: Introduce a TV margins structure
  drm/modes: Parse overscan properties
  drm/atomic: Add a function to reset connector TV properties
  drm/selftests: Add command line parser selftests
  drm/vc4: hdmi: Set default state margin at reset

 Documentation/fb/modedb.rst                         |  13 +-
 drivers/gpu/drm/drm_atomic_state_helper.c           |  18 +-
 drivers/gpu/drm/drm_client_modeset.c                |  54 +-
 drivers/gpu/drm/drm_connector.c                     |   3 +-
 drivers/gpu/drm/drm_fb_helper.c                     |   2 +-
 drivers/gpu/drm/drm_modes.c                         | 473 +++++--
 drivers/gpu/drm/selftests/Makefile                  |   2 +-
 drivers/gpu/drm/selftests/drm_cmdline_selftests.h   |  55 +-
 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c | 918 +++++++++++++-
 drivers/gpu/drm/vc4/vc4_hdmi.c                      |   8 +-
 include/drm/drm_atomic_state_helper.h               |   1 +-
 include/drm/drm_client.h                            |   2 +-
 include/drm/drm_connector.h                         | 149 +-
 13 files changed, 1557 insertions(+), 141 deletions(-)
 create mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h
 create mode 100644 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c

base-commit: a125097c841039deef9dd589b86467f7d20f4b3d
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v5 01/12] drm/connector: Add documentation for drm_cmdline_mode
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 02/12] drm/client: Restrict the plane_state scope Maxime Ripard
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, linux-arm-kernel

The struct drm_cmdline_mode holds the result of the command line parsers.
However, it wasn't documented so far, so let's do that.

Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 include/drm/drm_connector.h | 86 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 84 insertions(+), 2 deletions(-)

diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index c6f8486d8b8f..c802780b0bfc 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -923,18 +923,100 @@ struct drm_connector_funcs {
 				   const struct drm_connector_state *state);
 };
 
-/* mode specified on the command line */
+/**
+ * struct drm_cmdline_mode - DRM Mode passed through the kernel command-line
+ *
+ * Each connector can have an initial mode with additional options
+ * passed through the kernel command line. This structure allows to
+ * express those parameters and will be filled by the command-line
+ * parser.
+ */
 struct drm_cmdline_mode {
+	/**
+	 * @specified:
+	 *
+	 * Has a mode been read from the command-line?
+	 */
 	bool specified;
+
+	/**
+	 * @refresh_specified:
+	 *
+	 * Did the mode have a preferred refresh rate?
+	 */
 	bool refresh_specified;
+
+	/**
+	 * @bpp_specified:
+	 *
+	 * Did the mode have a preferred BPP?
+	 */
 	bool bpp_specified;
-	int xres, yres;
+
+	/**
+	 * @xres:
+	 *
+	 * Active resolution on the X axis, in pixels.
+	 */
+	int xres;
+
+	/**
+	 * @yres:
+	 *
+	 * Active resolution on the Y axis, in pixels.
+	 */
+	int yres;
+
+	/**
+	 * @bpp:
+	 *
+	 * Bits per pixels for the mode.
+	 */
 	int bpp;
+
+	/**
+	 * @refresh:
+	 *
+	 * Refresh rate, in Hertz.
+	 */
 	int refresh;
+
+	/**
+	 * @rb:
+	 *
+	 * Do we need to use reduced blanking?
+	 */
 	bool rb;
+
+	/**
+	 * @interlace:
+	 *
+	 * The mode is interlaced.
+	 */
 	bool interlace;
+
+	/**
+	 * @cvt:
+	 *
+	 * The timings will be calculated using the VESA Coordinated
+	 * Video Timings instead of looking up the mode from a table.
+	 */
 	bool cvt;
+
+	/**
+	 * @margins:
+	 *
+	 * Add margins to the mode calculation (1.8% of xres rounded
+	 * down to 8 pixels and 1.8% of yres).
+	 */
 	bool margins;
+
+	/**
+	 * @force:
+	 *
+	 * Ignore the hotplug state of the connector, and force its
+	 * state to one of the DRM_FORCE_* values.
+	 */
 	enum drm_connector_force force;
 };
 
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v5 02/12] drm/client: Restrict the plane_state scope
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 01/12] drm/connector: Add documentation for drm_cmdline_mode Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 03/12] drm/client: Restrict the rotation check to the rotation itself Maxime Ripard
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, linux-arm-kernel

The drm_client_modeset_commit_atomic function uses two times the
plane_state variable in inner blocks of code, but the variable has a scope
global to this function.

This will lead to inadvertent devs to reuse the variable in the second
block with the value left by the first, without any warning from the
compiler since value would have been initialized.

Fix this by moving the variable declaration to the proper scope.

Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 drivers/gpu/drm/drm_client_modeset.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index 006bf7390e7d..8264c3a732b0 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -861,7 +861,6 @@ EXPORT_SYMBOL(drm_client_panel_rotation);
 static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool active)
 {
 	struct drm_device *dev = client->dev;
-	struct drm_plane_state *plane_state;
 	struct drm_plane *plane;
 	struct drm_atomic_state *state;
 	struct drm_modeset_acquire_ctx ctx;
@@ -879,6 +878,8 @@ static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool 
 	state->acquire_ctx = &ctx;
 retry:
 	drm_for_each_plane(plane, dev) {
+		struct drm_plane_state *plane_state;
+
 		plane_state = drm_atomic_get_plane_state(state, plane);
 		if (IS_ERR(plane_state)) {
 			ret = PTR_ERR(plane_state);
@@ -901,6 +902,8 @@ static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool 
 		unsigned int rotation;
 
 		if (drm_client_panel_rotation(mode_set, &rotation)) {
+			struct drm_plane_state *plane_state;
+
 			/* Cannot fail as we've already gotten the plane state above */
 			plane_state = drm_atomic_get_new_plane_state(state, primary);
 			plane_state->rotation = rotation;
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v5 03/12] drm/client: Restrict the rotation check to the rotation itself
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 01/12] drm/connector: Add documentation for drm_cmdline_mode Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 02/12] drm/client: Restrict the plane_state scope Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 04/12] drm/client: Change drm_client_panel_rotation name Maxime Ripard
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, linux-arm-kernel

The drm_client_rotation has a check on the rotation value, but the
reflections are also stored in the same variable, and the check doesn't
take this into account.

Therefore, even though we might have a valid rotation, if we're also using
a reflection parameter, the test will fail for no particular reason.

Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 drivers/gpu/drm/drm_client_modeset.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index 8264c3a732b0..b4e5fb0a17cf 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -845,7 +845,8 @@ bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotat
 	 * depending on the hardware this may require the framebuffer
 	 * to be in a specific tiling format.
 	 */
-	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
+	if ((*rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_180 ||
+	    !plane->rotation_property)
 		return false;
 
 	for (i = 0; i < plane->rotation_property->num_values; i++)
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v5 04/12] drm/client: Change drm_client_panel_rotation name
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
                   ` (2 preceding siblings ...)
  2019-06-17 14:51 ` [PATCH v5 03/12] drm/client: Restrict the rotation check to the rotation itself Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 05/12] drm/modes: Rewrite the command line parser Maxime Ripard
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, linux-arm-kernel

The drm_client_panel_rotation function has been used so far to set the
default rotation based on the panel orientation.

However, we can have more sources of information to make that decision,
starting with the command line that we will introduce later in this series.

Change the name to remove the panel mention.

Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 drivers/gpu/drm/drm_client_modeset.c | 12 ++++++------
 drivers/gpu/drm/drm_fb_helper.c      |  2 +-
 include/drm/drm_client.h             |  2 +-
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index b4e5fb0a17cf..4869a0170bec 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -804,19 +804,19 @@ int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, 
 EXPORT_SYMBOL(drm_client_modeset_probe);
 
 /**
- * drm_client_panel_rotation() - Check panel orientation
+ * drm_client_rotation() - Check the initial rotation value
  * @modeset: DRM modeset
  * @rotation: Returned rotation value
  *
- * This function checks if the primary plane in @modeset can hw rotate to match
- * the panel orientation on its connector.
+ * This function checks if the primary plane in @modeset can hw rotate
+ * to match the rotation needed on its connector.
  *
  * Note: Currently only 0 and 180 degrees are supported.
  *
  * Return:
  * True if the plane can do the rotation, false otherwise.
  */
-bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
+bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
 {
 	struct drm_connector *connector = modeset->connectors[0];
 	struct drm_plane *plane = modeset->crtc->primary;
@@ -857,7 +857,7 @@ bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotat
 
 	return true;
 }
-EXPORT_SYMBOL(drm_client_panel_rotation);
+EXPORT_SYMBOL(drm_client_rotation);
 
 static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool active)
 {
@@ -902,7 +902,7 @@ static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool 
 		struct drm_plane *primary = mode_set->crtc->primary;
 		unsigned int rotation;
 
-		if (drm_client_panel_rotation(mode_set, &rotation)) {
+		if (drm_client_rotation(mode_set, &rotation)) {
 			struct drm_plane_state *plane_state;
 
 			/* Cannot fail as we've already gotten the plane state above */
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 42852cae749b..1984e5c54d58 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1722,7 +1722,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 
 		modeset->fb = fb_helper->fb;
 
-		if (drm_client_panel_rotation(modeset, &rotation))
+		if (drm_client_rotation(modeset, &rotation))
 			/* Rotating in hardware, fbcon should not rotate */
 			sw_rotations |= DRM_MODE_ROTATE_0;
 		else
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index f2d5ed745733..72d51d1e9dd9 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -153,7 +153,7 @@ void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
 int drm_client_modeset_create(struct drm_client_dev *client);
 void drm_client_modeset_free(struct drm_client_dev *client);
 int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height);
-bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
+bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
 int drm_client_modeset_commit_force(struct drm_client_dev *client);
 int drm_client_modeset_commit(struct drm_client_dev *client);
 int drm_client_modeset_dpms(struct drm_client_dev *client, int mode);
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v5 05/12] drm/modes: Rewrite the command line parser
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
                   ` (3 preceding siblings ...)
  2019-06-17 14:51 ` [PATCH v5 04/12] drm/client: Change drm_client_panel_rotation name Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-07-05 16:54   ` Dmitry Osipenko
  2019-08-19 18:54   ` [v5,05/12] " Jernej Škrabec
  2019-06-17 14:51 ` [PATCH v5 06/12] drm/modes: Support modes names on the command line Maxime Ripard
                   ` (6 subsequent siblings)
  11 siblings, 2 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, Maxime Ripard, linux-arm-kernel

From: Maxime Ripard <maxime.ripard@free-electrons.com>

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@free-electrons.com>
---
 drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++--------------
 1 file changed, 210 insertions(+), 115 deletions(-)

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 5a07a28fec6d..6debbd6c1763 100644
--- 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>
@@ -1408,6 +1409,151 @@ void drm_connector_list_update(struct drm_connector *connector)
 }
 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
@@ -1434,13 +1580,12 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 					       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)
@@ -1453,127 +1598,77 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 	}
 
 	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;
+	/* 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;
 	}
-done:
-	if (i >= 0) {
-		pr_warn("[drm] parse error at position %i in video mode '%s'\n",
-			i, name);
-		mode->specified = false;
+
+	ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
+					      parse_extras,
+					      connector,
+					      mode);
+	if (ret)
 		return false;
-	}
+	mode->specified = true;
 
-	if (res_specified) {
-		mode->specified = true;
-		mode->xres = xres;
-		mode->yres = yres;
+	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;
 }
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v5 06/12] drm/modes: Support modes names on the command line
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
                   ` (4 preceding siblings ...)
  2019-06-17 14:51 ` [PATCH v5 05/12] drm/modes: Rewrite the command line parser Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-06-26 15:26   ` Thierry Reding
  2019-06-17 14:51 ` [PATCH v5 07/12] drm/modes: Allow to specify rotation and reflection on the commandline Maxime Ripard
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, Maxime Ripard, linux-arm-kernel

From: Maxime Ripard <maxime.ripard@free-electrons.com>

The drm subsystem also uses the video= kernel parameter, and in the
documentation refers to the fbdev documentation for that parameter.

However, that documentation also says that instead of giving the mode using
its resolution we can also give a name. However, DRM doesn't handle that
case at the moment. Even though in most case it shouldn't make any
difference, it might be useful for analog modes, where different standards
might have the same resolution, but still have a few different parameters
that are not encoded in the modes (NTSC vs NTSC-J vs PAL-M for example).

Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/drm_client_modeset.c |  4 ++-
 drivers/gpu/drm/drm_connector.c      |  3 +-
 drivers/gpu/drm/drm_modes.c          | 62 +++++++++++++++++++++--------
 include/drm/drm_connector.h          |  7 +++-
 4 files changed, 59 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index 4869a0170bec..33d4988f22ae 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -149,6 +149,10 @@ drm_connector_pick_cmdline_mode(struct drm_connector *connector)
 	prefer_non_interlace = !cmdline_mode->interlace;
 again:
 	list_for_each_entry(mode, &connector->modes, head) {
+		/* Check (optional) mode name first */
+		if (!strcmp(mode->name, cmdline_mode->name))
+			return mode;
+
 		/* check width/height */
 		if (mode->hdisplay != cmdline_mode->xres ||
 		    mode->vdisplay != cmdline_mode->yres)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 3ccdcf3dfcde..3afed5677946 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -139,8 +139,9 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
 		connector->force = mode->force;
 	}
 
-	DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+	DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
 		      connector->name,
+		      mode->name ? mode->name : "",
 		      mode->xres, mode->yres,
 		      mode->refresh_specified ? mode->refresh : 60,
 		      mode->rb ? " reduced blanking" : "",
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 6debbd6c1763..429d3be17800 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1580,7 +1580,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 					       struct drm_cmdline_mode *mode)
 {
 	const char *name;
-	bool parse_extras = false;
+	bool named_mode = false, 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;
@@ -1599,8 +1599,22 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 
 	name = mode_option;
 
-	if (!isdigit(name[0]))
-		return false;
+	/*
+	 * This is a bit convoluted. To differentiate between the
+	 * named modes and poorly formatted resolutions, we need a
+	 * bunch of things:
+	 *   - We need to make sure that the first character (which
+	 *     would be our resolution in X) is a digit.
+	 *   - However, if the X resolution is missing, then we end up
+	 *     with something like x<yres>, with our first character
+	 *     being an alpha-numerical character, which would be
+	 *     considered a named mode.
+	 *
+	 * If this isn't enough, we should add more heuristics here,
+	 * and matching unit-tests.
+	 */
+	if (!isdigit(name[0]) && name[0] != 'x')
+		named_mode = true;
 
 	/* Try to locate the bpp and refresh specifiers, if any */
 	bpp_ptr = strchr(name, '-');
@@ -1611,6 +1625,9 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 
 	refresh_ptr = strchr(name, '@');
 	if (refresh_ptr) {
+		if (named_mode)
+			return false;
+
 		refresh_off = refresh_ptr - name;
 		mode->refresh_specified = true;
 	}
@@ -1627,12 +1644,16 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 		parse_extras = true;
 	}
 
-	ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
-					      parse_extras,
-					      connector,
-					      mode);
-	if (ret)
-		return false;
+	if (named_mode) {
+		strncpy(mode->name, name, mode_end);
+	} else {
+		ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
+						      parse_extras,
+						      connector,
+						      mode);
+		if (ret)
+			return false;
+	}
 	mode->specified = true;
 
 	if (bpp_ptr) {
@@ -1660,14 +1681,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 		extra_ptr = refresh_end_ptr;
 
 	if (extra_ptr) {
-		int remaining = strlen(name) - (extra_ptr - name);
+		if (!named_mode) {
+			int len = strlen(name) - (extra_ptr - name);
 
-		/*
-		 * We still have characters to process, while
-		 * we shouldn't have any
-		 */
-		if (remaining > 0)
-			return false;
+			ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
+							   connector, mode);
+			if (ret)
+				return false;
+		} else {
+			int remaining = strlen(name) - (extra_ptr - name);
+
+			/*
+			 * We still have characters to process, while
+			 * we shouldn't have any
+			 */
+			if (remaining > 0)
+				return false;
+		}
 	}
 
 	return true;
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index c802780b0bfc..cdf2fb910010 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -933,6 +933,13 @@ struct drm_connector_funcs {
  */
 struct drm_cmdline_mode {
 	/**
+	 * @name:
+	 *
+	 * Name of the mode.
+	 */
+	char name[DRM_DISPLAY_MODE_LEN];
+
+	/**
 	 * @specified:
 	 *
 	 * Has a mode been read from the command-line?
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v5 07/12] drm/modes: Allow to specify rotation and reflection on the commandline
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
                   ` (5 preceding siblings ...)
  2019-06-17 14:51 ` [PATCH v5 06/12] drm/modes: Support modes names on the command line Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-06-18 17:47   ` Noralf Trønnes
  2019-06-17 14:51 ` [PATCH v5 08/12] drm/connector: Introduce a TV margins structure Maxime Ripard
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, linux-arm-kernel

Rotations and reflections setup are needed in some scenarios to initialise
properly the initial framebuffer. Some drivers already had a bunch of
quirks to deal with this, such as either a private kernel command line
parameter (omapdss) or on the device tree (various panels).

In order to accomodate this, let's create a video mode parameter to deal
with the rotation and reflexion.

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 Documentation/fb/modedb.rst          |  11 +++-
 drivers/gpu/drm/drm_client_modeset.c |  30 +++++++-
 drivers/gpu/drm/drm_modes.c          | 114 +++++++++++++++++++++++-----
 include/drm/drm_connector.h          |  10 ++-
 4 files changed, 145 insertions(+), 20 deletions(-)

diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst
index 3c2397293977..3e8a6f79dcd7 100644
--- a/Documentation/fb/modedb.rst
+++ b/Documentation/fb/modedb.rst
@@ -53,6 +53,17 @@ Specifying the option multiple times for different ports is possible, e.g.::
 
     video=LVDS-1:d video=HDMI-1:D
 
+Options can also be passed after the mode, using commas as separator.
+
+       Sample usage: 720x480,rotate=180 - 720x480 mode, rotated by 180 degrees
+
+Valid options are:
+
+  - reflect_x (boolean): Perform an axial symetry on the X axis
+  - reflect_y (boolean): Perform an axial symetry on the Y axis
+  - rotate (integer): Rotate the initial framebuffer by x
+    degrees. Valid values are 0, 90, 180 and 270.
+
 -----------------------------------------------------------------------------
 
 What is the VESA(TM) Coordinated Video Timings (CVT)?
diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index 33d4988f22ae..e95fceac8f8b 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -824,6 +824,7 @@ bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
 {
 	struct drm_connector *connector = modeset->connectors[0];
 	struct drm_plane *plane = modeset->crtc->primary;
+	struct drm_cmdline_mode *cmdline;
 	u64 valid_mask = 0;
 	unsigned int i;
 
@@ -844,6 +845,35 @@ bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
 		*rotation = DRM_MODE_ROTATE_0;
 	}
 
+	/**
+	 * The panel already defined the default rotation
+	 * through its orientation. Whatever has been provided
+	 * on the command line needs to be added to that.
+	 *
+	 * Unfortunately, the rotations are at different bit
+	 * indices, so the math to add them up are not as
+	 * trivial as they could.
+	 *
+	 * Reflections on the other hand are pretty trivial to deal with, a
+	 * simple XOR between the two handle the addition nicely.
+	 */
+	cmdline = &connector->cmdline_mode;
+	if (cmdline->specified) {
+		unsigned int cmdline_rest, panel_rest;
+		unsigned int cmdline_rot, panel_rot;
+		unsigned int sum_rot, sum_rest;
+
+		panel_rot = ilog2(*rotation & DRM_MODE_ROTATE_MASK);
+		cmdline_rot = ilog2(cmdline->rotation_reflection & DRM_MODE_ROTATE_MASK);
+		sum_rot = (panel_rot + cmdline_rot) % 4;
+
+		panel_rest = *rotation & ~DRM_MODE_ROTATE_MASK;
+		cmdline_rest = cmdline->rotation_reflection & ~DRM_MODE_ROTATE_MASK;
+		sum_rest = panel_rest ^ cmdline_rest;
+
+		*rotation = (1 << sum_rot) | sum_rest;
+	}
+
 	/*
 	 * TODO: support 90 / 270 degree hardware rotation,
 	 * depending on the hardware this may require the framebuffer
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 429d3be17800..dc6d11292685 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1554,6 +1554,71 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
 	return 0;
 }
 
+static int drm_mode_parse_cmdline_options(char *str, size_t len,
+					  struct drm_connector *connector,
+					  struct drm_cmdline_mode *mode)
+{
+	unsigned int rotation = 0;
+	char *sep = str;
+
+	while ((sep = strchr(sep, ','))) {
+		char *delim, *option;
+
+		option = sep + 1;
+		delim = strchr(option, '=');
+		if (!delim) {
+			delim = strchr(option, ',');
+
+			if (!delim)
+				delim = str + len;
+		}
+
+		if (!strncmp(option, "rotate", delim - option)) {
+			const char *value = delim + 1;
+			unsigned int deg;
+
+			deg = simple_strtol(value, &sep, 10);
+
+			/* Make sure we have parsed something */
+			if (sep == value)
+				return -EINVAL;
+
+			switch (deg) {
+			case 0:
+				rotation |= DRM_MODE_ROTATE_0;
+				break;
+
+			case 90:
+				rotation |= DRM_MODE_ROTATE_90;
+				break;
+
+			case 180:
+				rotation |= DRM_MODE_ROTATE_180;
+				break;
+
+			case 270:
+				rotation |= DRM_MODE_ROTATE_270;
+				break;
+
+			default:
+				return -EINVAL;
+			}
+		} else if (!strncmp(option, "reflect_x", delim - option)) {
+			rotation |= DRM_MODE_REFLECT_X;
+			sep = delim;
+		} else if (!strncmp(option, "reflect_y", delim - option)) {
+			rotation |= DRM_MODE_REFLECT_Y;
+			sep = delim;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	mode->rotation_reflection = rotation;
+
+	return 0;
+}
+
 /**
  * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
  * @mode_option: optional per connector mode option
@@ -1569,6 +1634,10 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
  *
  *	<xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
  *
+ * Additionals options can be provided following the mode, using a comma to
+ * separate each option. Valid options can be found in
+ * Documentation/fb/modedb.txt.
+ *
  * The intermediate drm_cmdline_mode structure is required to store additional
  * options from the command line modline like the force-enable/disable flag.
  *
@@ -1581,9 +1650,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 {
 	const char *name;
 	bool named_mode = false, parse_extras = false;
-	unsigned int bpp_off = 0, refresh_off = 0;
+	unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
 	unsigned int mode_end = 0;
 	char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
+	char *options_ptr = NULL;
 	char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
 	int ret;
 
@@ -1632,13 +1702,18 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 		mode->refresh_specified = true;
 	}
 
+	/* Locate the start of named options */
+	options_ptr = strchr(name, ',');
+	if (options_ptr)
+		options_off = options_ptr - name;
+
 	/* 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) {
+	if (bpp_ptr) {
 		mode_end = bpp_off;
 	} else if (refresh_ptr) {
 		mode_end = refresh_off;
+	} else if (options_ptr) {
+		mode_end = options_off;
 	} else {
 		mode_end = strlen(name);
 		parse_extras = true;
@@ -1680,24 +1755,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 	else if (refresh_ptr)
 		extra_ptr = refresh_end_ptr;
 
-	if (extra_ptr) {
-		if (!named_mode) {
-			int len = strlen(name) - (extra_ptr - name);
+	if (extra_ptr &&
+	    extra_ptr != options_ptr) {
+		int len = strlen(name) - (extra_ptr - name);
 
-			ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
-							   connector, mode);
-			if (ret)
-				return false;
-		} else {
-			int remaining = strlen(name) - (extra_ptr - name);
+		ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
+						   connector, mode);
+		if (ret)
+			return false;
+	}
 
-			/*
-			 * We still have characters to process, while
-			 * we shouldn't have any
-			 */
-			if (remaining > 0)
-				return false;
-		}
+	if (options_ptr) {
+		int len = strlen(name) - (options_ptr - name);
+
+		ret = drm_mode_parse_cmdline_options(options_ptr, len,
+						     connector, mode);
+		if (ret)
+			return false;
 	}
 
 	return true;
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index cdf2fb910010..8eebe0432c73 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1025,6 +1025,16 @@ struct drm_cmdline_mode {
 	 * state to one of the DRM_FORCE_* values.
 	 */
 	enum drm_connector_force force;
+
+	/**
+	 * @rotation_reflection:
+	 *
+	 * Initial rotation and reflection of the mode setup from the
+	 * command line. See DRM_MODE_ROTATE_* and
+	 * DRM_MODE_REFLECT_*. The only rotations supported are
+	 * DRM_MODE_ROTATE_0 and DRM_MODE_ROTATE_180.
+	 */
+	unsigned int rotation_reflection;
 };
 
 /**
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v5 08/12] drm/connector: Introduce a TV margins structure
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
                   ` (6 preceding siblings ...)
  2019-06-17 14:51 ` [PATCH v5 07/12] drm/modes: Allow to specify rotation and reflection on the commandline Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 09/12] drm/modes: Parse overscan properties Maxime Ripard
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, linux-arm-kernel

The TV margins has been defined as a structure inside the
drm_connector_state structure so far. However, we will need it in other
structures as well, so let's move that structure definition so that it can
be reused.

Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 include/drm/drm_connector.h | 41 +++++++++++++++++++++++++++-----------
 1 file changed, 30 insertions(+), 11 deletions(-)

diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 8eebe0432c73..b22e3150e33d 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -464,13 +464,37 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
 				     unsigned int num_formats);
 
 /**
+ * struct drm_connector_tv_margins - TV connector related margins
+ *
+ * Describes the margins in pixels to put around the image on TV
+ * connectors to deal with overscan.
+ */
+struct drm_connector_tv_margins {
+	/**
+	 * @bottom: Bottom margin in pixels.
+	 */
+	unsigned int bottom;
+
+	/**
+	 * @left: Left margin in pixels.
+	 */
+	unsigned int left;
+
+	/**
+	 * @right: Right margin in pixels.
+	 */
+	unsigned int right;
+
+	/**
+	 * @top: Top margin in pixels.
+	 */
+	unsigned int top;
+};
+
+/**
  * struct drm_tv_connector_state - TV connector related states
  * @subconnector: selected subconnector
- * @margins: margins (all margins are expressed in pixels)
- * @margins.left: left margin
- * @margins.right: right margin
- * @margins.top: top margin
- * @margins.bottom: bottom margin
+ * @margins: TV margins
  * @mode: TV mode
  * @brightness: brightness in percent
  * @contrast: contrast in percent
@@ -481,12 +505,7 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
  */
 struct drm_tv_connector_state {
 	enum drm_mode_subconnector subconnector;
-	struct {
-		unsigned int left;
-		unsigned int right;
-		unsigned int top;
-		unsigned int bottom;
-	} margins;
+	struct drm_connector_tv_margins margins;
 	unsigned int mode;
 	unsigned int brightness;
 	unsigned int contrast;
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v5 09/12] drm/modes: Parse overscan properties
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
                   ` (7 preceding siblings ...)
  2019-06-17 14:51 ` [PATCH v5 08/12] drm/connector: Introduce a TV margins structure Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 10/12] drm/atomic: Add a function to reset connector TV properties Maxime Ripard
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, linux-arm-kernel

Properly configuring the overscan properties might be needed for the
initial setup of the framebuffer for display that still have overscan.
Let's allow for more properties on the kernel command line to setup each
margin.

Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 Documentation/fb/modedb.rst |  2 ++-
 drivers/gpu/drm/drm_modes.c | 44 ++++++++++++++++++++++++++++++++++++++-
 include/drm/drm_connector.h |  5 ++++-
 3 files changed, 51 insertions(+)

diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst
index 3e8a6f79dcd7..444bc329e5a8 100644
--- a/Documentation/fb/modedb.rst
+++ b/Documentation/fb/modedb.rst
@@ -59,6 +59,8 @@ Options can also be passed after the mode, using commas as separator.
 
 Valid options are:
 
+  - margin_top, margin_bottom, margin_left, margin_right (integer):
+    Number of pixels in the margins, typically to deal with overscan on TVs
   - reflect_x (boolean): Perform an axial symetry on the X axis
   - reflect_y (boolean): Perform an axial symetry on the Y axis
   - rotate (integer): Rotate the initial framebuffer by x
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index dc6d11292685..57e6408288c8 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1609,6 +1609,50 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
 		} else if (!strncmp(option, "reflect_y", delim - option)) {
 			rotation |= DRM_MODE_REFLECT_Y;
 			sep = delim;
+		} else if (!strncmp(option, "margin_right", delim - option)) {
+			const char *value = delim + 1;
+			unsigned int margin;
+
+			margin = simple_strtol(value, &sep, 10);
+
+			/* Make sure we have parsed something */
+			if (sep == value)
+				return -EINVAL;
+
+			mode->tv_margins.right = margin;
+		} else if (!strncmp(option, "margin_left", delim - option)) {
+			const char *value = delim + 1;
+			unsigned int margin;
+
+			margin = simple_strtol(value, &sep, 10);
+
+			/* Make sure we have parsed something */
+			if (sep == value)
+				return -EINVAL;
+
+			mode->tv_margins.left = margin;
+		} else if (!strncmp(option, "margin_top", delim - option)) {
+			const char *value = delim + 1;
+			unsigned int margin;
+
+			margin = simple_strtol(value, &sep, 10);
+
+			/* Make sure we have parsed something */
+			if (sep == value)
+				return -EINVAL;
+
+			mode->tv_margins.top = margin;
+		} else if (!strncmp(option, "margin_bottom", delim - option)) {
+			const char *value = delim + 1;
+			unsigned int margin;
+
+			margin = simple_strtol(value, &sep, 10);
+
+			/* Make sure we have parsed something */
+			if (sep == value)
+				return -EINVAL;
+
+			mode->tv_margins.bottom = margin;
 		} else {
 			return -EINVAL;
 		}
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index b22e3150e33d..ca745d9feaf5 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1054,6 +1054,11 @@ struct drm_cmdline_mode {
 	 * DRM_MODE_ROTATE_0 and DRM_MODE_ROTATE_180.
 	 */
 	unsigned int rotation_reflection;
+
+	/**
+	 * @tv_margins: TV margins to apply to the mode.
+	 */
+	struct drm_connector_tv_margins tv_margins;
 };
 
 /**
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v5 10/12] drm/atomic: Add a function to reset connector TV properties
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
                   ` (8 preceding siblings ...)
  2019-06-17 14:51 ` [PATCH v5 09/12] drm/modes: Parse overscan properties Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 11/12] drm/selftests: Add command line parser selftests Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 12/12] drm/vc4: hdmi: Set default state margin at reset Maxime Ripard
  11 siblings, 0 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, linux-arm-kernel

During the connector reset, if that connector has a TV property, it needs
to be reset to the value provided on the command line.

Provide a helper to do that.

Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 drivers/gpu/drm/drm_atomic_state_helper.c | 18 ++++++++++++++++++
 include/drm/drm_atomic_state_helper.h     |  1 +
 2 files changed, 19 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index 7d7347a6f194..46dc264a248b 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -380,6 +380,24 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector)
 EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
 
 /**
+ * drm_atomic_helper_connector_tv_reset - Resets TV connector properties
+ * @connector: DRM connector
+ *
+ * Resets the TV-related properties attached to a connector.
+ */
+void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
+{
+	struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
+	struct drm_connector_state *state = connector->state;
+
+	state->tv.margins.left = cmdline->tv_margins.left;
+	state->tv.margins.right = cmdline->tv_margins.right;
+	state->tv.margins.top = cmdline->tv_margins.top;
+	state->tv.margins.bottom = cmdline->tv_margins.bottom;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
+
+/**
  * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
  * @connector: connector object
  * @state: atomic connector state
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index 4e6d2e7a40b8..e4577cc11689 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -62,6 +62,7 @@ void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
 void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
 					 struct drm_connector_state *conn_state);
 void drm_atomic_helper_connector_reset(struct drm_connector *connector);
+void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector);
 void
 __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
 					   struct drm_connector_state *state);
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v5 11/12] drm/selftests: Add command line parser selftests
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
                   ` (9 preceding siblings ...)
  2019-06-17 14:51 ` [PATCH v5 10/12] drm/atomic: Add a function to reset connector TV properties Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-06-17 14:51 ` [PATCH v5 12/12] drm/vc4: hdmi: Set default state margin at reset Maxime Ripard
  11 siblings, 0 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, linux-arm-kernel

The command line parser is pretty tough to get right and very error prone,
so let's add a selftest to try to catch any regression.

Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 drivers/gpu/drm/selftests/Makefile                  |   2 +-
 drivers/gpu/drm/selftests/drm_cmdline_selftests.h   |  55 +-
 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c | 918 +++++++++++++-
 3 files changed, 974 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h
 create mode 100644 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 8ec64ecf0e36..aae88f8a016c 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -3,4 +3,4 @@ test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \
                       test-drm_format.o test-drm_framebuffer.o \
 		      test-drm_damage_helper.o
 
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
+obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o test-drm_cmdline_parser.o
diff --git a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
new file mode 100644
index 000000000000..b45824ec7c8f
--- /dev/null
+++ b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* List each unit test as selftest(function)
+ *
+ * The name is used as both an enum and expanded as igt__name to create
+ * a module parameter. It must be unique and legal for a C identifier.
+ *
+ * Tests are executed in order by igt/drm_mm
+ */
+
+#define cmdline_test(test)	selftest(test, test)
+
+cmdline_test(drm_cmdline_test_res)
+cmdline_test(drm_cmdline_test_res_missing_x)
+cmdline_test(drm_cmdline_test_res_missing_y)
+cmdline_test(drm_cmdline_test_res_bad_y)
+cmdline_test(drm_cmdline_test_res_missing_y_bpp)
+cmdline_test(drm_cmdline_test_res_vesa)
+cmdline_test(drm_cmdline_test_res_vesa_rblank)
+cmdline_test(drm_cmdline_test_res_rblank)
+cmdline_test(drm_cmdline_test_res_bpp)
+cmdline_test(drm_cmdline_test_res_bad_bpp)
+cmdline_test(drm_cmdline_test_res_refresh)
+cmdline_test(drm_cmdline_test_res_bad_refresh)
+cmdline_test(drm_cmdline_test_res_bpp_refresh)
+cmdline_test(drm_cmdline_test_res_bpp_refresh_interlaced)
+cmdline_test(drm_cmdline_test_res_bpp_refresh_margins)
+cmdline_test(drm_cmdline_test_res_bpp_refresh_force_off)
+cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_off)
+cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on)
+cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_analog)
+cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_digital)
+cmdline_test(drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on)
+cmdline_test(drm_cmdline_test_res_margins_force_on)
+cmdline_test(drm_cmdline_test_res_vesa_margins)
+cmdline_test(drm_cmdline_test_res_invalid_mode)
+cmdline_test(drm_cmdline_test_res_bpp_wrong_place_mode)
+cmdline_test(drm_cmdline_test_name)
+cmdline_test(drm_cmdline_test_name_bpp)
+cmdline_test(drm_cmdline_test_name_refresh)
+cmdline_test(drm_cmdline_test_name_bpp_refresh)
+cmdline_test(drm_cmdline_test_name_refresh_wrong_mode)
+cmdline_test(drm_cmdline_test_name_refresh_invalid_mode)
+cmdline_test(drm_cmdline_test_name_option)
+cmdline_test(drm_cmdline_test_name_bpp_option)
+cmdline_test(drm_cmdline_test_rotate_0)
+cmdline_test(drm_cmdline_test_rotate_90)
+cmdline_test(drm_cmdline_test_rotate_180)
+cmdline_test(drm_cmdline_test_rotate_270)
+cmdline_test(drm_cmdline_test_rotate_invalid_val)
+cmdline_test(drm_cmdline_test_rotate_truncated)
+cmdline_test(drm_cmdline_test_hmirror)
+cmdline_test(drm_cmdline_test_vmirror)
+cmdline_test(drm_cmdline_test_margin_options)
+cmdline_test(drm_cmdline_test_multiple_options)
+cmdline_test(drm_cmdline_test_invalid_option)
diff --git a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
new file mode 100644
index 000000000000..bef4edde6f9f
--- /dev/null
+++ b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
@@ -0,0 +1,918 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Bootlin
+ */
+
+#define pr_fmt(fmt) "drm_cmdline: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <drm/drm_connector.h>
+#include <drm/drm_modes.h>
+
+#define TESTS "drm_cmdline_selftests.h"
+#include "drm_selftest.h"
+#include "test-drm_modeset_common.h"
+
+static int drm_cmdline_test_res(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_missing_x(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("x480",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_missing_y(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("1024x",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bad_y(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("1024xtest",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_missing_y_bpp(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("1024x-24",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_vesa(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480M",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(!mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_vesa_rblank(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480MR",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(!mode.rb);
+	FAIL_ON(!mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_rblank(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480R",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(!mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bpp(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(!mode.bpp_specified);
+	FAIL_ON(mode.bpp != 24);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bad_bpp(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-test",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_refresh(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480@60",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(!mode.refresh_specified);
+	FAIL_ON(mode.refresh != 60);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bad_refresh(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480@refresh",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bpp_refresh(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(!mode.refresh_specified);
+	FAIL_ON(mode.refresh != 60);
+
+	FAIL_ON(!mode.bpp_specified);
+	FAIL_ON(mode.bpp != 24);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bpp_refresh_interlaced(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60i",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(!mode.refresh_specified);
+	FAIL_ON(mode.refresh != 60);
+
+	FAIL_ON(!mode.bpp_specified);
+	FAIL_ON(mode.bpp != 24);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(!mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bpp_refresh_margins(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60m",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(!mode.refresh_specified);
+	FAIL_ON(mode.refresh != 60);
+
+	FAIL_ON(!mode.bpp_specified);
+	FAIL_ON(mode.bpp != 24);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(!mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bpp_refresh_force_off(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60d",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(!mode.refresh_specified);
+	FAIL_ON(mode.refresh != 60);
+
+	FAIL_ON(!mode.bpp_specified);
+	FAIL_ON(mode.bpp != 24);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_OFF);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bpp_refresh_force_on_off(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-24@60de",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bpp_refresh_force_on(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60e",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(!mode.refresh_specified);
+	FAIL_ON(mode.refresh != 60);
+
+	FAIL_ON(!mode.bpp_specified);
+	FAIL_ON(mode.bpp != 24);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_ON);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bpp_refresh_force_on_analog(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(!mode.refresh_specified);
+	FAIL_ON(mode.refresh != 60);
+
+	FAIL_ON(!mode.bpp_specified);
+	FAIL_ON(mode.bpp != 24);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_ON);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bpp_refresh_force_on_digital(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	connector.connector_type = DRM_MODE_CONNECTOR_DVII;
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(!mode.refresh_specified);
+	FAIL_ON(mode.refresh != 60);
+
+	FAIL_ON(!mode.bpp_specified);
+	FAIL_ON(mode.bpp != 24);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60ime",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(!mode.refresh_specified);
+	FAIL_ON(mode.refresh != 60);
+
+	FAIL_ON(!mode.bpp_specified);
+	FAIL_ON(mode.bpp != 24);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(!mode.interlace);
+	FAIL_ON(!mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_ON);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_margins_force_on(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480me",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(!mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_ON);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_vesa_margins(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480Mm",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(!mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(!mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_invalid_mode(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480f",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_res_bpp_wrong_place_mode(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480e-24",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_name(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC",
+							   &connector,
+							   &mode));
+	FAIL_ON(strcmp(mode.name, "NTSC"));
+	FAIL_ON(mode.refresh_specified);
+	FAIL_ON(mode.bpp_specified);
+
+	return 0;
+}
+
+static int drm_cmdline_test_name_bpp(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24",
+							   &connector,
+							   &mode));
+	FAIL_ON(strcmp(mode.name, "NTSC"));
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(!mode.bpp_specified);
+	FAIL_ON(mode.bpp != 24);
+
+	return 0;
+}
+
+static int drm_cmdline_test_name_bpp_refresh(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC-24@60",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_name_refresh(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_name_refresh_wrong_mode(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60m",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_name_refresh_invalid_mode(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60f",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_name_option(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC,rotate=180",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(strcmp(mode.name, "NTSC"));
+	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
+
+	return 0;
+}
+
+static int drm_cmdline_test_name_bpp_option(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24,rotate=180",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(strcmp(mode.name, "NTSC"));
+	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
+	FAIL_ON(!mode.bpp_specified);
+	FAIL_ON(mode.bpp != 24);
+
+	return 0;
+}
+
+static int drm_cmdline_test_rotate_0(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=0",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_0);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_rotate_90(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=90",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_90);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_rotate_180(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=180",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_rotate_270(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_270);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_rotate_invalid_val(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=42",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_rotate_truncated(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+static int drm_cmdline_test_hmirror(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_x",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+	FAIL_ON(mode.rotation_reflection != DRM_MODE_REFLECT_X);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_vmirror(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_y",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+	FAIL_ON(mode.rotation_reflection != DRM_MODE_REFLECT_Y);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_margin_options(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+	FAIL_ON(mode.tv_margins.right != 14);
+	FAIL_ON(mode.tv_margins.left != 24);
+	FAIL_ON(mode.tv_margins.bottom != 36);
+	FAIL_ON(mode.tv_margins.top != 42);
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_multiple_options(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270,reflect_x",
+							   &connector,
+							   &mode));
+	FAIL_ON(!mode.specified);
+	FAIL_ON(mode.xres != 720);
+	FAIL_ON(mode.yres != 480);
+	FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X));
+
+	FAIL_ON(mode.refresh_specified);
+
+	FAIL_ON(mode.bpp_specified);
+
+	FAIL_ON(mode.rb);
+	FAIL_ON(mode.cvt);
+	FAIL_ON(mode.interlace);
+	FAIL_ON(mode.margins);
+	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+
+	return 0;
+}
+
+static int drm_cmdline_test_invalid_option(void *ignored)
+{
+	struct drm_connector connector = { };
+	struct drm_cmdline_mode mode = { };
+
+	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,test=42",
+							  &connector,
+							  &mode));
+
+	return 0;
+}
+
+#include "drm_selftest.c"
+
+static int __init test_drm_cmdline_init(void)
+{
+	int err;
+
+	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
+
+	return err > 0 ? 0 : err;
+}
+module_init(test_drm_cmdline_init);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
+MODULE_LICENSE("GPL");
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v5 12/12] drm/vc4: hdmi: Set default state margin at reset
  2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
                   ` (10 preceding siblings ...)
  2019-06-17 14:51 ` [PATCH v5 11/12] drm/selftests: Add command line parser selftests Maxime Ripard
@ 2019-06-17 14:51 ` Maxime Ripard
  2019-06-17 18:06   ` Eric Anholt
  11 siblings, 1 reply; 28+ messages in thread
From: Maxime Ripard @ 2019-06-17 14:51 UTC (permalink / raw)
  To: Maarten Lankhorst, Sean Paul, Maxime Ripard, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt, noralf,
	Thomas Petazzoni, linux-arm-kernel

Now that the TV margins are properly parsed and filled into
drm_cmdline_mode, we just need to initialise the first state at reset to
get those values and start using them.

Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 drivers/gpu/drm/vc4/vc4_hdmi.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 6beac1ca1f27..4a9c8c9fe2b1 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -258,11 +258,17 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
 	return ret;
 }
 
+static void vc4_hdmi_connector_reset(struct drm_connector *connector)
+{
+	drm_atomic_helper_connector_reset(connector);
+	drm_atomic_helper_connector_tv_reset(connector);
+}
+
 static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
 	.detect = vc4_hdmi_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.destroy = vc4_hdmi_connector_destroy,
-	.reset = drm_atomic_helper_connector_reset,
+	.reset = vc4_hdmi_connector_reset,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH v5 12/12] drm/vc4: hdmi: Set default state margin at reset
  2019-06-17 14:51 ` [PATCH v5 12/12] drm/vc4: hdmi: Set default state margin at reset Maxime Ripard
@ 2019-06-17 18:06   ` Eric Anholt
  0 siblings, 0 replies; 28+ messages in thread
From: Eric Anholt @ 2019-06-17 18:06 UTC (permalink / raw)
  To: Maxime Ripard, Maarten Lankhorst, Sean Paul, Maxime Ripard,
	Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, noralf, Thomas Petazzoni,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 393 bytes --]

Maxime Ripard <maxime.ripard@bootlin.com> writes:

> Now that the TV margins are properly parsed and filled into
> drm_cmdline_mode, we just need to initialise the first state at reset to
> get those values and start using them.
>
> Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>

Acked-by: Eric Anholt <eric@anholt.net>

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5 07/12] drm/modes: Allow to specify rotation and reflection on the commandline
  2019-06-17 14:51 ` [PATCH v5 07/12] drm/modes: Allow to specify rotation and reflection on the commandline Maxime Ripard
@ 2019-06-18 17:47   ` Noralf Trønnes
  2019-06-19 10:16     ` Maxime Ripard
  0 siblings, 1 reply; 28+ messages in thread
From: Noralf Trønnes @ 2019-06-18 17:47 UTC (permalink / raw)
  To: Maxime Ripard, Maarten Lankhorst, Sean Paul, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Eric Anholt,
	Thomas Petazzoni, linux-arm-kernel



Den 17.06.2019 16.51, skrev Maxime Ripard:
> Rotations and reflections setup are needed in some scenarios to initialise
> properly the initial framebuffer. Some drivers already had a bunch of
> quirks to deal with this, such as either a private kernel command line
> parameter (omapdss) or on the device tree (various panels).
> 
> In order to accomodate this, let's create a video mode parameter to deal
> with the rotation and reflexion.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
> ---
>  Documentation/fb/modedb.rst          |  11 +++-
>  drivers/gpu/drm/drm_client_modeset.c |  30 +++++++-
>  drivers/gpu/drm/drm_modes.c          | 114 +++++++++++++++++++++++-----
>  include/drm/drm_connector.h          |  10 ++-
>  4 files changed, 145 insertions(+), 20 deletions(-)
> 
> diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst
> index 3c2397293977..3e8a6f79dcd7 100644
> --- a/Documentation/fb/modedb.rst
> +++ b/Documentation/fb/modedb.rst
> @@ -53,6 +53,17 @@ Specifying the option multiple times for different ports is possible, e.g.::
>  
>      video=LVDS-1:d video=HDMI-1:D
>  
> +Options can also be passed after the mode, using commas as separator.
> +
> +       Sample usage: 720x480,rotate=180 - 720x480 mode, rotated by 180 degrees
> +
> +Valid options are:
> +
> +  - reflect_x (boolean): Perform an axial symetry on the X axis
> +  - reflect_y (boolean): Perform an axial symetry on the Y axis

2x s/symetry/symmetry/

Reviewed-by: Noralf Trønnes <noralf@tronnes.org>

> +  - rotate (integer): Rotate the initial framebuffer by x
> +    degrees. Valid values are 0, 90, 180 and 270.
> +
>  -----------------------------------------------------------------------------
>  
>  What is the VESA(TM) Coordinated Video Timings (CVT)?
> diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
> index 33d4988f22ae..e95fceac8f8b 100644
> --- a/drivers/gpu/drm/drm_client_modeset.c
> +++ b/drivers/gpu/drm/drm_client_modeset.c
> @@ -824,6 +824,7 @@ bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
>  {
>  	struct drm_connector *connector = modeset->connectors[0];
>  	struct drm_plane *plane = modeset->crtc->primary;
> +	struct drm_cmdline_mode *cmdline;
>  	u64 valid_mask = 0;
>  	unsigned int i;
>  
> @@ -844,6 +845,35 @@ bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
>  		*rotation = DRM_MODE_ROTATE_0;
>  	}
>  
> +	/**
> +	 * The panel already defined the default rotation
> +	 * through its orientation. Whatever has been provided
> +	 * on the command line needs to be added to that.
> +	 *
> +	 * Unfortunately, the rotations are at different bit
> +	 * indices, so the math to add them up are not as
> +	 * trivial as they could.
> +	 *
> +	 * Reflections on the other hand are pretty trivial to deal with, a
> +	 * simple XOR between the two handle the addition nicely.
> +	 */
> +	cmdline = &connector->cmdline_mode;
> +	if (cmdline->specified) {
> +		unsigned int cmdline_rest, panel_rest;
> +		unsigned int cmdline_rot, panel_rot;
> +		unsigned int sum_rot, sum_rest;
> +
> +		panel_rot = ilog2(*rotation & DRM_MODE_ROTATE_MASK);
> +		cmdline_rot = ilog2(cmdline->rotation_reflection & DRM_MODE_ROTATE_MASK);
> +		sum_rot = (panel_rot + cmdline_rot) % 4;
> +
> +		panel_rest = *rotation & ~DRM_MODE_ROTATE_MASK;
> +		cmdline_rest = cmdline->rotation_reflection & ~DRM_MODE_ROTATE_MASK;
> +		sum_rest = panel_rest ^ cmdline_rest;
> +
> +		*rotation = (1 << sum_rot) | sum_rest;
> +	}
> +
>  	/*
>  	 * TODO: support 90 / 270 degree hardware rotation,
>  	 * depending on the hardware this may require the framebuffer
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index 429d3be17800..dc6d11292685 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -1554,6 +1554,71 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
>  	return 0;
>  }
>  
> +static int drm_mode_parse_cmdline_options(char *str, size_t len,
> +					  struct drm_connector *connector,
> +					  struct drm_cmdline_mode *mode)
> +{
> +	unsigned int rotation = 0;
> +	char *sep = str;
> +
> +	while ((sep = strchr(sep, ','))) {
> +		char *delim, *option;
> +
> +		option = sep + 1;
> +		delim = strchr(option, '=');
> +		if (!delim) {
> +			delim = strchr(option, ',');
> +
> +			if (!delim)
> +				delim = str + len;
> +		}
> +
> +		if (!strncmp(option, "rotate", delim - option)) {
> +			const char *value = delim + 1;
> +			unsigned int deg;
> +
> +			deg = simple_strtol(value, &sep, 10);
> +
> +			/* Make sure we have parsed something */
> +			if (sep == value)
> +				return -EINVAL;
> +
> +			switch (deg) {
> +			case 0:
> +				rotation |= DRM_MODE_ROTATE_0;
> +				break;
> +
> +			case 90:
> +				rotation |= DRM_MODE_ROTATE_90;
> +				break;
> +
> +			case 180:
> +				rotation |= DRM_MODE_ROTATE_180;
> +				break;
> +
> +			case 270:
> +				rotation |= DRM_MODE_ROTATE_270;
> +				break;
> +
> +			default:
> +				return -EINVAL;
> +			}
> +		} else if (!strncmp(option, "reflect_x", delim - option)) {
> +			rotation |= DRM_MODE_REFLECT_X;
> +			sep = delim;
> +		} else if (!strncmp(option, "reflect_y", delim - option)) {
> +			rotation |= DRM_MODE_REFLECT_Y;
> +			sep = delim;
> +		} else {
> +			return -EINVAL;
> +		}
> +	}
> +
> +	mode->rotation_reflection = rotation;
> +
> +	return 0;
> +}
> +
>  /**
>   * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
>   * @mode_option: optional per connector mode option
> @@ -1569,6 +1634,10 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
>   *
>   *	<xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
>   *
> + * Additionals options can be provided following the mode, using a comma to
> + * separate each option. Valid options can be found in
> + * Documentation/fb/modedb.txt.
> + *
>   * The intermediate drm_cmdline_mode structure is required to store additional
>   * options from the command line modline like the force-enable/disable flag.
>   *
> @@ -1581,9 +1650,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>  {
>  	const char *name;
>  	bool named_mode = false, parse_extras = false;
> -	unsigned int bpp_off = 0, refresh_off = 0;
> +	unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
>  	unsigned int mode_end = 0;
>  	char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
> +	char *options_ptr = NULL;
>  	char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
>  	int ret;
>  
> @@ -1632,13 +1702,18 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>  		mode->refresh_specified = true;
>  	}
>  
> +	/* Locate the start of named options */
> +	options_ptr = strchr(name, ',');
> +	if (options_ptr)
> +		options_off = options_ptr - name;
> +
>  	/* 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) {
> +	if (bpp_ptr) {
>  		mode_end = bpp_off;
>  	} else if (refresh_ptr) {
>  		mode_end = refresh_off;
> +	} else if (options_ptr) {
> +		mode_end = options_off;
>  	} else {
>  		mode_end = strlen(name);
>  		parse_extras = true;
> @@ -1680,24 +1755,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>  	else if (refresh_ptr)
>  		extra_ptr = refresh_end_ptr;
>  
> -	if (extra_ptr) {
> -		if (!named_mode) {
> -			int len = strlen(name) - (extra_ptr - name);
> +	if (extra_ptr &&
> +	    extra_ptr != options_ptr) {
> +		int len = strlen(name) - (extra_ptr - name);
>  
> -			ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
> -							   connector, mode);
> -			if (ret)
> -				return false;
> -		} else {
> -			int remaining = strlen(name) - (extra_ptr - name);
> +		ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
> +						   connector, mode);
> +		if (ret)
> +			return false;
> +	}
>  
> -			/*
> -			 * We still have characters to process, while
> -			 * we shouldn't have any
> -			 */
> -			if (remaining > 0)
> -				return false;
> -		}
> +	if (options_ptr) {
> +		int len = strlen(name) - (options_ptr - name);
> +
> +		ret = drm_mode_parse_cmdline_options(options_ptr, len,
> +						     connector, mode);
> +		if (ret)
> +			return false;
>  	}
>  
>  	return true;
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index cdf2fb910010..8eebe0432c73 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -1025,6 +1025,16 @@ struct drm_cmdline_mode {
>  	 * state to one of the DRM_FORCE_* values.
>  	 */
>  	enum drm_connector_force force;
> +
> +	/**
> +	 * @rotation_reflection:
> +	 *
> +	 * Initial rotation and reflection of the mode setup from the
> +	 * command line. See DRM_MODE_ROTATE_* and
> +	 * DRM_MODE_REFLECT_*. The only rotations supported are
> +	 * DRM_MODE_ROTATE_0 and DRM_MODE_ROTATE_180.
> +	 */
> +	unsigned int rotation_reflection;
>  };
>  
>  /**
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5 07/12] drm/modes: Allow to specify rotation and reflection on the commandline
  2019-06-18 17:47   ` Noralf Trønnes
@ 2019-06-19 10:16     ` Maxime Ripard
  0 siblings, 0 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-19 10:16 UTC (permalink / raw)
  To: Noralf Trønnes
  Cc: eben, David Airlie, Maarten Lankhorst, dri-devel,
	Paul Kocialkowski, Eric Anholt, Sean Paul, Thomas Petazzoni,
	Daniel Vetter, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 999 bytes --]

On Tue, Jun 18, 2019 at 07:47:04PM +0200, Noralf Trønnes wrote:
> > diff --git a/Documentation/fb/modedb.rst b/Documentation/fb/modedb.rst
> > index 3c2397293977..3e8a6f79dcd7 100644
> > --- a/Documentation/fb/modedb.rst
> > +++ b/Documentation/fb/modedb.rst
> > @@ -53,6 +53,17 @@ Specifying the option multiple times for different ports is possible, e.g.::
> >
> >      video=LVDS-1:d video=HDMI-1:D
> >
> > +Options can also be passed after the mode, using commas as separator.
> > +
> > +       Sample usage: 720x480,rotate=180 - 720x480 mode, rotated by 180 degrees
> > +
> > +Valid options are:
> > +
> > +  - reflect_x (boolean): Perform an axial symetry on the X axis
> > +  - reflect_y (boolean): Perform an axial symetry on the Y axis
>
> 2x s/symetry/symmetry/
>
> Reviewed-by: Noralf Trønnes <noralf@tronnes.org>

I've fixed it and applied, thanks for your reviews!
Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5 06/12] drm/modes: Support modes names on the command line
  2019-06-17 14:51 ` [PATCH v5 06/12] drm/modes: Support modes names on the command line Maxime Ripard
@ 2019-06-26 15:26   ` Thierry Reding
  2019-06-28 13:43     ` Maxime Ripard
  0 siblings, 1 reply; 28+ messages in thread
From: Thierry Reding @ 2019-06-26 15:26 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: eben, David Airlie, Maarten Lankhorst, dri-devel,
	Paul Kocialkowski, Sean Paul, Thomas Petazzoni, Daniel Vetter,
	Maxime Ripard, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 10840 bytes --]

On Mon, Jun 17, 2019 at 04:51:33PM +0200, Maxime Ripard wrote:
> From: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
> The drm subsystem also uses the video= kernel parameter, and in the
> documentation refers to the fbdev documentation for that parameter.
> 
> However, that documentation also says that instead of giving the mode using
> its resolution we can also give a name. However, DRM doesn't handle that
> case at the moment. Even though in most case it shouldn't make any
> difference, it might be useful for analog modes, where different standards
> might have the same resolution, but still have a few different parameters
> that are not encoded in the modes (NTSC vs NTSC-J vs PAL-M for example).
> 
> Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/drm_client_modeset.c |  4 ++-
>  drivers/gpu/drm/drm_connector.c      |  3 +-
>  drivers/gpu/drm/drm_modes.c          | 62 +++++++++++++++++++++--------
>  include/drm/drm_connector.h          |  7 +++-
>  4 files changed, 59 insertions(+), 17 deletions(-)

This patch causes an issue on various Tegra boards that have so far been
running flawlessly. Here's an extract from the boot log:

	[    0.000000] Kernel command line: root=/dev/nfs rw netdevwait ip=:::::eth0:on nfsroot=192.168.23.1:/srv/nfs/tegra194 console=ttyTCU0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 rootfstype=ext4 video=tegrafb no_console_suspend=1 earlycon=tegra_comb_uart,mmio32,0x0c168000 gpt usbcore.old_scheme_first=1 tegraid=19.1.2.0.0 maxcpus=8 boot.slot_suffix= boot.ratchetvalues=0.2.2 vpr=0x8000000@0xf0000000 sdhci_tegra.en_boot_part_access=1
	...
	[   18.597001] [drm:drm_connector_init [drm]] cmdline mode for connector DP-1 tegrafb 0x0@60Hz
	...
	[   18.627145] [drm:drm_connector_init [drm]] cmdline mode for connector DP-2 tegrafb 0x0@60Hz
	...
	[   18.673770] [drm:drm_connector_init [drm]] cmdline mode for connector HDMI-A-1 tegrafb 0x0@60Hz
	...
	[   19.057500] [drm:drm_mode_debug_printmodeline [drm]] Modeline "0x0": 0 0 0 0 0 0 0 1 4 1 0x20 0x6
	[   19.066341] [drm:drm_mode_prune_invalid [drm]] Not using 0x0 mode: CLOCK_LOW
	...
	[   19.677803] [drm:drm_client_modeset_probe [drm]] looking for cmdline mode on connector 60
	[   19.686019] [drm:drm_client_modeset_probe [drm]] found mode 0x0
	...
	[   19.851843] drm drm: failed to set initial configuration: -28

So basically what's happening here is that the bootloader is passing a
video= parameter on the command-line and after this patch, the DRM core
will consider the tegrafb in that parameter to be a named video mode.
The mode is then filtered out because it doesn't make any sense, but
then drm_client_modeset_probe() still tries to use it, eventually
leading to failure because we can't allocate memory for a 0x0
framebuffer.

Now, there are obviously a couple of places where things go wrong. On
one hand I think if the mode specified on the command-line is already
filtered out, then drm_client_modeset_probe() should not be trying to
use it.

One could also argue that the bootloader shouldn't be passing that
video=tegrafb parameter in the first place. Then again, this is nothing
out of the ordinary (as documented in Documentation/fb/modedb.rst).

The problem with named modes, and you already highlighted this in your
comment in the code, is that it's not possible to distinguish between a
mode name and a video= option that defines the framebuffer device to
use.

That said, I wouldn't be surprised if this change ended up breaking on
other devices. I'm also not sure that under these circumstances it's a
good idea to support named modes. At least not until we have a better
way of determining what's a real mode name and what isn't. Looking at
the old modedb from fb, not even the standard modes listed there have
names associated with them, so I'm not sure how this was ever supposed
to work. From the looks of it, some of the fbdev drivers seem to take a
mode list from board-code (see for example the mx21ads_modes array from
arch/arm/mach-imx/mach-mx21ads.c). The imxfb driver can then take a mode
name from the command line and try to match it against a list of known
modes. That seems to match what the documentation says.

However, that also really only works because this is all directly dealt
with in the fbdev drivers. For DRM/KMS we don't do that and instead we
rely on the core to provide this backwards-compatibility. However, at
the time when we parse the mode from the command line we don't have the
list of modes that are considered to be valid, so your patch currently
needs to assume that it is a valid mode. I don't think that's a good
idea, because clearly not all strings that currently make it through the
filter are actually modes.

So if we really need this, I think we want some way for the connector to
provide the list of named modes that it supports so that by the time we
want to parse the command-line we can check whether it's actually a name
to avoid false positives like the ones I'm seeing on Tegra.

For now it might just be easiest to avoid any of this and disable the
named mode support until it's a bit more mature. The patch no longer
reverts cleanly, but it should be fairly easy to disable the feature in
a follow-up patch again.

Thierry

> diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
> index 4869a0170bec..33d4988f22ae 100644
> --- a/drivers/gpu/drm/drm_client_modeset.c
> +++ b/drivers/gpu/drm/drm_client_modeset.c
> @@ -149,6 +149,10 @@ drm_connector_pick_cmdline_mode(struct drm_connector *connector)
>  	prefer_non_interlace = !cmdline_mode->interlace;
>  again:
>  	list_for_each_entry(mode, &connector->modes, head) {
> +		/* Check (optional) mode name first */
> +		if (!strcmp(mode->name, cmdline_mode->name))
> +			return mode;
> +
>  		/* check width/height */
>  		if (mode->hdisplay != cmdline_mode->xres ||
>  		    mode->vdisplay != cmdline_mode->yres)
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 3ccdcf3dfcde..3afed5677946 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -139,8 +139,9 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
>  		connector->force = mode->force;
>  	}
>  
> -	DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
> +	DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
>  		      connector->name,
> +		      mode->name ? mode->name : "",
>  		      mode->xres, mode->yres,
>  		      mode->refresh_specified ? mode->refresh : 60,
>  		      mode->rb ? " reduced blanking" : "",
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index 6debbd6c1763..429d3be17800 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -1580,7 +1580,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>  					       struct drm_cmdline_mode *mode)
>  {
>  	const char *name;
> -	bool parse_extras = false;
> +	bool named_mode = false, 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;
> @@ -1599,8 +1599,22 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>  
>  	name = mode_option;
>  
> -	if (!isdigit(name[0]))
> -		return false;
> +	/*
> +	 * This is a bit convoluted. To differentiate between the
> +	 * named modes and poorly formatted resolutions, we need a
> +	 * bunch of things:
> +	 *   - We need to make sure that the first character (which
> +	 *     would be our resolution in X) is a digit.
> +	 *   - However, if the X resolution is missing, then we end up
> +	 *     with something like x<yres>, with our first character
> +	 *     being an alpha-numerical character, which would be
> +	 *     considered a named mode.
> +	 *
> +	 * If this isn't enough, we should add more heuristics here,
> +	 * and matching unit-tests.
> +	 */
> +	if (!isdigit(name[0]) && name[0] != 'x')
> +		named_mode = true;
>  
>  	/* Try to locate the bpp and refresh specifiers, if any */
>  	bpp_ptr = strchr(name, '-');
> @@ -1611,6 +1625,9 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>  
>  	refresh_ptr = strchr(name, '@');
>  	if (refresh_ptr) {
> +		if (named_mode)
> +			return false;
> +
>  		refresh_off = refresh_ptr - name;
>  		mode->refresh_specified = true;
>  	}
> @@ -1627,12 +1644,16 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>  		parse_extras = true;
>  	}
>  
> -	ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
> -					      parse_extras,
> -					      connector,
> -					      mode);
> -	if (ret)
> -		return false;
> +	if (named_mode) {
> +		strncpy(mode->name, name, mode_end);
> +	} else {
> +		ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
> +						      parse_extras,
> +						      connector,
> +						      mode);
> +		if (ret)
> +			return false;
> +	}
>  	mode->specified = true;
>  
>  	if (bpp_ptr) {
> @@ -1660,14 +1681,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>  		extra_ptr = refresh_end_ptr;
>  
>  	if (extra_ptr) {
> -		int remaining = strlen(name) - (extra_ptr - name);
> +		if (!named_mode) {
> +			int len = strlen(name) - (extra_ptr - name);
>  
> -		/*
> -		 * We still have characters to process, while
> -		 * we shouldn't have any
> -		 */
> -		if (remaining > 0)
> -			return false;
> +			ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
> +							   connector, mode);
> +			if (ret)
> +				return false;
> +		} else {
> +			int remaining = strlen(name) - (extra_ptr - name);
> +
> +			/*
> +			 * We still have characters to process, while
> +			 * we shouldn't have any
> +			 */
> +			if (remaining > 0)
> +				return false;
> +		}
>  	}
>  
>  	return true;
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index c802780b0bfc..cdf2fb910010 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -933,6 +933,13 @@ struct drm_connector_funcs {
>   */
>  struct drm_cmdline_mode {
>  	/**
> +	 * @name:
> +	 *
> +	 * Name of the mode.
> +	 */
> +	char name[DRM_DISPLAY_MODE_LEN];
> +
> +	/**
>  	 * @specified:
>  	 *
>  	 * Has a mode been read from the command-line?
> -- 
> git-series 0.9.1
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5 06/12] drm/modes: Support modes names on the command line
  2019-06-26 15:26   ` Thierry Reding
@ 2019-06-28 13:43     ` Maxime Ripard
  0 siblings, 0 replies; 28+ messages in thread
From: Maxime Ripard @ 2019-06-28 13:43 UTC (permalink / raw)
  To: Thierry Reding
  Cc: eben, David Airlie, Maarten Lankhorst, dri-devel,
	Paul Kocialkowski, Sean Paul, Thomas Petazzoni, Daniel Vetter,
	linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 6252 bytes --]

Hi Thierry,

On Wed, Jun 26, 2019 at 05:26:59PM +0200, Thierry Reding wrote:
> On Mon, Jun 17, 2019 at 04:51:33PM +0200, Maxime Ripard wrote:
> > From: Maxime Ripard <maxime.ripard@free-electrons.com>
> >
> > The drm subsystem also uses the video= kernel parameter, and in the
> > documentation refers to the fbdev documentation for that parameter.
> >
> > However, that documentation also says that instead of giving the mode using
> > its resolution we can also give a name. However, DRM doesn't handle that
> > case at the moment. Even though in most case it shouldn't make any
> > difference, it might be useful for analog modes, where different standards
> > might have the same resolution, but still have a few different parameters
> > that are not encoded in the modes (NTSC vs NTSC-J vs PAL-M for example).
> >
> > Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> >  drivers/gpu/drm/drm_client_modeset.c |  4 ++-
> >  drivers/gpu/drm/drm_connector.c      |  3 +-
> >  drivers/gpu/drm/drm_modes.c          | 62 +++++++++++++++++++++--------
> >  include/drm/drm_connector.h          |  7 +++-
> >  4 files changed, 59 insertions(+), 17 deletions(-)
>
> This patch causes an issue on various Tegra boards that have so far been
> running flawlessly. Here's an extract from the boot log:
>
> 	[    0.000000] Kernel command line: root=/dev/nfs rw netdevwait ip=:::::eth0:on nfsroot=192.168.23.1:/srv/nfs/tegra194 console=ttyTCU0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 rootfstype=ext4 video=tegrafb no_console_suspend=1 earlycon=tegra_comb_uart,mmio32,0x0c168000 gpt usbcore.old_scheme_first=1 tegraid=19.1.2.0.0 maxcpus=8 boot.slot_suffix= boot.ratchetvalues=0.2.2 vpr=0x8000000@0xf0000000 sdhci_tegra.en_boot_part_access=1
> 	...
> 	[   18.597001] [drm:drm_connector_init [drm]] cmdline mode for connector DP-1 tegrafb 0x0@60Hz
> 	...
> 	[   18.627145] [drm:drm_connector_init [drm]] cmdline mode for connector DP-2 tegrafb 0x0@60Hz
> 	...
> 	[   18.673770] [drm:drm_connector_init [drm]] cmdline mode for connector HDMI-A-1 tegrafb 0x0@60Hz
> 	...
> 	[   19.057500] [drm:drm_mode_debug_printmodeline [drm]] Modeline "0x0": 0 0 0 0 0 0 0 1 4 1 0x20 0x6
> 	[   19.066341] [drm:drm_mode_prune_invalid [drm]] Not using 0x0 mode: CLOCK_LOW
> 	...
> 	[   19.677803] [drm:drm_client_modeset_probe [drm]] looking for cmdline mode on connector 60
> 	[   19.686019] [drm:drm_client_modeset_probe [drm]] found mode 0x0
> 	...
> 	[   19.851843] drm drm: failed to set initial configuration: -28
>
> So basically what's happening here is that the bootloader is passing a
> video= parameter on the command-line and after this patch, the DRM core
> will consider the tegrafb in that parameter to be a named video mode.
> The mode is then filtered out because it doesn't make any sense, but
> then drm_client_modeset_probe() still tries to use it, eventually
> leading to failure because we can't allocate memory for a 0x0
> framebuffer.

What was the behaviour before? That it wouldn't set a mode at all?

> Now, there are obviously a couple of places where things go wrong. On
> one hand I think if the mode specified on the command-line is already
> filtered out, then drm_client_modeset_probe() should not be trying to
> use it.

Yeah, that would make sense

> One could also argue that the bootloader shouldn't be passing that
> video=tegrafb parameter in the first place. Then again, this is nothing
> out of the ordinary (as documented in Documentation/fb/modedb.rst).

I've read that documentation, and I'm not sure which section in there
allows to do that?

> The problem with named modes, and you already highlighted this in your
> comment in the code, is that it's not possible to distinguish between a
> mode name and a video= option that defines the framebuffer device to
> use.
>
> That said, I wouldn't be surprised if this change ended up breaking on
> other devices. I'm also not sure that under these circumstances it's a
> good idea to support named modes. At least not until we have a better
> way of determining what's a real mode name and what isn't. Looking at
> the old modedb from fb, not even the standard modes listed there have
> names associated with them, so I'm not sure how this was ever supposed
> to work. From the looks of it, some of the fbdev drivers seem to take a
> mode list from board-code (see for example the mx21ads_modes array from
> arch/arm/mach-imx/mach-mx21ads.c). The imxfb driver can then take a mode
> name from the command line and try to match it against a list of known
> modes. That seems to match what the documentation says.
>
> However, that also really only works because this is all directly dealt
> with in the fbdev drivers. For DRM/KMS we don't do that and instead we
> rely on the core to provide this backwards-compatibility. However, at
> the time when we parse the mode from the command line we don't have the
> list of modes that are considered to be valid, so your patch currently
> needs to assume that it is a valid mode. I don't think that's a good
> idea, because clearly not all strings that currently make it through the
> filter are actually modes.

We have a list of named modes in the connector, and we match against
that. It already works for sunxi (minus the bugs..).

> So if we really need this, I think we want some way for the connector to
> provide the list of named modes that it supports so that by the time we
> want to parse the command-line we can check whether it's actually a name
> to avoid false positives like the ones I'm seeing on Tegra.

I guess that could work yep

> For now it might just be easiest to avoid any of this and disable the
> named mode support until it's a bit more mature. The patch no longer
> reverts cleanly, but it should be fairly easy to disable the feature in
> a follow-up patch again.

If we were to do that, I'd really like to have least get a unit test
for that case, and some documentation on how we're supposed to deal
with this case.

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5 05/12] drm/modes: Rewrite the command line parser
  2019-06-17 14:51 ` [PATCH v5 05/12] drm/modes: Rewrite the command line parser Maxime Ripard
@ 2019-07-05 16:54   ` Dmitry Osipenko
  2019-07-09 12:45     ` Maxime Ripard
  2019-08-19 18:54   ` [v5,05/12] " Jernej Škrabec
  1 sibling, 1 reply; 28+ messages in thread
From: Dmitry Osipenko @ 2019-07-05 16:54 UTC (permalink / raw)
  To: Maxime Ripard, Maarten Lankhorst, Sean Paul, Daniel Vetter, David Airlie
  Cc: eben, dri-devel, Paul Kocialkowski, Thierry Reding,
	Thomas Petazzoni, linux-tegra, Maxime Ripard, linux-arm-kernel

17.06.2019 17:51, Maxime Ripard пишет:
> From: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
> 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@free-electrons.com>
> ---
>  drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++--------------
>  1 file changed, 210 insertions(+), 115 deletions(-)

Hello,

I have a Tegra device that uses a stock android bootloader which passes "video=tegrafb" in
the kernels cmdline. That wasn't a problem before this patch, but now Tegra DRM driver
fails to probe because the mode is 0x0:0 and hence framebuffer allocation fails. Is it a
legit regression that should be fixed in upstream?

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5 05/12] drm/modes: Rewrite the command line parser
  2019-07-05 16:54   ` Dmitry Osipenko
@ 2019-07-09 12:45     ` Maxime Ripard
  2019-07-09 12:52       ` Dmitry Osipenko
  0 siblings, 1 reply; 28+ messages in thread
From: Maxime Ripard @ 2019-07-09 12:45 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: eben, David Airlie, Maarten Lankhorst, dri-devel,
	Paul Kocialkowski, Thierry Reding, Sean Paul, Thomas Petazzoni,
	linux-tegra, Daniel Vetter, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 1246 bytes --]

Hi,

On Fri, Jul 05, 2019 at 07:54:47PM +0300, Dmitry Osipenko wrote:
> 17.06.2019 17:51, Maxime Ripard пишет:
> > From: Maxime Ripard <maxime.ripard@free-electrons.com>
> >
> > 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@free-electrons.com>
> > ---
> >  drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++--------------
> >  1 file changed, 210 insertions(+), 115 deletions(-)
>
> I have a Tegra device that uses a stock android bootloader which
> passes "video=tegrafb" in the kernels cmdline. That wasn't a problem
> before this patch, but now Tegra DRM driver fails to probe because
> the mode is 0x0:0 and hence framebuffer allocation fails. Is it a
> legit regression that should be fixed in upstream?

Thierry indeed reported that issue, but the discussion pretty much
stalled since then.

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5 05/12] drm/modes: Rewrite the command line parser
  2019-07-09 12:45     ` Maxime Ripard
@ 2019-07-09 12:52       ` Dmitry Osipenko
  2019-07-09 13:26         ` Jon Hunter
  0 siblings, 1 reply; 28+ messages in thread
From: Dmitry Osipenko @ 2019-07-09 12:52 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: eben, David Airlie, Maarten Lankhorst, dri-devel,
	Paul Kocialkowski, Thierry Reding, Sean Paul, Thomas Petazzoni,
	linux-tegra, Daniel Vetter, linux-arm-kernel

09.07.2019 15:45, Maxime Ripard пишет:
> Hi,
> 
> On Fri, Jul 05, 2019 at 07:54:47PM +0300, Dmitry Osipenko wrote:
>> 17.06.2019 17:51, Maxime Ripard пишет:
>>> From: Maxime Ripard <maxime.ripard@free-electrons.com>
>>>
>>> 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@free-electrons.com>
>>> ---
>>>  drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++--------------
>>>  1 file changed, 210 insertions(+), 115 deletions(-)
>>
>> I have a Tegra device that uses a stock android bootloader which
>> passes "video=tegrafb" in the kernels cmdline. That wasn't a problem
>> before this patch, but now Tegra DRM driver fails to probe because
>> the mode is 0x0:0 and hence framebuffer allocation fails. Is it a
>> legit regression that should be fixed in upstream?
> 
> Thierry indeed reported that issue, but the discussion pretty much
> stalled since then.

Sorry, this doesn't answer my question. Where it was reported?

If it's a valid regression (my device is broken), then the patch should either be fixed or
reverted.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5 05/12] drm/modes: Rewrite the command line parser
  2019-07-09 12:52       ` Dmitry Osipenko
@ 2019-07-09 13:26         ` Jon Hunter
  2019-07-09 13:28           ` Jon Hunter
  0 siblings, 1 reply; 28+ messages in thread
From: Jon Hunter @ 2019-07-09 13:26 UTC (permalink / raw)
  To: Dmitry Osipenko, Maxime Ripard
  Cc: eben, David Airlie, Maarten Lankhorst, dri-devel,
	Paul Kocialkowski, Thierry Reding, Sean Paul, Thomas Petazzoni,
	linux-tegra, Daniel Vetter, linux-arm-kernel


On 09/07/2019 13:52, Dmitry Osipenko wrote:
> 09.07.2019 15:45, Maxime Ripard пишет:
>> Hi,
>>
>> On Fri, Jul 05, 2019 at 07:54:47PM +0300, Dmitry Osipenko wrote:
>>> 17.06.2019 17:51, Maxime Ripard пишет:
>>>> From: Maxime Ripard <maxime.ripard@free-electrons.com>
>>>>
>>>> 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@free-electrons.com>
>>>> ---
>>>>  drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++--------------
>>>>  1 file changed, 210 insertions(+), 115 deletions(-)
>>>
>>> I have a Tegra device that uses a stock android bootloader which
>>> passes "video=tegrafb" in the kernels cmdline. That wasn't a problem
>>> before this patch, but now Tegra DRM driver fails to probe because
>>> the mode is 0x0:0 and hence framebuffer allocation fails. Is it a
>>> legit regression that should be fixed in upstream?
>>
>> Thierry indeed reported that issue, but the discussion pretty much
>> stalled since then.

Yes Thierry is currently out and hence has not responded. I had been
planning to look at this this week and responded.

> Sorry, this doesn't answer my question. Where it was reported?

Same thread [0]. Dmitry, are you able to respond to Maxime's response to
Thierry?

Cheers
Jon

[0] https://patchwork.kernel.org/patch/10999393/

-- 
nvpublic

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5 05/12] drm/modes: Rewrite the command line parser
  2019-07-09 13:26         ` Jon Hunter
@ 2019-07-09 13:28           ` Jon Hunter
  2019-07-09 13:40             ` Dmitry Osipenko
  0 siblings, 1 reply; 28+ messages in thread
From: Jon Hunter @ 2019-07-09 13:28 UTC (permalink / raw)
  To: Dmitry Osipenko, Maxime Ripard
  Cc: eben, David Airlie, Maarten Lankhorst, dri-devel,
	Paul Kocialkowski, Thierry Reding, Sean Paul, Thomas Petazzoni,
	linux-tegra, Daniel Vetter, linux-arm-kernel


On 09/07/2019 14:26, Jon Hunter wrote:
> 
> On 09/07/2019 13:52, Dmitry Osipenko wrote:
>> 09.07.2019 15:45, Maxime Ripard пишет:
>>> Hi,
>>>
>>> On Fri, Jul 05, 2019 at 07:54:47PM +0300, Dmitry Osipenko wrote:
>>>> 17.06.2019 17:51, Maxime Ripard пишет:
>>>>> From: Maxime Ripard <maxime.ripard@free-electrons.com>
>>>>>
>>>>> 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@free-electrons.com>
>>>>> ---
>>>>>  drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++--------------
>>>>>  1 file changed, 210 insertions(+), 115 deletions(-)
>>>>
>>>> I have a Tegra device that uses a stock android bootloader which
>>>> passes "video=tegrafb" in the kernels cmdline. That wasn't a problem
>>>> before this patch, but now Tegra DRM driver fails to probe because
>>>> the mode is 0x0:0 and hence framebuffer allocation fails. Is it a
>>>> legit regression that should be fixed in upstream?
>>>
>>> Thierry indeed reported that issue, but the discussion pretty much
>>> stalled since then.
> 
> Yes Thierry is currently out and hence has not responded. I had been
> planning to look at this this week and responded.
> 
>> Sorry, this doesn't answer my question. Where it was reported?
> 
> Same thread [0].

Correction, it was on patch 6/12 and not this one.

Jon

-- 
nvpublic

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5 05/12] drm/modes: Rewrite the command line parser
  2019-07-09 13:28           ` Jon Hunter
@ 2019-07-09 13:40             ` Dmitry Osipenko
  0 siblings, 0 replies; 28+ messages in thread
From: Dmitry Osipenko @ 2019-07-09 13:40 UTC (permalink / raw)
  To: Jon Hunter, Maxime Ripard
  Cc: eben, David Airlie, Maarten Lankhorst, dri-devel,
	Paul Kocialkowski, Thierry Reding, Sean Paul, Thomas Petazzoni,
	linux-tegra, Daniel Vetter, linux-arm-kernel

09.07.2019 16:28, Jon Hunter пишет:
> 
> On 09/07/2019 14:26, Jon Hunter wrote:
>>
>> On 09/07/2019 13:52, Dmitry Osipenko wrote:
>>> 09.07.2019 15:45, Maxime Ripard пишет:
>>>> Hi,
>>>>
>>>> On Fri, Jul 05, 2019 at 07:54:47PM +0300, Dmitry Osipenko wrote:
>>>>> 17.06.2019 17:51, Maxime Ripard пишет:
>>>>>> From: Maxime Ripard <maxime.ripard@free-electrons.com>
>>>>>>
>>>>>> 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@free-electrons.com>
>>>>>> ---
>>>>>>  drivers/gpu/drm/drm_modes.c | 325 +++++++++++++++++++++++--------------
>>>>>>  1 file changed, 210 insertions(+), 115 deletions(-)
>>>>>
>>>>> I have a Tegra device that uses a stock android bootloader which
>>>>> passes "video=tegrafb" in the kernels cmdline. That wasn't a problem
>>>>> before this patch, but now Tegra DRM driver fails to probe because
>>>>> the mode is 0x0:0 and hence framebuffer allocation fails. Is it a
>>>>> legit regression that should be fixed in upstream?
>>>>
>>>> Thierry indeed reported that issue, but the discussion pretty much
>>>> stalled since then.
>>
>> Yes Thierry is currently out and hence has not responded. I had been
>> planning to look at this this week and responded.
>>
>>> Sorry, this doesn't answer my question. Where it was reported?
>>
>> Same thread [0].
> 
> Correction, it was on patch 6/12 and not this one.

Thank you very much, Jon! So looks like this patch is simply broken because it silently
copies the "mode's name" and then drm_connector_get_cmdline_mode() doesn't even try to
validate the mode.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [v5,05/12] drm/modes: Rewrite the command line parser
  2019-06-17 14:51 ` [PATCH v5 05/12] drm/modes: Rewrite the command line parser Maxime Ripard
  2019-07-05 16:54   ` Dmitry Osipenko
@ 2019-08-19 18:54   ` Jernej Škrabec
  2019-08-19 19:20     ` Thomas Graichen
  1 sibling, 1 reply; 28+ messages in thread
From: Jernej Škrabec @ 2019-08-19 18:54 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: eben, David Airlie, thomas.graichen, Maarten Lankhorst,
	dri-devel, Paul Kocialkowski, Sean Paul, Thomas Petazzoni,
	Daniel Vetter, Maxime Ripard, linux-arm-kernel

+CC: Thomas Graichen

Dne ponedeljek, 17. junij 2019 ob 16:51:32 CEST je Maxime Ripard napisal(a):
> From: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
> 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@free-electrons.com>

Thomas reported to me that this patch breaks "video=CONNECTOR:e" kernel 
parameter which he currently uses as a workaround for H6 HDMI monitor 
detection issue on one STB.

I suppose this is the same issue that Dmitry noticed.

Thomas Graichen (in CC) can provide more information if needed.

Best regards,
Jernej




_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [v5,05/12] drm/modes: Rewrite the command line parser
  2019-08-19 18:54   ` [v5,05/12] " Jernej Škrabec
@ 2019-08-19 19:20     ` Thomas Graichen
  2019-08-20 15:00       ` Maxime Ripard
  0 siblings, 1 reply; 28+ messages in thread
From: Thomas Graichen @ 2019-08-19 19:20 UTC (permalink / raw)
  To: Jernej Škrabec
  Cc: eben, Maxime Ripard, Maarten Lankhorst, dri-devel,
	Paul Kocialkowski, David Airlie, Sean Paul, Thomas Petazzoni,
	Daniel Vetter, Maxime Ripard, linux-arm-kernel

On Mon, Aug 19, 2019 at 8:54 PM Jernej Škrabec <jernej.skrabec@gmail.com> wrote:
>
> +CC: Thomas Graichen
>
> Dne ponedeljek, 17. junij 2019 ob 16:51:32 CEST je Maxime Ripard napisal(a):
> > From: Maxime Ripard <maxime.ripard@free-electrons.com>
> >
> > 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@free-electrons.com>
>
> Thomas reported to me that this patch breaks "video=CONNECTOR:e" kernel
> parameter which he currently uses as a workaround for H6 HDMI monitor
> detection issue on one STB.
>
> I suppose this is the same issue that Dmitry noticed.
>
> Thomas Graichen (in CC) can provide more information if needed.
>
> Best regards,
> Jernej

as jernej already mentioned i am currently having to use the kernel
cmdline option video=HDMI-A-1:e to get a working hdmi output on an
eachlink h6 mini tv box and was wondering that i did not get any hdmi
output even with this option when switching from the
https://github.com/megous/linux oprange-pi-5.2 to the orange-pi-5.3
branch which seems to contain this patch. as i had no idea what might
have caused the breakage of the hdmi output and did a full bisect of
the kernel between those two versions, which ended reliably at exactly
this patch - so i guess there is a regression at least with the
video=CONNECTOR:e option (maybe others too?) with this patches code
which makes it not working anymore.

best wishes - thomas

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [v5,05/12] drm/modes: Rewrite the command line parser
  2019-08-19 19:20     ` Thomas Graichen
@ 2019-08-20 15:00       ` Maxime Ripard
  2019-08-23 14:04         ` Thomas Graichen
  0 siblings, 1 reply; 28+ messages in thread
From: Maxime Ripard @ 2019-08-20 15:00 UTC (permalink / raw)
  To: Thomas Graichen
  Cc: eben, David Airlie, Maarten Lankhorst, Jernej Škrabec,
	Paul Kocialkowski, Sean Paul, dri-devel, Thomas Petazzoni,
	Daniel Vetter, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 2431 bytes --]

Hi,

On Mon, Aug 19, 2019 at 09:20:00PM +0200, Thomas Graichen wrote:
> On Mon, Aug 19, 2019 at 8:54 PM Jernej Škrabec <jernej.skrabec@gmail.com> wrote:
> >
> > +CC: Thomas Graichen
> >
> > Dne ponedeljek, 17. junij 2019 ob 16:51:32 CEST je Maxime Ripard napisal(a):
> > > From: Maxime Ripard <maxime.ripard@free-electrons.com>
> > >
> > > 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@free-electrons.com>
> >
> > Thomas reported to me that this patch breaks "video=CONNECTOR:e" kernel
> > parameter which he currently uses as a workaround for H6 HDMI monitor
> > detection issue on one STB.
> >
> > I suppose this is the same issue that Dmitry noticed.
> >
> > Thomas Graichen (in CC) can provide more information if needed.
>
> as jernej already mentioned i am currently having to use the kernel
> cmdline option video=HDMI-A-1:e to get a working hdmi output on an
> eachlink h6 mini tv box and was wondering that i did not get any hdmi
> output even with this option when switching from the
> https://github.com/megous/linux oprange-pi-5.2 to the orange-pi-5.3
> branch which seems to contain this patch.

Which kernel version is that based on?

> as i had no idea what might have caused the breakage of the hdmi
> output and did a full bisect of the kernel between those two
> versions, which ended reliably at exactly this patch - so i guess
> there is a regression at least with the video=CONNECTOR:e option
> (maybe others too?) with this patches code which makes it not
> working anymore.

I'm not sure I'll have the time to look into it this week (or the
next, unfortunately). However, the e parameter is supposed to be
parsed by drm_mode_parse_cmdline_extra, which in turn is supposed to
be called there:
https://elixir.bootlin.com/linux/v5.3-rc5/source/drivers/gpu/drm/drm_modes.c#L1810

If you can test that, having an idea of if that function is called,
which return code it returns, and if it isn't if why would be super
helpful.

Thanks!
Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [v5,05/12] drm/modes: Rewrite the command line parser
  2019-08-20 15:00       ` Maxime Ripard
@ 2019-08-23 14:04         ` Thomas Graichen
  0 siblings, 0 replies; 28+ messages in thread
From: Thomas Graichen @ 2019-08-23 14:04 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: eben, David Airlie, Maarten Lankhorst, Jernej Škrabec,
	Paul Kocialkowski, Sean Paul, dri-devel, Thomas Petazzoni,
	Daniel Vetter, linux-arm-kernel

hi maxim,

On Tue, Aug 20, 2019 at 5:00 PM Maxime Ripard <maxime.ripard@bootlin.com> wrote:
>
> Hi,
>
> On Mon, Aug 19, 2019 at 09:20:00PM +0200, Thomas Graichen wrote:
> > On Mon, Aug 19, 2019 at 8:54 PM Jernej Škrabec <jernej.skrabec@gmail.com> wrote:
> > >
> > > +CC: Thomas Graichen
> > >
> > > Dne ponedeljek, 17. junij 2019 ob 16:51:32 CEST je Maxime Ripard napisal(a):
> > > > From: Maxime Ripard <maxime.ripard@free-electrons.com>
> > > >
> > > > 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@free-electrons.com>
> > >
> > > Thomas reported to me that this patch breaks "video=CONNECTOR:e" kernel
> > > parameter which he currently uses as a workaround for H6 HDMI monitor
> > > detection issue on one STB.
> > >
> > > I suppose this is the same issue that Dmitry noticed.
> > >
> > > Thomas Graichen (in CC) can provide more information if needed.
> >
> > as jernej already mentioned i am currently having to use the kernel
> > cmdline option video=HDMI-A-1:e to get a working hdmi output on an
> > eachlink h6 mini tv box and was wondering that i did not get any hdmi
> > output even with this option when switching from the
> > https://github.com/megous/linux oprange-pi-5.2 to the orange-pi-5.3
> > branch which seems to contain this patch.
>
> Which kernel version is that based on?

5.3-rc3

> > as i had no idea what might have caused the breakage of the hdmi
> > output and did a full bisect of the kernel between those two
> > versions, which ended reliably at exactly this patch - so i guess
> > there is a regression at least with the video=CONNECTOR:e option
> > (maybe others too?) with this patches code which makes it not
> > working anymore.
>
> I'm not sure I'll have the time to look into it this week (or the
> next, unfortunately). However, the e parameter is supposed to be
> parsed by drm_mode_parse_cmdline_extra, which in turn is supposed to
> be called there:
> https://elixir.bootlin.com/linux/v5.3-rc5/source/drivers/gpu/drm/drm_modes.c#L1810
>
> If you can test that, having an idea of if that function is called,
> which return code it returns, and if it isn't if why would be super
> helpful.

i just added a printk and it looks like it is not getting called:

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index b0369e690f36..4c58fdb1d7be 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1813,6 +1813,7 @@ bool
drm_mode_parse_command_line_for_connector(const char *mode_option,

                ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
                                                   connector, mode);
+               printk(KERN_WARNING "DEBUG -
drm_mode_parse_cmdline_extra %d", ret);
                if (ret)
                        return false;
        }

no output from it in dmesg (my loglevel=8 and on the kernel cmdline
and in /proc/cmdline i have "video=HDMI-A-1:e") - so looks like it
really gets lost somewhere along the way ...

best wishes - thomas

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2019-08-23 14:04 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-17 14:51 [PATCH v5 00/12] drm/vc4: Allow for more boot-time configuration Maxime Ripard
2019-06-17 14:51 ` [PATCH v5 01/12] drm/connector: Add documentation for drm_cmdline_mode Maxime Ripard
2019-06-17 14:51 ` [PATCH v5 02/12] drm/client: Restrict the plane_state scope Maxime Ripard
2019-06-17 14:51 ` [PATCH v5 03/12] drm/client: Restrict the rotation check to the rotation itself Maxime Ripard
2019-06-17 14:51 ` [PATCH v5 04/12] drm/client: Change drm_client_panel_rotation name Maxime Ripard
2019-06-17 14:51 ` [PATCH v5 05/12] drm/modes: Rewrite the command line parser Maxime Ripard
2019-07-05 16:54   ` Dmitry Osipenko
2019-07-09 12:45     ` Maxime Ripard
2019-07-09 12:52       ` Dmitry Osipenko
2019-07-09 13:26         ` Jon Hunter
2019-07-09 13:28           ` Jon Hunter
2019-07-09 13:40             ` Dmitry Osipenko
2019-08-19 18:54   ` [v5,05/12] " Jernej Škrabec
2019-08-19 19:20     ` Thomas Graichen
2019-08-20 15:00       ` Maxime Ripard
2019-08-23 14:04         ` Thomas Graichen
2019-06-17 14:51 ` [PATCH v5 06/12] drm/modes: Support modes names on the command line Maxime Ripard
2019-06-26 15:26   ` Thierry Reding
2019-06-28 13:43     ` Maxime Ripard
2019-06-17 14:51 ` [PATCH v5 07/12] drm/modes: Allow to specify rotation and reflection on the commandline Maxime Ripard
2019-06-18 17:47   ` Noralf Trønnes
2019-06-19 10:16     ` Maxime Ripard
2019-06-17 14:51 ` [PATCH v5 08/12] drm/connector: Introduce a TV margins structure Maxime Ripard
2019-06-17 14:51 ` [PATCH v5 09/12] drm/modes: Parse overscan properties Maxime Ripard
2019-06-17 14:51 ` [PATCH v5 10/12] drm/atomic: Add a function to reset connector TV properties Maxime Ripard
2019-06-17 14:51 ` [PATCH v5 11/12] drm/selftests: Add command line parser selftests Maxime Ripard
2019-06-17 14:51 ` [PATCH v5 12/12] drm/vc4: hdmi: Set default state margin at reset Maxime Ripard
2019-06-17 18:06   ` Eric Anholt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).